File Coverage

blib/lib/DBD/Gofer.pm
Criterion Covered Total %
statement 302 340 88.8
branch 137 192 71.3
condition 57 86 66.2
subroutine 37 42 88.1
pod 0 4 0.0
total 533 664 80.2


line stmt bran cond sub pod time code
1             {
2             package DBD::Gofer;
3              
4 56     56   339 use strict;
  56         106  
  56         33106  
5              
6             require DBI;
7             require DBI::Gofer::Request;
8             require DBI::Gofer::Response;
9             require Carp;
10              
11             our $VERSION = "0.015327";
12              
13             # $Id: Gofer.pm 15326 2012-06-06 16:32:38Z Tim $
14             #
15             # Copyright (c) 2007, Tim Bunce, Ireland
16             #
17             # You may distribute under the terms of either the GNU General Public
18             # License or the Artistic License, as specified in the Perl README file.
19              
20              
21              
22             # attributes we'll allow local STORE
23             our %xxh_local_store_attrib = map { $_=>1 } qw(
24             Active
25             CachedKids
26             Callbacks
27             DbTypeSubclass
28             ErrCount Executed
29             FetchHashKeyName
30             HandleError HandleSetErr
31             InactiveDestroy
32             AutoInactiveDestroy
33             PrintError PrintWarn
34             Profile
35             RaiseError
36             RootClass
37             ShowErrorStatement
38             Taint TaintIn TaintOut
39             TraceLevel
40             Warn
41             dbi_quote_identifier_cache
42             dbi_connect_closure
43             dbi_go_execute_unique
44             );
45             our %xxh_local_store_attrib_if_same_value = map { $_=>1 } qw(
46             Username
47             dbi_connect_method
48             );
49              
50             our $drh = undef; # holds driver handle once initialized
51             our $methods_already_installed;
52              
53             sub driver{
54 56 50   56 0 201 return $drh if $drh;
55              
56 56         212 DBI->setup_driver('DBD::Gofer');
57              
58 56 50       285 unless ($methods_already_installed++) {
59 56         219 my $opts = { O=> 0x0004 }; # IMA_KEEP_ERR
60 56         519 DBD::Gofer::db->install_method('go_dbh_method', $opts);
61 56         492 DBD::Gofer::st->install_method('go_sth_method', $opts);
62 56         318 DBD::Gofer::st->install_method('go_clone_sth', $opts);
63 56         306 DBD::Gofer::db->install_method('go_cache', $opts);
64 56         314 DBD::Gofer::st->install_method('go_cache', $opts);
65             }
66              
67 56         231 my($class, $attr) = @_;
68 56         165 $class .= "::dr";
69 56         402 ($drh) = DBI::_new_drh($class, {
70             'Name' => 'Gofer',
71             'Version' => $VERSION,
72             'Attribution' => 'DBD Gofer by Tim Bunce',
73             });
74              
75 56         258 $drh;
76             }
77              
78              
79             sub CLONE {
80 0     0   0 undef $drh;
81             }
82              
83              
84             sub go_cache {
85 4     4 0 44 my $h = shift;
86 4 50       10 $h->{go_cache} = shift if @_;
87             # return handle's override go_cache, if it has one
88 4 100       18 return $h->{go_cache} if defined $h->{go_cache};
89             # or else the transports default go_cache
90 2         8 return $h->{go_transport}->{go_cache};
91             }
92              
93              
94             sub set_err_from_response { # set error/warn/info and propagate warnings
95 7138     7138 0 9899 my $h = shift;
96 7138         8990 my $response = shift;
97 7138 100       15943 if (my $warnings = $response->warnings) {
98 22         283 warn $_ for @$warnings;
99             }
100 7138         18873 my ($err, $errstr, $state) = $response->err_errstr_state;
101             # Only set_err() if there's an error else leave the current values
102             # (The current values will normally be set undef by the DBI dispatcher
103             # except for methods marked KEEPERR such as ping.)
104 7138 100       25552 $h->set_err($err, $errstr, $state) if defined $err;
105 7138         12176 return undef;
106             }
107              
108              
109             sub install_methods_proxy {
110 580     580 0 1408 my ($installed_methods) = @_;
111 580         3554 while ( my ($full_method, $attr) = each %$installed_methods ) {
112             # need to install both a DBI dispatch stub and a proxy stub
113             # (the dispatch stub may be already here due to local driver use)
114              
115             DBI->_install_method($full_method, "", $attr||{})
116 4866 50 0     6709 unless defined &{$full_method};
  4866         15565  
117              
118             # now install proxy stubs on the driver side
119 4866 50       16422 $full_method =~ m/^DBI::(\w\w)::(\w+)$/
120             or die "Invalid method name '$full_method' for install_method";
121 4866         12526 my ($type, $method) = ($1, $2);
122 4866         9087 my $driver_method = "DBD::Gofer::${type}::${method}";
123 4866 100       5819 next if defined &{$driver_method};
  4866         24279  
124 166         227 my $sub;
125 166 100       322 if ($type eq 'db') {
126 126     20   365 $sub = sub { return shift->go_dbh_method(undef, $method, @_) };
  20         7639  
127             }
128             else {
129 40     0   162 $sub = sub { shift->set_err($DBI::stderr, "Can't call \$${type}h->$method when using DBD::Gofer"); return; };
  0         0  
  0         0  
130             }
131 56     56   400 no strict 'refs';
  56         114  
  56         4694  
132 166         802 *$driver_method = $sub;
133             }
134             }
135             }
136              
137              
138             { package DBD::Gofer::dr; # ====== DRIVER ======
139              
140             $imp_data_size = 0;
141 56     56   1298 use strict;
  56         120  
  56         45839  
142              
143             sub connect_cached {
144 10     10   178 my ($drh, $dsn, $user, $auth, $attr)= @_;
145 10   50     30 $attr ||= {};
146             return $drh->SUPER::connect_cached($dsn, $user, $auth, {
147             (%$attr),
148 10   50     116 go_connect_method => $attr->{go_connect_method} || 'connect_cached',
149             });
150             }
151              
152              
153             sub connect {
154 716     716   13928 my($drh, $dsn, $user, $auth, $attr)= @_;
155 716         1392 my $orig_dsn = $dsn;
156              
157             # first remove dsn= and everything after it
158 716 50 33     9895 my $remote_dsn = ($dsn =~ s/;?\bdsn=(.*)$// && $1)
159             or return $drh->set_err($DBI::stderr, "No dsn= argument in '$orig_dsn'");
160              
161 716 100       2572 if ($attr->{go_bypass}) { # don't use DBD::Gofer for this connection
162             # useful for testing with DBI_AUTOPROXY, e.g., t/03handle.t
163 1         4 return DBI->connect($remote_dsn, $user, $auth, $attr);
164             }
165              
166 715         1242 my %go_attr;
167             # extract any go_ attributes from the connect() attr arg
168 715         3113 for my $k (grep { /^go_/ } keys %$attr) {
  4932         10332  
169 13         48 $go_attr{$k} = delete $attr->{$k};
170             }
171             # then override those with any attributes embedded in our dsn (not remote_dsn)
172 715         5397 for my $kv (grep /=/, split /;/, $dsn, -1) {
173 2108         6279 my ($k, $v) = split /=/, $kv, 2;
174 2108         6605 $go_attr{ "go_$k" } = $v;
175             }
176              
177 715 50       2527 if (not ref $go_attr{go_policy}) { # if not a policy object already
178 715   50     2425 my $policy_class = $go_attr{go_policy} || 'classic';
179 715 50       2993 $policy_class = "DBD::Gofer::Policy::$policy_class"
180             unless $policy_class =~ /::/;
181 715 50       2298 _load_class($policy_class)
182             or return $drh->set_err($DBI::stderr, "Can't load $policy_class: $@");
183             # replace policy name in %go_attr with policy object
184 715 50       1474 $go_attr{go_policy} = eval { $policy_class->new(\%go_attr) }
  715         4604  
185             or return $drh->set_err($DBI::stderr, "Can't instanciate $policy_class: $@");
186             }
187             # policy object is left in $go_attr{go_policy} so transport can see it
188 715         1646 my $go_policy = $go_attr{go_policy};
189              
190 715 100 100     2276 if ($go_attr{go_cache} and not ref $go_attr{go_cache}) { # if not a cache object already
191 4         11 my $cache_class = $go_attr{go_cache};
192 4 50       15 $cache_class = "DBI::Util::CacheMemory" if $cache_class eq '1';
193 4 50       12 _load_class($cache_class)
194             or return $drh->set_err($DBI::stderr, "Can't load $cache_class $@");
195 4 50       9 $go_attr{go_cache} = eval { $cache_class->new() }
  4         28  
196             or $drh->set_err(0, "Can't instanciate $cache_class: $@"); # warning
197             }
198              
199             # delete any other attributes that don't apply to transport
200 715         1391 my $go_connect_method = delete $go_attr{go_connect_method};
201              
202             my $transport_class = delete $go_attr{go_transport}
203 715 50       2163 or return $drh->set_err($DBI::stderr, "No transport= argument in '$orig_dsn'");
204 715 50       3021 $transport_class = "DBD::Gofer::Transport::$transport_class"
205             unless $transport_class =~ /::/;
206 715 50       2037 _load_class($transport_class)
207             or return $drh->set_err($DBI::stderr, "Can't load $transport_class: $@");
208 715 50       1410 my $go_transport = eval { $transport_class->new(\%go_attr) }
  715         4719  
209             or return $drh->set_err($DBI::stderr, "Can't instanciate $transport_class: $@");
210              
211 715         1671 my $request_class = "DBI::Gofer::Request";
212 715 50       1212 my $go_request = eval {
213 715         4646 my $go_attr = { %$attr };
214             # XXX user/pass of fwd server vs db server ? also impact of autoproxy
215 715 100       2295 if ($user) {
216 13         22 $go_attr->{Username} = $user;
217 13         27 $go_attr->{Password} = $auth;
218             }
219             # delete any attributes we can't serialize (or don't want to)
220 715         1484 delete @{$go_attr}{qw(Profile HandleError HandleSetErr Callbacks)};
  715         2084  
221             # delete any attributes that should only apply to the client-side
222 715         1334 delete @{$go_attr}{qw(RootClass DbTypeSubclass)};
  715         2012  
223              
224 715   50     4741 $go_connect_method ||= $go_policy->connect_method($remote_dsn, $go_attr) || 'connect';
      66        
225 715         4754 $request_class->new({
226             dbh_connect_call => [ $go_connect_method, $remote_dsn, $user, $auth, $go_attr ],
227             })
228             } or return $drh->set_err($DBI::stderr, "Can't instanciate $request_class: $@");
229              
230 715         5969 my ($dbh, $dbh_inner) = DBI::_new_dbh($drh, {
231             'Name' => $dsn,
232             'USER' => $user,
233             go_transport => $go_transport,
234             go_request => $go_request,
235             go_policy => $go_policy,
236             });
237              
238             # mark as inactive temporarily for STORE. Active not set until connected() called.
239 715         4713 $dbh->STORE(Active => 0);
240              
241             # should we ping to check the connection
242             # and fetch dbh attributes
243 715         5867 my $skip_connect_check = $go_policy->skip_connect_check($attr, $dbh);
244 715 100       2014 if (not $skip_connect_check) {
245 530 100       2657 if (not $dbh->go_dbh_method(undef, 'ping')) {
246 26 50       735 return undef if $dbh->err; # error already recorded, typically
247 0         0 return $dbh->set_err($DBI::stderr, "ping failed");
248             }
249             }
250              
251 689         10911 return $dbh;
252             }
253              
254             sub _load_class { # return true or false+$@
255 1434     1434   2439 my $class = shift;
256 1434         5924 (my $pm = $class) =~ s{::}{/}g;
257 1434         3411 $pm .= ".pm";
258 1434 50       2287 return 1 if eval { require $pm };
  1434         49648  
259 0         0 delete $INC{$pm}; # shouldn't be needed (perl bug?) and assigning undef isn't enough
260 0         0 undef; # error in $@
261             }
262              
263             }
264              
265              
266             { package DBD::Gofer::db; # ====== DATABASE ======
267             $imp_data_size = 0;
268 56     56   440 use strict;
  56         156  
  56         1422  
269 56     56   291 use Carp qw(carp croak);
  56         124  
  56         43770  
270              
271             my %dbh_local_store_attrib = %DBD::Gofer::xxh_local_store_attrib;
272              
273             sub connected {
274 694     694   7364 shift->STORE(Active => 1);
275             }
276              
277             sub go_dbh_method {
278 4077     4077   16642 my $dbh = shift;
279 4077         5065 my $meta = shift;
280             # @_ now contains ($method_name, @args)
281              
282 4077         6316 my $request = $dbh->{go_request};
283 4077         18814 $request->init_request([ wantarray, @_ ], $dbh);
284 4077         6879 ++$dbh->{go_request_count};
285              
286 4077         6498 my $go_policy = $dbh->{go_policy};
287 4077         11090 my $dbh_attribute_update = $go_policy->dbh_attribute_update();
288             $request->dbh_attributes( $go_policy->dbh_attribute_list() )
289             if $dbh_attribute_update eq 'every'
290 4077 100 100     18896 or $dbh->{go_request_count}==1;
291              
292             $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
293 4077 50       8143 if $meta->{go_last_insert_id_args};
294              
295             my $transport = $dbh->{go_transport}
296 4077 50       8477 or return $dbh->set_err($DBI::stderr, "Not connected (no transport)");
297              
298             local $transport->{go_cache} = $dbh->{go_cache}
299 4077 50       7807 if defined $dbh->{go_cache};
300              
301 4077         10617 my ($response, $retransmit_sub) = $transport->transmit_request($request);
302 4077   33     18425 $response ||= $transport->receive_response($request, $retransmit_sub);
303 4077 50       19999 $dbh->{go_response} = $response
304             or die "No response object returned by $transport";
305              
306 4077 50       13821 die "response '$response' returned by $transport is not a response object"
307             unless UNIVERSAL::isa($response,"DBI::Gofer::Response");
308              
309 4077 100       9102 if (my $dbh_attributes = $response->dbh_attributes) {
310              
311             # XXX installed_methods piggybacks on dbh_attributes for now
312 1067 50       3482 if (my $installed_methods = delete $dbh_attributes->{dbi_installed_methods}) {
313             DBD::Gofer::install_methods_proxy($installed_methods)
314 1067 100       4710 if $dbh->{go_request_count}==1;
315             }
316              
317             # XXX we don't STORE here, we just stuff the value into the attribute cache
318             $dbh->{$_} = $dbh_attributes->{$_}
319 1067         14210 for keys %$dbh_attributes;
320             }
321              
322 4077         10609 my $rv = $response->rv;
323 4077 100       8844 if (my $resultset_list = $response->sth_resultsets) {
    50          
324             # dbh method call returned one or more resultsets
325             # (was probably a metadata method like table_info)
326             #
327             # setup an sth but don't execute/forward it
328 10         83 my $sth = $dbh->prepare(undef, { go_skip_prepare_check => 1 });
329             # set the sth response to our dbh response
330 10         117 (tied %$sth)->{go_response} = $response;
331             # setup the sth with the results in our response
332 10         56 $sth->more_results;
333             # and return that new sth as if it came from original request
334 10         69 $rv = [ $sth ];
335             }
336             elsif (!$rv) { # should only occur for major transport-level error
337             #carp("no rv in response { @{[ %$response ]} }");
338 0         0 $rv = [ ];
339             }
340              
341 4077         11029 DBD::Gofer::set_err_from_response($dbh, $response);
342              
343 4077 100       51547 return (wantarray) ? @$rv : $rv->[0];
344             }
345              
346              
347             # Methods that should be forwarded but can be cached
348             for my $method (qw(
349             tables table_info column_info primary_key_info foreign_key_info statistics_info
350             data_sources type_info_all get_info
351             parse_trace_flags parse_trace_flag
352             func
353             )) {
354             my $policy_name = "cache_$method";
355             my $super_name = "SUPER::$method";
356             my $sub = sub {
357 209     209   70985 my $dbh = shift;
358 209         371 my $rv;
359              
360             # if we know the remote side doesn't override the DBI's default method
361             # then we might as well just call the DBI's default method on the client
362             # (which may, in turn, call other methods that are forwarded, like get_info)
363 209 50 66     1179 if ($dbh->{dbi_default_methods}{$method} && $dbh->{go_policy}->skip_default_methods()) {
364 0         0 $dbh->trace_msg(" !! $method: using local default as remote method is also default\n");
365 0         0 return $dbh->$super_name(@_);
366             }
367              
368 209         481 my $cache;
369             my $cache_key;
370 209 100       1373 if (my $cache_it = $dbh->{go_policy}->$policy_name(undef, $dbh, @_)) {
371 185   100     772 $cache = $dbh->{go_meta_cache} ||= {}; # keep separate from go_cache
372             $cache_key = sprintf "%s_wa%d(%s)", $policy_name, wantarray||0,
373             join(",\t", map { # XXX basic but sufficient for now
374 185   100     931 !ref($_) ? DBI::neat($_,1e6)
375             : ref($_) eq 'ARRAY' ? DBI::neat_list($_,1e6,",\001")
376 108         561 : ref($_) eq 'HASH' ? do { my @k = sort keys %$_; DBI::neat_list([@k,@{$_}{@k}],1e6,",\002") }
  108         274  
  108         682  
377 182 50       1202 : do { warn "unhandled argument type ($_)"; $_ }
  0 50       0  
  0 100       0  
378             } @_);
379 185 100       702 if ($rv = $cache->{$cache_key}) {
380 58         628 $dbh->trace_msg("$method(@_) returning previously cached value ($cache_key)\n",4);
381 58         386 my @cache_rv = @$rv;
382             # if it's an sth we have to clone it
383 58 50       264 $cache_rv[0] = $cache_rv[0]->go_clone_sth if UNIVERSAL::isa($cache_rv[0],'DBI::st');
384 58 50       458 return (wantarray) ? @cache_rv : $cache_rv[0];
385             }
386             }
387              
388             $rv = [ (wantarray)
389 151 100       1083 ? ($dbh->go_dbh_method(undef, $method, @_))
390             : scalar $dbh->go_dbh_method(undef, $method, @_)
391             ];
392              
393 151 100       1434 if ($cache) {
394 127         1662 $dbh->trace_msg("$method(@_) caching return value ($cache_key)\n",4);
395 127         900 my @cache_rv = @$rv;
396             # if it's an sth we have to clone it
397             #$cache_rv[0] = $cache_rv[0]->go_clone_sth
398             # if UNIVERSAL::isa($cache_rv[0],'DBI::st');
399 127 50       1067 $cache->{$cache_key} = \@cache_rv
400             unless UNIVERSAL::isa($cache_rv[0],'DBI::st'); # XXX cloning sth not yet done
401             }
402              
403 151 100       1170 return (wantarray) ? @$rv : $rv->[0];
404             };
405 56     56   837 no strict 'refs';
  56         123  
  56         9904  
406             *$method = $sub;
407             }
408              
409              
410             # Methods that can use the DBI defaults for some situations/drivers
411             for my $method (qw(
412             quote quote_identifier
413             )) { # XXX keep DBD::Gofer::Policy::Base in sync
414             my $policy_name = "locally_$method";
415             my $super_name = "SUPER::$method";
416             my $sub = sub {
417 18     18   5117 my $dbh = shift;
418              
419             # if we know the remote side doesn't override the DBI's default method
420             # then we might as well just call the DBI's default method on the client
421             # (which may, in turn, call other methods that are forwarded, like get_info)
422 18 50 33     111 if ($dbh->{dbi_default_methods}{$method} && $dbh->{go_policy}->skip_default_methods()) {
423 0         0 $dbh->trace_msg(" !! $method: using local default as remote method is also default\n");
424 0         0 return $dbh->$super_name(@_);
425             }
426              
427             # false: use remote gofer
428             # 1: use local DBI default method
429             # code ref: use the code ref
430 18         79 my $locally = $dbh->{go_policy}->$policy_name($dbh, @_);
431 18 50       43 if ($locally) {
432 0 0       0 return $locally->($dbh, @_) if ref $locally eq 'CODE';
433 0         0 return $dbh->$super_name(@_);
434             }
435 18         72 return $dbh->go_dbh_method(undef, $method, @_); # propagate context
436             };
437 56     56   342 no strict 'refs';
  56         114  
  56         3150  
438             *$method = $sub;
439             }
440              
441              
442             # Methods that should always fail
443             for my $method (qw(
444             begin_work commit rollback
445             )) {
446 56     56   316 no strict 'refs';
  56         112  
  56         40719  
447 1     1   1766 *$method = sub { return shift->set_err($DBI::stderr, "$method not available with DBD::Gofer") }
448             }
449              
450              
451             sub do {
452 3324     3324   284454 my ($dbh, $sql, $attr, @args) = @_;
453 3324         5829 delete $dbh->{Statement}; # avoid "Modification of non-creatable hash value attempted"
454 3324         6028 $dbh->{Statement} = $sql; # for profiling and ShowErrorStatement
455 3324         7409 my $meta = { go_last_insert_id_args => $attr->{go_last_insert_id_args} };
456 3324         10890 return $dbh->go_dbh_method($meta, 'do', $sql, $attr, @args);
457             }
458              
459             sub ping {
460 57     57   1857 my $dbh = shift;
461 57 100       322 return $dbh->set_err('', "can't ping while not connected") # info
462             unless $dbh->SUPER::FETCH('Active');
463 51         387 my $skip_ping = $dbh->{go_policy}->skip_ping();
464 51 100       307 return ($skip_ping) ? 1 : $dbh->go_dbh_method(undef, 'ping', @_);
465             }
466              
467             sub last_insert_id {
468 0     0   0 my $dbh = shift;
469 0 0       0 my $response = $dbh->{go_response} or return undef;
470 0         0 return $response->last_insert_id;
471             }
472              
473             sub FETCH {
474 2408     2408   41337 my ($dbh, $attrib) = @_;
475              
476             # FETCH is effectively already cached because the DBI checks the
477             # attribute cache in the handle before calling FETCH
478             # and this FETCH copies the value into the attribute cache
479              
480             # forward driver-private attributes (except ours)
481 2408 100 66     9510 if ($attrib =~ m/^[a-z]/ && $attrib !~ /^go_/) {
482 7         40 my $value = $dbh->go_dbh_method(undef, 'FETCH', $attrib);
483 7         211 $dbh->{$attrib} = $value; # XXX forces caching by DBI
484 7         39 return $dbh->{$attrib} = $value;
485             }
486              
487             # else pass up to DBI to handle
488 2401         17180 return $dbh->SUPER::FETCH($attrib);
489             }
490              
491             sub STORE {
492 7343     7343   107462 my ($dbh, $attrib, $value) = @_;
493 7343 100       15240 if ($attrib eq 'AutoCommit') {
494 696 50       1859 croak "Can't enable transactions when using DBD::Gofer" if !$value;
495 696 50       4090 return $dbh->SUPER::STORE($attrib => ($value) ? -901 : -900);
496             }
497             return $dbh->SUPER::STORE($attrib => $value)
498             # we handle this attribute locally
499 6647 100 100     40601 if $dbh_local_store_attrib{$attrib}
      100        
500             # or it's a private_ (application) attribute
501             or $attrib =~ /^private_/
502             # or not yet connected (ie being called by DBI->connect)
503             or not $dbh->FETCH('Active');
504              
505             return $dbh->SUPER::STORE($attrib => $value)
506             if $DBD::Gofer::xxh_local_store_attrib_if_same_value{$attrib}
507 14 50 66     127 && do { # values are the same
508 10         34 my $crnt = $dbh->FETCH($attrib);
509 10         55 local $^W;
510 10 50       84 (defined($value) ^ defined($crnt))
511             ? 0 # definedness differs
512             : $value eq $crnt;
513             };
514              
515             # dbh attributes are set at connect-time - see connect()
516 4 50       15 carp("Can't alter \$dbh->{$attrib} after handle created with DBD::Gofer") if $dbh->FETCH('Warn');
517 4         656 return $dbh->set_err($DBI::stderr, "Can't alter \$dbh->{$attrib} after handle created with DBD::Gofer");
518             }
519              
520             sub disconnect {
521 107     107   248945 my $dbh = shift;
522 107         1029 $dbh->{go_transport} = undef;
523 107         774 $dbh->STORE(Active => 0);
524             }
525              
526             sub prepare {
527 1104     1104   202689 my ($dbh, $statement, $attr)= @_;
528              
529 1104 50       4459 return $dbh->set_err($DBI::stderr, "Can't prepare when disconnected")
530             unless $dbh->FETCH('Active');
531              
532 1104 100       8447 $attr = { %$attr } if $attr; # copy so we can edit
533              
534 1104   33     6158 my $policy = delete($attr->{go_policy}) || $dbh->{go_policy};
535 1104         2430 my $lii_args = delete $attr->{go_last_insert_id_args};
536             my $go_prepare = delete($attr->{go_prepare_method})
537             || $dbh->{go_prepare_method}
538 1104   100     8662 || $policy->prepare_method($dbh, $statement, $attr)
539             || 'prepare'; # e.g. for code not using placeholders
540 1104         2369 my $go_cache = delete $attr->{go_cache};
541             # set to undef if there are no attributes left for the actual prepare call
542 1104 100 66     5509 $attr = undef if $attr and not %$attr;
543              
544             my ($sth, $sth_inner) = DBI::_new_sth($dbh, {
545             Statement => $statement,
546             go_prepare_call => [ 0, $go_prepare, $statement, $attr ],
547             # go_method_calls => [], # autovivs if needed
548             go_request => $dbh->{go_request},
549             go_transport => $dbh->{go_transport},
550 1104         10134 go_policy => $policy,
551             go_last_insert_id_args => $lii_args,
552             go_cache => $go_cache,
553             });
554 1104         6323 $sth->STORE(Active => 0); # XXX needed? It should be the default
555              
556 1104         8048 my $skip_prepare_check = $policy->skip_prepare_check($attr, $dbh, $statement, $attr, $sth);
557 1104 100       2787 if (not $skip_prepare_check) {
558 594 100       2477 $sth->go_sth_method() or return undef;
559             }
560              
561 1032         8613 return $sth;
562             }
563              
564             sub prepare_cached {
565 14     14   9469 my ($dbh, $sql, $attr, $if_active)= @_;
566 14   100     68 $attr ||= {};
567             return $dbh->SUPER::prepare_cached($sql, {
568             %$attr,
569 14   50     111 go_prepare_method => $attr->{go_prepare_method} || 'prepare_cached',
570             }, $if_active);
571             }
572              
573             *go_cache = \&DBD::Gofer::go_cache;
574             }
575              
576              
577             { package DBD::Gofer::st; # ====== STATEMENT ======
578             $imp_data_size = 0;
579 56     56   406 use strict;
  56         98  
  56         73984  
580              
581             my %sth_local_store_attrib = (%DBD::Gofer::xxh_local_store_attrib, NUM_OF_FIELDS => 1);
582              
583             sub go_sth_method {
584 3061     3061   15436 my ($sth, $meta) = @_;
585              
586 3061 100       7637 if (my $ParamValues = $sth->{ParamValues}) {
587 2157         3223 my $ParamAttr = $sth->{ParamAttr};
588             # XXX the sort here is a hack to work around a DBD::Sybase bug
589             # but only works properly for params 1..9
590             # (reverse because of the unshift)
591 2157         8677 my @params = reverse sort keys %$ParamValues;
592 2157 50 50     6096 if (@params > 9 && ($sth->{Database}{go_dsn}||'') =~ /dbi:Sybase/) {
      66        
593             # if more than 9 then we need to do a proper numeric sort
594             # also warn to alert user of this issue
595 0         0 warn "Sybase param binding order hack in use";
596 0         0 @params = sort { $b <=> $a } @params;
  0         0  
597             }
598 2157         3679 for my $p (@params) {
599             # unshift to put binds before execute call
600 5418         16267 unshift @{ $sth->{go_method_calls} },
601 5418         5957 [ 'bind_param', $p, $ParamValues->{$p}, $ParamAttr->{$p} ];
602             }
603             }
604              
605 3061 50       7337 my $dbh = $sth->{Database} or die "panic";
606 3061         5083 ++$dbh->{go_request_count};
607              
608 3061         4330 my $request = $sth->{go_request};
609 3061         11470 $request->init_request($sth->{go_prepare_call}, $sth);
610             $request->sth_method_calls(delete $sth->{go_method_calls})
611 3061 100       11193 if $sth->{go_method_calls};
612 3061         8776 $request->sth_result_attr({}); # (currently) also indicates this is an sth request
613              
614             $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
615 3061 50       6843 if $meta->{go_last_insert_id_args};
616              
617 3061         4838 my $go_policy = $sth->{go_policy};
618 3061         9077 my $dbh_attribute_update = $go_policy->dbh_attribute_update();
619             $request->dbh_attributes( $go_policy->dbh_attribute_list() )
620             if $dbh_attribute_update eq 'every'
621 3061 100 100     12745 or $dbh->{go_request_count}==1;
622              
623             my $transport = $sth->{go_transport}
624 3061 50       7028 or return $sth->set_err($DBI::stderr, "Not connected (no transport)");
625              
626             local $transport->{go_cache} = $sth->{go_cache}
627 3061 100       6263 if defined $sth->{go_cache};
628              
629 3061         8565 my ($response, $retransmit_sub) = $transport->transmit_request($request);
630 3061   66     14491 $response ||= $transport->receive_response($request, $retransmit_sub);
631 3061 50       10612 $sth->{go_response} = $response
632             or die "No response object returned by $transport";
633 3061         13740 $dbh->{go_response} = $response; # mainly for last_insert_id
634              
635 3061 100       7651 if (my $dbh_attributes = $response->dbh_attributes) {
636             # XXX we don't STORE here, we just stuff the value into the attribute cache
637             $dbh->{$_} = $dbh_attributes->{$_}
638 2917         23870 for keys %$dbh_attributes;
639             # record the values returned, so we know that we have fetched
640             # values are which we have fetched (see dbh->FETCH method)
641 2917         19021 $dbh->{go_dbh_attributes_fetched} = $dbh_attributes;
642             }
643              
644 3061         7668 my $rv = $response->rv; # may be undef on error
645 3061 100       6577 if ($response->sth_resultsets) {
646             # setup first resultset - including sth attributes
647 2989         16256 $sth->more_results;
648             }
649             else {
650 72         486 $sth->STORE(Active => 0);
651 72         515 $sth->{go_rows} = $rv;
652             }
653             # set error/warn/info (after more_results as that'll clear err)
654 3061         15843 DBD::Gofer::set_err_from_response($sth, $response);
655              
656 3061         35647 return $rv;
657             }
658              
659              
660             sub bind_param {
661 5378     5378   20745 my ($sth, $param, $value, $attr) = @_;
662 5378         11927 $sth->{ParamValues}{$param} = $value;
663 5378 50       9214 $sth->{ParamAttr}{$param} = $attr
664             if defined $attr; # attr is sticky if not explicitly set
665 5378         13655 return 1;
666             }
667              
668              
669             sub execute {
670 2467     2467   133474 my $sth = shift;
671 2467         11682 $sth->bind_param($_, $_[$_-1]) for (1..@_);
672 2467         4288 push @{ $sth->{go_method_calls} }, [ 'execute' ];
  2467         8335  
673 2467         6422 my $meta = { go_last_insert_id_args => $sth->{go_last_insert_id_args} };
674 2467         8516 return $sth->go_sth_method($meta);
675             }
676              
677              
678             sub more_results {
679 3275     3275   28439 my $sth = shift;
680              
681 3275         13478 $sth->finish;
682              
683 3275 100       14404 my $response = $sth->{go_response} or do {
684             # e.g., we haven't sent a request yet (ie prepare then more_results)
685 96         478 $sth->trace_msg(" No response object present", 3);
686 96         1075 return;
687             };
688              
689 3179 50       6636 my $resultset_list = $response->sth_resultsets
690             or return $sth->set_err($DBI::stderr, "No sth_resultsets");
691              
692 3179 100       8633 my $meta = shift @$resultset_list
693             or return undef; # no more result sets
694             #warn "more_results: ".Data::Dumper::Dumper($meta);
695              
696             # pull out the special non-attributes first
697             my ($rowset, $err, $errstr, $state)
698 2999         4447 = delete @{$meta}{qw(rowset err errstr state)};
  2999         9772  
699              
700             # copy meta attributes into attribute cache
701 2999         6129 my $NUM_OF_FIELDS = delete $meta->{NUM_OF_FIELDS};
702 2999         12171 $sth->STORE('NUM_OF_FIELDS', $NUM_OF_FIELDS);
703             # XXX need to use STORE for some?
704 2999         27657 $sth->{$_} = $meta->{$_} for keys %$meta;
705              
706 2999 100 100     11227 if (($NUM_OF_FIELDS||0) > 0) {
707 2472 100       5709 $sth->{go_rows} = ($rowset) ? @$rowset : -1;
708 2472         19945 $sth->{go_current_rowset} = $rowset;
709 2472 100       5689 $sth->{go_current_rowset_err} = [ $err, $errstr, $state ]
710             if defined $err;
711 2472 100       8481 $sth->STORE(Active => 1) if $rowset;
712             }
713              
714 2999         12045 return $sth;
715             }
716              
717              
718             sub go_clone_sth {
719 0     0   0 my ($sth1) = @_;
720             # clone an (un-fetched-from) sth - effectively undoes the initial more_results
721             # not 100% so just for use in caching returned sth e.g. table_info
722 0         0 my $sth2 = $sth1->{Database}->prepare($sth1->{Statement}, { go_skip_prepare_check => 1 });
723 0         0 $sth2->STORE($_, $sth1->{$_}) for qw(NUM_OF_FIELDS Active);
724 0         0 my $sth2_inner = tied %$sth2;
725 0         0 $sth2_inner->{$_} = $sth1->{$_} for qw(NUM_OF_PARAMS FetchHashKeyName);
726 0         0 die "not fully implemented yet";
727 0         0 return $sth2;
728             }
729              
730              
731             sub fetchrow_arrayref {
732 4724     4724   44057 my ($sth) = @_;
733 4724   33     8990 my $resultset = $sth->{go_current_rowset} || do {
734             # should only happen if fetch called after execute failed
735             my $rowset_err = $sth->{go_current_rowset_err}
736             || [ 1, 'no result set (did execute fail)' ];
737             return $sth->set_err( @$rowset_err );
738             };
739 4724 100       34795 return $sth->_set_fbav(shift @$resultset) if @$resultset;
740 153         488 $sth->finish; # no more data so finish
741 153         860 return undef;
742             }
743             *fetch = \&fetchrow_arrayref; # alias
744              
745              
746             sub fetchall_arrayref {
747 238     238   20341 my ($sth, $slice, $max_rows) = @_;
748 238   66     1042 my $resultset = $sth->{go_current_rowset} || do {
749             # should only happen if fetch called after execute failed
750             my $rowset_err = $sth->{go_current_rowset_err}
751             || [ 1, 'no result set (did execute fail)' ];
752             return $sth->set_err( @$rowset_err );
753             };
754 214   100     1192 my $mode = ref($slice) || 'ARRAY';
755 214 100 66     1178 return $sth->SUPER::fetchall_arrayref($slice, $max_rows)
756             if ref($slice) or defined $max_rows;
757 184         731 $sth->finish; # no more data after this so finish
758 184         1320 return $resultset;
759             }
760              
761              
762             sub rows {
763 24     24   9157 return shift->{go_rows};
764             }
765              
766              
767             sub STORE {
768 6428     6428   45525 my ($sth, $attrib, $value) = @_;
769              
770             return $sth->SUPER::STORE($attrib => $value)
771 6428 50 33     38270 if $sth_local_store_attrib{$attrib} # handle locally
772             # or it's a private_ (application) attribute
773             or $attrib =~ /^private_/;
774              
775             # otherwise warn but do it anyway
776             # this will probably need refining later
777 0           my $msg = "Altering \$sth->{$attrib} won't affect proxied handle";
778 0 0         Carp::carp($msg) if $sth->FETCH('Warn');
779              
780             # XXX could perhaps do
781             # push @{ $sth->{go_method_calls} }, [ 'STORE', $attrib, $value ]
782             # if not $sth->FETCH('Executed');
783             # but how to handle repeat executions? How to we know when an
784             # attribute is being set to affect the current resultset or the
785             # next execution?
786             # Could just always use go_method_calls I guess.
787              
788             # do the store locally anyway, just in case
789 0           $sth->SUPER::STORE($attrib => $value);
790              
791 0           return $sth->set_err($DBI::stderr, $msg);
792             }
793              
794             # sub bind_param_array
795             # we use DBI's default, which sets $sth->{ParamArrays}{$param} = $value
796             # and calls bind_param($param, undef, $attr) if $attr.
797              
798             sub execute_array {
799 0     0     my $sth = shift;
800 0           my $attr = shift;
801 0           $sth->bind_param_array($_, $_[$_-1]) for (1..@_);
802 0           push @{ $sth->{go_method_calls} }, [ 'execute_array', $attr ];
  0            
803 0           return $sth->go_sth_method($attr);
804             }
805              
806             *go_cache = \&DBD::Gofer::go_cache;
807             }
808              
809             1;
810              
811             __END__