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 52     52   214 use strict;
  52         62  
  52         29376  
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 52 50   52 0 172 return $drh if $drh;
55              
56 52         163 DBI->setup_driver('DBD::Gofer');
57              
58 52 50       200 unless ($methods_already_installed++) {
59 52         148 my $opts = { O=> 0x0004 }; # IMA_KEEP_ERR
60 52         484 DBD::Gofer::db->install_method('go_dbh_method', $opts);
61 52         447 DBD::Gofer::st->install_method('go_sth_method', $opts);
62 52         234 DBD::Gofer::st->install_method('go_clone_sth', $opts);
63 52         314 DBD::Gofer::db->install_method('go_cache', $opts);
64 52         253 DBD::Gofer::st->install_method('go_cache', $opts);
65             }
66              
67 52         153 my($class, $attr) = @_;
68 52         104 $class .= "::dr";
69 52         388 ($drh) = DBI::_new_drh($class, {
70             'Name' => 'Gofer',
71             'Version' => $VERSION,
72             'Attribution' => 'DBD Gofer by Tim Bunce',
73             });
74              
75 52         221 $drh;
76             }
77              
78              
79             sub CLONE {
80 0     0   0 undef $drh;
81             }
82              
83              
84             sub go_cache {
85 4     4 0 79 my $h = shift;
86 4 50       13 $h->{go_cache} = shift if @_;
87             # return handle's override go_cache, if it has one
88 4 100       40 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 5588     5588 0 6239 my $h = shift;
96 5588         5712 my $response = shift;
97 5588 100       14174 if (my $warnings = $response->warnings) {
98 22         188 warn $_ for @$warnings;
99             }
100 5588         16868 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 5588 100       21117 $h->set_err($err, $errstr, $state) if defined $err;
105 5588         8075 return undef;
106             }
107              
108              
109             sub install_methods_proxy {
110 570     570 0 928 my ($installed_methods) = @_;
111 570         3151 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 4342         13483 DBI->_install_method($full_method, "", $attr||{})
116 4342 50 0     3350 unless defined &{$full_method};
117              
118             # now install proxy stubs on the driver side
119 4342 50       13720 $full_method =~ m/^DBI::(\w\w)::(\w+)$/
120             or die "Invalid method name '$full_method' for install_method";
121 4342         7720 my ($type, $method) = ($1, $2);
122 4342         6327 my $driver_method = "DBD::Gofer::${type}::${method}";
123 4342 100       3322 next if defined &{$driver_method};
  4342         22428  
124 140         131 my $sub;
125 140 100       236 if ($type eq 'db') {
126 100     20   310 $sub = sub { return shift->go_dbh_method(undef, $method, @_) };
  20         7187  
127             }
128             else {
129 40     0   156 $sub = sub { shift->set_err($DBI::stderr, "Can't call \$${type}h->$method when using DBD::Gofer"); return; };
  0         0  
  0         0  
130             }
131 52     52   270 no strict 'refs';
  52         106  
  52         3513  
132 140         648 *$driver_method = $sub;
133             }
134             }
135             }
136              
137              
138             { package DBD::Gofer::dr; # ====== DRIVER ======
139              
140             $imp_data_size = 0;
141 52     52   204 use strict;
  52         60  
  52         42926  
142              
143             sub connect_cached {
144 10     10   112 my ($drh, $dsn, $user, $auth, $attr)= @_;
145 10   50     21 $attr ||= {};
146 10   50     101 return $drh->SUPER::connect_cached($dsn, $user, $auth, {
147             (%$attr),
148             go_connect_method => $attr->{go_connect_method} || 'connect_cached',
149             });
150             }
151              
152              
153             sub connect {
154 706     706   9734 my($drh, $dsn, $user, $auth, $attr)= @_;
155 706         951 my $orig_dsn = $dsn;
156              
157             # first remove dsn= and everything after it
158 706 50 33     9009 my $remote_dsn = ($dsn =~ s/;?\bdsn=(.*)$// && $1)
159             or return $drh->set_err($DBI::stderr, "No dsn= argument in '$orig_dsn'");
160              
161 706 100       2028 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         5 return DBI->connect($remote_dsn, $user, $auth, $attr);
164             }
165              
166 705         905 my %go_attr;
167             # extract any go_ attributes from the connect() attr arg
168 705         2582 for my $k (grep { /^go_/ } keys %$attr) {
  4896         7765  
169 13         43 $go_attr{$k} = delete $attr->{$k};
170             }
171             # then override those with any attributes embedded in our dsn (not remote_dsn)
172 705         5246 for my $kv (grep /=/, split /;/, $dsn, -1) {
173 2088         4128 my ($k, $v) = split /=/, $kv, 2;
174 2088         5734 $go_attr{ "go_$k" } = $v;
175             }
176              
177 705 50       2502 if (not ref $go_attr{go_policy}) { # if not a policy object already
178 705   50     2103 my $policy_class = $go_attr{go_policy} || 'classic';
179 705 50       2834 $policy_class = "DBD::Gofer::Policy::$policy_class"
180             unless $policy_class =~ /::/;
181 705 50       1931 _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 705 50       1116 $go_attr{go_policy} = eval { $policy_class->new(\%go_attr) }
  705         4701  
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 705         1510 my $go_policy = $go_attr{go_policy};
189              
190 705 100 100     2282 if ($go_attr{go_cache} and not ref $go_attr{go_cache}) { # if not a cache object already
191 4         7 my $cache_class = $go_attr{go_cache};
192 4 50       15 $cache_class = "DBI::Util::CacheMemory" if $cache_class eq '1';
193 4 50       9 _load_class($cache_class)
194             or return $drh->set_err($DBI::stderr, "Can't load $cache_class $@");
195 4 50       6 $go_attr{go_cache} = eval { $cache_class->new() }
  4         30  
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 705         1385 my $go_connect_method = delete $go_attr{go_connect_method};
201              
202 705 50       2631 my $transport_class = delete $go_attr{go_transport}
203             or return $drh->set_err($DBI::stderr, "No transport= argument in '$orig_dsn'");
204 705 50       3173 $transport_class = "DBD::Gofer::Transport::$transport_class"
205             unless $transport_class =~ /::/;
206 705 50       1602 _load_class($transport_class)
207             or return $drh->set_err($DBI::stderr, "Can't load $transport_class: $@");
208 705 50       1182 my $go_transport = eval { $transport_class->new(\%go_attr) }
  705         4631  
209             or return $drh->set_err($DBI::stderr, "Can't instanciate $transport_class: $@");
210              
211 705         1538 my $request_class = "DBI::Gofer::Request";
212 705 50       955 my $go_request = eval {
213 705         4480 my $go_attr = { %$attr };
214             # XXX user/pass of fwd server vs db server ? also impact of autoproxy
215 705 100       1856 if ($user) {
216 13         24 $go_attr->{Username} = $user;
217 13         18 $go_attr->{Password} = $auth;
218             }
219             # delete any attributes we can't serialize (or don't want to)
220 705         1251 delete @{$go_attr}{qw(Profile HandleError HandleSetErr Callbacks)};
  705         1778  
221             # delete any attributes that should only apply to the client-side
222 705         1183 delete @{$go_attr}{qw(RootClass DbTypeSubclass)};
  705         1227  
223              
224 705   50     4508 $go_connect_method ||= $go_policy->connect_method($remote_dsn, $go_attr) || 'connect';
      66        
225 705         5177 $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 705         5992 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 705         4131 $dbh->STORE(Active => 0);
240              
241             # should we ping to check the connection
242             # and fetch dbh attributes
243 705         5345 my $skip_connect_check = $go_policy->skip_connect_check($attr, $dbh);
244 705 100       1778 if (not $skip_connect_check) {
245 520 100       2344 if (not $dbh->go_dbh_method(undef, 'ping')) {
246 26 50       799 return undef if $dbh->err; # error already recorded, typically
247 0         0 return $dbh->set_err($DBI::stderr, "ping failed");
248             }
249             }
250              
251 679         10472 return $dbh;
252             }
253              
254             sub _load_class { # return true or false+$@
255 1414     1414   1893 my $class = shift;
256 1414         5277 (my $pm = $class) =~ s{::}{/}g;
257 1414         1978 $pm .= ".pm";
258 1414 50       1656 return 1 if eval { require $pm };
  1414         57300  
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 52     52   270 use strict;
  52         407  
  52         1680  
269 52     52   219 use Carp qw(carp croak);
  52         66  
  52         39752  
270              
271             my %dbh_local_store_attrib = %DBD::Gofer::xxh_local_store_attrib;
272              
273             sub connected {
274 684     684   6418 shift->STORE(Active => 1);
275             }
276              
277             sub go_dbh_method {
278 4049     4049   13506 my $dbh = shift;
279 4049         3915 my $meta = shift;
280             # @_ now contains ($method_name, @args)
281              
282 4049         5520 my $request = $dbh->{go_request};
283 4049         17903 $request->init_request([ wantarray, @_ ], $dbh);
284 4049         5761 ++$dbh->{go_request_count};
285              
286 4049         5272 my $go_policy = $dbh->{go_policy};
287 4049         10835 my $dbh_attribute_update = $go_policy->dbh_attribute_update();
288 4049 100 100     20343 $request->dbh_attributes( $go_policy->dbh_attribute_list() )
289             if $dbh_attribute_update eq 'every'
290             or $dbh->{go_request_count}==1;
291              
292 4049 50       7866 $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
293             if $meta->{go_last_insert_id_args};
294              
295 4049 50       8863 my $transport = $dbh->{go_transport}
296             or return $dbh->set_err($DBI::stderr, "Not connected (no transport)");
297              
298 4049 50       8160 local $transport->{go_cache} = $dbh->{go_cache}
299             if defined $dbh->{go_cache};
300              
301 4049         10450 my ($response, $retransmit_sub) = $transport->transmit_request($request);
302 4049   33     17296 $response ||= $transport->receive_response($request, $retransmit_sub);
303 4049 50       11962 $dbh->{go_response} = $response
304             or die "No response object returned by $transport";
305              
306 4049 50       23687 die "response '$response' returned by $transport is not a response object"
307             unless UNIVERSAL::isa($response,"DBI::Gofer::Response");
308              
309 4049 100       10519 if (my $dbh_attributes = $response->dbh_attributes) {
310              
311             # XXX installed_methods piggybacks on dbh_attributes for now
312 1039 50       3395 if (my $installed_methods = delete $dbh_attributes->{dbi_installed_methods}) {
313 1039 100       4679 DBD::Gofer::install_methods_proxy($installed_methods)
314             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 1039         14411 for keys %$dbh_attributes;
320             }
321              
322 4049         10707 my $rv = $response->rv;
323 4049 100       8531 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         81 my $sth = $dbh->prepare(undef, { go_skip_prepare_check => 1 });
329             # set the sth response to our dbh response
330 10         96 (tied %$sth)->{go_response} = $response;
331             # setup the sth with the results in our response
332 10         53 $sth->more_results;
333             # and return that new sth as if it came from original request
334 10         50 $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 4049         8454 DBD::Gofer::set_err_from_response($dbh, $response);
342              
343 4049 100       59645 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 205     205   59984 my $dbh = shift;
358 205         275 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 205 50 66     1274 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 205         300 my $cache;
369             my $cache_key;
370 205 100       1286 if (my $cache_it = $dbh->{go_policy}->$policy_name(undef, $dbh, @_)) {
371 185   100     781 $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     1023 !ref($_) ? DBI::neat($_,1e6)
375             : ref($_) eq 'ARRAY' ? DBI::neat_list($_,1e6,",\001")
376 108         566 : ref($_) eq 'HASH' ? do { my @k = sort keys %$_; DBI::neat_list([@k,@{$_}{@k}],1e6,",\002") }
  108         202  
  108         753  
377 182 50       1195 : do { warn "unhandled argument type ($_)"; $_ }
  0 50       0  
  0 100       0  
378             } @_);
379 185 100       633 if ($rv = $cache->{$cache_key}) {
380 58         554 $dbh->trace_msg("$method(@_) returning previously cached value ($cache_key)\n",4);
381 58         358 my @cache_rv = @$rv;
382             # if it's an sth we have to clone it
383 58 50       249 $cache_rv[0] = $cache_rv[0]->go_clone_sth if UNIVERSAL::isa($cache_rv[0],'DBI::st');
384 58 50       404 return (wantarray) ? @cache_rv : $cache_rv[0];
385             }
386             }
387              
388             $rv = [ (wantarray)
389 147 100       923 ? ($dbh->go_dbh_method(undef, $method, @_))
390             : scalar $dbh->go_dbh_method(undef, $method, @_)
391             ];
392              
393 147 100       1268 if ($cache) {
394 127         1618 $dbh->trace_msg("$method(@_) caching return value ($cache_key)\n",4);
395 127         763 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       986 $cache->{$cache_key} = \@cache_rv
400             unless UNIVERSAL::isa($cache_rv[0],'DBI::st'); # XXX cloning sth not yet done
401             }
402              
403 147 100       1080 return (wantarray) ? @$rv : $rv->[0];
404             };
405 52     52   272 no strict 'refs';
  52         70  
  52         8936  
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   7144 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     150 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         94 my $locally = $dbh->{go_policy}->$policy_name($dbh, @_);
431 18 50       40 if ($locally) {
432 0 0       0 return $locally->($dbh, @_) if ref $locally eq 'CODE';
433 0         0 return $dbh->$super_name(@_);
434             }
435 18         71 return $dbh->go_dbh_method(undef, $method, @_); # propagate context
436             };
437 52     52   413 no strict 'refs';
  52         66  
  52         2916  
438             *$method = $sub;
439             }
440              
441              
442             # Methods that should always fail
443             for my $method (qw(
444             begin_work commit rollback
445             )) {
446 52     52   257 no strict 'refs';
  52         64  
  52         37600  
447 1     1   1509 *$method = sub { return shift->set_err($DBI::stderr, "$method not available with DBD::Gofer") }
448             }
449              
450              
451             sub do {
452 3310     3310   240692 my ($dbh, $sql, $attr, @args) = @_;
453 3310         5719 delete $dbh->{Statement}; # avoid "Modification of non-creatable hash value attempted"
454 3310         5453 $dbh->{Statement} = $sql; # for profiling and ShowErrorStatement
455 3310         7250 my $meta = { go_last_insert_id_args => $attr->{go_last_insert_id_args} };
456 3310         10329 return $dbh->go_dbh_method($meta, 'do', $sql, $attr, @args);
457             }
458              
459             sub ping {
460 57     57   2034 my $dbh = shift;
461 57 100       293 return $dbh->set_err('', "can't ping while not connected") # info
462             unless $dbh->SUPER::FETCH('Active');
463 51         359 my $skip_ping = $dbh->{go_policy}->skip_ping();
464 51 100       320 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 2386     2386   32286 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 2386 100 66     9647 if ($attrib =~ m/^[a-z]/ && $attrib !~ /^go_/) {
482 7         34 my $value = $dbh->go_dbh_method(undef, 'FETCH', $attrib);
483 7         33 $dbh->{$attrib} = $value; # XXX forces caching by DBI
484 7         29 return $dbh->{$attrib} = $value;
485             }
486              
487             # else pass up to DBI to handle
488 2379         17108 return $dbh->SUPER::FETCH($attrib);
489             }
490              
491             sub STORE {
492 7273     7273   84721 my ($dbh, $attrib, $value) = @_;
493 7273 100       13944 if ($attrib eq 'AutoCommit') {
494 686 50       1632 croak "Can't enable transactions when using DBD::Gofer" if !$value;
495 686 50       4307 return $dbh->SUPER::STORE($attrib => ($value) ? -901 : -900);
496             }
497 6587 100 100     43697 return $dbh->SUPER::STORE($attrib => $value)
      100        
498             # we handle this attribute locally
499             if $dbh_local_store_attrib{$attrib}
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     101 && do { # values are the same
508 10         27 my $crnt = $dbh->FETCH($attrib);
509 10         41 local $^W;
510 10 50       75 (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         755 return $dbh->set_err($DBI::stderr, "Can't alter \$dbh->{$attrib} after handle created with DBD::Gofer");
518             }
519              
520             sub disconnect {
521 105     105   192363 my $dbh = shift;
522 105         334 $dbh->{go_transport} = undef;
523 105         1467 $dbh->STORE(Active => 0);
524             }
525              
526             sub prepare {
527 1084     1084   164337 my ($dbh, $statement, $attr)= @_;
528              
529 1084 50       3910 return $dbh->set_err($DBI::stderr, "Can't prepare when disconnected")
530             unless $dbh->FETCH('Active');
531              
532 1084 100       7008 $attr = { %$attr } if $attr; # copy so we can edit
533              
534 1084   33     6505 my $policy = delete($attr->{go_policy}) || $dbh->{go_policy};
535 1084         1684 my $lii_args = delete $attr->{go_last_insert_id_args};
536 1084   100     9485 my $go_prepare = delete($attr->{go_prepare_method})
537             || $dbh->{go_prepare_method}
538             || $policy->prepare_method($dbh, $statement, $attr)
539             || 'prepare'; # e.g. for code not using placeholders
540 1084         1839 my $go_cache = delete $attr->{go_cache};
541             # set to undef if there are no attributes left for the actual prepare call
542 1084 100 66     6143 $attr = undef if $attr and not %$attr;
543              
544 1084         11497 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             go_policy => $policy,
551             go_last_insert_id_args => $lii_args,
552             go_cache => $go_cache,
553             });
554 1084         5215 $sth->STORE(Active => 0); # XXX needed? It should be the default
555              
556 1084         7057 my $skip_prepare_check = $policy->skip_prepare_check($attr, $dbh, $statement, $attr, $sth);
557 1084 100       2673 if (not $skip_prepare_check) {
558 574 100       2522 $sth->go_sth_method() or return undef;
559             }
560              
561 1012         7091 return $sth;
562             }
563              
564             sub prepare_cached {
565 10     10   11250 my ($dbh, $sql, $attr, $if_active)= @_;
566 10   100     56 $attr ||= {};
567 10   50     118 return $dbh->SUPER::prepare_cached($sql, {
568             %$attr,
569             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 52     52   270 use strict;
  52         70  
  52         59378  
580              
581             my %sth_local_store_attrib = (%DBD::Gofer::xxh_local_store_attrib, NUM_OF_FIELDS => 1);
582              
583             sub go_sth_method {
584 1539     1539   10216 my ($sth, $meta) = @_;
585              
586 1539 100       4709 if (my $ParamValues = $sth->{ParamValues}) {
587 655         1244 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 655         4941 my @params = reverse sort keys %$ParamValues;
592 655 50 50     2433 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 655         1333 for my $p (@params) {
599             # unshift to put binds before execute call
600 3916         2924 unshift @{ $sth->{go_method_calls} },
  3916         10649  
601             [ 'bind_param', $p, $ParamValues->{$p}, $ParamAttr->{$p} ];
602             }
603             }
604              
605 1539 50       4801 my $dbh = $sth->{Database} or die "panic";
606 1539         2643 ++$dbh->{go_request_count};
607              
608 1539         2303 my $request = $sth->{go_request};
609 1539         6821 $request->init_request($sth->{go_prepare_call}, $sth);
610 1539 100       6016 $request->sth_method_calls(delete $sth->{go_method_calls})
611             if $sth->{go_method_calls};
612 1539         4769 $request->sth_result_attr({}); # (currently) also indicates this is an sth request
613              
614 1539 50       3976 $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
615             if $meta->{go_last_insert_id_args};
616              
617 1539         3113 my $go_policy = $sth->{go_policy};
618 1539         5364 my $dbh_attribute_update = $go_policy->dbh_attribute_update();
619 1539 100 100     8569 $request->dbh_attributes( $go_policy->dbh_attribute_list() )
620             if $dbh_attribute_update eq 'every'
621             or $dbh->{go_request_count}==1;
622              
623 1539 50       4722 my $transport = $sth->{go_transport}
624             or return $sth->set_err($DBI::stderr, "Not connected (no transport)");
625              
626 1539 100       3900 local $transport->{go_cache} = $sth->{go_cache}
627             if defined $sth->{go_cache};
628              
629 1539         5454 my ($response, $retransmit_sub) = $transport->transmit_request($request);
630 1539   66     9209 $response ||= $transport->receive_response($request, $retransmit_sub);
631 1539 50       7204 $sth->{go_response} = $response
632             or die "No response object returned by $transport";
633 1539         3301 $dbh->{go_response} = $response; # mainly for last_insert_id
634              
635 1539 100       10109 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 1395         15087 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 1395         3496 $dbh->{go_dbh_attributes_fetched} = $dbh_attributes;
642             }
643              
644 1539         11470 my $rv = $response->rv; # may be undef on error
645 1539 100       3987 if ($response->sth_resultsets) {
646             # setup first resultset - including sth attributes
647 1467         9503 $sth->more_results;
648             }
649             else {
650 72         463 $sth->STORE(Active => 0);
651 72         445 $sth->{go_rows} = $rv;
652             }
653             # set error/warn/info (after more_results as that'll clear err)
654 1539         8783 DBD::Gofer::set_err_from_response($sth, $response);
655              
656 1539         22207 return $rv;
657             }
658              
659              
660             sub bind_param {
661 3876     3876   12237 my ($sth, $param, $value, $attr) = @_;
662 3876         7527 $sth->{ParamValues}{$param} = $value;
663 3876 50       5784 $sth->{ParamAttr}{$param} = $attr
664             if defined $attr; # attr is sticky if not explicitly set
665 3876         9543 return 1;
666             }
667              
668              
669             sub execute {
670 965     965   89967 my $sth = shift;
671 965         5496 $sth->bind_param($_, $_[$_-1]) for (1..@_);
672 965         2277 push @{ $sth->{go_method_calls} }, [ 'execute' ];
  965         3997  
673 965         3195 my $meta = { go_last_insert_id_args => $sth->{go_last_insert_id_args} };
674 965         3759 return $sth->go_sth_method($meta);
675             }
676              
677              
678             sub more_results {
679 1753     1753   20751 my $sth = shift;
680              
681 1753         7270 $sth->finish;
682              
683 1753 100       10298 my $response = $sth->{go_response} or do {
684             # e.g., we haven't sent a request yet (ie prepare then more_results)
685 96         438 $sth->trace_msg(" No response object present", 3);
686 96         975 return;
687             };
688              
689 1657 50       4204 my $resultset_list = $response->sth_resultsets
690             or return $sth->set_err($DBI::stderr, "No sth_resultsets");
691              
692 1657 100       5737 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 1477         4628 my ($rowset, $err, $errstr, $state)
698 1477         2296 = delete @{$meta}{qw(rowset err errstr state)};
699              
700             # copy meta attributes into attribute cache
701 1477         2990 my $NUM_OF_FIELDS = delete $meta->{NUM_OF_FIELDS};
702 1477         6961 $sth->STORE('NUM_OF_FIELDS', $NUM_OF_FIELDS);
703             # XXX need to use STORE for some?
704 1477         16848 $sth->{$_} = $meta->{$_} for keys %$meta;
705              
706 1477 100 100     6984 if (($NUM_OF_FIELDS||0) > 0) {
707 950 100       2892 $sth->{go_rows} = ($rowset) ? @$rowset : -1;
708 950         1762 $sth->{go_current_rowset} = $rowset;
709 950 100       6860 $sth->{go_current_rowset_err} = [ $err, $errstr, $state ]
710             if defined $err;
711 950 100       3534 $sth->STORE(Active => 1) if $rowset;
712             }
713              
714 1477         6333 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 3122     3122   28549 my ($sth) = @_;
733 3122   33     6561 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 3122 100       23157 return $sth->_set_fbav(shift @$resultset) if @$resultset;
740 153         483 $sth->finish; # no more data so finish
741 153         822 return undef;
742             }
743             *fetch = \&fetchrow_arrayref; # alias
744              
745              
746             sub fetchall_arrayref {
747 236     236   18435 my ($sth, $slice, $max_rows) = @_;
748 236   66     966 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 212   100     1380 my $mode = ref($slice) || 'ARRAY';
755 212 100 66     1252 return $sth->SUPER::fetchall_arrayref($slice, $max_rows)
756             if ref($slice) or defined $max_rows;
757 182         668 $sth->finish; # no more data after this so finish
758 182         1150 return $resultset;
759             }
760              
761              
762             sub rows {
763 24     24   9760 return shift->{go_rows};
764             }
765              
766              
767             sub STORE {
768 3384     3384   41586 my ($sth, $attrib, $value) = @_;
769              
770 3384 50 33     24475 return $sth->SUPER::STORE($attrib => $value)
771             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__