Author: timbo
Date: Tue Feb 20 14:58:25 2007
New Revision: 9143

Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm
   dbi/trunk/lib/DBD/ExampleP.pm
   dbi/trunk/lib/DBD/Gofer.pm
   dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm
   dbi/trunk/lib/DBD/Gofer/Transport/stream.pm
   dbi/trunk/lib/DBI/DBD.pm
   dbi/trunk/lib/DBI/Gofer/Execute.pm
   dbi/trunk/lib/DBI/Gofer/Response.pm
   dbi/trunk/t/85gofer.t

Log:
Move go_perl and related logic down from stream into pipeone.
(SAMEPERL concept should be probably be removed now)
Added private_attribute_info to DBD::ExampleP (not tested yet)
Tweaked some DBD::Gofer docs
Chomp errstr in new() Response.
Refactor private_attribute_info logic into new sub with caching.
Added policy=pedantic to xgp test variants.
Added perl attribute to pipeone t/85gofer.t transport tests.
Sort t/85gofer.t to (handling, currently) put null first.
Released as RC7


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Tue Feb 20 14:58:25 2007
@@ -10,6 +10,11 @@
 Terminology for client and server ends
 I could make the short transport/policy name do a lookup in both 
DBD::Gofer::Transport and DBIx::Gofer::Transport.
 Document user/passwd issues at the various levels of the stack
+is_sth_request via dbh_method_call->[0] =~ /^prepare/?
+Policy for dbh attr FETCH (ie example_driver_path)
+    or piggyback on skip_connect_check
+    could also remember which attr have been returned to us
+    so not bother FETCHing them (unless pedantic)
 
 
 =head2 Changes in DBI 1.54 (svn rev 9140),  19th February 2007

Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Tue Feb 20 14:58:25 2007
@@ -3257,11 +3257,11 @@
 
 =item C<private_attribute_info>
 
-  $array_ref = $h->private_attribute_info();
+  $hash_ref = $h->private_attribute_info();
 
-Returns a reference to an array containing the names of driver-private
-attributes available for that kind of handle (driver, database, statement),
-or else undef.
+Returns a reference to a hash whose keys are the names of driver-private
+attributes available for that kind of handle (driver, database, statement).
+(The values should be undef. Meanings may be assigned to particular values in 
future.)
 
 =item C<swap_inner_handle>
 

Modified: dbi/trunk/lib/DBD/ExampleP.pm
==============================================================================
--- dbi/trunk/lib/DBD/ExampleP.pm       (original)
+++ dbi/trunk/lib/DBD/ExampleP.pm       Tue Feb 20 14:58:25 2007
@@ -274,6 +274,9 @@
        return $h->SUPER::parse_trace_flag($name);
     }
 
+    sub private_attribute_info {
+        return { example_driver_path => undef };
+    }
 }
 
 

Modified: dbi/trunk/lib/DBD/Gofer.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer.pm  (original)
+++ dbi/trunk/lib/DBD/Gofer.pm  Tue Feb 20 14:58:25 2007
@@ -120,10 +120,10 @@
             $policy_class = "DBD::Gofer::Policy::$policy_class"
                 unless $policy_class =~ /::/;
             _load_class($policy_class)
-                or return $drh->set_err(1, "Error loading $policy_class: $@");
+                or return $drh->set_err(1, "Can't load $policy_class: $@");
             # replace policy name in %go_attr with policy object
             $go_attr{go_policy} = eval { $policy_class->new(\%go_attr) }
-                or return $drh->set_err(1, "Error instanciating $policy_class: 
$@");
+                or return $drh->set_err(1, "Can't instanciate $policy_class: 
$@");
         }
         # policy object is left in $go_attr{go_policy} so transport can see it
         my $go_policy = $go_attr{go_policy};
@@ -133,9 +133,9 @@
         $transport_class = "DBD::Gofer::Transport::$transport_class"
             unless $transport_class =~ /::/;
         _load_class($transport_class)
-            or return $drh->set_err(1, "Error loading $transport_class: $@");
+            or return $drh->set_err(1, "Can't load $transport_class: $@");
         my $go_trans = eval { $transport_class->new(\%go_attr) }
-            or return $drh->set_err(1, "Error instanciating $transport_class: 
$@");
+            or return $drh->set_err(1, "Can't instanciate $transport_class: 
$@");
 
         my $request_class = "DBI::Gofer::Request";
         my $go_request = eval {
@@ -150,7 +150,7 @@
             $request_class->new({
                 connect_args => [ $remote_dsn, $go_attr ]
             })
-        } or return $drh->set_err(1, "Error instanciating $request_class $@");
+        } or return $drh->set_err(1, "Can't instanciate $request_class $@");
 
         my ($dbh, $dbh_inner) = DBI::_new_dbh($drh, {
             'Name' => $dsn,
@@ -394,7 +394,7 @@
             }
         }
 
-        my $dbh = $sth->{Database} or die 42; # XXX
+        my $dbh = $sth->{Database} or die "panic";
         ++$dbh->{go_request_count};
 
         my $request = $sth->{go_request};
@@ -677,7 +677,7 @@
 
 =head2 You can't call driver-private sth methods
 
-But few people need to do that.
+But that's rarely needed anyway.
 
 =head2 Array Methods are not supported
 
@@ -690,17 +690,17 @@
 
 =head2 Driver-private Database Handle Attributes
 
-Some driver-private dbh attributes may not be available, currently.
-In future it will be possible to indicate which attributes you'd like to be
-able to read.
+Driver-private drh attributes can be set in the connect() call.
+
+Some driver-private dbh attributes may not be available if the driver does not
+implemented the private_attribute_info() method (added in DBI 1.54).
 
 =head2 Driver-private Statement Handle Attributes
 
 Driver-private sth attributes can be set in the prepare() call. TODO
 
-Some driver-private sth attributes may not be available, currently.
-In future it will be possible to indicate which attributes you'd like to be
-able to read.
+Some driver-private dbh attributes may not be available if the driver does not
+implemented the private_attribute_info() method (added in DBI 1.54).
 
 =head1 Multiple Resultsets
 
@@ -736,9 +736,14 @@
     DBD::Gofer::Transport::<foo>
     DBI::Gofer::Transport::<foo>
 
+Sometimes the transports on the DBD and DBI sides may have different names. For
+example DBD::Gofer::Transport::http is typically used with 
DBI::Gofer::Transport::mod_perl
+
+=head2 Bundled Transports
+
 Several transport modules are provided with DBD::Gofer:
 
-=head2 null
+=head3 null
 
 The null transport is the simplest of them all. It doesn't actually transport 
the request anywhere.
 It just serializes (freezes) the request into a string, then thaws it back into
@@ -751,7 +756,7 @@
 
 It doesn't take any parameters.
 
-=head2 pipeone
+=head3 pipeone
 
 The pipeone transport launches a subprocess for each request. It passes in the
 request and reads the response. The fact that a new subprocess is started for
@@ -761,7 +766,7 @@
 
 It doesn't take any parameters.
 
-=head2 stream
+=head3 stream
 
 The stream driver also launches a subprocess and writes requests and reads
 responses, like the pipeone transport.  In this case, however, the subprocess
@@ -772,15 +777,25 @@
 to easily access any databases that's accessible from any system you can login 
to.
 You also get all the benefits of ssh, including encryption and optional 
compression.
 
+It's also likely that this transport will support safe timeouts in future.
+
 See L</DBI_AUTOPROXY> below for an example.
 
-=head2 http
+=head3 http
 
 The http driver uses the http protocol to send Gofer requests and receive 
replies.
 
 The DBI::Gofer::Transport::mod_perl module implements the corresponding 
server-side
 transport.
 
+=head2 Other Transports
+
+I know Ask Bj�rn Hansen has implemented a transport for the gearman distributed
+job system. (Not yet on CPAN.)
+
+Implementing a transport is very simple, and more transports are very welcome.
+Just take a look at any existing transports that are similar to your needs.
+
 =head1 CONNECTING
 
 Simply prefix your existing DSN with "C<dbi:Gofer:transport=$transport;dsn=>"
@@ -842,10 +857,12 @@
 
 Document policy mechanism
 
-Add mecahism for transports to list config params and for Gofer to apply any 
that match (and warn if any left over?)
+Add mechanism for transports to list config params and for Gofer to apply any 
that match (and warn if any left over?)
 
 Driver-private sth attributes - set via prepare() - change DBI spec
 
+Timeout for stream and http drivers.
+
 Caching of get_info values
 
 prepare vs prepare_cached

Modified: dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm        (original)
+++ dbi/trunk/lib/DBD/Gofer/Transport/pipeone.pm        Tue Feb 20 14:58:25 2007
@@ -21,6 +21,7 @@
 __PACKAGE__->mk_accessors(qw(
     connection_info
     response_info
+    go_perl
 )); 
 
 
@@ -29,13 +30,32 @@
     if $^O ne 'VMS' && $this_perl !~ m/$Config{_exe}$/i;
 
 
+sub new {
+    my ($self, $args) = @_;
+    if ($args->{go_perl} and not ref $args->{go_perl}) {
+        # user can override the perl to be used, either with an array ref
+        # containing the command name and args to use, or with a string
+        # (ie via the DSN) in which case, to enable args to be passed,
+        # we split on two or more consecutive spaces (otherwise the path
+        # to perl couldn't contain a space itself).
+        $args->{go_perl} = [ split /\s{2,}/, $args->{go_perl} ];
+    }
+    return $self->SUPER::new($args);
+}
+
+
 sub start_pipe_command {
     my ($self, $cmd) = @_;
     $cmd = [ $cmd ] unless ref $cmd eq 'ARRAY';
 
     # translate any SAMEPERL in cmd to $this_perl
-    $_ eq 'SAMEPERL' and $_ = $this_perl
-        for @$cmd;
+    my $perl = $self->go_perl || [ $this_perl ];
+    for (my $i=0; $i < @$cmd; $i++) {
+        next unless $cmd->[$i] eq 'SAMEPERL';
+        splice @$cmd, $i, 1, @$perl;
+        $i += @$perl - 1;
+    }
+    $_ eq 'SAMEPERL' and $_ = $this_perl for @$cmd;
 
     # if it's important that the subprocess uses the same
     # (versions of) modules as us then the caller should

Modified: dbi/trunk/lib/DBD/Gofer/Transport/stream.pm
==============================================================================
--- dbi/trunk/lib/DBD/Gofer/Transport/stream.pm (original)
+++ dbi/trunk/lib/DBD/Gofer/Transport/stream.pm Tue Feb 20 14:58:25 2007
@@ -18,7 +18,6 @@
 our $VERSION = sprintf("0.%06d", q$Revision$ =~ /(\d+)/o);
 
 __PACKAGE__->mk_accessors(qw(
-    go_perl
     go_persist
 )); 
 
@@ -28,19 +27,6 @@
 sub nonblock;
 
 
-sub new {
-    my ($self, $args) = @_;
-    if ($args->{go_perl} and not ref $args->{go_perl}) {
-        # user can override the perl to be used, either with an array ref
-        # containing the command name and args to use, or with a string
-        # (ie via the DSN) in which case, to enable args to be passed,
-        # we split on two or more consecutive spaces (otherwise the path
-        # to perl couldn't contain a space itself).
-        $args->{go_perl} = [ split /\s{2,}/, $args->{go_perl} ];
-    }
-    return $self->SUPER::new($args);
-}
-
 
 sub _connection_key {
     my ($self) = @_;
@@ -98,7 +84,7 @@
     my ($self) = @_;
 
     my $cmd = [qw(SAMEPERL -MDBI::Gofer::Transport::stream -e run_stdio_hex)];
-    if (my $perl = $self->go_perl) {
+    if (0 and my $perl = $self->go_perl) {
         splice @$cmd, 0, 1, @$perl;
     }
 

Modified: dbi/trunk/lib/DBI/DBD.pm
==============================================================================
--- dbi/trunk/lib/DBI/DBD.pm    (original)
+++ dbi/trunk/lib/DBI/DBD.pm    Tue Feb 20 14:58:25 2007
@@ -3017,7 +3017,7 @@
                        add => [ q{$ENV{DBI_AUTOPROXY} = 
'dbi:Gofer:transport=null;policy=pedantic'} ],
            },
            xgp => {    name => "PurePerl & Gofer",
-                       add => [ q{$ENV{DBI_PUREPERL} = 2; $ENV{DBI_AUTOPROXY} 
= 'dbi:Gofer:transport=null'} ],
+                       add => [ q{$ENV{DBI_PUREPERL} = 2; $ENV{DBI_AUTOPROXY} 
= 'dbi:Gofer:transport=null;policy=pedantic'} ],
            },
        #   mx => {     name => "DBD::Multiplex",
        #               add => [ q{local $ENV{DBI_AUTOPROXY} = 
'dbi:Multiplex:';} ],

Modified: dbi/trunk/lib/DBI/Gofer/Execute.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Execute.pm  (original)
+++ dbi/trunk/lib/DBI/Gofer/Execute.pm  Tue Feb 20 14:58:25 2007
@@ -48,6 +48,7 @@
 
 my %extra_attr = (
     # what driver-specific attributes should be returned for the driver being 
used?
+    # Only referenced if the driver doesn't support private_attribute_info 
method.
     # keyed by $dbh->{Driver}{Name}
     # XXX for dbh attr only need to be returned on first access by client
     # the client should then cache them. So need a way to indicate that.
@@ -232,12 +233,7 @@
         my @req_attr_names = @$dbh_attributes;
         if ($req_attr_names[0] eq '*') { # auto include std + private
             shift @req_attr_names;
-            # add ChopBlanks LongReadLen LongTruncOk because drivers may have 
different defaults
-            # plus Name so the client gets the real Name of the connection
-            push @req_attr_names, qw(ChopBlanks LongReadLen LongTruncOk Name);
-            my $pai = $dbh->private_attribute_info
-                   || $extra_attr{ $dbh->{Driver}{Name} }{dbh} || [];
-            push @req_attr_names, @$pai;
+            push @req_attr_names, @{ $self->_get_std_attributes($dbh) };
         }
         my %dbh_attr_values;
         $dbh_attr_values{$_} = $dbh->FETCH($_) for @req_attr_names;
@@ -264,6 +260,27 @@
 }
 
 
+sub _get_std_attributes {
+    my ($self, $h) = @_;
+    $h = tied(%$h) || $h; # switch to inner handle
+    my $attr_names = $h->{private_gofer_std_attr_names};
+    return $attr_names if $attr_names;
+    # add ChopBlanks LongReadLen LongTruncOk because drivers may have 
different defaults
+    # plus Name so the client gets the real Name of the connection
+    my @attr_names = qw(ChopBlanks LongReadLen LongTruncOk Name);
+    if (my $pai = $h->private_attribute_info) {
+        push @attr_names, keys %$pai;
+    }
+    elsif (my $drh = $h->{Driver}) { # is a dbh
+        push @attr_names, @{ $extra_attr{ $drh->{Name} }{dbh} || []};
+    }
+    elsif ($drh = $h->{Driver}{Database}) { # is an sth
+        push @attr_names, @{ $extra_attr{ $drh->{Name} }{sth} || []};
+    }
+    return $h->{private_gofer_std_attr_names} = [EMAIL PROTECTED];
+}
+
+
 sub execute_sth_request {
     my ($self, $request) = @_;
     my $dbh;

Modified: dbi/trunk/lib/DBI/Gofer/Response.pm
==============================================================================
--- dbi/trunk/lib/DBI/Gofer/Response.pm (original)
+++ dbi/trunk/lib/DBI/Gofer/Response.pm Tue Feb 20 14:58:25 2007
@@ -27,6 +27,7 @@
 sub new {
     my ($self, $args) = @_;
     $args->{version} ||= $VERSION;
+    chomp $args->{errstr} if $args->{errstr};
     return $self->SUPER::new($args);
 }   
 

Modified: dbi/trunk/t/85gofer.t
==============================================================================
--- dbi/trunk/t/85gofer.t       (original)
+++ dbi/trunk/t/85gofer.t       Tue Feb 20 14:58:25 2007
@@ -47,13 +47,14 @@
 my $getcwd = getcwd();
 my $username = eval { getpwuid($>) } || ''; # fails on windows
 my $can_ssh = ($username && $username eq 'timbo' && -d '.svn');
+my $perl = "SAMEPERL  -Mblib=$getcwd/blib"; # ensure sameperl and our blib 
(note two spaces)
 
 my %trials = (
     null       => {},
-    pipeone    => {},
-    stream     => {},
+    pipeone    => { perl=>$perl },
+    stream     => { perl=>$perl },
     stream_ssh => ($can_ssh)
-                ? { url => "ssh:[EMAIL PROTECTED]", perl=>"SAMEPERL  
-Mblib=$getcwd/blib" }
+                ? { perl=>$perl, url => "ssh:[EMAIL PROTECTED]" }
                 : undef,
     http       => { url => "http://localhost:8001/gofer"; },
 );
@@ -61,11 +62,14 @@
 # too dependant on local config to make a standard test
 delete $trials{http} unless $username eq 'timbo' && -d '.svn';
 
-for my $trial (keys %trials) {
+for my $trial (sort keys %trials) {
     (my $transport = $trial) =~ s/_.*//;
     my $trans_attr = $trials{$trial}
         or next;
 
+    # XXX temporary restriction, hopefully
+    next if $transport eq 'stream' and $^O eq 'MSWin32'; # need Fcntl macro 
F_GETFL for non-blocking
+
     for my $policy_name (qw(pedantic classic rush)) {
 
         eval { run_tests($transport, $trans_attr, $policy_name) };
@@ -109,7 +113,7 @@
     print " $dsn\n";
 
     my $dbh = DBI->connect($dsn, undef, undef, { } );
-    ok $dbh, 'should connect';
+    ok $dbh, sprintf "should connect to %s (%s)", $dsn, $DBI::errstr||'';
     die "$test_run_tag aborted\n" unless $dbh;
 
     is $dbh->{Name}, ($policy->skip_connect_check or 
$policy->dbh_attribute_update eq 'none')

Reply via email to