Author: timbo
Date: Tue Mar 29 03:28:23 2005
New Revision: 940

Modified:
   dbi/trunk/DBI.pm
   dbi/trunk/DBI.xs
   dbi/trunk/t/11fetch.t
   dbi/trunk/t/70callbacks.t
Log:
Callbacks invoked with local $_ = method_name
Callbacks are passed all parameters of corresponding method call.
Special case "connect" callback removed, added "connect_cached.new" special 
case.
Added tests.


Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Tue Mar 29 03:28:23 2005
@@ -652,12 +652,6 @@
        # if we've been subclassed then let the subclass know that we're 
connected
        $dbh->connected($dsn, $user, $pass, $attr) if ref $dbh ne 'DBI::db';
 
-       # If the caller has provided a callback then call it
-       if (my $cb = $dbh->{Callbacks}) { # take care not to autovivify
-           $cb = $cb->{connect};
-           $cb->($dbh, $dsn, $user, $pass, $attr) if $cb;
-       }
-
        DBI->trace_msg("    <- connect= $dbh\n") if $DBI::dbi_debug;
 
        return $dbh;
@@ -1410,14 +1404,22 @@
            join "~~", $dsn, $user||'', $auth||'', $attr ? (@attr_keys,@[EMAIL 
PROTECTED]) : ()
        };
        my $dbh = $cache->{$key};
+        my $cb = $attr->{Callbacks}; # take care not to autovivify
        if ($dbh && $dbh->FETCH('Active') && eval { $dbh->ping }) {
             # If the caller has provided a callback then call it
-            if (my $cb = $dbh->{Callbacks}) { # take care not to autovivify
-                $cb = $cb->{"connect_cached.reused"};
-                $cb->($dbh, $dsn, $user, $auth, $attr) if $cb;
+            if ($cb and $cb = $cb->{"connect_cached.reused"}) {
+               local $_ = "connect_cached.reused";
+               $cb->($dbh, $dsn, $user, $auth, $attr);
             }
            return $dbh;
        }
+
+       # If the caller has provided a callback then call it
+       if ($cb and $cb = $cb->{"connect_cached.new"}) {
+           local $_ = "connect_cached.new";
+           $cb->($dbh, $dsn, $user, $auth, $attr);
+       }
+
        $dbh = $drh->connect(@_);
        $cache->{$key} = $dbh;  # replace prev entry, even if connect failed
        return $dbh;

Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs    (original)
+++ dbi/trunk/DBI.xs    Tue Mar 29 03:28:23 2005
@@ -2408,18 +2408,28 @@
        && (hook_svp = hv_fetch((HV*)SvRV(*hook_svp), meth_name, 
strlen(meth_name), 0))
        && SvROK(*hook_svp)
     ) {
-       dSP;
        SV *code = SvRV(*hook_svp);
+       I32 count;
        if (trace_level)
            PerlIO_printf(DBILOGFP, "%c   {{ %s callback %s being invoked\n",
                (dirty?'!':' '), meth_name, neatsvpv(*hook_svp,0));
+       ENTER;
+       SAVETMPS;
+       EXTEND(SP, items+1);
        PUSHMARK(SP);
-       XPUSHs(h);
-       /* XXX add more params */
+       PUSHs(h);                       /* push inner handle, then others 
params */
+       for (i=1; i < items; ++i) {     /* start at 1 to skip handle */
+           PUSHs( ST(i) );
+       }
        PUTBACK;
-       if (call_sv(code, G_ARRAY))
-           die("Callback for %s must not return any values (temporary 
restriction in current version)");
+       SAVE_DEFSV; /* local($_) = $method_name */
+       DEFSV = sv_2mortal(newSVpv(meth_name,0));
+       count = call_sv(code, G_ARRAY);
+       if (count != 0)
+           die("Callback for %s returned %d values but must not return any 
(temporary restriction in current version)", meth_name, count);
        SPAGAIN;
+       FREETMPS;
+       LEAVE;
        if (trace_level)
            PerlIO_printf(DBILOGFP, "%c   }} %s callback %s returned\n",
                (dirty?'!':' '), meth_name, neatsvpv(*hook_svp,0));

Modified: dbi/trunk/t/11fetch.t
==============================================================================
--- dbi/trunk/t/11fetch.t       (original)
+++ dbi/trunk/t/11fetch.t       Tue Mar 29 03:28:23 2005
@@ -104,4 +104,4 @@
 }
 
 
-# end
+1; # end

Modified: dbi/trunk/t/70callbacks.t
==============================================================================
--- dbi/trunk/t/70callbacks.t   (original)
+++ dbi/trunk/t/70callbacks.t   Tue Mar 29 03:28:23 2005
@@ -1,4 +1,5 @@
 #!perl -w
+# vim:ts=8:sw=4
 
 use strict;
 
@@ -8,7 +9,7 @@
 BEGIN {
         plan skip_all => '$h->{Callbacks} attribute not supported for 
DBI::PurePerl'
                 if $DBI::PurePerl && $DBI::PurePerl; # doubled to avoid typo 
warning
-        plan tests => 24;
+        plan tests => 35;
 }
 
 $| = 1;
@@ -25,13 +26,43 @@
 $dbh->{Callbacks} = undef;
 is $dbh->{Callbacks}, undef, "Callbacks set to undef again";
 
-ok $dbh->{Callbacks} = { ping => sub { $called{ping}++; return; } };
-is keys %{ $dbh->{Callbacks} }, 1;
+ok $dbh->{Callbacks} = {
+    ping => sub {
+       is $_, 'ping', '$_ holds method name';
+       $called{$_}++;
+       return;
+    },
+    quote_identifier => sub {
+       is @_, 4, '@_ holds 4 values';
+       my $dbh = shift;
+       is ref $dbh, 'DBI::db', 'first is $dbh';
+       is $_[0], 'foo';
+       is $_[1], 'bar';
+       is $_[2], undef;
+       $_[2] = { baz => 1 };
+       is $_, 'quote_identifier', '$_ holds method name';
+       $called{$_}++;
+       return (1,2,3); # return something
+    },
+};
+is keys %{ $dbh->{Callbacks} }, 2;
+
 is ref $dbh->{Callbacks}->{ping}, 'CODE';
+
+$_ = 42;
 ok $dbh->ping;
 is $called{ping}, 1;
+is $_, 42, '$_ not altered by callback';
+
 ok $dbh->ping;
 is $called{ping}, 2;
+
+my $attr;
+eval { $dbh->quote_identifier('foo','bar', $attr) };
+is $called{quote_identifier}, 1;
+ok $@, 'quote_identifier callback caused fatal error';
+is ref $attr, 'HASH', 'param modified by callback - not recommended!';
+
 $dbh->{Callbacks} = undef;
 ok $dbh->ping;
 is $called{ping}, 2;
@@ -39,12 +70,12 @@
 =for comment XXX
 
 The big problem here is that conceptually the Callbacks attribute
-is # applied to the $dbh _during_ the $drh->connect() call, so you can't
+is applied to the $dbh _during_ the $drh->connect() call, so you can't
 set a callback on "connect" on the $dbh because connect isn't called
 on the dbh, but on the $drh.
 
 So a "connect" callback would have to be defined on the $drh, but that's
-cumbersom for the user and then it would apply to all future connects
+cumbersome for the user and then it would apply to all future connects
 using that driver.
 
 The best thing to do is probably to special-case "connect", "connect_cached"
@@ -55,21 +86,22 @@
 my @args = (
     $dsn, '', '', {
         Callbacks => {
-            connect                 => sub { $called{connect}++; return; },
+            "connect_cached.new"    => sub { $called{new}++; return; },
             "connect_cached.reused" => sub { $called{cached}++; return; },
         }
     }
 );
 
+%called = ();
+
 ok $dbh = DBI->connect(@args), "Create handle with callbacks";
-is $called{connect}, 1, "Connect callback called once.";
-is $called{cached}, undef, "Cached not yet called";
+is keys %called, 0, 'no callback for plain connect';
 
 ok $dbh = DBI->connect_cached(@args), "Create handle with callbacks";
-is $called{connect}, 2, "Connect callback called by connect_cached.";
-is $called{cached}, undef, "Cached still not yet called";
+is $called{new}, 1, "connect_cached.new called";
+is $called{cached}, undef, "connect_cached.reused not yet called";
 
 ok $dbh = DBI->connect_cached(@args), "Create handle with callbacks";
-is $called{connect}, 3, "Connect callback called by second connect_cached.";
-is $called{cached}, 1, "Cached called";
+is $called{cached}, 1, "connect_cached.reused called";
+is $called{new}, 1, "connect_cached.new not called again";
 

Reply via email to