perl5-dbi / dbi

DBI - The Perl 5 Database Interface
Other
81 stars 58 forks source link

Reordering @_ in Callbacks #115

Open CyprusSocialite opened 6 months ago

CyprusSocialite commented 6 months ago

I am subclassing DBI and am using @bind_values quite heavily, unlike \%attr. For convenience and aesthetics, I prefer to supply @bind_values right after $statement, with \%attr at the very end.

In the code this is achieved like so:

my $dbh = MyDBI->connect(..., {
    Callbacks => {
        selectall_arrayref => sub {
            splice @_, 2, 0, ((ref($_[-1]) eq 'HASH') ? pop : undef);
            return;
        }
    }
});

$dbh->selectall_arrayref('select foo from bar where baz = ?' => 'value');

_(note the use of fat comma to connect $statement with @bind_values, which brings me immense aesthetic pleasure)_

For some inexplicable reason, though, the above results in the following call:

DBD::mysql::db::prepare(MyDBI::db=HASH(...), "select foo from bar where baz = ?", "value");

and then DBD::mysql::st::_prepare gets $attribs = "value" and tries to dereference that as a hash - disastrously.

This does not look like a copy vs reference issue. If my callback simply alters some argument (eg the statement string), it goes on to DBD::mysql::db::prepare in this altered state as expected, but perhaps DBI's implementation of selectall_arrayref splits @_ into separate references, thereby allowing for modification but not reordering?

mauke commented 1 month ago

This does not look like a copy vs reference issue.

I disagree. Modifying @_ does not alter the caller's argument list. Only the elements of @_ (i.e. $_[0], $_[1], $_[2], etc) are aliases of the passed-in arguments; the @_ array itself is not.