Author: timbo
Date: Tue Mar 20 15:11:55 2007
New Revision: 9286

Modified:
   dbi/trunk/lib/DBD/Gofer.pm
   dbi/trunk/lib/DBD/Gofer/Policy/Base.pm
   dbi/trunk/lib/DBD/Gofer/Policy/classic.pm
   dbi/trunk/lib/DBI/Gofer/Request.pm
   dbi/trunk/lib/DBI/Gofer/Response.pm
   dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm
   dbi/trunk/t/10examp.t
   dbi/trunk/t/12quote.t

Log:
Add locally_quote and locally_quote_identifier policy hooks.
Fixup whitespace in DBD::Gofer.
Also forward tables method.
Start work on cache_* policy wrapper for schema metadata methods etc.
Forward prepare_cached.
Improve level 1 gofer trace.


Modified: dbi/trunk/lib/DBD/Gofer.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer.pm  (original)
+++ dbi/trunk/lib/DBD/Gofer.pm  Tue Mar 20 15:11:55 2007
@@ -46,11 +46,11 @@
         dbi_connect_method
     );
 
-    our $drh = undef;  # holds driver handle once initialised
+    our $drh = undef;    # holds driver handle once initialised
     our $methods_already_installed;
 
     sub driver{
-       return $drh if $drh;
+        return $drh if $drh;
 
         DBI->setup_driver('DBD::Gofer');
 
@@ -59,15 +59,15 @@
             DBD::Gofer::st->install_method('go_sth_method', { O=> 0x0004 }); # 
IMA_KEEP_ERR
         }
 
-       my($class, $attr) = @_;
-       $class .= "::dr";
-       ($drh) = DBI::_new_drh($class, {
-           'Name' => 'Gofer',
-           'Version' => $VERSION,
-           'Attribution' => 'DBD Gofer by Tim Bunce',
+        my($class, $attr) = @_;
+        $class .= "::dr";
+        ($drh) = DBI::_new_drh($class, {
+            'Name' => 'Gofer',
+            'Version' => $VERSION,
+            'Attribution' => 'DBD Gofer by Tim Bunce',
         });
 
-       $drh;
+        $drh;
     }
 
 
@@ -288,28 +288,51 @@
         return (wantarray) ? @$rv : $rv->[0];
     }
 
-    # Methods that should be forwarded
-    # XXX get_info? special sub to lazy-cache individual values
+
+    # Methods that should be forwarded but can be cached
     for my $method (qw(
-        data_sources
-        table_info column_info primary_key_info foreign_key_info 
statistics_info
-        type_info_all get_info
+        tables table_info column_info primary_key_info foreign_key_info 
statistics_info
+        data_sources type_info_all get_info
         parse_trace_flags parse_trace_flag
         func
     )) {
+        my $policy_name = "cache_$method";
+        my $sub = sub {
+            my $dbh = shift;
+            # XXX add local (in-handle) cache logic
+            my @rv = (wantarray)
+                ?       ($dbh->go_dbh_method(undef, $method, @_))
+                : scalar $dbh->go_dbh_method(undef, $method, @_);
+            return (wantarray) ? @rv : $rv[0];
+        };
         no strict 'refs';
-        *$method = sub { return shift->go_dbh_method(undef, $method, @_) }
+        *$method = $sub;
     }
 
-    # Methods that should be forwarded if policy says so
+
+    # Methods that can use the DBI defaults for some situations/drivers
     for my $method (qw(
-        quote
-    )) {
+        quote quote_identifier
+    )) {    # XXX keep DBD::Gofer::Policy::Base in sync
+        my $policy_name = "locally_$method";
+        my $super_name  = "SUPER::$method";
+        my $sub = sub {
+            my $dbh = shift;
+            # false:    use remote gofer
+            # 1:        use local DBI default method
+            # code ref: use the code ref
+            my $locally = $dbh->{go_policy}->$policy_name($dbh, @_);
+            if ($locally) {
+                return $locally->($dbh, @_) if ref $locally eq 'CODE';
+                return $dbh->$super_name(@_);
+            }
+            return $dbh->go_dbh_method(undef, $method, @_);
+        };
         no strict 'refs';
-        # XXX add policy checks
-        *$method = sub { return shift->go_dbh_method(undef, $method, @_) }
+        *$method = $sub;
     }
 
+
     # Methods that should always fail
     for my $method (qw(
         begin_work commit rollback
@@ -318,8 +341,6 @@
         *$method = sub { return shift->set_err(1, "$method not available with 
DBD::Gofer") }
     }
 
-    # for quote we rely on the default method + type_info_all
-    # for quote_identifier we rely on the default method + get_info
 
     sub do {
         my ($dbh, $sql, $attr, @args) = @_;
@@ -344,7 +365,7 @@
     }
 
     sub FETCH {
-       my ($dbh, $attrib) = @_;
+        my ($dbh, $attrib) = @_;
 
         # forward driver-private attributes
         if ($attrib =~ m/^[a-z]/) { # XXX policy? precache on connect?
@@ -353,17 +374,17 @@
             return $value;
         }
 
-       # else pass up to DBI to handle
-       return $dbh->SUPER::FETCH($attrib);
+        # else pass up to DBI to handle
+        return $dbh->SUPER::FETCH($attrib);
     }
 
     sub STORE {
-       my ($dbh, $attrib, $value) = @_;
+        my ($dbh, $attrib, $value) = @_;
         if ($attrib eq 'AutoCommit') {
             return $dbh->SUPER::STORE($attrib => -901) if $value;
             croak "Can't enable transactions when using DBD::Gofer";
         }
-       return $dbh->SUPER::STORE($attrib => $value)
+        return $dbh->SUPER::STORE($attrib => $value)
             # we handle this attribute locally
             if $dbh_local_store_attrib{$attrib}
             # or it's a private_ (application) attribute
@@ -371,7 +392,7 @@
             # or not yet connected (and being called by connect())
             or not $dbh->FETCH('Active');
 
-       return $dbh->SUPER::STORE($attrib => $value)
+        return $dbh->SUPER::STORE($attrib => $value)
             if $DBD::Gofer::xxh_local_store_attrib_if_same_value{$attrib}
             && do { # return true if values are the same
                 my $crnt = $dbh->FETCH($attrib);
@@ -387,23 +408,21 @@
     }
 
     sub disconnect {
-       my $dbh = shift;
+        my $dbh = shift;
         $dbh->{go_trans} = undef;
-       $dbh->STORE(Active => 0);
+        $dbh->STORE(Active => 0);
     }
 
-    # XXX + prepare_cached ?
-    #
     sub prepare {
-       my ($dbh, $statement, $attr)= @_;
+        my ($dbh, $statement, $attr)= @_;
 
         return $dbh->set_err(1, "Can't prepare when disconnected")
             unless $dbh->FETCH('Active');
 
         my $policy = $attr->{go_policy} || $dbh->{go_policy};
 
-       my ($sth, $sth_inner) = DBI::_new_sth($dbh, {
-           Statement => $statement,
+        my ($sth, $sth_inner) = DBI::_new_sth($dbh, {
+            Statement => $statement,
             go_prepare_call => [ 'prepare', $statement, $attr ],
             # go_method_calls => [], # autovivs if needed
             go_request => $dbh->{go_request},
@@ -418,7 +437,15 @@
             $sth->go_sth_method() or return undef;
         }
 
-       return $sth;
+        return $sth;
+    }
+
+    sub prepare_cached {
+        my ($dbh, @args)= @_;
+        my $sth = $dbh->SUPER::prepare_cached(@args)
+            or return undef;
+        $sth->{go_prepare_call}->[0] = 'prepare_cached';
+        return $sth;
     }
 
 }
@@ -519,7 +546,7 @@
 
 
     sub execute {
-       my $sth = shift;
+        my $sth = shift;
         $sth->bind_param($_, $_[$_-1]) for ([EMAIL PROTECTED]);
         push @{ $sth->{go_method_calls} }, [ 'execute' ];
         my $meta = { go_last_insert_id_args => $sth->{go_last_insert_id_args} 
};
@@ -528,17 +555,17 @@
 
 
     sub more_results {
-       my $sth = shift;
+        my $sth = shift;
 
-       $sth->finish;
+        $sth->finish;
 
-       my $response = $sth->{go_response} or do {
+        my $response = $sth->{go_response} or do {
             # e.g., we haven't sent a request yet (ie prepare then 
more_results)
             $sth->trace_msg("    No response object present", 3);
             return;
         };
 
-       my $resultset_list = $response->sth_resultsets
+        my $resultset_list = $response->sth_resultsets
             or return $sth->set_err(1, "No sth_resultsets");
 
         my $meta = shift @$resultset_list
@@ -563,28 +590,28 @@
             $sth->STORE(Active => 1) if $rowset;
         }
 
-       return $sth;
+        return $sth;
     }
 
 
     sub fetchrow_arrayref {
-       my ($sth) = @_;
-       my $resultset = $sth->{go_current_rowset} || do {
+        my ($sth) = @_;
+        my $resultset = $sth->{go_current_rowset} || do {
             # should only happen if fetch called after execute failed
             my $rowset_err = $sth->{go_current_rowset_err}
                 || [ 1, 'no result set (did execute fail)' ];
             return $sth->set_err( @$rowset_err );
         };
         return $sth->_set_fbav(shift @$resultset) if @$resultset;
-       $sth->finish;     # no more data so finish
-       return undef;
+        $sth->finish;     # no more data so finish
+        return undef;
     }
     *fetch = \&fetchrow_arrayref; # alias
 
 
     sub fetchall_arrayref {
         my ($sth, $slice, $max_rows) = @_;
-       my $resultset = $sth->{go_current_rowset} || do {
+        my $resultset = $sth->{go_current_rowset} || do {
             # should only happen if fetch called after execute failed
             my $rowset_err = $sth->{go_current_rowset_err}
                 || [ 1, 'no result set (did execute fail)' ];
@@ -593,7 +620,7 @@
         my $mode = ref($slice) || 'ARRAY';
         return $sth->SUPER::fetchall_arrayref($slice, $max_rows)
             if ref($slice) or defined $max_rows;
-       $sth->finish;     # no more data after this so finish
+        $sth->finish;     # no more data after this so finish
         return $resultset;
     }
 
@@ -604,9 +631,9 @@
 
 
     sub STORE {
-       my ($sth, $attrib, $value) = @_;
+        my ($sth, $attrib, $value) = @_;
 
-       return $sth->SUPER::STORE($attrib => $value)
+        return $sth->SUPER::STORE($attrib => $value)
             if $sth_local_store_attrib{$attrib} # handle locally
             # or it's a private_ (application) attribute
             or $attrib =~ /^private_/;
@@ -625,7 +652,7 @@
         # Could just always use go_method_calls I guess.
 
         # do the store locally anyway, just in case
-       $sth->SUPER::STORE($attrib => $value);
+        $sth->SUPER::STORE($attrib => $value);
 
         return $sth->set_err(1, $msg);
     }

Modified: dbi/trunk/lib/DBD/Gofer/Policy/Base.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer/Policy/Base.pm      (original)
+++ dbi/trunk/lib/DBD/Gofer/Policy/Base.pm      Tue Mar 20 15:11:55 2007
@@ -20,6 +20,8 @@
     skip_ping => 0,
     dbh_attribute_update => 'every',
     dbh_attribute_list => ['*'],
+    locally_quote => 0,
+    locally_quote_identifier => 0,
 );
 
 my $base_policy_file = $INC{"DBD/Gofer/Policy/Base.pm"};
@@ -46,6 +48,9 @@
 
 sub AUTOLOAD {
     carp "Unknown policy name $AUTOLOAD used";
+    # only warn once
+    no strict 'refs';
+    *$AUTOLOAD = sub { undef };
     return undef;
 }
 

Modified: dbi/trunk/lib/DBD/Gofer/Policy/classic.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer/Policy/classic.pm   (original)
+++ dbi/trunk/lib/DBD/Gofer/Policy/classic.pm   Tue Mar 20 15:11:55 2007
@@ -27,6 +27,9 @@
     # ping is almost meaningless for DBD::Gofer and most transports anyway
     skip_ping => 1,
 
+    # we'd like to set locally_* but can't because drivers differ
+
+    # XXX we could set some cache_* though
 });
 
 

Modified: dbi/trunk/lib/DBI/Gofer/Request.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Request.pm  (original)
+++ dbi/trunk/lib/DBI/Gofer/Request.pm  Tue Mar 20 15:11:55 2007
@@ -57,11 +57,15 @@
     my @s = '';
 
     my ($dsn, $attr) = @{ $self->connect_args };
-    push @s, "dbh= connect('$dsn', , , { %{$attr||{}} ]} })";
+    push @s, sprintf "dbh= connect('%s', , , { %s })", $dsn, neat_list([ 
%{$attr||{}} ]);
 
     my ($meth, @args) = @{ $self->dbh_method_call };
     push @s, sprintf "dbh->%s(%s)", $meth, neat_list([EMAIL PROTECTED]);
 
+    if (my $lii_args = $self->dbh_last_insert_id_args) {
+        push @s, sprintf "dbh->last_insert_id(%s)", neat_list($lii_args);
+    }
+
     for my $call (@{ $self->sth_method_calls || [] }) {
         my ($meth, @args) = @$call;
         push @s, sprintf "sth->%s(%s)", $meth, neat_list([EMAIL PROTECTED]);

Modified: dbi/trunk/lib/DBI/Gofer/Response.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Response.pm (original)
+++ dbi/trunk/lib/DBI/Gofer/Response.pm Tue Mar 20 15:11:55 2007
@@ -82,20 +82,28 @@
 sub summary_as_text {
     my $self = shift;
     my ($rv, $err, $errstr, $state) = ($self->{rv}, $self->{err}, 
$self->{errstr}, $self->{state});
-    my @s = sprintf("rv=%s", (ref $rv) ? "[".neat_list($rv)."]" : $rv);
-    $s[-1] .= sprintf(" err=%s errstr=%s", $err, neat($errstr)) if defined 
$err;
+    my @s = sprintf("rv=%s", (ref $rv) ? "[".neat_list($rv)."]" : neat($rv));
+    $s[-1] .= sprintf(" err=%s, errstr=%s", $err, neat($errstr))
+        if defined $err;
+    push @s, "last_insert_id=%s", $self->last_insert_id
+        if defined $self->last_insert_id;
     for my $rs (@{$self->sth_resultsets || []}) {
         my ($rowset, $err, $errstr, $state)
             = @{$rs}{qw(rowset err errstr state)};
         my $summary = "rowset: ";
-        if ($rowset || $rs->{NUM_OF_FIELDS} > 0) {
-            $summary .= sprintf "%d rows, %d columns", scalar @{$rowset||[]}, 
$rs->{NUM_OF_FIELDS}
+        my $NUM_OF_FIELDS = $rs->{NUM_OF_FIELDS} || 0;
+        if ($rowset || $NUM_OF_FIELDS > 0) {
+            $summary .= sprintf "%d rows, %d columns", scalar @{$rowset||[]}, 
$NUM_OF_FIELDS
         }
         if (defined $err) {
             $summary .= sprintf(", err=%s errstr=%s", $err, neat($errstr))
         }
         push @s, $summary;
     }
+    for my $w (@{$self->warnings || []}) {
+        chomp $w;
+        push @s, "warning: $w";
+    }
     return join("\n\t", @s). "\n";
 }
 

Modified: dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm       (original)
+++ dbi/trunk/lib/DBI/Gofer/Transport/mod_perl.pm       Tue Mar 20 15:11:55 2007
@@ -246,7 +246,7 @@
 The DBI::Gofer::Transport::mod_perl->configuration({...}) call defines named 
configurations.
 The C<PerlSetVar GoferConfig> clause specifies the configuration to be used 
for that location.
 
-XXX add detail inclusing specific examples
+XXX add detail including specific examples
 
 A single location can specify multiple configurations using C<PerlAddVar>:
 

Modified: dbi/trunk/t/10examp.t
==============================================================================
--- dbi/trunk/t/10examp.t       (original)
+++ dbi/trunk/t/10examp.t       Tue Mar 20 15:11:55 2007
@@ -548,15 +548,18 @@
 }
 
 
-print "Testing \$dbh->func().\n";
-my %tables;
-unless ($dbh->{mx_handle_list}) {
-       %tables = map { $_ =~ /lib/ ? ($_, 1) : () } $dbh->tables();
-       foreach my $t ($dbh->func('lib', 'examplep_tables')) {
-               defined(delete $tables{$t}) or print "Unexpected table: $t\n";
-       }
+SKIP: {
+    skip "test not tested with Multiplex", 1
+        if $dbh->{mx_handle_list};
+    print "Testing \$dbh->func().\n";
+    my %tables;
+    %tables = map { $_ =~ /lib/ ? ($_, 1) : () } $dbh->tables();
+    my @func_tables = $dbh->func('lib', 'examplep_tables');
+    foreach my $t (@func_tables) {
+        defined(delete $tables{$t}) or print "Unexpected table: $t\n";
+    }
+    is(keys(%tables), 0);
 }
-ok((%tables == 0));
 
 $dbh->disconnect;
 ok(!$dbh->{Active});

Modified: dbi/trunk/t/12quote.t
==============================================================================
--- dbi/trunk/t/12quote.t       (original)
+++ dbi/trunk/t/12quote.t       Tue Mar 20 15:11:55 2007
@@ -19,19 +19,13 @@
        is($dbh->quote("quote's"),         "'quote''s'", '... quoting strings 
with embedded single quotes');
        is($dbh->quote("42", SQL_VARCHAR), "'42'",       '... quoting number as 
SQL_VARCHAR');
        is($dbh->quote("42", SQL_INTEGER), "42",         '... quoting number as 
SQL_INTEGER');
-       is($dbh->quote(undef),                     "NULL",               '... 
quoting undef as NULL');
+       is($dbh->quote(undef),             "NULL",       '... quoting undef as 
NULL');
 }
 
 check_quote();
 
 sub check_quote_identifier {
 
-        my $qi = $dbh->{dbi_quote_identifier_cache} = [
-            '"', # 29:  SQL_IDENTIFIER_QUOTE_CHAR
-            '.', # 41:  SQL_CATALOG_NAME_SEPARATOR
-            1,   # 114: SSQL_CATALOG_LOCATION 
-        ];  
-
        is($dbh->quote_identifier('foo'),             '"foo"',       '... 
properly quotes foo as "foo"');
        is($dbh->quote_identifier('f"o'),             '"f""o"',      '... 
properly quotes f"o as "f""o"');
        is($dbh->quote_identifier('foo','bar'),       '"foo"."bar"', '... 
properly quotes foo, bar as "foo"."bar"');
@@ -39,9 +33,14 @@
 
        is($dbh->quote_identifier('foo',undef,'bar'), '"foo"."bar"', '... 
properly quotes foo, undef, bar as "foo"."bar"');
 
+    SKIP: {
+        skip "Can't test alternate quote_identifier logic with DBI_AUTOPROXY", 
1
+            if $ENV{DBI_AUTOPROXY};
+        my $qi = $dbh->{dbi_quote_identifier_cache} || die "test out of date 
with dbi internals?";
        $qi->[1] = '@';   # SQL_CATALOG_NAME_SEPARATOR
        $qi->[2] = 2;     # SQL_CATALOG_LOCATION
        is($dbh->quote_identifier('foo',undef,'bar'), '"bar"@"foo"', '... now 
quotes it as "bar"@"foo" after flushing cache');
+    }
 }
 
 check_quote_identifier();

Reply via email to