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   366 use strict;
  56         111  
  56         36879  
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 226 return $drh if $drh;
55              
56 56         244 DBI->setup_driver('DBD::Gofer');
57              
58 56 50       237 unless ($methods_already_installed++) {
59 56         200 my $opts = { O=> 0x0004 }; # IMA_KEEP_ERR
60 56         639 DBD::Gofer::db->install_method('go_dbh_method', $opts);
61 56         540 DBD::Gofer::st->install_method('go_sth_method', $opts);
62 56         350 DBD::Gofer::st->install_method('go_clone_sth', $opts);
63 56         395 DBD::Gofer::db->install_method('go_cache', $opts);
64 56         297 DBD::Gofer::st->install_method('go_cache', $opts);
65             }
66              
67 56         227 my($class, $attr) = @_;
68 56         171 $class .= "::dr";
69 56         481 ($drh) = DBI::_new_drh($class, {
70             'Name' => 'Gofer',
71             'Version' => $VERSION,
72             'Attribution' => 'DBD Gofer by Tim Bunce',
73             });
74              
75 56         289 $drh;
76             }
77              
78              
79             sub CLONE {
80 0     0   0 undef $drh;
81             }
82              
83              
84             sub go_cache {
85 4     4 0 87 my $h = shift;
86 4 50       20 $h->{go_cache} = shift if @_;
87             # return handle's override go_cache, if it has one
88 4 100       27 return $h->{go_cache} if defined $h->{go_cache};
89             # or else the transports default go_cache
90 2         12 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 11833 my $h = shift;
96 7138         11175 my $response = shift;
97 7138 100       20777 if (my $warnings = $response->warnings) {
98 22         364 warn $_ for @$warnings;
99             }
100 7138         25679 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       28606 $h->set_err($err, $errstr, $state) if defined $err;
105 7138         13703 return undef;
106             }
107              
108              
109             sub install_methods_proxy {
110 580     580 0 1740 my ($installed_methods) = @_;
111 580         4299 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     7164 unless defined &{$full_method};
  4866         18846  
117              
118             # now install proxy stubs on the driver side
119 4866 50       19116 $full_method =~ m/^DBI::(\w\w)::(\w+)$/
120             or die "Invalid method name '$full_method' for install_method";
121 4866         15326 my ($type, $method) = ($1, $2);
122 4866         9939 my $driver_method = "DBD::Gofer::${type}::${method}";
123 4866 100       6094 next if defined &{$driver_method};
  4866         27809  
124 166         229 my $sub;
125 166 100       323 if ($type eq 'db') {
126 126     20   424 $sub = sub { return shift->go_dbh_method(undef, $method, @_) };
  20         8920  
127             }
128             else {
129 40     0   176 $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   427 no strict 'refs';
  56         113  
  56         5646  
132 166         830 *$driver_method = $sub;
133             }
134             }
135             }
136              
137              
138             { package DBD::Gofer::dr; # ====== DRIVER ======
139              
140             $imp_data_size = 0;
141 56     56   429 use strict;
  56         112  
  56         51222  
142              
143             sub connect_cached {
144 10     10   149 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     92 go_connect_method => $attr->{go_connect_method} || 'connect_cached',
149             });
150             }
151              
152              
153             sub connect {
154 716     716   15368 my($drh, $dsn, $user, $auth, $attr)= @_;
155 716         1689 my $orig_dsn = $dsn;
156              
157             # first remove dsn= and everything after it
158 716 50 33     13482 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       2962 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         6 return DBI->connect($remote_dsn, $user, $auth, $attr);
164             }
165              
166 715         1614 my %go_attr;
167             # extract any go_ attributes from the connect() attr arg
168 715         3450 for my $k (grep { /^go_/ } keys %$attr) {
  4932         10991  
169 13         47 $go_attr{$k} = delete $attr->{$k};
170             }
171             # then override those with any attributes embedded in our dsn (not remote_dsn)
172 715         6110 for my $kv (grep /=/, split /;/, $dsn, -1) {
173 2108         6834 my ($k, $v) = split /=/, $kv, 2;
174 2108         7523 $go_attr{ "go_$k" } = $v;
175             }
176              
177 715 50       3179 if (not ref $go_attr{go_policy}) { # if not a policy object already
178 715   50     2919 my $policy_class = $go_attr{go_policy} || 'classic';
179 715 50       3304 $policy_class = "DBD::Gofer::Policy::$policy_class"
180             unless $policy_class =~ /::/;
181 715 50       3045 _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       1732 $go_attr{go_policy} = eval { $policy_class->new(\%go_attr) }
  715         5621  
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         2034 my $go_policy = $go_attr{go_policy};
189              
190 715 100 100     2879 if ($go_attr{go_cache} and not ref $go_attr{go_cache}) { # if not a cache object already
191 4         13 my $cache_class = $go_attr{go_cache};
192 4 50       24 $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       12 $go_attr{go_cache} = eval { $cache_class->new() }
  4         38  
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         1666 my $go_connect_method = delete $go_attr{go_connect_method};
201              
202             my $transport_class = delete $go_attr{go_transport}
203 715 50       5284 or return $drh->set_err($DBI::stderr, "No transport= argument in '$orig_dsn'");
204 715 50       3604 $transport_class = "DBD::Gofer::Transport::$transport_class"
205             unless $transport_class =~ /::/;
206 715 50       2157 _load_class($transport_class)
207             or return $drh->set_err($DBI::stderr, "Can't load $transport_class: $@");
208 715 50       1560 my $go_transport = eval { $transport_class->new(\%go_attr) }
  715         6159  
209             or return $drh->set_err($DBI::stderr, "Can't instanciate $transport_class: $@");
210              
211 715         1931 my $request_class = "DBI::Gofer::Request";
212 715 50       1302 my $go_request = eval {
213 715         4436 my $go_attr = { %$attr };
214             # XXX user/pass of fwd server vs db server ? also impact of autoproxy
215 715 100       2449 if ($user) {
216 13         31 $go_attr->{Username} = $user;
217 13         29 $go_attr->{Password} = $auth;
218             }
219             # delete any attributes we can't serialize (or don't want to)
220 715         1649 delete @{$go_attr}{qw(Profile HandleError HandleSetErr Callbacks)};
  715         2126  
221             # delete any attributes that should only apply to the client-side
222 715         1444 delete @{$go_attr}{qw(RootClass DbTypeSubclass)};
  715         1561  
223              
224 715   50     6325 $go_connect_method ||= $go_policy->connect_method($remote_dsn, $go_attr) || 'connect';
      66        
225 715         6000 $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         7474 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         5669 $dbh->STORE(Active => 0);
240              
241             # should we ping to check the connection
242             # and fetch dbh attributes
243 715         7144 my $skip_connect_check = $go_policy->skip_connect_check($attr, $dbh);
244 715 100       2402 if (not $skip_connect_check) {
245 530 100       3035 if (not $dbh->go_dbh_method(undef, 'ping')) {
246 26 50       765 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         17206 return $dbh;
252             }
253              
254             sub _load_class { # return true or false+$@
255 1434     1434   2914 my $class = shift;
256 1434         7454 (my $pm = $class) =~ s{::}{/}g;
257 1434         3167 $pm .= ".pm";
258 1434 50       2664 return 1 if eval { require $pm };
  1434         69386  
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   558 use strict;
  56         138  
  56         1771  
269 56     56   331 use Carp qw(carp croak);
  56         132  
  56         49471  
270              
271             my %dbh_local_store_attrib = %DBD::Gofer::xxh_local_store_attrib;
272              
273             sub connected {
274 694     694   8960 shift->STORE(Active => 1);
275             }
276              
277             sub go_dbh_method {
278 4077     4077   18608 my $dbh = shift;
279 4077         5312 my $meta = shift;
280             # @_ now contains ($method_name, @args)
281              
282 4077         6425 my $request = $dbh->{go_request};
283 4077         21231 $request->init_request([ wantarray, @_ ], $dbh);
284 4077         7595 ++$dbh->{go_request_count};
285              
286 4077         6421 my $go_policy = $dbh->{go_policy};
287 4077         13732 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     20960 or $dbh->{go_request_count}==1;
291              
292             $request->dbh_last_insert_id_args($meta->{go_last_insert_id_args})
293 4077 50       9382 if $meta->{go_last_insert_id_args};
294              
295             my $transport = $dbh->{go_transport}
296 4077 50       9399 or return $dbh->set_err($DBI::stderr, "Not connected (no transport)");
297              
298             local $transport->{go_cache} = $dbh->{go_cache}
299 4077 50       8282 if defined $dbh->{go_cache};
300              
301 4077         11520 my ($response, $retransmit_sub) = $transport->transmit_request($request);
302 4077   33     22790 $response ||= $transport->receive_response($request, $retransmit_sub);
303 4077 50       22975 $dbh->{go_response} = $response
304             or die "No response object returned by $transport";
305              
306 4077 50       15069 die "response '$response' returned by $transport is not a response object"
307             unless UNIVERSAL::isa($response,"DBI::Gofer::Response");
308              
309 4077 100       11173 if (my $dbh_attributes = $response->dbh_attributes) {
310              
311             # XXX installed_methods piggybacks on dbh_attributes for now
312 1067 50       3888 if (my $installed_methods = delete $dbh_attributes->{dbi_installed_methods}) {
313             DBD::Gofer::install_methods_proxy($installed_methods)
314 1067 100       6506 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         15883 for keys %$dbh_attributes;
320             }
321              
322 4077         12623 my $rv = $response->rv;
323 4077 100       10059 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         119 my $sth = $dbh->prepare(undef, { go_skip_prepare_check => 1 });
329             # set the sth response to our dbh response
330 10         146 (tied %$sth)->{go_response} = $response;
331             # setup the sth with the results in our response
332 10         63 $sth->more_results;
333             # and return that new sth as if it came from original request
334 10         92 $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         12612 DBD::Gofer::set_err_from_response($dbh, $response);
342              
343 4077 100       60891 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   106232 my $dbh = shift;
358 209         411 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     1281 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         484 my $cache;
369             my $cache_key;
370 209 100       1619 if (my $cache_it = $dbh->{go_policy}->$policy_name(undef, $dbh, @_)) {
371 185   100     986 $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     1404 !ref($_) ? DBI::neat($_,1e6)
375             : ref($_) eq 'ARRAY' ? DBI::neat_list($_,1e6,",\001")
376 108         584 : ref($_) eq 'HASH' ? do { my @k = sort keys %$_; DBI::neat_list([@k,@{$_}{@k}],1e6,",\002") }
  108         259  
  108         865  
377 182 50       1312 : do { warn "unhandled argument type ($_)"; $_ }
  0 50       0  
  0 100       0  
378             } @_);
379 185 100       783 if ($rv = $cache->{$cache_key}) {
380 58         637 $dbh->trace_msg("$method(@_) returning previously cached value ($cache_key)\n",4);
381 58         432 my @cache_rv = @$rv;
382             # if it's an sth we have to clone it
383 58 50       311 $cache_rv[0] = $cache_rv[0]->go_clone_sth if UNIVERSAL::isa($cache_rv[0],'DBI::st');
384 58 50       362 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       2019 if ($cache) {
394 127         2253 $dbh->trace_msg("$method(@_) caching return value ($cache_key)\n",4);
395 127         1056 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       1336 $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       1611 return (wantarray) ? @$rv : $rv->[0];
404             };
405 56     56   431 no strict 'refs';
  56         129  
  56         11159  
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   6927 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     114 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       34 if ($locally) {
432 0 0       0 return $locally->($dbh, @_) if ref $locally eq 'CODE';
433 0         0 return $dbh->$super_name(@_);
434             }
435 18         62 return $dbh->go_dbh_method(undef, $method, @_); # propagate context
436             };
437 56     56   391 no strict 'refs';
  56         112  
  56         4205  
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   364 no strict 'refs';
  56         123  
  56         47221  
447 1     1   2972 *$method = sub { return shift->set_err($DBI::stderr, "$method not available with DBD::Gofer") }
448             }
449              
450              
451             sub do {
452 3324     3324   350625 my ($dbh, $sql, $attr, @args) = @_;
453 3324         6610 delete $dbh->{Statement}; # avoid "Modification of non-creatable hash value attempted"
454 3324         7207 $dbh->{Statement} = $sql; # for profiling and ShowErrorStatement
455 3324         8772 my $meta = { go_last_insert_id_args => $attr->{go_last_insert_id_args} };
456 3324         12053 return $dbh->go_dbh_method($meta, 'do', $sql, $attr, @args);
457             }
458              
459             sub ping {
460 57     57   1999 my $dbh = shift;
461 57 100       336 return $dbh->set_err('', "can't ping while not connected") # info
462             unless $dbh->SUPER::FETCH('Active');
463 51         570 my $skip_ping = $dbh->{go_policy}->skip_ping();
464 51 100       400 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   36885 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     11192 if ($attrib =~ m/^[a-z]/ && $attrib !~ /^go_/) {
482 7         45 my $value = $dbh->go_dbh_method(undef, 'FETCH', $attrib);
483 7         56 $dbh->{$attrib} = $value; # XXX forces caching by DBI
484 7         34 return $dbh->{$attrib} = $value;
485             }
486              
487             # else pass up to DBI to handle
488 2401         21225 return $dbh->SUPER::FETCH($attrib);
489             }
490              
491             sub STORE {
492 7343     7343   114782 my ($dbh, $attrib, $value) = @_;
493 7343 100       17407 if ($attrib eq 'AutoCommit') {
494 696 50       1997 croak "Can't enable transactions when using DBD::Gofer" if !$value;
495 696 50       4888 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     47274 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     124 && do { # values are the same
508 10         30 my $crnt = $dbh->FETCH($attrib);
509 10         63 local $^W;
510 10 50       76 (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       18 carp("Can't alter \$dbh->{$attrib} after handle created with DBD::Gofer") if $dbh->FETCH('Warn');
517 4         1204 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   303483 my $dbh = shift;
522 107         1263 $dbh->{go_transport} = undef;
523 107         1094 $dbh->STORE(Active => 0);
524             }
525              
526             sub prepare {
527 1104     1104   254017 my ($dbh, $statement, $attr)= @_;
528              
529 1104 50       5167 return $dbh->set_err($DBI::stderr, "Can't prepare when disconnected")
530             unless $dbh->FETCH('Active');
531              
532 1104 100       9710 $attr = { %$attr } if $attr; # copy so we can edit
533              
534 1104   33     7641 my $policy = delete($attr->{go_policy}) || $dbh->{go_policy};
535 1104         2360 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     11463 || $policy->prepare_method($dbh, $statement, $attr)
539             || 'prepare'; # e.g. for code not using placeholders
540 1104         2733 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     7094 $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         13431 go_policy => $policy,
551             go_last_insert_id_args => $lii_args,
552             go_cache => $go_cache,
553             });
554 1104         7707 $sth->STORE(Active => 0); # XXX needed? It should be the default
555              
556 1104         8985 my $skip_prepare_check = $policy->skip_prepare_check($attr, $dbh, $statement, $attr, $sth);
557 1104 100       3682 if (not $skip_prepare_check) {
558 594 100       3290 $sth->go_sth_method() or return undef;
559             }
560              
561 1032         10690 return $sth;
562             }
563              
564             sub prepare_cached {
565 14     14   13003 my ($dbh, $sql, $attr, $if_active)= @_;
566 14   100     71 $attr ||= {};
567             return $dbh->SUPER::prepare_cached($sql, {
568             %$attr,
569 14   50     121 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   464 use strict;
  56         108  
  56         74322  
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   22462 my ($sth, $meta) = @_;
585              
586 3061 100       10596 if (my $ParamValues = $sth->{ParamValues}) {
587 2157         3883 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         11272 my @params = reverse sort keys %$ParamValues;
592 2157 50 50     8348 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         5111 for my $p (@params) {
599             # unshift to put binds before execute call
600 5418         19303 unshift @{ $sth->{go_method_calls} },
601 5418         7104 [ 'bind_param', $p, $ParamValues->{$p}, $ParamAttr->{$p} ];
602             }
603             }
604              
605 3061 50       10300 my $dbh = $sth->{Database} or die "panic";
606 3061         6415 ++$dbh->{go_request_count};
607              
608 3061         5443 my $request = $sth->{go_request};
609 3061         16192 $request->init_request($sth->{go_prepare_call}, $sth);
610             $request->sth_method_calls(delete $sth->{go_method_calls})
611 3061 100       14050 if $sth->{go_method_calls};
612 3061         11102 $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       8664 if $meta->{go_last_insert_id_args};
616              
617 3061         6060 my $go_policy = $sth->{go_policy};
618 3061         13044 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     17088 or $dbh->{go_request_count}==1;
622              
623             my $transport = $sth->{go_transport}
624 3061 50       9443 or return $sth->set_err($DBI::stderr, "Not connected (no transport)");
625              
626             local $transport->{go_cache} = $sth->{go_cache}
627 3061 100       8439 if defined $sth->{go_cache};
628              
629 3061         11123 my ($response, $retransmit_sub) = $transport->transmit_request($request);
630 3061   66     21053 $response ||= $transport->receive_response($request, $retransmit_sub);
631 3061 50       14454 $sth->{go_response} = $response
632             or die "No response object returned by $transport";
633 3061         19491 $dbh->{go_response} = $response; # mainly for last_insert_id
634              
635 3061 100       11034 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         31099 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         27467 $dbh->{go_dbh_attributes_fetched} = $dbh_attributes;
642             }
643              
644 3061         11171 my $rv = $response->rv; # may be undef on error
645 3061 100       9147 if ($response->sth_resultsets) {
646             # setup first resultset - including sth attributes
647 2989         22756 $sth->more_results;
648             }
649             else {
650 72         632 $sth->STORE(Active => 0);
651 72         631 $sth->{go_rows} = $rv;
652             }
653             # set error/warn/info (after more_results as that'll clear err)
654 3061         18437 DBD::Gofer::set_err_from_response($sth, $response);
655              
656 3061         53245 return $rv;
657             }
658              
659              
660             sub bind_param {
661 5378     5378   24972 my ($sth, $param, $value, $attr) = @_;
662 5378         12990 $sth->{ParamValues}{$param} = $value;
663 5378 50       10541 $sth->{ParamAttr}{$param} = $attr
664             if defined $attr; # attr is sticky if not explicitly set
665 5378         15081 return 1;
666             }
667              
668              
669             sub execute {
670 2467     2467   171692 my $sth = shift;
671 2467         16552 $sth->bind_param($_, $_[$_-1]) for (1..@_);
672 2467         6084 push @{ $sth->{go_method_calls} }, [ 'execute' ];
  2467         12020  
673 2467         8377 my $meta = { go_last_insert_id_args => $sth->{go_last_insert_id_args} };
674 2467         11327 return $sth->go_sth_method($meta);
675             }
676              
677              
678             sub more_results {
679 3275     3275   34323 my $sth = shift;
680              
681 3275         18508 $sth->finish;
682              
683 3275 100       18045 my $response = $sth->{go_response} or do {
684             # e.g., we haven't sent a request yet (ie prepare then more_results)
685 96         614 $sth->trace_msg(" No response object present", 3);
686 96         1361 return;
687             };
688              
689 3179 50       9228 my $resultset_list = $response->sth_resultsets
690             or return $sth->set_err($DBI::stderr, "No sth_resultsets");
691              
692 3179 100       11586 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         5814 = delete @{$meta}{qw(rowset err errstr state)};
  2999         13132  
699              
700             # copy meta attributes into attribute cache
701 2999         7357 my $NUM_OF_FIELDS = delete $meta->{NUM_OF_FIELDS};
702 2999         17937 $sth->STORE('NUM_OF_FIELDS', $NUM_OF_FIELDS);
703             # XXX need to use STORE for some?
704 2999         34051 $sth->{$_} = $meta->{$_} for keys %$meta;
705              
706 2999 100 100     15315 if (($NUM_OF_FIELDS||0) > 0) {
707 2472 100       8743 $sth->{go_rows} = ($rowset) ? @$rowset : -1;
708 2472         31572 $sth->{go_current_rowset} = $rowset;
709 2472 100       7783 $sth->{go_current_rowset_err} = [ $err, $errstr, $state ]
710             if defined $err;
711 2472 100       11822 $sth->STORE(Active => 1) if $rowset;
712             }
713              
714 2999         14606 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 4777     4777   54633 my ($sth) = @_;
733 4777   33     11926 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 4777 100       42885 return $sth->_set_fbav(shift @$resultset) if @$resultset;
740 153         582 $sth->finish; # no more data so finish
741 153         935 return undef;
742             }
743             *fetch = \&fetchrow_arrayref; # alias
744              
745              
746             sub fetchall_arrayref {
747 238     238   29254 my ($sth, $slice, $max_rows) = @_;
748 238   66     1573 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     1850 my $mode = ref($slice) || 'ARRAY';
755 214 100 66     1726 return $sth->SUPER::fetchall_arrayref($slice, $max_rows)
756             if ref($slice) or defined $max_rows;
757 184         922 $sth->finish; # no more data after this so finish
758 184         1589 return $resultset;
759             }
760              
761              
762             sub rows {
763 24     24   10039 return shift->{go_rows};
764             }
765              
766              
767             sub STORE {
768 6428     6428   55589 my ($sth, $attrib, $value) = @_;
769              
770             return $sth->SUPER::STORE($attrib => $value)
771 6428 50 33     50227 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__