Author: theory
Date: Tue Mar  2 17:04:12 2010
New Revision: 13835

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm

Log:
Document the `Callbacks` attribute.

Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Tue Mar  2 17:04:12 2010
@@ -6,8 +6,6 @@
 
 =cut
 
-XXX awaiting docs for Callbacks and ChildCallbacks from David Wheeler
-
 =head2 Changes in DBI 1.611 (svn r13833) 2nd March 2010
 
   NOTE: minimum perl version is now 5.8.1 (as announced in DBI 1.607)
@@ -37,6 +35,7 @@
   Updated DBI::Profile and DBD::File docs to fix pod nits
     thanks to Frank Wiegand.
   Corrected typos in Gopher documentation reported by Jan Krynicky.
+  Documented the Callbacks attribute.
 
   Updated dbipport.h to Devel::PPPort 3.19 (H.Merijn Brand)
 

Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Tue Mar  2 17:04:12 2010
@@ -3991,6 +3991,147 @@
 
 The attribute should be set to 1 or 0 (or undef). Other values are reserved.
 
+=head3 C<Callbacks> (hash ref)
+
+The DBI callback mechanism lets you intercept, and optionally replace, any
+method call on a DBI handle. At the extreme, it lets you become a puppet
+master, deceiving the application in any way you want.
+
+The C<Callbacks> attribute is a hash reference where the keys are DBI method
+names and the values are code references. For each key naming a method, the
+DBI will execute the associated code reference before executing the method.
+
+The arguments to the code reference will be the same as to the method,
+including the invocant (a database handle or statement handle). For example,
+say that to callback to some code on a call to C<prepare()>:
+
+  $dbh->{Callbacks} = {
+      prepare => sub {
+          my ($dbh, $query, $attrs) = @_;
+          print "Preparing q{$query}\n"
+      },
+  };
+
+The callback would then be executed when you called the C<prepare()> method:
+
+  $dbh->prepare('SELECT 1');
+
+And the output of course would be:
+
+  Preparing q{SELECT 1}
+
+The cool thing is that, because callbacks are executed before the methods
+they're associated with, you can modify the arguments before they're passed on
+to the method call. For example, to make sure that all calls to C<prepare()>
+are immediately prepared by L<DBD::Pg>, add a callback that makes sure that
+C<pg_prepare_now> is always set:
+
+  my $dbh = DBI->connect($dsn, $username, $auth, {
+      Callbacks => {
+          prepare => sub {
+              if ($_[2]) {
+                  $_[2]->{pg_prepare_now} = 1;
+              } else {
+                  $_[2] = { pg_prepare_now => 1 };
+              }
+              return;
+          },
+      }
+  });
+
+Note that we've created the attributes hash if it's not passed to the
+C<prepare>.
+
+You can also prevent the associated method from ever executing. While a
+callback executes, C<$_> holds the method name. To prevent the method from
+executing, simply C<undef $_>. For example, if you wanted to disable calls to
+C<ping()>, you could do this:
+
+  $dbh->{Callbacks} = {
+      ping => sub {
+          undef $_;   # tell dispatch to not call the method
+          return "42 bells";
+      }
+  };
+
+As with other attributes, Callbacks can be specified on a handle or via the
+attributes to C<connect()>. Callbacks can also be applied to a statement
+methods on a statement handle:
+
+  $sth->{Callbacks} = {
+      execute => sub {
+          print "Executing ", shift->{Statement}, "\n";
+      }
+  };
+
+In addition to the all of the DBI methods, the C<Callbacks> hash reference
+supports three additional keys. The first is the C<ChildCallbacks> keys, which
+allows one to define callbacks for all statement handles created from a
+database handle. For example, if you wanted to count how many times C<execute>
+was called in your application, you could write:
+
+  my $exec_count = 0;
+  my $dbh = DBI->connect('dbi:Pg:dbname=bric', '', '', {
+      Callbacks => {
+          ChildCallbacks => {
+              execute => sub { $exec_count++; return; }
+          }
+      }
+  });
+
+  END {
+      print "Execute was called $exec_count times\n";
+  }
+
+The other two special keys are C<connect_cached.new> and
+C<connect_cached.reused>. These keys define callbacks that are called when
+C<connect_cached()> is called, but allow different behaviors depending on
+whether a new handle is created or a handle is returned. For example, if your
+app uses C<connect_cached()> in a utility method, it might be prudent to
+prevent it from interfering with open transactions. To prevent a cached handle
+from having its transactions committed before it's returned, simply eliminate
+the C<AutoCommit> attribute in a C<connect_cached.reused> callback, like so:
+
+  my $cb = {
+      ‘connect_cached.reused’ => sub { delete $_[4]->{AutoCommit} },
+  };
+
+  sub dbh {
+      my $self = shift;
+      DBI->connect_cached( $dsn $username $auth, {
+          PrintError => 0,
+          RaiseError => 1,
+          AutoCommit => 1,
+          Callbacks  => $cb,
+      });
+  }
+
+The upshot is that new database handles are created with C<AutoCommit>
+enabled, while cached database handles are left in whatever transaction state
+they happened to be in when retrieved from the cache.
+
+One more useful hint: applying callbacks to the C<connected()> method. This
+method is a no-op (unless you subclass the DBI and change it), but you can
+give it a bit of added functionality by applying a callback to it. For
+example, to make sure that MySQL understands your application's ANSI-compliant
+SQL, set it up like so:
+
+  my $dbh = DBI->connect($dsn, $username, $auth, {
+      Callbacks => {
+          connected => sub {
+              my $dbh = shift;
+              $dbh->do(q{
+                  SET SESSION 
sql_mode='ansi,strict_trans_tables,no_auto_value_on_zero';
+              }) unless exists $dbh->{private_myapp_sql_mode};
+              $dbh->{private_myapp_sql_mode} = 1;
+              return;
+          },
+      }
+  });
+
+The setting of C<< $dbh->{private_myapp_sql_mode} >> ensures that the
+configuration code is called only once.
+
 =head3 C<private_your_module_name_*>
 
 The DBI provides a way to store extra information in a DBI handle as

Reply via email to