Author: timbo
Date: Fri Jun  5 15:13:00 2009
New Revision: 12810

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm
   dbi/trunk/DBI.xs
   dbi/trunk/t/72childhandles.t

Log:
Added DBI->visit_handles($coderef) method.
Added $h->visit_child_handles($coderef) method.


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Fri Jun  5 15:13:00 2009
@@ -59,10 +59,11 @@
   Fixes to DBD::File (H.Merijn Brand)
     added f_schema attribute
     table names case sensitive when quoted, insensitive when unquoted
-    workaround a bug in SQL::Statement (temporary fix)
-      "You passed x parameters where y required" now only warns if it
-      finds a mismatch on the first execute of the handle
+    workaround a bug in SQL::Statement (temporary fix) related
+      to the "You passed x parameters where y required" error
 
+  Added DBI->visit_handles($coderef) method.
+  Added $h->visit_child_handles($coderef) method.
   Added docs form column_info()'s COLUMN_DEF value.
   Clarified docs on stickyness of data type via bind_param().
   Clarified docs on stickyness of data type via bind_col().

Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Fri Jun  5 15:13:00 2009
@@ -399,6 +399,7 @@
        trace_msg       => { U =>[2,3,'$message_text [, $min_level ]' ],        
O=>0x0004, T=>8 },
        swap_inner_handle => { U =>[2,3,'$h [, $allow_reparent ]'] },
         private_attribute_info => { },
+        visit_child_handles => { U => [2,3,'$coderef [, $info ]'], O=>0x0404, 
T=>4 },
     },
     dr => {            # Database Driver Interface
        'connect'  =>   { U =>[1,5,'[$db [,$user [,$passwd [,\%attr]]]]'], 
H=>3, O=>0x8000 },
@@ -534,6 +535,18 @@
     return ($scheme, $driver, $attr, $attr_hash, $dsn);
 }
 
+sub visit_handles {
+    my ($class, $code, $outer_info) = @_;
+    $outer_info = {} if not defined $outer_info;
+    my %drh = DBI->installed_drivers;
+    for my $h (values %drh) {
+       my $child_info = $code->($h, $outer_info)
+           or next;
+       $h->visit_child_handles($code, $child_info);
+    }
+    return $outer_info;
+}
+
 
 # --- The DBI->connect Front Door methods
 
@@ -1399,6 +1412,17 @@
         return undef;
     }
 
+    sub visit_child_handles {
+       my ($h, $code, $info) = @_;
+       $info = {} if not defined $info;
+       for my $ch (@{ $h->{ChildHandles} || []}) {
+           next unless $ch;
+           my $child_info = $code->($ch, $info)
+               or next;
+           $ch->visit_child_handles($code, $child_info);
+       }
+       return $info;
+    }
 }
 
 
@@ -2860,6 +2884,31 @@
 tracing facilities.
 
 
+=head3 C<visit_handles>
+
+  DBI->visit_handles( $coderef );
+  DBI->visit_handles( $coderef, $info );
+
+Where $coderef is a reference to a subroutine and $info is an arbitrary value
+which, if undefined, defaults to a reference to an empty hash. Returns $info.
+
+For each installed driver handle, if any, $coderef is invoked as:
+
+  $coderef->($driver_handle, $info);
+
+If the execution of $coderef returns a true value then L</visit_child_handles>
+is called on that child handle and passed the returned value as $info.
+
+For example:
+
+  my $info = $dbh->{Driver}->visit_child_handles(sub {
+      my ($h, $info) = @_;
+      ++$info->{ $h->{Type} }; # count types of handles (dr/db/st)
+      return $info; # visit kids
+  });
+
+See also L</visit_child_handles>.
+
 
 =head2 DBI Utility Functions
 
@@ -3327,6 +3376,32 @@
             dbh1o -> dbh2i
             sthAo -> sthBi(dbh2i)
 
+=head3 C<visit_child_handles>
+
+  $h->visit_child_handles( $coderef );
+  $h->visit_child_handles( $coderef, $info );
+
+Where $coderef is a reference to a subroutine and $info is an arbitrary value
+which, if undefined, defaults to a reference to an empty hash. Returns $info.
+
+For each child handle of $h, if any, $coderef is invoked as:
+
+  $coderef->($child_handle, $info);
+
+If the execution of $coderef returns a true value then C<visit_child_handles>
+is called on that child handle and passed the returned value as $info.
+
+For example:
+
+  # count database connections with names (DSN) matching a pattern
+  my $connections = 0;
+  $dbh->{Driver}->visit_child_handles(sub {
+      my ($h, $info) = @_;
+      ++$connections if $h->{Name} =~ /foo/;
+      return 0; # don't visit kids
+  })
+
+See also L</visit_handles>.
 
 =head1 ATTRIBUTES COMMON TO ALL HANDLES
 

Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs    (original)
+++ dbi/trunk/DBI.xs    Fri Jun  5 15:13:00 2009
@@ -111,7 +111,7 @@
 #define IMA_NO_TAINT_IN        0x0010  /* don't check for tainted args */
 #define IMA_NO_TAINT_OUT       0x0020  /* don't taint results          */
 #define IMA_COPY_UP_STMT       0x0040  /* copy sth Statement to dbh    */
-#define IMA_END_WORK           0x0080  /* set on commit & rollback     */
+#define IMA_END_WORK           0x0080  /* method is commit or rollback */
 #define IMA_STUB               0x0100  /* donothing eg $dbh->connected */
 #define IMA_CLEAR_STMT         0x0200  /* clear Statement before call  */
 #define IMA_UNRELATED_TO_STMT  0x0400  /* profile as empty Statement   */

Modified: dbi/trunk/t/72childhandles.t
==============================================================================
--- dbi/trunk/t/72childhandles.t        (original)
+++ dbi/trunk/t/72childhandles.t        Fri Jun  5 15:13:00 2009
@@ -23,7 +23,7 @@
     exit 0;
 }
 
-plan tests => 14;
+plan tests => 16;
 
 my $using_dbd_gofer = ($ENV{DBI_AUTOPROXY}||'') =~ /^dbi:Gofer.*transport=/i;
 
@@ -101,6 +101,38 @@
 my @live = grep { defined $_ } @$handles;
 is scalar @live, 0, "handles should be gone now";
 
+# test visit_child_handles
+{
+    my $info;
+    my $visitor = sub {
+        my ($h, $info) = @_;
+        my $type = $h->{Type};
+        ++$info->{ $type }{ ($type eq 'st') ? $h->{Statement} : $h->{Name} };
+        return $info;
+    };
+    DBI->visit_handles($visitor, $info = {});
+    is_deeply $info, {
+        'dr' => {
+            'ExampleP' => 1,
+            ($using_dbd_gofer) ? (Gofer => 1) : ()
+        },
+        'db' => { '' => 1 },
+    };
+
+    my $sth1 = $dbh->prepare('SELECT name FROM t');
+    my $sth2 = $dbh->prepare('SELECT name FROM t');
+    DBI->visit_handles($visitor, $info = {});
+    is_deeply $info, {
+        'dr' => {
+            'ExampleP' => 1,
+            ($using_dbd_gofer) ? (Gofer => 1) : ()
+        },
+        'db' => { '' => 1 },
+        'st' => { 'SELECT name FROM t' => 2 }
+    };
+
+}
+
 # test that the childhandle array does not grow uncontrollably
 SKIP: {
     skip "slow tests avoided when using DBD::Gofer", 2 if $using_dbd_gofer;

Reply via email to