Re: Time to Document Callbacks
"David E. Wheeler" <[email protected]>
| Newsgroups | gmane.comp.lang.perl.modules.dbi.sybase.devel |
|---|---|
| Message-ID | <[email protected]> |
On Oct 26, 2009, at 1:59 PM, Tim Bunce wrote:
>> It output nothing. When I uncommented that second-to-last line, it
>> output
>> "Set in STH". So it seems that a callback added to the dbh for a
>> statement
>> method name does not end up getting passed on to the statement
>> handle. So I
>> guess the Callbacks attribute is not passed on to statement handles
>> created
>> for the database handle?
>
> Yeap.
>
>> Seems a shame…
>
> I recall thinking about it but opting not to. I can't recall why
> though.
> Possibly just to err on the side of caution.
>
> I'm open to persuasion.
I understand the caution, but it does seem inconsistent to me. I'd
really like to be able to set STH callbacks once in a DBH and be done
with it, just as a I can any other DBH attributes that also apply to
STHs.
>> One other thing: It's nice that the callbacks execute before the
>> method
>> call, so that you can disable it by undefing $_. But it'd be
>> equally handle
>> to have callbacks after the method call.
>
> Yes, I'd always planned for that but never had a need to implement
> it myself.
> I'd figured the callback code ref could, optionally, be an array ref
> and
> if so, the second element would be the callback to call on method
> return.
Yes, I saw that in our [exchange](http://markmail.org/message/m2lr3n74nluh52jn
) in 2005. What would it take to make this happen?
> Note that a post-prepare() callback could be used to implement
> inheritance of Callbacks.
>
> (If the method attributes of prepare($sql, \%attr) were applied to the
> newly created sth, in the same way as connect(), then a pre-prepare
> callback could be used to pass down the $dbh->{Callbacks} to the
> $sth.)
Oh, that kind of callback. I'd love to see attributes to prepare
passed on to the sth. It makes perfect sense to me. I note that you
thought in 2005 that it wouldn't happen before DBI2, but since that's
probably another 5 years away at this rate…
>> For example, I'd love to be able
>> to create a callback on a statement handle to convert a timestamp
>> column to
>> a DateTime object:
>>
>> $sth->{PostCallbacks}{fetch} = sub {
>> my ($sth, $row) = @_;
>> $row->[3] = DateTime::Format::Pg->parse_datetime($row->[3]);
>> };
>
> That particular example is potentially risky - or at least unportable.
> What if the driver doesn't implement a higher-level method (like
> fetchrow_hashref or fetchall_* etc) in terms of fetch?
Is that not a problem for any callback on any driver-implemented method?
> I've always felt the best way to do that kind of thing would be to
> tie()
> the individual elements of the row buffer array - but I've never
> needed
> to do it myself so never explored it.
Well, and tie is pretty hackish IMHO. But let me cite another example.
In our prior discussions, you [wrote](http://markmail.org/message/dgnpmnzkk4g532lc
):
> Note that sth callbacks, for example, give you a relatively clean
> way to set the UTF8 flag on fetched data.
Given that callbacks execute before data is fetched, how, exactly,
could this be done with the current implementation? I would exepct
something like this (using post-callbacks):
$sth->{PostCallbacks}{fetch} = sub {
my ($sth, $row) = @_;
Encode::_utf8_on $_ for @$row;
return;
};
But that obviously won't work.
> Another issue to keep in mind is that there's only one callback per
> method.
> In other words there's no way for multiple callbacks for a single
> method to coexist on a handle. That limits the usefulness of Callbacks
> in general.
Maybe. I don't think it's like JavaScript where you have any number of
libraries all adding their callbacks to global DOM elements. We have
lexical handles that can be modified only in scope. I don't think
there's much need to worry about supporting multiple callbacks until
someone needs them. And even then I'd suggest:
if (my $cb = $sth->{Callbacks}{fetch}) {
$sth->{Callbacks}{fetch} = sub {
$cb->(@_);
... #other stuff ...
}
} else {
$sth->{Callbacks}{fetch} = sub {
... #other stuff ...
}
}
I dont think additional infrastructure is needed until the cowpaths
demand it.
> Ideally I'd like to see an abstract interface for managing callbacks,
> rather than the current "stuff it in a hash". That way future support
> for post-method callbacks and multi-callbacks per method and handle
> could be added without exposing (and locking us into) particular
> implementation details.
Do you have something in mind? What would it look like?
Best,
David