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   312 use strict;
  56         103  
  56         30307  
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 215 return $drh if $drh;
55              
56 56         192 DBI->setup_driver('DBD::Gofer');
57              
58 56 50       232 unless ($methods_already_installed++) {
59 56         152 my $opts = { O=> 0x0004 }; # IMA_KEEP_ERR
60 56         432 DBD::Gofer::db->install_method('go_dbh_method', $opts);
61 56         441 DBD::Gofer::st->install_method('go_sth_method', $opts);
62 56         274 DBD::Gofer::st->install_method('go_clone_sth', $opts);
63 56         285 DBD::Gofer::db->install_method('go_cache', $opts);
64 56         273 DBD::Gofer::st->install_method('go_cache', $opts);
65             }
66              
67 56         201 my($class, $attr) = @_;
68 56         149 $class .= "::dr";
69 56         355 ($drh) = DBI::_new_drh($class, {
70             'Name' => 'Gofer',
71             'Version' => $VERSION,
72             'Attribution' => 'DBD Gofer by Tim Bunce',
73             });
74              
75 56         213 $drh;
76             }
77              
78              
79             sub CLONE {
80 0     0   0 undef $drh;
81             }
82              
83              
84             sub go_cache {
85 4     4 0 49 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       20 return $h->{go_cache} if defined $h->{go_cache};
89             # or else the transports default go_cache
90 2         7 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 10056 my $h = shift;
96 7138         8709 my $response = shift;
97 7138 100       15130 if (my $warnings = $response->warnings) {
98 22         252 warn $_ for @$warnings;
99             }
100 7138         18060 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       24561 $h->set_err($err, $errstr, $state) if defined $err;
105 7138         11940 return undef;
106             }
107              
108              
109             sub install_methods_proxy {
110 580     580 0 1576 my ($installed_methods) = @_;
111 580         3224 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     6511 unless defined &{$full_method};
  4866         15082  
117              
118             # now install proxy stubs on the driver side
119 4866 50       16471 $full_method =~ m/^DBI::(\w\w)::(\w+)$/
120             or die "Invalid method name '$full_method' for install_method";
121 4866         11995 my ($type, $method) = ($1, $2);
122 4866         8582 my $driver_method = "DBD::Gofer::${type}::${method}";
123 4866 100       5649 next if defined &{$driver_method};
  4866         22946  
124 166         236 my $sub;
125 166 100       311 if ($type eq 'db') {
126 126     20   356 $sub = sub { return shift->go_dbh_method(undef, $method, @_) };
  20         6469  
127             }
128             else {
129 40     0   151 $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   371 no strict 'refs';
  56         107  
  56         4361  
132 166         822 *$driver_method = $sub;
133             }
134             }
135             }
136              
137              
138             { package DBD::Gofer::dr; # ====== DRIVER ======
139              
140             $imp_data_size = 0;
141 56     56   1206 use strict;
  56         105  
  56         42343  
142              
143             sub connect_cached {
144 10     10   153 my ($drh, $dsn, $user, $auth, $attr)= @_;
145 10   50     24 $attr ||= {};
146             return $drh->SUPER::connect_cached($dsn, $user, $auth, {
147             (%$attr),
148 10   50     99 go_connect_method => $attr->{go_connect_method} || 'connect_cached',
149             });
150             }
151              
152              
153             sub connect {
154 716     716   12975 my($drh, $dsn, $user, $auth, $attr)= @_;
155 716         1265 my $orig_dsn = $dsn;
156              
157             # first remove dsn= and everything after it
158 716 50 33     9114 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       2483 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 715         1266 my %go_attr;
167             # extract any go_ attributes from the connect() attr arg
168 715         2951 for my $k (grep { /^go_/ } keys %$attr) {
  4932         9715  
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 715         4956 for my $kv (grep /=/, split /;/, $dsn, -1) {
173 2108         5521 my ($k, $v) = split /=/, $kv, 2;
174 2108         6020 $go_attr{ "go_$k" } = $v;
175             }
176              
177 715 50       2396 if (not ref $go_attr{go_policy}) { # if not a policy object already
178 715   50     2105 my $policy_class = $go_attr{go_policy} || 'classic';
179 715 50       2605 $policy_class = "DBD::Gofer::Policy::$policy_class"
180             unless $policy_class =~ /::/;
181 715 50       2370 _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       1515 $go_attr{go_policy} = eval { $policy_class->new(\%go_attr) }
  715         4261  
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         1590 my $go_policy = $go_attr{go_policy};
189              
190 715 100 100     2225 if ($go_attr{go_cache} and not ref $go_attr{go_cache}) { # if not a cache object already
191 4         9 my $cache_class = $go_attr{go_cache};
192 4 50       16 $cache_class = "DBI::Util::CacheMemory" if $cache_class eq '1';
193 4 50       8 _load_class($cache_class)
194             or return $drh->set_err($DBI::stderr, "Can't load $cache_class $@");
195 4 50       5 $go_attr{go_cache} = eval { $cache_class->new() }
  4         24  
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         1352 my $go_connect_method = delete $go_attr{go_connect_method};
201              
202             my $transport_class = delete $go_attr{go_transport}
203 715 50       2018 or return $drh->set_err($DBI::stderr, "No transport= argument in '$orig_dsn'");
204 715 50       2756 $transport_class = "DBD::Gofer::Transport::$transport_class"
205             unless $transport_class =~ /::/;
206 715 50       1720 _load_class($transport_class)
207             or return $drh->set_err($DBI::stderr, "Can't load $transport_class: $@");
208 715 50       1311 my $go_transport = eval { $transport_class->new(\%go_attr) }
  715         4379  
209             or return $drh->set_err($DBI::stderr, "Can't instanciate $transport_class: $@");
210              
211 715         1660 my $request_class = "DBI::Gofer::Request";
212 715 50       1151 my $go_request = eval {
213 715         4201 my $go_attr = { %$attr };
214             # XXX user/pass of fwd server vs db server ? also impact of autoproxy
215 715 100       2225 if ($user) {
216 13         25 $go_attr->{Username} = $user;
217 13         28 $go_attr->{Password} = $auth;
218             }
219             # delete any attributes we can't serialize (or don't want to)
220 715         1325 delete @{$go_attr}{qw(Profile HandleError HandleSetErr Callbacks)};
  715         1889  
221             # delete any attributes that should only apply to the client-side
222 715         1270 delete @{$go_attr}{qw(RootClass DbTypeSubclass)};
  715         1761  
223              
224 715   50     4090 $go_connect_method ||= $go_policy->connect_method($remote_dsn, $go_attr) || 'connect';
      66        
225 715         4236 $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         5394 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         4377 $dbh->STORE(Active => 0);
240              
241             # should we ping to check the connection
242             # and fetch dbh attributes
243 715         5581 my $skip_connect_check = $go_policy->skip_connect_check($attr, $dbh);
244 715 100       1927 if (not $skip_connect_check) {
245 530 100       2183 if (not $dbh->go_dbh_method(undef, 'ping')) {
246 26 50       642 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         10089 return $dbh;
252             }
253              
254             sub _load_class { # return true or false+$@
255 1434     1434   2186 my $class = shift;
256 1434         5638 (my $pm = $class) =~ s{::}{/}g;
257 1434         2581 $pm .= ".pm";
258 1434 50       2170 return 1 if eval { require $pm };
  1434         45658  
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   418 use strict;
  56         126  
  56         1302  
269 56     56   270 use Carp qw(carp croak);
  56         114  
  56         40141  
270              
271             my %dbh_local_store_attrib = %DBD::Gofer::xxh_local_store_attrib;
272              
273             sub connected {
274 694     694   7576 shift->STORE(Active => 1);
275             }
276              
277             sub go_dbh_method {
278 4077     4077   15419 my $dbh = shift;
279 4077         5309 my $meta = shift;
280             # @_ now contains ($method_name, @args)
281              
282 4077         5939 my $request = $dbh->{go_request};
283 4077         17576 $request->init_request([ wantarray, @_ ], $dbh);
284 4077         6559 ++$dbh->{go_request_count};
285              
286 4077         5591 my $go_policy = $dbh->{go_policy};
287 4077         10190 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     16868 or $dbh->{go_request_count}==1;
291              
292             $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
293 4077 50       8131 if $meta->{go_last_insert_id_args};
294              
295             my $transport = $dbh->{go_transport}
296 4077 50       7858 or return $dbh->set_err($DBI::stderr, "Not connected (no transport)");
297              
298             local $transport->{go_cache} = $dbh->{go_cache}
299 4077 50       8086 if defined $dbh->{go_cache};
300              
301 4077         9849 my ($response, $retransmit_sub) = $transport->transmit_request($request);
302 4077   33     16661 $response ||= $transport->receive_response($request, $retransmit_sub);
303 4077 50       18897 $dbh->{go_response} = $response
304             or die "No response object returned by $transport";
305              
306 4077 50       13081 die "response '$response' returned by $transport is not a response object"
307             unless UNIVERSAL::isa($response,"DBI::Gofer::Response");
308              
309 4077 100       9322 if (my $dbh_attributes = $response->dbh_attributes) {
310              
311             # XXX installed_methods piggybacks on dbh_attributes for now
312 1067 50       4689 if (my $installed_methods = delete $dbh_attributes->{dbi_installed_methods}) {
313             DBD::Gofer::install_methods_proxy($installed_methods)
314 1067 100       4188 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         12538 for keys %$dbh_attributes;
320             }
321              
322 4077         10306 my $rv = $response->rv;
323 4077 100       7635 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         109 my $sth = $dbh->prepare(undef, { go_skip_prepare_check => 1 });
329             # set the sth response to our dbh response
330 10         105 (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         60 $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         9864 DBD::Gofer::set_err_from_response($dbh, $response);
342              
343 4077 100       47741 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   63687 my $dbh = shift;
358 209         342 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     960 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         395 my $cache;
369             my $cache_key;
370 209 100       1169 if (my $cache_it = $dbh->{go_policy}->$policy_name(undef, $dbh, @_)) {
371 185   100     627 $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     809 !ref($_) ? DBI::neat($_,1e6)
375             : ref($_) eq 'ARRAY' ? DBI::neat_list($_,1e6,",\001")
376 108         506 : ref($_) eq 'HASH' ? do { my @k = sort keys %$_; DBI::neat_list([@k,@{$_}{@k}],1e6,",\002") }
  108         283  
  108         623  
377 182 50       955 : do { warn "unhandled argument type ($_)"; $_ }
  0 50       0  
  0 100       0  
378             } @_);
379 185 100       603 if ($rv = $cache->{$cache_key}) {
380 58         476 $dbh->trace_msg("$method(@_) returning previously cached value ($cache_key)\n",4);
381 58         368 my @cache_rv = @$rv;
382             # if it's an sth we have to clone it
383 58 50       224 $cache_rv[0] = $cache_rv[0]->go_clone_sth if UNIVERSAL::isa($cache_rv[0],'DBI::st');
384 58 50       306 return (wantarray) ? @cache_rv : $cache_rv[0];
385             }
386             }
387              
388             $rv = [ (wantarray)
389 151 100       834 ? ($dbh->go_dbh_method(undef, $method, @_))
390             : scalar $dbh->go_dbh_method(undef, $method, @_)
391             ];
392              
393 151 100       1290 if ($cache) {
394 127         1377 $dbh->trace_msg("$method(@_) caching return value ($cache_key)\n",4);
395 127         878 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       894 $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       1057 return (wantarray) ? @$rv : $rv->[0];
404             };
405 56     56   690 no strict 'refs';
  56         108  
  56         9034  
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   5089 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     100 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         68 my $locally = $dbh->{go_policy}->$policy_name($dbh, @_);
431 18 50       32 if ($locally) {
432 0 0       0 return $locally->($dbh, @_) if ref $locally eq 'CODE';
433 0         0 return $dbh->$super_name(@_);
434             }
435 18         55 return $dbh->go_dbh_method(undef, $method, @_); # propagate context
436             };
437 56     56   314 no strict 'refs';
  56         100  
  56         2970  
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   332 no strict 'refs';
  56         107  
  56         37843  
447 1     1   1751 *$method = sub { return shift->set_err($DBI::stderr, "$method not available with DBD::Gofer") }
448             }
449              
450              
451             sub do {
452 3324     3324   269521 my ($dbh, $sql, $attr, @args) = @_;
453 3324         5772 delete $dbh->{Statement}; # avoid "Modification of non-creatable hash value attempted"
454 3324         5837 $dbh->{Statement} = $sql; # for profiling and ShowErrorStatement
455 3324         7194 my $meta = { go_last_insert_id_args => $attr->{go_last_insert_id_args} };
456 3324         10203 return $dbh->go_dbh_method($meta, 'do', $sql, $attr, @args);
457             }
458              
459             sub ping {
460 57     57   1832 my $dbh = shift;
461 57 100       291 return $dbh->set_err('', "can't ping while not connected") # info
462             unless $dbh->SUPER::FETCH('Active');
463 51         371 my $skip_ping = $dbh->{go_policy}->skip_ping();
464 51 100       306 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   31232 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     8682 if ($attrib =~ m/^[a-z]/ && $attrib !~ /^go_/) {
482 7         28 my $value = $dbh->go_dbh_method(undef, 'FETCH', $attrib);
483 7         252 $dbh->{$attrib} = $value; # XXX forces caching by DBI
484 7         37 return $dbh->{$attrib} = $value;
485             }
486              
487             # else pass up to DBI to handle
488 2401         14919 return $dbh->SUPER::FETCH($attrib);
489             }
490              
491             sub STORE {
492 7343     7343   105648 my ($dbh, $attrib, $value) = @_;
493 7343 100       14591 if ($attrib eq 'AutoCommit') {
494 696 50       1623 croak "Can't enable transactions when using DBD::Gofer" if !$value;
495 696 50       3823 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     36772 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     110 && do { # values are the same
508 10         35 my $crnt = $dbh->FETCH($attrib);
509 10         68 local $^W;
510 10 50       87 (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         660 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   224299 my $dbh = shift;
522 107         895 $dbh->{go_transport} = undef;
523 107         667 $dbh->STORE(Active => 0);
524             }
525              
526             sub prepare {
527 1104     1104   174649 my ($dbh, $statement, $attr)= @_;
528              
529 1104 50       3838 return $dbh->set_err($DBI::stderr, "Can't prepare when disconnected")
530             unless $dbh->FETCH('Active');
531              
532 1104 100       8101 $attr = { %$attr } if $attr; # copy so we can edit
533              
534 1104   33     5700 my $policy = delete($attr->{go_policy}) || $dbh->{go_policy};
535 1104         1936 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     8045 || $policy->prepare_method($dbh, $statement, $attr)
539             || 'prepare'; # e.g. for code not using placeholders
540 1104         2224 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     5332 $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         9734 go_policy => $policy,
551             go_last_insert_id_args => $lii_args,
552             go_cache => $go_cache,
553             });
554 1104         5889 $sth->STORE(Active => 0); # XXX needed? It should be the default
555              
556 1104         7487 my $skip_prepare_check = $policy->skip_prepare_check($attr, $dbh, $statement, $attr, $sth);
557 1104 100       2600 if (not $skip_prepare_check) {
558 594 100       2315 $sth->go_sth_method() or return undef;
559             }
560              
561 1032         8138 return $sth;
562             }
563              
564             sub prepare_cached {
565 14     14   12460 my ($dbh, $sql, $attr, $if_active)= @_;
566 14   100     74 $attr ||= {};
567             return $dbh->SUPER::prepare_cached($sql, {
568             %$attr,
569 14   50     124 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   383 use strict;
  56         92  
  56         59955  
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   15487 my ($sth, $meta) = @_;
585              
586 3061 100       7171 if (my $ParamValues = $sth->{ParamValues}) {
587 2157         3233 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         9028 my @params = reverse sort keys %$ParamValues;
592 2157 50 50     6008 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         3572 for my $p (@params) {
599             # unshift to put binds before execute call
600 5418         16431 unshift @{ $sth->{go_method_calls} },
601 5418         6681 [ 'bind_param', $p, $ParamValues->{$p}, $ParamAttr->{$p} ];
602             }
603             }
604              
605 3061 50       7530 my $dbh = $sth->{Database} or die "panic";
606 3061         4798 ++$dbh->{go_request_count};
607              
608 3061         4147 my $request = $sth->{go_request};
609 3061         11279 $request->init_request($sth->{go_prepare_call}, $sth);
610             $request->sth_method_calls(delete $sth->{go_method_calls})
611 3061 100       10882 if $sth->{go_method_calls};
612 3061         8660 $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       6734 if $meta->{go_last_insert_id_args};
616              
617 3061         4696 my $go_policy = $sth->{go_policy};
618 3061         8558 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     11858 or $dbh->{go_request_count}==1;
622              
623             my $transport = $sth->{go_transport}
624 3061 50       7143 or return $sth->set_err($DBI::stderr, "Not connected (no transport)");
625              
626             local $transport->{go_cache} = $sth->{go_cache}
627 3061 100       6465 if defined $sth->{go_cache};
628              
629 3061         7922 my ($response, $retransmit_sub) = $transport->transmit_request($request);
630 3061   66     13850 $response ||= $transport->receive_response($request, $retransmit_sub);
631 3061 50       10157 $sth->{go_response} = $response
632             or die "No response object returned by $transport";
633 3061         13146 $dbh->{go_response} = $response; # mainly for last_insert_id
634              
635 3061 100       7837 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         22925 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         18737 $dbh->{go_dbh_attributes_fetched} = $dbh_attributes;
642             }
643              
644 3061         8003 my $rv = $response->rv; # may be undef on error
645 3061 100       6439 if ($response->sth_resultsets) {
646             # setup first resultset - including sth attributes
647 2989         15640 $sth->more_results;
648             }
649             else {
650 72         432 $sth->STORE(Active => 0);
651 72         497 $sth->{go_rows} = $rv;
652             }
653             # set error/warn/info (after more_results as that'll clear err)
654 3061         13812 DBD::Gofer::set_err_from_response($sth, $response);
655              
656 3061         35518 return $rv;
657             }
658              
659              
660             sub bind_param {
661 5378     5378   20613 my ($sth, $param, $value, $attr) = @_;
662 5378         12680 $sth->{ParamValues}{$param} = $value;
663 5378 50       9275 $sth->{ParamAttr}{$param} = $attr
664             if defined $attr; # attr is sticky if not explicitly set
665 5378         14055 return 1;
666             }
667              
668              
669             sub execute {
670 2467     2467   111388 my $sth = shift;
671 2467         11426 $sth->bind_param($_, $_[$_-1]) for (1..@_);
672 2467         4254 push @{ $sth->{go_method_calls} }, [ 'execute' ];
  2467         8312  
673 2467         6036 my $meta = { go_last_insert_id_args => $sth->{go_last_insert_id_args} };
674 2467         7888 return $sth->go_sth_method($meta);
675             }
676              
677              
678             sub more_results {
679 3275     3275   28273 my $sth = shift;
680              
681 3275         12949 $sth->finish;
682              
683 3275 100       14542 my $response = $sth->{go_response} or do {
684             # e.g., we haven't sent a request yet (ie prepare then more_results)
685 96         452 $sth->trace_msg(" No response object present", 3);
686 96         1006 return;
687             };
688              
689 3179 50       6732 my $resultset_list = $response->sth_resultsets
690             or return $sth->set_err($DBI::stderr, "No sth_resultsets");
691              
692 3179 100       8844 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         4617 = delete @{$meta}{qw(rowset err errstr state)};
  2999         9925  
699              
700             # copy meta attributes into attribute cache
701 2999         5742 my $NUM_OF_FIELDS = delete $meta->{NUM_OF_FIELDS};
702 2999         12459 $sth->STORE('NUM_OF_FIELDS', $NUM_OF_FIELDS);
703             # XXX need to use STORE for some?
704 2999         26435 $sth->{$_} = $meta->{$_} for keys %$meta;
705              
706 2999 100 100     10776 if (($NUM_OF_FIELDS||0) > 0) {
707 2472 100       5929 $sth->{go_rows} = ($rowset) ? @$rowset : -1;
708 2472         19779 $sth->{go_current_rowset} = $rowset;
709 2472 100       5544 $sth->{go_current_rowset_err} = [ $err, $errstr, $state ]
710             if defined $err;
711 2472 100       8436 $sth->STORE(Active => 1) if $rowset;
712             }
713              
714 2999         11581 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   44762 my ($sth) = @_;
733 4724   33     9119 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       35023 return $sth->_set_fbav(shift @$resultset) if @$resultset;
740 153         557 $sth->finish; # no more data so finish
741 153         832 return undef;
742             }
743             *fetch = \&fetchrow_arrayref; # alias
744              
745              
746             sub fetchall_arrayref {
747 238     238   20171 my ($sth, $slice, $max_rows) = @_;
748 238   66     985 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     1149 my $mode = ref($slice) || 'ARRAY';
755 214 100 66     1096 return $sth->SUPER::fetchall_arrayref($slice, $max_rows)
756             if ref($slice) or defined $max_rows;
757 184         761 $sth->finish; # no more data after this so finish
758 184         1405 return $resultset;
759             }
760              
761              
762             sub rows {
763 24     24   8637 return shift->{go_rows};
764             }
765              
766              
767             sub STORE {
768 6428     6428   45155 my ($sth, $attrib, $value) = @_;
769              
770             return $sth->SUPER::STORE($attrib => $value)
771 6428 50 33     37519 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__