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__ |