line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# $Id$ |
2
|
|
|
|
|
|
|
# vim: ts=8:sw=4:et |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Copyright (c) 1994-2012 Tim Bunce Ireland |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# See COPYRIGHT section in pod text below for usage and distribution rights. |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package DBI; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
require 5.008_001; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
BEGIN { |
14
|
194
|
|
|
194
|
|
9231083
|
our $XS_VERSION = our $VERSION = "1.641"; # ==> ALSO update the version in the pod text below! |
15
|
194
|
|
|
|
|
9116
|
$VERSION = eval $VERSION; |
16
|
|
|
|
|
|
|
} |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
DBI - Database independent interface for Perl |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 SYNOPSIS |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use DBI; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
@driver_names = DBI->available_drivers; |
27
|
|
|
|
|
|
|
%drivers = DBI->installed_drivers; |
28
|
|
|
|
|
|
|
@data_sources = DBI->data_sources($driver_name, \%attr); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
$dbh = DBI->connect($data_source, $username, $auth, \%attr); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
$rv = $dbh->do($statement); |
33
|
|
|
|
|
|
|
$rv = $dbh->do($statement, \%attr); |
34
|
|
|
|
|
|
|
$rv = $dbh->do($statement, \%attr, @bind_values); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
$ary_ref = $dbh->selectall_arrayref($statement); |
37
|
|
|
|
|
|
|
$hash_ref = $dbh->selectall_hashref($statement, $key_field); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
$ary_ref = $dbh->selectcol_arrayref($statement); |
40
|
|
|
|
|
|
|
$ary_ref = $dbh->selectcol_arrayref($statement, \%attr); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
@row_ary = $dbh->selectrow_array($statement); |
43
|
|
|
|
|
|
|
$ary_ref = $dbh->selectrow_arrayref($statement); |
44
|
|
|
|
|
|
|
$hash_ref = $dbh->selectrow_hashref($statement); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
$sth = $dbh->prepare($statement); |
47
|
|
|
|
|
|
|
$sth = $dbh->prepare_cached($statement); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
$rc = $sth->bind_param($p_num, $bind_value); |
50
|
|
|
|
|
|
|
$rc = $sth->bind_param($p_num, $bind_value, $bind_type); |
51
|
|
|
|
|
|
|
$rc = $sth->bind_param($p_num, $bind_value, \%attr); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
$rv = $sth->execute; |
54
|
|
|
|
|
|
|
$rv = $sth->execute(@bind_values); |
55
|
|
|
|
|
|
|
$rv = $sth->execute_array(\%attr, ...); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
$rc = $sth->bind_col($col_num, \$col_variable); |
58
|
|
|
|
|
|
|
$rc = $sth->bind_columns(@list_of_refs_to_vars_to_bind); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
@row_ary = $sth->fetchrow_array; |
61
|
|
|
|
|
|
|
$ary_ref = $sth->fetchrow_arrayref; |
62
|
|
|
|
|
|
|
$hash_ref = $sth->fetchrow_hashref; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
$ary_ref = $sth->fetchall_arrayref; |
65
|
|
|
|
|
|
|
$ary_ref = $sth->fetchall_arrayref( $slice, $max_rows ); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
$hash_ref = $sth->fetchall_hashref( $key_field ); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
$rv = $sth->rows; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$rc = $dbh->begin_work; |
72
|
|
|
|
|
|
|
$rc = $dbh->commit; |
73
|
|
|
|
|
|
|
$rc = $dbh->rollback; |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
$quoted_string = $dbh->quote($string); |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
$rc = $h->err; |
78
|
|
|
|
|
|
|
$str = $h->errstr; |
79
|
|
|
|
|
|
|
$rv = $h->state; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
$rc = $dbh->disconnect; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
I |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=head2 GETTING HELP |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=head3 General |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Before asking any questions, reread this document, consult the |
91
|
|
|
|
|
|
|
archives and read the DBI FAQ. The archives are listed |
92
|
|
|
|
|
|
|
at the end of this document and on the DBI home page L |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
You might also like to read the Advanced DBI Tutorial at |
95
|
|
|
|
|
|
|
L |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
To help you make the best use of the dbi-users mailing list, |
98
|
|
|
|
|
|
|
and any other lists or forums you may use, I recommend that you read |
99
|
|
|
|
|
|
|
"Getting Answers" by Mike Ash: L. |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head3 Mailing Lists |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
If you have questions about DBI, or DBD driver modules, you can get |
104
|
|
|
|
|
|
|
help from the I mailing list. This is the best way to get |
105
|
|
|
|
|
|
|
help. You don't have to subscribe to the list in order to post, though I'd |
106
|
|
|
|
|
|
|
recommend it. You can get help on subscribing and using the list by emailing |
107
|
|
|
|
|
|
|
I. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Please note that Tim Bunce does not maintain the mailing lists or the |
110
|
|
|
|
|
|
|
web pages (generous volunteers do that). So please don't send mail |
111
|
|
|
|
|
|
|
directly to him; he just doesn't have the time to answer questions |
112
|
|
|
|
|
|
|
personally. The I mailing list has lots of experienced |
113
|
|
|
|
|
|
|
people who should be able to help you if you need it. If you do email |
114
|
|
|
|
|
|
|
Tim he is very likely to just forward it to the mailing list. |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head3 IRC |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
DBI IRC Channel: #dbi on irc.perl.org (L) |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=for html (click for instant chatroom login) |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head3 Online |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
StackOverflow has a DBI tag L |
125
|
|
|
|
|
|
|
with over 800 questions. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
The DBI home page at L and the DBI FAQ |
128
|
|
|
|
|
|
|
at L may be worth a visit. |
129
|
|
|
|
|
|
|
They include links to other resources, but I. |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=head3 Reporting a Bug |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
If you think you've found a bug then please read |
134
|
|
|
|
|
|
|
"How to Report Bugs Effectively" by Simon Tatham: |
135
|
|
|
|
|
|
|
L. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
If you think you've found a memory leak then read L. |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Your problem is most likely related to the specific DBD driver module you're |
140
|
|
|
|
|
|
|
using. If that's the case then click on the 'Bugs' link on the L |
141
|
|
|
|
|
|
|
page for your driver. Only submit a bug report against the DBI itself if you're |
142
|
|
|
|
|
|
|
sure that your issue isn't related to the driver you're using. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=head2 NOTES |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
This is the DBI specification that corresponds to DBI version 1.641 |
147
|
|
|
|
|
|
|
(see L for details). |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
The DBI is evolving at a steady pace, so it's good to check that |
150
|
|
|
|
|
|
|
you have the latest copy. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
The significant user-visible changes in each release are documented |
153
|
|
|
|
|
|
|
in the L module so you can read them by executing |
154
|
|
|
|
|
|
|
C. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Some DBI changes require changes in the drivers, but the drivers |
157
|
|
|
|
|
|
|
can take some time to catch up. Newer versions of the DBI have |
158
|
|
|
|
|
|
|
added features that may not yet be supported by the drivers you |
159
|
|
|
|
|
|
|
use. Talk to the authors of your drivers if you need a new feature |
160
|
|
|
|
|
|
|
that is not yet supported. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Features added after DBI 1.21 (February 2002) are marked in the |
163
|
|
|
|
|
|
|
text with the version number of the DBI release they first appeared in. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Extensions to the DBI API often use the C namespace. |
166
|
|
|
|
|
|
|
See L. DBI extension modules |
167
|
|
|
|
|
|
|
can be found at L. And all modules |
168
|
|
|
|
|
|
|
related to the DBI can be found at L. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=cut |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# The POD text continues at the end of the file. |
173
|
|
|
|
|
|
|
|
174
|
194
|
|
|
194
|
|
1612
|
use Scalar::Util (); |
|
194
|
|
|
|
|
413
|
|
|
194
|
|
|
|
|
2715
|
|
175
|
194
|
|
|
194
|
|
969
|
use Carp(); |
|
194
|
|
|
|
|
380
|
|
|
194
|
|
|
|
|
3142
|
|
176
|
194
|
|
|
194
|
|
960
|
use DynaLoader (); |
|
194
|
|
|
|
|
381
|
|
|
194
|
|
|
|
|
3282
|
|
177
|
194
|
|
|
194
|
|
972
|
use Exporter (); |
|
194
|
|
|
|
|
402
|
|
|
194
|
|
|
|
|
65001
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
BEGIN { |
180
|
194
|
|
|
194
|
|
5681
|
@ISA = qw(Exporter DynaLoader); |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# Make some utility functions available if asked for |
183
|
194
|
|
|
|
|
665
|
@EXPORT = (); # we export nothing by default |
184
|
194
|
|
|
|
|
553
|
@EXPORT_OK = qw(%DBI %DBI_methods hash); # also populated by export_ok_tags: |
185
|
194
|
|
|
|
|
3438
|
%EXPORT_TAGS = ( |
186
|
|
|
|
|
|
|
sql_types => [ qw( |
187
|
|
|
|
|
|
|
SQL_GUID |
188
|
|
|
|
|
|
|
SQL_WLONGVARCHAR |
189
|
|
|
|
|
|
|
SQL_WVARCHAR |
190
|
|
|
|
|
|
|
SQL_WCHAR |
191
|
|
|
|
|
|
|
SQL_BIGINT |
192
|
|
|
|
|
|
|
SQL_BIT |
193
|
|
|
|
|
|
|
SQL_TINYINT |
194
|
|
|
|
|
|
|
SQL_LONGVARBINARY |
195
|
|
|
|
|
|
|
SQL_VARBINARY |
196
|
|
|
|
|
|
|
SQL_BINARY |
197
|
|
|
|
|
|
|
SQL_LONGVARCHAR |
198
|
|
|
|
|
|
|
SQL_UNKNOWN_TYPE |
199
|
|
|
|
|
|
|
SQL_ALL_TYPES |
200
|
|
|
|
|
|
|
SQL_CHAR |
201
|
|
|
|
|
|
|
SQL_NUMERIC |
202
|
|
|
|
|
|
|
SQL_DECIMAL |
203
|
|
|
|
|
|
|
SQL_INTEGER |
204
|
|
|
|
|
|
|
SQL_SMALLINT |
205
|
|
|
|
|
|
|
SQL_FLOAT |
206
|
|
|
|
|
|
|
SQL_REAL |
207
|
|
|
|
|
|
|
SQL_DOUBLE |
208
|
|
|
|
|
|
|
SQL_DATETIME |
209
|
|
|
|
|
|
|
SQL_DATE |
210
|
|
|
|
|
|
|
SQL_INTERVAL |
211
|
|
|
|
|
|
|
SQL_TIME |
212
|
|
|
|
|
|
|
SQL_TIMESTAMP |
213
|
|
|
|
|
|
|
SQL_VARCHAR |
214
|
|
|
|
|
|
|
SQL_BOOLEAN |
215
|
|
|
|
|
|
|
SQL_UDT |
216
|
|
|
|
|
|
|
SQL_UDT_LOCATOR |
217
|
|
|
|
|
|
|
SQL_ROW |
218
|
|
|
|
|
|
|
SQL_REF |
219
|
|
|
|
|
|
|
SQL_BLOB |
220
|
|
|
|
|
|
|
SQL_BLOB_LOCATOR |
221
|
|
|
|
|
|
|
SQL_CLOB |
222
|
|
|
|
|
|
|
SQL_CLOB_LOCATOR |
223
|
|
|
|
|
|
|
SQL_ARRAY |
224
|
|
|
|
|
|
|
SQL_ARRAY_LOCATOR |
225
|
|
|
|
|
|
|
SQL_MULTISET |
226
|
|
|
|
|
|
|
SQL_MULTISET_LOCATOR |
227
|
|
|
|
|
|
|
SQL_TYPE_DATE |
228
|
|
|
|
|
|
|
SQL_TYPE_TIME |
229
|
|
|
|
|
|
|
SQL_TYPE_TIMESTAMP |
230
|
|
|
|
|
|
|
SQL_TYPE_TIME_WITH_TIMEZONE |
231
|
|
|
|
|
|
|
SQL_TYPE_TIMESTAMP_WITH_TIMEZONE |
232
|
|
|
|
|
|
|
SQL_INTERVAL_YEAR |
233
|
|
|
|
|
|
|
SQL_INTERVAL_MONTH |
234
|
|
|
|
|
|
|
SQL_INTERVAL_DAY |
235
|
|
|
|
|
|
|
SQL_INTERVAL_HOUR |
236
|
|
|
|
|
|
|
SQL_INTERVAL_MINUTE |
237
|
|
|
|
|
|
|
SQL_INTERVAL_SECOND |
238
|
|
|
|
|
|
|
SQL_INTERVAL_YEAR_TO_MONTH |
239
|
|
|
|
|
|
|
SQL_INTERVAL_DAY_TO_HOUR |
240
|
|
|
|
|
|
|
SQL_INTERVAL_DAY_TO_MINUTE |
241
|
|
|
|
|
|
|
SQL_INTERVAL_DAY_TO_SECOND |
242
|
|
|
|
|
|
|
SQL_INTERVAL_HOUR_TO_MINUTE |
243
|
|
|
|
|
|
|
SQL_INTERVAL_HOUR_TO_SECOND |
244
|
|
|
|
|
|
|
SQL_INTERVAL_MINUTE_TO_SECOND |
245
|
|
|
|
|
|
|
) ], |
246
|
|
|
|
|
|
|
sql_cursor_types => [ qw( |
247
|
|
|
|
|
|
|
SQL_CURSOR_FORWARD_ONLY |
248
|
|
|
|
|
|
|
SQL_CURSOR_KEYSET_DRIVEN |
249
|
|
|
|
|
|
|
SQL_CURSOR_DYNAMIC |
250
|
|
|
|
|
|
|
SQL_CURSOR_STATIC |
251
|
|
|
|
|
|
|
SQL_CURSOR_TYPE_DEFAULT |
252
|
|
|
|
|
|
|
) ], # for ODBC cursor types |
253
|
|
|
|
|
|
|
utils => [ qw( |
254
|
|
|
|
|
|
|
neat neat_list $neat_maxlen dump_results looks_like_number |
255
|
|
|
|
|
|
|
data_string_diff data_string_desc data_diff sql_type_cast |
256
|
|
|
|
|
|
|
DBIstcf_DISCARD_STRING |
257
|
|
|
|
|
|
|
DBIstcf_STRICT |
258
|
|
|
|
|
|
|
) ], |
259
|
|
|
|
|
|
|
profile => [ qw( |
260
|
|
|
|
|
|
|
dbi_profile dbi_profile_merge dbi_profile_merge_nodes dbi_time |
261
|
|
|
|
|
|
|
) ], # notionally "in" DBI::Profile and normally imported from there |
262
|
|
|
|
|
|
|
); |
263
|
|
|
|
|
|
|
|
264
|
194
|
|
|
|
|
502
|
$DBI::dbi_debug = 0; # mixture of bit fields and int sub-fields |
265
|
194
|
|
|
|
|
393
|
$DBI::neat_maxlen = 1000; |
266
|
194
|
|
|
|
|
411
|
$DBI::stderr = 2_000_000_000; # a very round number below 2**31 |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# If you get an error here like "Can't find loadable object ..." |
269
|
|
|
|
|
|
|
# then you haven't installed the DBI correctly. Read the README |
270
|
|
|
|
|
|
|
# then install it again. |
271
|
194
|
100
|
|
|
|
1009
|
if ( $ENV{DBI_PUREPERL} ) { |
272
|
97
|
50
|
|
|
|
560
|
eval { bootstrap DBI $XS_VERSION } if $ENV{DBI_PUREPERL} == 1; |
|
0
|
|
|
|
|
0
|
|
273
|
97
|
50
|
33
|
|
|
48031
|
require DBI::PurePerl if $@ or $ENV{DBI_PUREPERL} >= 2; |
274
|
97
|
|
50
|
|
|
528
|
$DBI::PurePerl ||= 0; # just to silence "only used once" warnings |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
else { |
277
|
97
|
|
|
|
|
70808
|
bootstrap DBI $XS_VERSION; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
194
|
|
|
|
|
804
|
$EXPORT_TAGS{preparse_flags} = [ grep { /^DBIpp_\w\w_/ } keys %{__PACKAGE__."::"} ]; |
|
24836
|
|
|
|
|
36776
|
|
|
194
|
|
|
|
|
4862
|
|
281
|
|
|
|
|
|
|
|
282
|
194
|
|
|
|
|
21663
|
Exporter::export_ok_tags(keys %EXPORT_TAGS); |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Alias some handle methods to also be DBI class methods |
287
|
|
|
|
|
|
|
for (qw(trace_msg set_err parse_trace_flag parse_trace_flags)) { |
288
|
194
|
|
|
194
|
|
1444
|
no strict; |
|
194
|
|
|
|
|
416
|
|
|
194
|
|
|
|
|
10756
|
|
289
|
|
|
|
|
|
|
*$_ = \&{"DBD::_::common::$_"}; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
194
|
|
|
194
|
|
1199
|
use strict; |
|
194
|
|
|
|
|
425
|
|
|
194
|
|
|
|
|
258580
|
|
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
DBI->trace(split /=/, $ENV{DBI_TRACE}, 2) if $ENV{DBI_TRACE}; |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
$DBI::connect_via ||= "connect"; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# check if user wants a persistent database connection ( Apache + mod_perl ) |
299
|
|
|
|
|
|
|
if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) { |
300
|
|
|
|
|
|
|
$DBI::connect_via = "Apache::DBI::connect"; |
301
|
|
|
|
|
|
|
DBI->trace_msg("DBI connect via $DBI::connect_via in $INC{'Apache/DBI.pm'}\n"); |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
%DBI::installed_drh = (); # maps driver names to installed driver handles |
305
|
24
|
|
|
24
|
1
|
17075
|
sub installed_drivers { %DBI::installed_drh } |
306
|
|
|
|
|
|
|
%DBI::installed_methods = (); # XXX undocumented, may change |
307
|
3428
|
|
|
3428
|
0
|
31274
|
sub installed_methods { %DBI::installed_methods } |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
# Setup special DBI dynamic variables. See DBI::var::FETCH for details. |
310
|
|
|
|
|
|
|
# These are dynamically associated with the last handle used. |
311
|
|
|
|
|
|
|
tie $DBI::err, 'DBI::var', '*err'; # special case: referenced via IHA list |
312
|
|
|
|
|
|
|
tie $DBI::state, 'DBI::var', '"state'; # special case: referenced via IHA list |
313
|
|
|
|
|
|
|
tie $DBI::lasth, 'DBI::var', '!lasth'; # special case: return boolean |
314
|
|
|
|
|
|
|
tie $DBI::errstr, 'DBI::var', '&errstr'; # call &errstr in last used pkg |
315
|
|
|
|
|
|
|
tie $DBI::rows, 'DBI::var', '&rows'; # call &rows in last used pkg |
316
|
970
|
|
|
970
|
|
1600
|
sub DBI::var::TIESCALAR{ my $var = $_[1]; bless \$var, 'DBI::var'; } |
|
970
|
|
|
|
|
2637
|
|
317
|
2
|
|
|
2
|
|
2840
|
sub DBI::var::STORE { Carp::croak("Can't modify \$DBI::${$_[0]} special variable") } |
|
2
|
|
|
|
|
417
|
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# --- Driver Specific Prefix Registry --- |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
my $dbd_prefix_registry = { |
322
|
|
|
|
|
|
|
ad_ => { class => 'DBD::AnyData', }, |
323
|
|
|
|
|
|
|
ad2_ => { class => 'DBD::AnyData2', }, |
324
|
|
|
|
|
|
|
ado_ => { class => 'DBD::ADO', }, |
325
|
|
|
|
|
|
|
amzn_ => { class => 'DBD::Amazon', }, |
326
|
|
|
|
|
|
|
best_ => { class => 'DBD::BestWins', }, |
327
|
|
|
|
|
|
|
csv_ => { class => 'DBD::CSV', }, |
328
|
|
|
|
|
|
|
cubrid_ => { class => 'DBD::cubrid', }, |
329
|
|
|
|
|
|
|
db2_ => { class => 'DBD::DB2', }, |
330
|
|
|
|
|
|
|
dbi_ => { class => 'DBI', }, |
331
|
|
|
|
|
|
|
dbm_ => { class => 'DBD::DBM', }, |
332
|
|
|
|
|
|
|
df_ => { class => 'DBD::DF', }, |
333
|
|
|
|
|
|
|
examplep_ => { class => 'DBD::ExampleP', }, |
334
|
|
|
|
|
|
|
f_ => { class => 'DBD::File', }, |
335
|
|
|
|
|
|
|
file_ => { class => 'DBD::TextFile', }, |
336
|
|
|
|
|
|
|
go_ => { class => 'DBD::Gofer', }, |
337
|
|
|
|
|
|
|
ib_ => { class => 'DBD::InterBase', }, |
338
|
|
|
|
|
|
|
ing_ => { class => 'DBD::Ingres', }, |
339
|
|
|
|
|
|
|
ix_ => { class => 'DBD::Informix', }, |
340
|
|
|
|
|
|
|
jdbc_ => { class => 'DBD::JDBC', }, |
341
|
|
|
|
|
|
|
mariadb_ => { class => 'DBD::MariaDB', }, |
342
|
|
|
|
|
|
|
mem_ => { class => 'DBD::Mem', }, |
343
|
|
|
|
|
|
|
mo_ => { class => 'DBD::MO', }, |
344
|
|
|
|
|
|
|
monetdb_ => { class => 'DBD::monetdb', }, |
345
|
|
|
|
|
|
|
msql_ => { class => 'DBD::mSQL', }, |
346
|
|
|
|
|
|
|
mvsftp_ => { class => 'DBD::MVS_FTPSQL', }, |
347
|
|
|
|
|
|
|
mysql_ => { class => 'DBD::mysql', }, |
348
|
|
|
|
|
|
|
multi_ => { class => 'DBD::Multi' }, |
349
|
|
|
|
|
|
|
mx_ => { class => 'DBD::Multiplex', }, |
350
|
|
|
|
|
|
|
neo_ => { class => 'DBD::Neo4p', }, |
351
|
|
|
|
|
|
|
nullp_ => { class => 'DBD::NullP', }, |
352
|
|
|
|
|
|
|
odbc_ => { class => 'DBD::ODBC', }, |
353
|
|
|
|
|
|
|
ora_ => { class => 'DBD::Oracle', }, |
354
|
|
|
|
|
|
|
pg_ => { class => 'DBD::Pg', }, |
355
|
|
|
|
|
|
|
pgpp_ => { class => 'DBD::PgPP', }, |
356
|
|
|
|
|
|
|
plb_ => { class => 'DBD::Plibdata', }, |
357
|
|
|
|
|
|
|
po_ => { class => 'DBD::PO', }, |
358
|
|
|
|
|
|
|
proxy_ => { class => 'DBD::Proxy', }, |
359
|
|
|
|
|
|
|
ram_ => { class => 'DBD::RAM', }, |
360
|
|
|
|
|
|
|
rdb_ => { class => 'DBD::RDB', }, |
361
|
|
|
|
|
|
|
sapdb_ => { class => 'DBD::SAP_DB', }, |
362
|
|
|
|
|
|
|
snmp_ => { class => 'DBD::SNMP', }, |
363
|
|
|
|
|
|
|
solid_ => { class => 'DBD::Solid', }, |
364
|
|
|
|
|
|
|
spatialite_ => { class => 'DBD::Spatialite', }, |
365
|
|
|
|
|
|
|
sponge_ => { class => 'DBD::Sponge', }, |
366
|
|
|
|
|
|
|
sql_ => { class => 'DBI::DBD::SqlEngine', }, |
367
|
|
|
|
|
|
|
sqlite_ => { class => 'DBD::SQLite', }, |
368
|
|
|
|
|
|
|
syb_ => { class => 'DBD::Sybase', }, |
369
|
|
|
|
|
|
|
sys_ => { class => 'DBD::Sys', }, |
370
|
|
|
|
|
|
|
tdat_ => { class => 'DBD::Teradata', }, |
371
|
|
|
|
|
|
|
tmpl_ => { class => 'DBD::Template', }, |
372
|
|
|
|
|
|
|
tmplss_ => { class => 'DBD::TemplateSS', }, |
373
|
|
|
|
|
|
|
tree_ => { class => 'DBD::TreeData', }, |
374
|
|
|
|
|
|
|
tuber_ => { class => 'DBD::Tuber', }, |
375
|
|
|
|
|
|
|
uni_ => { class => 'DBD::Unify', }, |
376
|
|
|
|
|
|
|
vt_ => { class => 'DBD::Vt', }, |
377
|
|
|
|
|
|
|
wmi_ => { class => 'DBD::WMI', }, |
378
|
|
|
|
|
|
|
x_ => { }, # for private use |
379
|
|
|
|
|
|
|
xbase_ => { class => 'DBD::XBase', }, |
380
|
|
|
|
|
|
|
xmlsimple_ => { class => 'DBD::XMLSimple', }, |
381
|
|
|
|
|
|
|
xl_ => { class => 'DBD::Excel', }, |
382
|
|
|
|
|
|
|
yaswi_ => { class => 'DBD::Yaswi', }, |
383
|
|
|
|
|
|
|
}; |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
my %dbd_class_registry = map { $dbd_prefix_registry->{$_}->{class} => { prefix => $_ } } |
386
|
|
|
|
|
|
|
grep { exists $dbd_prefix_registry->{$_}->{class} } |
387
|
|
|
|
|
|
|
keys %{$dbd_prefix_registry}; |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub dump_dbd_registry { |
390
|
0
|
|
|
0
|
0
|
0
|
require Data::Dumper; |
391
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Sortkeys=1; |
392
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Indent=1; |
393
|
0
|
|
|
|
|
0
|
print Data::Dumper->Dump([$dbd_prefix_registry], [qw($dbd_prefix_registry)]); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# --- Dynamically create the DBI Standard Interface |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
my $keeperr = { O=>0x0004 }; |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
%DBI::DBI_methods = ( # Define the DBI interface methods per class: |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
common => { # Interface methods common to all DBI handle classes |
403
|
|
|
|
|
|
|
'DESTROY' => { O=>0x004|0x10000 }, |
404
|
|
|
|
|
|
|
'CLEAR' => $keeperr, |
405
|
|
|
|
|
|
|
'EXISTS' => $keeperr, |
406
|
|
|
|
|
|
|
'FETCH' => { O=>0x0404 }, |
407
|
|
|
|
|
|
|
'FETCH_many' => { O=>0x0404 }, |
408
|
|
|
|
|
|
|
'FIRSTKEY' => $keeperr, |
409
|
|
|
|
|
|
|
'NEXTKEY' => $keeperr, |
410
|
|
|
|
|
|
|
'STORE' => { O=>0x0418 | 0x4 }, |
411
|
|
|
|
|
|
|
'DELETE' => { O=>0x0404 }, |
412
|
|
|
|
|
|
|
can => { O=>0x0100 }, # special case, see dispatch |
413
|
|
|
|
|
|
|
debug => { U =>[1,2,'[$debug_level]'], O=>0x0004 }, # old name for trace |
414
|
|
|
|
|
|
|
dump_handle => { U =>[1,3,'[$message [, $level]]'], O=>0x0004 }, |
415
|
|
|
|
|
|
|
err => $keeperr, |
416
|
|
|
|
|
|
|
errstr => $keeperr, |
417
|
|
|
|
|
|
|
state => $keeperr, |
418
|
|
|
|
|
|
|
func => { O=>0x0006 }, |
419
|
|
|
|
|
|
|
parse_trace_flag => { U =>[2,2,'$name'], O=>0x0404, T=>8 }, |
420
|
|
|
|
|
|
|
parse_trace_flags => { U =>[2,2,'$flags'], O=>0x0404, T=>8 }, |
421
|
|
|
|
|
|
|
private_data => { U =>[1,1], O=>0x0004 }, |
422
|
|
|
|
|
|
|
set_err => { U =>[3,6,'$err, $errmsg [, $state, $method, $rv]'], O=>0x0010 }, |
423
|
|
|
|
|
|
|
trace => { U =>[1,3,'[$trace_level, [$filename]]'], O=>0x0004 }, |
424
|
|
|
|
|
|
|
trace_msg => { U =>[2,3,'$message_text [, $min_level ]' ], O=>0x0004, T=>8 }, |
425
|
|
|
|
|
|
|
swap_inner_handle => { U =>[2,3,'$h [, $allow_reparent ]'] }, |
426
|
|
|
|
|
|
|
private_attribute_info => { }, |
427
|
|
|
|
|
|
|
visit_child_handles => { U => [2,3,'$coderef [, $info ]'], O=>0x0404, T=>4 }, |
428
|
|
|
|
|
|
|
}, |
429
|
|
|
|
|
|
|
dr => { # Database Driver Interface |
430
|
|
|
|
|
|
|
'connect' => { U =>[1,5,'[$db [,$user [,$passwd [,\%attr]]]]'], H=>3, O=>0x8000, T=>0x200 }, |
431
|
|
|
|
|
|
|
'connect_cached'=>{U=>[1,5,'[$db [,$user [,$passwd [,\%attr]]]]'], H=>3, O=>0x8000, T=>0x200 }, |
432
|
|
|
|
|
|
|
'disconnect_all'=>{ U =>[1,1], O=>0x0800, T=>0x200 }, |
433
|
|
|
|
|
|
|
data_sources => { U =>[1,2,'[\%attr]' ], O=>0x0800, T=>0x200 }, |
434
|
|
|
|
|
|
|
default_user => { U =>[3,4,'$user, $pass [, \%attr]' ], T=>0x200 }, |
435
|
|
|
|
|
|
|
dbixs_revision => $keeperr, |
436
|
|
|
|
|
|
|
}, |
437
|
|
|
|
|
|
|
db => { # Database Session Class Interface |
438
|
|
|
|
|
|
|
data_sources => { U =>[1,2,'[\%attr]' ], O=>0x0200 }, |
439
|
|
|
|
|
|
|
take_imp_data => { U =>[1,1], O=>0x10000 }, |
440
|
|
|
|
|
|
|
clone => { U =>[1,2,'[\%attr]'], T=>0x200 }, |
441
|
|
|
|
|
|
|
connected => { U =>[1,0], O => 0x0004, T=>0x200, H=>3 }, |
442
|
|
|
|
|
|
|
begin_work => { U =>[1,2,'[ \%attr ]'], O=>0x0400, T=>0x1000 }, |
443
|
|
|
|
|
|
|
commit => { U =>[1,1], O=>0x0480|0x0800, T=>0x1000 }, |
444
|
|
|
|
|
|
|
rollback => { U =>[1,1], O=>0x0480|0x0800, T=>0x1000 }, |
445
|
|
|
|
|
|
|
'do' => { U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x3200 }, |
446
|
|
|
|
|
|
|
last_insert_id => { U =>[5,6,'$catalog, $schema, $table_name, $field_name [, \%attr ]'], O=>0x2800 }, |
447
|
|
|
|
|
|
|
preparse => { }, # XXX |
448
|
|
|
|
|
|
|
prepare => { U =>[2,3,'$statement [, \%attr]'], O=>0xA200 }, |
449
|
|
|
|
|
|
|
prepare_cached => { U =>[2,4,'$statement [, \%attr [, $if_active ] ]'], O=>0xA200 }, |
450
|
|
|
|
|
|
|
selectrow_array => { U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 }, |
451
|
|
|
|
|
|
|
selectrow_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 }, |
452
|
|
|
|
|
|
|
selectrow_hashref=>{ U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 }, |
453
|
|
|
|
|
|
|
selectall_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 }, |
454
|
|
|
|
|
|
|
selectall_array =>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 }, |
455
|
|
|
|
|
|
|
selectall_hashref=>{ U =>[3,0,'$statement, $keyfield [, \%attr [, @bind_params ] ]'], O=>0x2000 }, |
456
|
|
|
|
|
|
|
selectcol_arrayref=>{U =>[2,0,'$statement [, \%attr [, @bind_params ] ]'], O=>0x2000 }, |
457
|
|
|
|
|
|
|
ping => { U =>[1,1], O=>0x0404 }, |
458
|
|
|
|
|
|
|
disconnect => { U =>[1,1], O=>0x0400|0x0800|0x10000, T=>0x200 }, |
459
|
|
|
|
|
|
|
quote => { U =>[2,3, '$string [, $data_type ]' ], O=>0x0430, T=>2 }, |
460
|
|
|
|
|
|
|
quote_identifier=> { U =>[2,6, '$name [, ...] [, \%attr ]' ], O=>0x0430, T=>2 }, |
461
|
|
|
|
|
|
|
rows => $keeperr, |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
tables => { U =>[1,6,'$catalog, $schema, $table, $type [, \%attr ]' ], O=>0x2200 }, |
464
|
|
|
|
|
|
|
table_info => { U =>[1,6,'$catalog, $schema, $table, $type [, \%attr ]' ], O=>0x2200|0x8800 }, |
465
|
|
|
|
|
|
|
column_info => { U =>[5,6,'$catalog, $schema, $table, $column [, \%attr ]'],O=>0x2200|0x8800 }, |
466
|
|
|
|
|
|
|
primary_key_info=> { U =>[4,5,'$catalog, $schema, $table [, \%attr ]' ], O=>0x2200|0x8800 }, |
467
|
|
|
|
|
|
|
primary_key => { U =>[4,5,'$catalog, $schema, $table [, \%attr ]' ], O=>0x2200 }, |
468
|
|
|
|
|
|
|
foreign_key_info=> { U =>[7,8,'$pk_catalog, $pk_schema, $pk_table, $fk_catalog, $fk_schema, $fk_table [, \%attr ]' ], O=>0x2200|0x8800 }, |
469
|
|
|
|
|
|
|
statistics_info => { U =>[6,7,'$catalog, $schema, $table, $unique_only, $quick, [, \%attr ]' ], O=>0x2200|0x8800 }, |
470
|
|
|
|
|
|
|
type_info_all => { U =>[1,1], O=>0x2200|0x0800 }, |
471
|
|
|
|
|
|
|
type_info => { U =>[1,2,'$data_type'], O=>0x2200 }, |
472
|
|
|
|
|
|
|
get_info => { U =>[2,2,'$info_type'], O=>0x2200|0x0800 }, |
473
|
|
|
|
|
|
|
}, |
474
|
|
|
|
|
|
|
st => { # Statement Class Interface |
475
|
|
|
|
|
|
|
bind_col => { U =>[3,4,'$column, \\$var [, \%attr]'] }, |
476
|
|
|
|
|
|
|
bind_columns => { U =>[2,0,'\\$var1 [, \\$var2, ...]'] }, |
477
|
|
|
|
|
|
|
bind_param => { U =>[3,4,'$parameter, $var [, \%attr]'] }, |
478
|
|
|
|
|
|
|
bind_param_inout=> { U =>[4,5,'$parameter, \\$var, $maxlen, [, \%attr]'] }, |
479
|
|
|
|
|
|
|
execute => { U =>[1,0,'[@args]'], O=>0x1040 }, |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
bind_param_array => { U =>[3,4,'$parameter, $var [, \%attr]'] }, |
482
|
|
|
|
|
|
|
bind_param_inout_array => { U =>[4,5,'$parameter, \\@var, $maxlen, [, \%attr]'] }, |
483
|
|
|
|
|
|
|
execute_array => { U =>[2,0,'\\%attribs [, @args]'], O=>0x1040|0x4000 }, |
484
|
|
|
|
|
|
|
execute_for_fetch => { U =>[2,3,'$fetch_sub [, $tuple_status]'], O=>0x1040|0x4000 }, |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
fetch => undef, # alias for fetchrow_arrayref |
487
|
|
|
|
|
|
|
fetchrow_arrayref => undef, |
488
|
|
|
|
|
|
|
fetchrow_hashref => undef, |
489
|
|
|
|
|
|
|
fetchrow_array => undef, |
490
|
|
|
|
|
|
|
fetchrow => undef, # old alias for fetchrow_array |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
fetchall_arrayref => { U =>[1,3, '[ $slice [, $max_rows]]'] }, |
493
|
|
|
|
|
|
|
fetchall_hashref => { U =>[2,2,'$key_field'] }, |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
blob_read => { U =>[4,5,'$field, $offset, $len [, \\$buf [, $bufoffset]]'] }, |
496
|
|
|
|
|
|
|
blob_copy_to_file => { U =>[3,3,'$field, $filename_or_handleref'] }, |
497
|
|
|
|
|
|
|
dump_results => { U =>[1,5,'$maxfieldlen, $linesep, $fieldsep, $filehandle'] }, |
498
|
|
|
|
|
|
|
more_results => { U =>[1,1] }, |
499
|
|
|
|
|
|
|
finish => { U =>[1,1] }, |
500
|
|
|
|
|
|
|
cancel => { U =>[1,1], O=>0x0800 }, |
501
|
|
|
|
|
|
|
rows => $keeperr, |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
_get_fbav => undef, |
504
|
|
|
|
|
|
|
_set_fbav => { T=>6 }, |
505
|
|
|
|
|
|
|
}, |
506
|
|
|
|
|
|
|
); |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
while ( my ($class, $meths) = each %DBI::DBI_methods ) { |
509
|
|
|
|
|
|
|
my $ima_trace = 0+($ENV{DBI_IMA_TRACE}||0); |
510
|
|
|
|
|
|
|
while ( my ($method, $info) = each %$meths ) { |
511
|
|
|
|
|
|
|
my $fullmeth = "DBI::${class}::$method"; |
512
|
|
|
|
|
|
|
if (($DBI::dbi_debug & 0xF) == 15) { # quick hack to list DBI methods |
513
|
|
|
|
|
|
|
# and optionally filter by IMA flags |
514
|
|
|
|
|
|
|
my $O = $info->{O}||0; |
515
|
|
|
|
|
|
|
printf "0x%04x %-20s\n", $O, $fullmeth |
516
|
|
|
|
|
|
|
unless $ima_trace && !($O & $ima_trace); |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
DBI->_install_method($fullmeth, 'DBI.pm', $info); |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
{ |
523
|
|
|
|
|
|
|
package DBI::common; |
524
|
|
|
|
|
|
|
@DBI::dr::ISA = ('DBI::common'); |
525
|
|
|
|
|
|
|
@DBI::db::ISA = ('DBI::common'); |
526
|
|
|
|
|
|
|
@DBI::st::ISA = ('DBI::common'); |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
# End of init code |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
END { |
532
|
194
|
50
|
|
194
|
|
3266250
|
return unless defined &DBI::trace_msg; # return unless bootstrap'd ok |
533
|
194
|
|
|
|
|
2739
|
local ($!,$?); |
534
|
194
|
|
50
|
|
|
4497
|
DBI->trace_msg(sprintf(" -- DBI::END (\$\@: %s, \$!: %s)\n", $@||'', $!||''), 2); |
|
|
|
50
|
|
|
|
|
535
|
|
|
|
|
|
|
# Let drivers know why we are calling disconnect_all: |
536
|
194
|
|
|
|
|
922
|
$DBI::PERL_ENDING = $DBI::PERL_ENDING = 1; # avoid typo warning |
537
|
194
|
100
|
|
|
|
2592
|
DBI->disconnect_all() if %DBI::installed_drh; |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
sub CLONE { |
542
|
0
|
0
|
|
0
|
|
0
|
_clone_dbis() unless $DBI::PurePerl; # clone the DBIS structure |
543
|
0
|
|
|
|
|
0
|
DBI->trace_msg("CLONE DBI for new thread\n"); |
544
|
0
|
|
|
|
|
0
|
while ( my ($driver, $drh) = each %DBI::installed_drh) { |
545
|
194
|
|
|
194
|
|
1627
|
no strict 'refs'; |
|
194
|
|
|
|
|
532
|
|
|
194
|
|
|
|
|
227157
|
|
546
|
0
|
0
|
|
|
|
0
|
next if defined &{"DBD::${driver}::CLONE"}; |
|
0
|
|
|
|
|
0
|
|
547
|
0
|
|
|
|
|
0
|
warn("$driver has no driver CLONE() function so is unsafe threaded\n"); |
548
|
|
|
|
|
|
|
} |
549
|
0
|
|
|
|
|
0
|
%DBI::installed_drh = (); # clear loaded drivers so they have a chance to reinitialize |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
sub parse_dsn { |
553
|
630
|
|
|
630
|
1
|
1468
|
my ($class, $dsn) = @_; |
554
|
630
|
100
|
|
|
|
3372
|
$dsn =~ s/^(dbi):(\w*?)(?:\((.*?)\))?://i or return; |
555
|
2
|
|
|
|
|
18
|
my ($scheme, $driver, $attr, $attr_hash) = (lc($1), $2, $3); |
556
|
2
|
|
0
|
|
|
10
|
$driver ||= $ENV{DBI_DRIVER} || ''; |
|
|
|
33
|
|
|
|
|
557
|
2
|
50
|
|
|
|
30
|
$attr_hash = { split /\s*=>?\s*|\s*,\s*/, $attr, -1 } if $attr; |
558
|
2
|
|
|
|
|
12
|
return ($scheme, $driver, $attr, $attr_hash, $dsn); |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
sub visit_handles { |
562
|
8
|
|
|
8
|
1
|
8946
|
my ($class, $code, $outer_info) = @_; |
563
|
8
|
50
|
|
|
|
33
|
$outer_info = {} if not defined $outer_info; |
564
|
8
|
|
|
|
|
36
|
my %drh = DBI->installed_drivers; |
565
|
8
|
|
|
|
|
31
|
for my $h (values %drh) { |
566
|
12
|
50
|
|
|
|
55
|
my $child_info = $code->($h, $outer_info) |
567
|
|
|
|
|
|
|
or next; |
568
|
12
|
|
|
|
|
449
|
$h->visit_child_handles($code, $child_info); |
569
|
|
|
|
|
|
|
} |
570
|
8
|
|
|
|
|
71
|
return $outer_info; |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
# --- The DBI->connect Front Door methods |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
sub connect_cached { |
577
|
|
|
|
|
|
|
# For library code using connect_cached() with mod_perl |
578
|
|
|
|
|
|
|
# we redirect those calls to Apache::DBI::connect() as well |
579
|
3146
|
|
|
3146
|
1
|
8882
|
my ($class, $dsn, $user, $pass, $attr) = @_; |
580
|
3146
|
50
|
|
|
|
6110
|
my $dbi_connect_method = ($DBI::connect_via eq "Apache::DBI::connect") |
581
|
|
|
|
|
|
|
? 'Apache::DBI::connect' : 'connect_cached'; |
582
|
3146
|
50
|
|
|
|
16243
|
$attr = { |
583
|
|
|
|
|
|
|
$attr ? %$attr : (), # clone, don't modify callers data |
584
|
|
|
|
|
|
|
dbi_connect_method => $dbi_connect_method, |
585
|
|
|
|
|
|
|
}; |
586
|
3146
|
|
|
|
|
8546
|
return $class->connect($dsn, $user, $pass, $attr); |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
sub connect { |
590
|
6973
|
|
|
6973
|
1
|
1505993
|
my $class = shift; |
591
|
6973
|
|
|
|
|
23712
|
my ($dsn, $user, $pass, $attr, $old_driver) = my @orig_args = @_; |
592
|
6973
|
|
|
|
|
12687
|
my $driver; |
593
|
|
|
|
|
|
|
|
594
|
6973
|
50
|
66
|
|
|
33983
|
if ($attr and !ref($attr)) { # switch $old_driver<->$attr if called in old style |
595
|
0
|
|
|
|
|
0
|
Carp::carp("DBI->connect using 'old-style' syntax is deprecated and will be an error in future versions"); |
596
|
0
|
|
|
|
|
0
|
($old_driver, $attr) = ($attr, $old_driver); |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
6973
|
|
|
|
|
14236
|
my $connect_meth = $attr->{dbi_connect_method}; |
600
|
6973
|
|
66
|
|
|
26167
|
$connect_meth ||= $DBI::connect_via; # fallback to default |
601
|
|
|
|
|
|
|
|
602
|
6973
|
50
|
0
|
|
|
19344
|
$dsn ||= $ENV{DBI_DSN} || $ENV{DBI_DBNAME} || '' unless $old_driver; |
|
|
|
33
|
|
|
|
|
603
|
|
|
|
|
|
|
|
604
|
6973
|
100
|
|
|
|
15927
|
if ($DBI::dbi_debug) { |
605
|
29
|
|
|
|
|
120
|
local $^W = 0; |
606
|
29
|
50
|
|
|
|
97
|
pop @_ if $connect_meth ne 'connect'; |
607
|
29
|
|
|
|
|
91
|
my @args = @_; $args[2] = '****'; # hide password |
|
29
|
|
|
|
|
60
|
|
608
|
29
|
|
|
|
|
272
|
DBI->trace_msg(" -> $class->$connect_meth(".join(", ",@args).")\n"); |
609
|
|
|
|
|
|
|
} |
610
|
6973
|
100
|
33
|
|
|
45093
|
Carp::croak('Usage: $class->connect([$dsn [,$user [,$passwd [,\%attr]]]])') |
|
|
|
33
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
611
|
|
|
|
|
|
|
if (ref $old_driver or ($attr and not ref $attr) or |
612
|
|
|
|
|
|
|
(ref $pass and not defined Scalar::Util::blessed($pass))); |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# extract dbi:driver prefix from $dsn into $1 |
615
|
6969
|
50
|
|
|
|
64711
|
$dsn =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i |
616
|
|
|
|
|
|
|
or '' =~ /()/; # ensure $1 etc are empty if match fails |
617
|
6969
|
|
100
|
|
|
32673
|
my $driver_attrib_spec = $2 || ''; |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
# Set $driver. Old style driver, if specified, overrides new dsn style. |
620
|
|
|
|
|
|
|
$driver = $old_driver || $1 || $ENV{DBI_DRIVER} |
621
|
6969
|
50
|
33
|
|
|
37567
|
or Carp::croak("Can't connect to data source '$dsn' " |
622
|
|
|
|
|
|
|
."because I can't work out what driver to use " |
623
|
|
|
|
|
|
|
."(it doesn't seem to contain a 'dbi:driver:' prefix " |
624
|
|
|
|
|
|
|
."and the DBI_DRIVER env var is not set)"); |
625
|
|
|
|
|
|
|
|
626
|
6969
|
|
|
|
|
10666
|
my $proxy; |
627
|
6969
|
100
|
66
|
|
|
20946
|
if ($ENV{DBI_AUTOPROXY} && $driver ne 'Proxy' && $driver ne 'Sponge' && $driver ne 'Switch') { |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
628
|
194
|
|
|
|
|
567
|
my $dbi_autoproxy = $ENV{DBI_AUTOPROXY}; |
629
|
194
|
|
|
|
|
395
|
$proxy = 'Proxy'; |
630
|
194
|
50
|
|
|
|
1456
|
if ($dbi_autoproxy =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i) { |
631
|
194
|
|
|
|
|
538
|
$proxy = $1; |
632
|
194
|
100
|
|
|
|
941
|
$driver_attrib_spec = join ",", |
|
|
50
|
|
|
|
|
|
633
|
|
|
|
|
|
|
($driver_attrib_spec) ? $driver_attrib_spec : (), |
634
|
|
|
|
|
|
|
($2 ) ? $2 : (); |
635
|
|
|
|
|
|
|
} |
636
|
194
|
|
|
|
|
783
|
$dsn = "$dbi_autoproxy;dsn=dbi:$driver:$dsn"; |
637
|
194
|
|
|
|
|
379
|
$driver = $proxy; |
638
|
194
|
|
|
|
|
1257
|
DBI->trace_msg(" DBI_AUTOPROXY: dbi:$driver($driver_attrib_spec):$dsn\n"); |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
# avoid recursion if proxy calls DBI->connect itself |
641
|
6969
|
100
|
|
|
|
17415
|
local $ENV{DBI_AUTOPROXY} if $ENV{DBI_AUTOPROXY}; |
642
|
|
|
|
|
|
|
|
643
|
6969
|
|
|
|
|
10350
|
my %attributes; # take a copy we can delete from |
644
|
6969
|
50
|
|
|
|
13614
|
if ($old_driver) { |
645
|
0
|
0
|
|
|
|
0
|
%attributes = %$attr if $attr; |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
else { # new-style connect so new default semantics |
648
|
6969
|
50
|
|
|
|
59328
|
%attributes = ( |
|
|
100
|
|
|
|
|
|
649
|
|
|
|
|
|
|
PrintError => 1, |
650
|
|
|
|
|
|
|
AutoCommit => 1, |
651
|
|
|
|
|
|
|
ref $attr ? %$attr : (), |
652
|
|
|
|
|
|
|
# attributes in DSN take precedence over \%attr connect parameter |
653
|
|
|
|
|
|
|
$driver_attrib_spec ? (split /\s*=>?\s*|\s*,\s*/, $driver_attrib_spec, -1) : (), |
654
|
|
|
|
|
|
|
); |
655
|
|
|
|
|
|
|
} |
656
|
6969
|
|
|
|
|
16453
|
$attr = \%attributes; # now set $attr to refer to our local copy |
657
|
|
|
|
|
|
|
|
658
|
6969
|
50
|
66
|
|
|
27966
|
my $drh = $DBI::installed_drh{$driver} || $class->install_driver($driver) |
659
|
|
|
|
|
|
|
or die "panic: $class->install_driver($driver) failed"; |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
# attributes in DSN take precedence over \%attr connect parameter |
662
|
6965
|
100
|
|
|
|
19247
|
$user = $attr->{Username} if defined $attr->{Username}; |
663
|
6965
|
100
|
|
|
|
17079
|
$pass = $attr->{Password} if defined $attr->{Password}; |
664
|
6965
|
|
|
|
|
12261
|
delete $attr->{Password}; # always delete Password as closure stores it securely |
665
|
6965
|
100
|
66
|
|
|
23918
|
if ( !(defined $user && defined $pass) ) { |
666
|
1606
|
|
|
|
|
11795
|
($user, $pass) = $drh->default_user($user, $pass, $attr); |
667
|
|
|
|
|
|
|
} |
668
|
6965
|
|
|
|
|
23278
|
$attr->{Username} = $user; # force the Username to be the actual one used |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
my $connect_closure = sub { |
671
|
6981
|
|
|
6981
|
|
12689
|
my ($old_dbh, $override_attr) = @_; |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
#use Data::Dumper; |
674
|
|
|
|
|
|
|
#warn "connect_closure: ".Data::Dumper::Dumper([$attr,\%attributes, $override_attr]); |
675
|
|
|
|
|
|
|
|
676
|
6981
|
|
|
|
|
8482
|
my $dbh; |
677
|
6981
|
100
|
|
|
|
43411
|
unless ($dbh = $drh->$connect_meth($dsn, $user, $pass, $attr)) { |
678
|
38
|
100
|
|
|
|
862
|
$user = '' if !defined $user; |
679
|
38
|
50
|
|
|
|
106
|
$dsn = '' if !defined $dsn; |
680
|
|
|
|
|
|
|
# $drh->errstr isn't safe here because $dbh->DESTROY may not have |
681
|
|
|
|
|
|
|
# been called yet and so the dbh errstr would not have been copied |
682
|
|
|
|
|
|
|
# up to the drh errstr. Certainly true for connect_cached! |
683
|
38
|
|
|
|
|
181
|
my $errstr = $DBI::errstr; |
684
|
|
|
|
|
|
|
# Getting '(no error string)' here is a symptom of a ref loop |
685
|
38
|
50
|
|
|
|
127
|
$errstr = '(no error string)' if !defined $errstr; |
686
|
38
|
|
|
|
|
190
|
my $msg = "$class connect('$dsn','$user',...) failed: $errstr"; |
687
|
38
|
|
|
|
|
183
|
DBI->trace_msg(" $msg\n"); |
688
|
|
|
|
|
|
|
# XXX HandleWarn |
689
|
38
|
50
|
33
|
|
|
239
|
unless ($attr->{HandleError} && $attr->{HandleError}->($msg, $drh, $dbh)) { |
690
|
38
|
100
|
|
|
|
2049
|
Carp::croak($msg) if $attr->{RaiseError}; |
691
|
24
|
50
|
|
|
|
75
|
Carp::carp ($msg) if $attr->{PrintError}; |
692
|
|
|
|
|
|
|
} |
693
|
24
|
|
|
|
|
60
|
$! = 0; # for the daft people who do DBI->connect(...) || die "$!"; |
694
|
24
|
|
|
|
|
73
|
return $dbh; # normally undef, but HandleError could change it |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
# merge any attribute overrides but don't change $attr itself (for closure) |
698
|
6907
|
100
|
|
|
|
69654
|
my $apply = { ($override_attr) ? (%$attr, %$override_attr ) : %$attr }; |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
# handle basic RootClass subclassing: |
701
|
6907
|
|
100
|
|
|
39402
|
my $rebless_class = $apply->{RootClass} || ($class ne 'DBI' ? $class : ''); |
702
|
6907
|
100
|
|
|
|
15557
|
if ($rebless_class) { |
703
|
194
|
|
|
194
|
|
2916
|
no strict 'refs'; |
|
194
|
|
|
|
|
496
|
|
|
194
|
|
|
|
|
166973
|
|
704
|
32
|
100
|
|
|
|
95
|
if ($apply->{RootClass}) { # explicit attribute (ie not static method call class) |
705
|
24
|
|
|
|
|
41
|
delete $apply->{RootClass}; |
706
|
24
|
|
|
|
|
56
|
DBI::_load_class($rebless_class, 0); |
707
|
|
|
|
|
|
|
} |
708
|
28
|
50
|
33
|
|
|
40
|
unless (@{"$rebless_class\::db::ISA"} && @{"$rebless_class\::st::ISA"}) { |
|
28
|
|
|
|
|
134
|
|
|
28
|
|
|
|
|
109
|
|
709
|
0
|
|
|
|
|
0
|
Carp::carp("DBI subclasses '$rebless_class\::db' and ::st are not setup, RootClass ignored"); |
710
|
0
|
|
|
|
|
0
|
$rebless_class = undef; |
711
|
0
|
|
|
|
|
0
|
$class = 'DBI'; |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
else { |
714
|
28
|
|
|
|
|
183
|
$dbh->{RootClass} = $rebless_class; # $dbh->STORE called via plain DBI::db |
715
|
28
|
|
|
|
|
210
|
DBI::_set_isa([$rebless_class], 'DBI'); # sets up both '::db' and '::st' |
716
|
28
|
|
|
|
|
75
|
DBI::_rebless($dbh, $rebless_class); # appends '::db' |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
6903
|
100
|
|
|
|
16056
|
if (%$apply) { |
721
|
|
|
|
|
|
|
|
722
|
6321
|
50
|
|
|
|
13093
|
if ($apply->{DbTypeSubclass}) { |
723
|
0
|
|
|
|
|
0
|
my $DbTypeSubclass = delete $apply->{DbTypeSubclass}; |
724
|
0
|
|
0
|
|
|
0
|
DBI::_rebless_dbtype_subclass($dbh, $rebless_class||$class, $DbTypeSubclass); |
725
|
|
|
|
|
|
|
} |
726
|
6321
|
|
|
|
|
8202
|
my $a; |
727
|
6321
|
|
|
|
|
12036
|
foreach $a (qw(Profile RaiseError PrintError AutoCommit)) { # do these first |
728
|
25284
|
100
|
|
|
|
63463
|
next unless exists $apply->{$a}; |
729
|
18856
|
|
|
|
|
97355
|
$dbh->{$a} = delete $apply->{$a}; |
730
|
|
|
|
|
|
|
} |
731
|
6321
|
|
|
|
|
33665
|
while ( my ($a, $v) = each %$apply) { |
732
|
28547
|
|
|
|
|
38335
|
eval { $dbh->{$a} = $v }; # assign in void context to avoid re-FETCH |
|
28547
|
|
|
|
|
106538
|
|
733
|
28547
|
50
|
|
|
|
129611
|
warn $@ if $@; |
734
|
|
|
|
|
|
|
} |
735
|
|
|
|
|
|
|
} |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
# confirm to driver (ie if subclassed) that we've connected successfully |
738
|
|
|
|
|
|
|
# and finished the attribute setup. pass in the original arguments |
739
|
6903
|
|
|
|
|
34353
|
$dbh->connected(@orig_args); #if ref $dbh ne 'DBI::db' or $proxy; |
740
|
|
|
|
|
|
|
|
741
|
6903
|
100
|
|
|
|
25671
|
DBI->trace_msg(" <- connect= $dbh\n") if $DBI::dbi_debug & 0xF; |
742
|
|
|
|
|
|
|
|
743
|
6903
|
|
|
|
|
22890
|
return $dbh; |
744
|
6965
|
|
|
|
|
42758
|
}; |
745
|
|
|
|
|
|
|
|
746
|
6965
|
|
|
|
|
18084
|
my $dbh = &$connect_closure(undef, undef); |
747
|
|
|
|
|
|
|
|
748
|
6911
|
100
|
|
|
|
35722
|
$dbh->{dbi_connect_closure} = $connect_closure if $dbh; |
749
|
|
|
|
|
|
|
|
750
|
6911
|
|
|
|
|
42404
|
return $dbh; |
751
|
|
|
|
|
|
|
} |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
sub disconnect_all { |
755
|
140
|
|
|
140
|
0
|
759
|
keys %DBI::installed_drh; # reset iterator |
756
|
140
|
|
|
|
|
1376
|
while ( my ($name, $drh) = each %DBI::installed_drh ) { |
757
|
236
|
50
|
|
|
|
6980
|
$drh->disconnect_all() if ref $drh; |
758
|
|
|
|
|
|
|
} |
759
|
|
|
|
|
|
|
} |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
sub disconnect { # a regular beginners bug |
763
|
0
|
|
|
0
|
1
|
0
|
Carp::croak("DBI->disconnect is not a DBI method (read the DBI manual)"); |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
sub install_driver { # croaks on failure |
768
|
248
|
|
|
248
|
0
|
77392
|
my $class = shift; |
769
|
248
|
|
|
|
|
1269
|
my($driver, $attr) = @_; |
770
|
248
|
|
|
|
|
534
|
my $drh; |
771
|
|
|
|
|
|
|
|
772
|
248
|
|
0
|
|
|
820
|
$driver ||= $ENV{DBI_DRIVER} || ''; |
|
|
|
33
|
|
|
|
|
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
# allow driver to be specified as a 'dbi:driver:' string |
775
|
248
|
100
|
|
|
|
1144
|
$driver = $1 if $driver =~ s/^DBI:(.*?)://i; |
776
|
|
|
|
|
|
|
|
777
|
248
|
50
|
33
|
|
|
1678
|
Carp::croak("usage: $class->install_driver(\$driver [, \%attr])") |
778
|
|
|
|
|
|
|
unless ($driver and @_<=3); |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# already installed |
781
|
248
|
100
|
|
|
|
998
|
return $drh if $drh = $DBI::installed_drh{$driver}; |
782
|
|
|
|
|
|
|
|
783
|
240
|
100
|
|
|
|
1112
|
$class->trace_msg(" -> $class->install_driver($driver" |
784
|
|
|
|
|
|
|
.") for $^O perl=$] pid=$$ ruid=$< euid=$>\n") |
785
|
|
|
|
|
|
|
if $DBI::dbi_debug & 0xF; |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
# --- load the code |
788
|
240
|
|
|
|
|
785
|
my $driver_class = "DBD::$driver"; |
789
|
240
|
|
|
|
|
18231
|
eval qq{package # hide from PAUSE |
790
|
|
|
|
|
|
|
DBI::_firesafe; # just in case |
791
|
|
|
|
|
|
|
require $driver_class; # load the driver |
792
|
|
|
|
|
|
|
}; |
793
|
240
|
100
|
|
|
|
1532
|
if ($@) { |
794
|
4
|
|
|
|
|
8
|
my $err = $@; |
795
|
4
|
|
|
|
|
9
|
my $advice = ""; |
796
|
4
|
50
|
|
|
|
108
|
if ($err =~ /Can't find loadable object/) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
797
|
0
|
|
|
|
|
0
|
$advice = "Perhaps DBD::$driver was statically linked into a new perl binary." |
798
|
|
|
|
|
|
|
."\nIn which case you need to use that new perl binary." |
799
|
|
|
|
|
|
|
."\nOr perhaps only the .pm file was installed but not the shared object file." |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
elsif ($err =~ /Can't locate.*?DBD\/$driver\.pm in \@INC/) { |
802
|
4
|
|
|
|
|
25
|
my @drv = $class->available_drivers(1); |
803
|
4
|
|
|
|
|
35
|
$advice = "Perhaps the DBD::$driver perl module hasn't been fully installed,\n" |
804
|
|
|
|
|
|
|
."or perhaps the capitalisation of '$driver' isn't right.\n" |
805
|
|
|
|
|
|
|
."Available drivers: ".join(", ", @drv)."."; |
806
|
|
|
|
|
|
|
} |
807
|
|
|
|
|
|
|
elsif ($err =~ /Can't load .*? for module DBD::/) { |
808
|
0
|
|
|
|
|
0
|
$advice = "Perhaps a required shared library or dll isn't installed where expected"; |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
elsif ($err =~ /Can't locate .*? in \@INC/) { |
811
|
0
|
|
|
|
|
0
|
$advice = "Perhaps a module that DBD::$driver requires hasn't been fully installed"; |
812
|
|
|
|
|
|
|
} |
813
|
4
|
|
|
|
|
1023
|
Carp::croak("install_driver($driver) failed: $err$advice\n"); |
814
|
|
|
|
|
|
|
} |
815
|
236
|
100
|
|
|
|
1048
|
if ($DBI::dbi_debug & 0xF) { |
816
|
194
|
|
|
194
|
|
1589
|
no strict 'refs'; |
|
194
|
|
|
|
|
433
|
|
|
194
|
|
|
|
|
59201
|
|
817
|
6
|
|
|
|
|
49
|
(my $driver_file = $driver_class) =~ s/::/\//g; |
818
|
6
|
|
50
|
|
|
15
|
my $dbd_ver = ${"$driver_class\::VERSION"} || "undef"; |
819
|
6
|
|
|
|
|
123
|
$class->trace_msg(" install_driver: $driver_class version $dbd_ver" |
820
|
|
|
|
|
|
|
." loaded from $INC{qq($driver_file.pm)}\n"); |
821
|
|
|
|
|
|
|
} |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
# --- do some behind-the-scenes checks and setups on the driver |
824
|
236
|
|
|
|
|
1446
|
$class->setup_driver($driver_class); |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
# --- run the driver function |
827
|
236
|
|
50
|
|
|
562
|
$drh = eval { $driver_class->driver($attr || {}) }; |
|
236
|
|
|
|
|
2138
|
|
828
|
236
|
50
|
33
|
|
|
5791
|
unless ($drh && ref $drh && !$@) { |
|
|
|
33
|
|
|
|
|
829
|
0
|
|
|
|
|
0
|
my $advice = ""; |
830
|
0
|
|
0
|
|
|
0
|
$@ ||= "$driver_class->driver didn't return a handle"; |
831
|
|
|
|
|
|
|
# catch people on case in-sensitive systems using the wrong case |
832
|
0
|
0
|
|
|
|
0
|
$advice = "\nPerhaps the capitalisation of DBD '$driver' isn't right." |
833
|
|
|
|
|
|
|
if $@ =~ /locate object method/; |
834
|
0
|
|
|
|
|
0
|
Carp::croak("$driver_class initialisation failed: $@$advice"); |
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
|
837
|
236
|
|
|
|
|
917
|
$DBI::installed_drh{$driver} = $drh; |
838
|
236
|
100
|
|
|
|
1019
|
$class->trace_msg(" <- install_driver= $drh\n") if $DBI::dbi_debug & 0xF; |
839
|
236
|
|
|
|
|
1496
|
$drh; |
840
|
|
|
|
|
|
|
} |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
*driver = \&install_driver; # currently an alias, may change |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
sub setup_driver { |
846
|
540
|
|
|
540
|
0
|
1917
|
my ($class, $driver_class) = @_; |
847
|
540
|
|
|
|
|
1024
|
my $h_type; |
848
|
540
|
|
|
|
|
1567
|
foreach $h_type (qw(dr db st)){ |
849
|
1620
|
|
|
|
|
4100
|
my $h_class = $driver_class."::$h_type"; |
850
|
194
|
|
|
194
|
|
1534
|
no strict 'refs'; |
|
194
|
|
|
|
|
431
|
|
|
194
|
|
|
|
|
57055
|
|
851
|
1620
|
100
|
|
|
|
12288
|
push @{"${h_class}::ISA"}, "DBD::_::$h_type" |
|
1314
|
|
|
|
|
15492
|
|
852
|
|
|
|
|
|
|
unless UNIVERSAL::isa($h_class, "DBD::_::$h_type"); |
853
|
|
|
|
|
|
|
# The _mem class stuff is (IIRC) a crufty hack for global destruction |
854
|
|
|
|
|
|
|
# timing issues in early versions of perl5 and possibly no longer needed. |
855
|
1620
|
|
|
|
|
4982
|
my $mem_class = "DBD::_mem::$h_type"; |
856
|
1620
|
100
|
100
|
|
|
13032
|
push @{"${h_class}_mem::ISA"}, $mem_class |
|
765
|
|
|
|
|
9238
|
|
857
|
|
|
|
|
|
|
unless UNIVERSAL::isa("${h_class}_mem", $mem_class) |
858
|
|
|
|
|
|
|
or $DBI::PurePerl; |
859
|
|
|
|
|
|
|
} |
860
|
|
|
|
|
|
|
} |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
sub _rebless { |
864
|
28
|
|
|
28
|
|
48
|
my $dbh = shift; |
865
|
28
|
|
|
|
|
95
|
my ($outer, $inner) = DBI::_handles($dbh); |
866
|
28
|
|
|
|
|
57
|
my $class = shift(@_).'::db'; |
867
|
28
|
|
|
|
|
52
|
bless $inner => $class; |
868
|
28
|
|
|
|
|
55
|
bless $outer => $class; # outer last for return |
869
|
|
|
|
|
|
|
} |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
sub _set_isa { |
873
|
28
|
|
|
28
|
|
56
|
my ($classes, $topclass) = @_; |
874
|
28
|
|
|
|
|
128
|
my $trace = DBI->trace_msg(" _set_isa([@$classes])\n"); |
875
|
28
|
|
|
|
|
60
|
foreach my $suffix ('::db','::st') { |
876
|
56
|
|
50
|
|
|
111
|
my $previous = $topclass || 'DBI'; # trees are rooted here |
877
|
56
|
|
|
|
|
86
|
foreach my $class (@$classes) { |
878
|
56
|
|
|
|
|
73
|
my $base_class = $previous.$suffix; |
879
|
56
|
|
|
|
|
74
|
my $sub_class = $class.$suffix; |
880
|
56
|
|
|
|
|
77
|
my $sub_class_isa = "${sub_class}::ISA"; |
881
|
194
|
|
|
194
|
|
1443
|
no strict 'refs'; |
|
194
|
|
|
|
|
465
|
|
|
194
|
|
|
|
|
133901
|
|
882
|
56
|
50
|
|
|
|
140
|
if (@$sub_class_isa) { |
883
|
56
|
50
|
|
|
|
112
|
DBI->trace_msg(" $sub_class_isa skipped (already set to @$sub_class_isa)\n") |
884
|
|
|
|
|
|
|
if $trace; |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
else { |
887
|
0
|
0
|
|
|
|
0
|
@$sub_class_isa = ($base_class) unless @$sub_class_isa; |
888
|
0
|
0
|
|
|
|
0
|
DBI->trace_msg(" $sub_class_isa = $base_class\n") |
889
|
|
|
|
|
|
|
if $trace; |
890
|
|
|
|
|
|
|
} |
891
|
56
|
|
|
|
|
115
|
$previous = $class; |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
} |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
sub _rebless_dbtype_subclass { |
898
|
0
|
|
|
0
|
|
0
|
my ($dbh, $rootclass, $DbTypeSubclass) = @_; |
899
|
|
|
|
|
|
|
# determine the db type names for class hierarchy |
900
|
0
|
|
|
|
|
0
|
my @hierarchy = DBI::_dbtype_names($dbh, $DbTypeSubclass); |
901
|
|
|
|
|
|
|
# add the rootclass prefix to each ('DBI::' or 'MyDBI::' etc) |
902
|
0
|
|
|
|
|
0
|
$_ = $rootclass.'::'.$_ foreach (@hierarchy); |
903
|
|
|
|
|
|
|
# load the modules from the 'top down' |
904
|
0
|
|
|
|
|
0
|
DBI::_load_class($_, 1) foreach (reverse @hierarchy); |
905
|
|
|
|
|
|
|
# setup class hierarchy if needed, does both '::db' and '::st' |
906
|
0
|
|
|
|
|
0
|
DBI::_set_isa(\@hierarchy, $rootclass); |
907
|
|
|
|
|
|
|
# finally bless the handle into the subclass |
908
|
0
|
|
|
|
|
0
|
DBI::_rebless($dbh, $hierarchy[0]); |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
sub _dbtype_names { # list dbtypes for hierarchy, ie Informix=>ADO=>ODBC |
913
|
0
|
|
|
0
|
|
0
|
my ($dbh, $DbTypeSubclass) = @_; |
914
|
|
|
|
|
|
|
|
915
|
0
|
0
|
0
|
|
|
0
|
if ($DbTypeSubclass && $DbTypeSubclass ne '1' && ref $DbTypeSubclass ne 'CODE') { |
|
|
|
0
|
|
|
|
|
916
|
|
|
|
|
|
|
# treat $DbTypeSubclass as a comma separated list of names |
917
|
0
|
|
|
|
|
0
|
my @dbtypes = split /\s*,\s*/, $DbTypeSubclass; |
918
|
0
|
|
|
|
|
0
|
$dbh->trace_msg(" DbTypeSubclass($DbTypeSubclass)=@dbtypes (explicit)\n"); |
919
|
0
|
|
|
|
|
0
|
return @dbtypes; |
920
|
|
|
|
|
|
|
} |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
# XXX will call $dbh->get_info(17) (=SQL_DBMS_NAME) in future? |
923
|
|
|
|
|
|
|
|
924
|
0
|
|
|
|
|
0
|
my $driver = $dbh->{Driver}->{Name}; |
925
|
0
|
0
|
|
|
|
0
|
if ( $driver eq 'Proxy' ) { |
926
|
|
|
|
|
|
|
# XXX Looking into the internals of DBD::Proxy is questionable! |
927
|
0
|
0
|
|
|
|
0
|
($driver) = $dbh->{proxy_client}->{application} =~ /^DBI:(.+?):/i |
928
|
|
|
|
|
|
|
or die "Can't determine driver name from proxy"; |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
|
931
|
0
|
|
|
|
|
0
|
my @dbtypes = (ucfirst($driver)); |
932
|
0
|
0
|
0
|
|
|
0
|
if ($driver eq 'ODBC' || $driver eq 'ADO') { |
933
|
|
|
|
|
|
|
# XXX will move these out and make extensible later: |
934
|
0
|
|
|
|
|
0
|
my $_dbtype_name_regexp = 'Oracle'; # eg 'Oracle|Foo|Bar' |
935
|
0
|
|
|
|
|
0
|
my %_dbtype_name_map = ( |
936
|
|
|
|
|
|
|
'Microsoft SQL Server' => 'MSSQL', |
937
|
|
|
|
|
|
|
'SQL Server' => 'Sybase', |
938
|
|
|
|
|
|
|
'Adaptive Server Anywhere' => 'ASAny', |
939
|
|
|
|
|
|
|
'ADABAS D' => 'AdabasD', |
940
|
|
|
|
|
|
|
); |
941
|
|
|
|
|
|
|
|
942
|
0
|
|
|
|
|
0
|
my $name; |
943
|
0
|
0
|
|
|
|
0
|
$name = $dbh->func(17, 'GetInfo') # SQL_DBMS_NAME |
944
|
|
|
|
|
|
|
if $driver eq 'ODBC'; |
945
|
0
|
0
|
|
|
|
0
|
$name = $dbh->{ado_conn}->Properties->Item('DBMS Name')->Value |
946
|
|
|
|
|
|
|
if $driver eq 'ADO'; |
947
|
0
|
0
|
|
|
|
0
|
die "Can't determine driver name! ($DBI::errstr)\n" |
948
|
|
|
|
|
|
|
unless $name; |
949
|
|
|
|
|
|
|
|
950
|
0
|
|
|
|
|
0
|
my $dbtype; |
951
|
0
|
0
|
|
|
|
0
|
if ($_dbtype_name_map{$name}) { |
952
|
0
|
|
|
|
|
0
|
$dbtype = $_dbtype_name_map{$name}; |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
else { |
955
|
0
|
0
|
|
|
|
0
|
if ($name =~ /($_dbtype_name_regexp)/) { |
956
|
0
|
|
|
|
|
0
|
$dbtype = lc($1); |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
else { # generic mangling for other names: |
959
|
0
|
|
|
|
|
0
|
$dbtype = lc($name); |
960
|
|
|
|
|
|
|
} |
961
|
0
|
|
|
|
|
0
|
$dbtype =~ s/\b(\w)/\U$1/g; |
962
|
0
|
|
|
|
|
0
|
$dbtype =~ s/\W+/_/g; |
963
|
|
|
|
|
|
|
} |
964
|
|
|
|
|
|
|
# add ODBC 'behind' ADO |
965
|
0
|
0
|
|
|
|
0
|
push @dbtypes, 'ODBC' if $driver eq 'ADO'; |
966
|
|
|
|
|
|
|
# add discovered dbtype in front of ADO/ODBC |
967
|
0
|
|
|
|
|
0
|
unshift @dbtypes, $dbtype; |
968
|
|
|
|
|
|
|
} |
969
|
0
|
0
|
|
|
|
0
|
@dbtypes = &$DbTypeSubclass($dbh, \@dbtypes) |
970
|
|
|
|
|
|
|
if (ref $DbTypeSubclass eq 'CODE'); |
971
|
0
|
|
|
|
|
0
|
$dbh->trace_msg(" DbTypeSubclass($DbTypeSubclass)=@dbtypes\n"); |
972
|
0
|
|
|
|
|
0
|
return @dbtypes; |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
sub _load_class { |
976
|
24
|
|
|
24
|
|
48
|
my ($load_class, $missing_ok) = @_; |
977
|
24
|
|
|
|
|
116
|
DBI->trace_msg(" _load_class($load_class, $missing_ok)\n", 2); |
978
|
194
|
|
|
194
|
|
1553
|
no strict 'refs'; |
|
194
|
|
|
|
|
2349
|
|
|
194
|
|
|
|
|
128577
|
|
979
|
24
|
100
|
|
|
|
33
|
return 1 if @{"$load_class\::ISA"}; # already loaded/exists |
|
24
|
|
|
|
|
116
|
|
980
|
4
|
|
|
|
|
17
|
(my $module = $load_class) =~ s!::!/!g; |
981
|
4
|
|
|
|
|
22
|
DBI->trace_msg(" _load_class require $module\n", 2); |
982
|
4
|
|
|
|
|
9
|
eval { require "$module.pm"; }; |
|
4
|
|
|
|
|
803
|
|
983
|
4
|
50
|
|
|
|
24
|
return 1 unless $@; |
984
|
4
|
50
|
33
|
|
|
22
|
return 0 if $missing_ok && $@ =~ /^Can't locate \Q$module.pm\E/; |
985
|
4
|
|
|
|
|
106
|
die $@; |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
sub init_rootclass { # deprecated |
990
|
0
|
|
|
0
|
0
|
0
|
return 1; |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
*internal = \&DBD::Switch::dr::driver; |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
sub driver_prefix { |
997
|
5324
|
|
|
5324
|
0
|
10183
|
my ($class, $driver) = @_; |
998
|
5324
|
50
|
|
|
|
18689
|
return $dbd_class_registry{$driver}->{prefix} if exists $dbd_class_registry{$driver}; |
999
|
0
|
|
|
|
|
0
|
return; |
1000
|
|
|
|
|
|
|
} |
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
sub available_drivers { |
1003
|
12
|
|
|
12
|
1
|
4770
|
my($quiet) = @_; |
1004
|
12
|
|
|
|
|
24
|
my(@drivers, $d, $f); |
1005
|
12
|
|
|
|
|
35
|
local(*DBI::DIR, $@); |
1006
|
12
|
|
|
|
|
24
|
my(%seen_dir, %seen_dbd); |
1007
|
12
|
|
|
|
|
25
|
my $haveFileSpec = eval { require File::Spec }; |
|
12
|
|
|
|
|
78
|
|
1008
|
12
|
|
|
|
|
60
|
foreach $d (@INC){ |
1009
|
132
|
|
|
|
|
269
|
chomp($d); # Perl 5 beta 3 bug in #!./perl -Ilib from Test::Harness |
1010
|
132
|
50
|
|
|
|
815
|
my $dbd_dir = |
1011
|
|
|
|
|
|
|
($haveFileSpec ? File::Spec->catdir($d, 'DBD') : "$d/DBD"); |
1012
|
132
|
100
|
|
|
|
1549
|
next unless -d $dbd_dir; |
1013
|
36
|
100
|
|
|
|
130
|
next if $seen_dir{$d}; |
1014
|
28
|
|
|
|
|
72
|
$seen_dir{$d} = 1; |
1015
|
|
|
|
|
|
|
# XXX we have a problem here with case insensitive file systems |
1016
|
|
|
|
|
|
|
# XXX since we can't tell what case must be used when loading. |
1017
|
28
|
50
|
|
|
|
731
|
opendir(DBI::DIR, $dbd_dir) || Carp::carp "opendir $dbd_dir: $!\n"; |
1018
|
28
|
|
|
|
|
754
|
foreach $f (readdir(DBI::DIR)){ |
1019
|
336
|
100
|
|
|
|
849
|
next unless $f =~ s/\.pm$//; |
1020
|
224
|
100
|
|
|
|
361
|
next if $f eq 'NullP'; |
1021
|
196
|
100
|
|
|
|
268
|
if ($seen_dbd{$f}){ |
1022
|
112
|
50
|
|
|
|
155
|
Carp::carp "DBD::$f in $d is hidden by DBD::$f in $seen_dbd{$f}\n" |
1023
|
|
|
|
|
|
|
unless $quiet; |
1024
|
|
|
|
|
|
|
} else { |
1025
|
84
|
|
|
|
|
137
|
push(@drivers, $f); |
1026
|
|
|
|
|
|
|
} |
1027
|
196
|
|
|
|
|
282
|
$seen_dbd{$f} = $d; |
1028
|
|
|
|
|
|
|
} |
1029
|
28
|
|
|
|
|
337
|
closedir(DBI::DIR); |
1030
|
|
|
|
|
|
|
} |
1031
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
# "return sort @drivers" will not DWIM in scalar context. |
1033
|
12
|
100
|
|
|
|
159
|
return wantarray ? sort @drivers : @drivers; |
1034
|
|
|
|
|
|
|
} |
1035
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
sub installed_versions { |
1037
|
0
|
|
|
0
|
1
|
0
|
my ($class, $quiet) = @_; |
1038
|
0
|
|
|
|
|
0
|
my %error; |
1039
|
|
|
|
|
|
|
my %version; |
1040
|
0
|
|
|
|
|
0
|
for my $driver ($class->available_drivers($quiet)) { |
1041
|
0
|
0
|
0
|
|
|
0
|
next if $DBI::PurePerl && grep { -d "$_/auto/DBD/$driver" } @INC; |
|
0
|
|
|
|
|
0
|
|
1042
|
0
|
|
|
|
|
0
|
my $drh = eval { |
1043
|
0
|
|
|
0
|
|
0
|
local $SIG{__WARN__} = sub {}; |
1044
|
0
|
|
|
|
|
0
|
$class->install_driver($driver); |
1045
|
|
|
|
|
|
|
}; |
1046
|
0
|
0
|
|
|
|
0
|
($error{"DBD::$driver"}=$@),next if $@; |
1047
|
194
|
|
|
194
|
|
1494
|
no strict 'refs'; |
|
194
|
|
|
|
|
445
|
|
|
194
|
|
|
|
|
478706
|
|
1048
|
0
|
|
|
|
|
0
|
my $vers = ${"DBD::$driver" . '::VERSION'}; |
|
0
|
|
|
|
|
0
|
|
1049
|
0
|
|
0
|
|
|
0
|
$version{"DBD::$driver"} = $vers || '?'; |
1050
|
|
|
|
|
|
|
} |
1051
|
0
|
0
|
|
|
|
0
|
if (wantarray) { |
1052
|
0
|
0
|
|
|
|
0
|
return map { m/^DBD::(\w+)/ ? ($1) : () } sort keys %version; |
|
0
|
|
|
|
|
0
|
|
1053
|
|
|
|
|
|
|
} |
1054
|
0
|
|
|
|
|
0
|
$version{"DBI"} = $DBI::VERSION; |
1055
|
0
|
0
|
|
|
|
0
|
$version{"DBI::PurePerl"} = $DBI::PurePerl::VERSION if $DBI::PurePerl; |
1056
|
0
|
0
|
|
|
|
0
|
if (!defined wantarray) { # void context |
1057
|
0
|
|
|
|
|
0
|
require Config; # add more detail |
1058
|
0
|
|
|
|
|
0
|
$version{OS} = "$^O\t($Config::Config{osvers})"; |
1059
|
0
|
|
|
|
|
0
|
$version{Perl} = "$]\t($Config::Config{archname})"; |
1060
|
|
|
|
|
|
|
$version{$_} = (($error{$_} =~ s/ \(\@INC.*//s),$error{$_}) |
1061
|
0
|
|
|
|
|
0
|
for keys %error; |
1062
|
|
|
|
|
|
|
printf " %-16s: %s\n",$_,$version{$_} |
1063
|
0
|
|
|
|
|
0
|
for reverse sort keys %version; |
1064
|
|
|
|
|
|
|
} |
1065
|
0
|
|
|
|
|
0
|
return \%version; |
1066
|
|
|
|
|
|
|
} |
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
sub data_sources { |
1070
|
12
|
|
|
12
|
1
|
45457
|
my ($class, $driver, @other) = @_; |
1071
|
12
|
|
|
|
|
88
|
my $drh = $class->install_driver($driver); |
1072
|
12
|
|
|
|
|
187
|
my @ds = $drh->data_sources(@other); |
1073
|
12
|
|
|
|
|
3914
|
return @ds; |
1074
|
|
|
|
|
|
|
} |
1075
|
|
|
|
|
|
|
|
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
sub neat_list { |
1078
|
132
|
|
|
132
|
1
|
67622
|
my ($listref, $maxlen, $sep) = @_; |
1079
|
132
|
100
|
|
|
|
433
|
$maxlen = 0 unless defined $maxlen; # 0 == use internal default |
1080
|
132
|
100
|
|
|
|
336
|
$sep = ", " unless defined $sep; |
1081
|
132
|
|
|
|
|
339
|
join($sep, map { neat($_,$maxlen) } @$listref); |
|
296
|
|
|
|
|
1567
|
|
1082
|
|
|
|
|
|
|
} |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
sub dump_results { # also aliased as a method in DBD::_::st |
1086
|
4
|
|
|
4
|
1
|
2887
|
my ($sth, $maxlen, $lsep, $fsep, $fh) = @_; |
1087
|
4
|
50
|
|
|
|
20
|
return 0 unless $sth; |
1088
|
4
|
|
50
|
|
|
17
|
$maxlen ||= 35; |
1089
|
4
|
|
50
|
|
|
18
|
$lsep ||= "\n"; |
1090
|
4
|
|
50
|
|
|
16
|
$fh ||= \*STDOUT; |
1091
|
4
|
|
|
|
|
8
|
my $rows = 0; |
1092
|
4
|
|
|
|
|
10
|
my $ref; |
1093
|
4
|
|
|
|
|
43
|
while($ref = $sth->fetch) { |
1094
|
16
|
100
|
66
|
|
|
300
|
print $fh $lsep if $rows++ and $lsep; |
1095
|
16
|
|
|
|
|
46
|
my $str = neat_list($ref,$maxlen,$fsep); |
1096
|
16
|
|
|
|
|
110
|
print $fh $str; # done on two lines to avoid 5.003 errors |
1097
|
|
|
|
|
|
|
} |
1098
|
4
|
50
|
|
|
|
72
|
print $fh "\n$rows rows".($DBI::err ? " ($DBI::err: $DBI::errstr)" : "")."\n"; |
1099
|
4
|
|
|
|
|
26
|
$rows; |
1100
|
|
|
|
|
|
|
} |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
sub data_diff { |
1104
|
28
|
|
|
28
|
1
|
76
|
my ($a, $b, $logical) = @_; |
1105
|
|
|
|
|
|
|
|
1106
|
28
|
|
|
|
|
61
|
my $diff = data_string_diff($a, $b); |
1107
|
28
|
100
|
66
|
|
|
101
|
return "" if $logical and !$diff; |
1108
|
|
|
|
|
|
|
|
1109
|
24
|
|
|
|
|
48
|
my $a_desc = data_string_desc($a); |
1110
|
24
|
|
|
|
|
135
|
my $b_desc = data_string_desc($b); |
1111
|
24
|
100
|
100
|
|
|
204
|
return "" if !$diff and $a_desc eq $b_desc; |
1112
|
|
|
|
|
|
|
|
1113
|
12
|
100
|
100
|
|
|
59
|
$diff ||= "Strings contain the same sequence of characters" |
1114
|
|
|
|
|
|
|
if length($a); |
1115
|
12
|
50
|
|
|
|
34
|
$diff .= "\n" if $diff; |
1116
|
12
|
|
|
|
|
81
|
return "a: $a_desc\nb: $b_desc\n$diff"; |
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
sub data_string_diff { |
1121
|
|
|
|
|
|
|
# Compares 'logical' characters, not bytes, so a latin1 string and an |
1122
|
|
|
|
|
|
|
# an equivalent Unicode string will compare as equal even though their |
1123
|
|
|
|
|
|
|
# byte encodings are different. |
1124
|
60
|
|
|
60
|
1
|
2284
|
my ($a, $b) = @_; |
1125
|
60
|
100
|
100
|
|
|
256
|
unless (defined $a and defined $b) { # one undef |
1126
|
16
|
50
|
66
|
|
|
80
|
return "" |
1127
|
|
|
|
|
|
|
if !defined $a and !defined $b; |
1128
|
8
|
50
|
|
|
|
18
|
return "String a is undef, string b has ".length($b)." characters" |
1129
|
|
|
|
|
|
|
if !defined $a; |
1130
|
8
|
50
|
|
|
|
49
|
return "String b is undef, string a has ".length($a)." characters" |
1131
|
|
|
|
|
|
|
if !defined $b; |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
|
1134
|
44
|
|
|
|
|
201
|
require utf8; |
1135
|
|
|
|
|
|
|
# hack to cater for perl 5.6 |
1136
|
44
|
50
|
|
0
|
|
99
|
*utf8::is_utf8 = sub { (DBI::neat(shift)=~/^"/) } unless defined &utf8::is_utf8; |
|
0
|
|
|
|
|
0
|
|
1137
|
|
|
|
|
|
|
|
1138
|
44
|
50
|
|
|
|
180
|
my @a_chars = (utf8::is_utf8($a)) ? unpack("U*", $a) : unpack("C*", $a); |
1139
|
44
|
100
|
|
|
|
142
|
my @b_chars = (utf8::is_utf8($b)) ? unpack("U*", $b) : unpack("C*", $b); |
1140
|
44
|
|
|
|
|
67
|
my $i = 0; |
1141
|
44
|
|
100
|
|
|
149
|
while (@a_chars && @b_chars) { |
1142
|
72
|
100
|
|
|
|
214
|
++$i, shift(@a_chars), shift(@b_chars), next |
1143
|
|
|
|
|
|
|
if $a_chars[0] == $b_chars[0];# compare ordinal values |
1144
|
|
|
|
|
|
|
my @desc = map { |
1145
|
12
|
50
|
|
|
|
25
|
$_ > 255 ? # if wide character... |
|
24
|
50
|
|
|
|
114
|
|
1146
|
|
|
|
|
|
|
sprintf("\\x{%04X}", $_) : # \x{...} |
1147
|
|
|
|
|
|
|
chr($_) =~ /[[:cntrl:]]/ ? # else if control character ... |
1148
|
|
|
|
|
|
|
sprintf("\\x%02X", $_) : # \x.. |
1149
|
|
|
|
|
|
|
chr($_) # else as themselves |
1150
|
|
|
|
|
|
|
} ($a_chars[0], $b_chars[0]); |
1151
|
|
|
|
|
|
|
# highlight probable double-encoding? |
1152
|
12
|
|
|
|
|
25
|
foreach my $c ( @desc ) { |
1153
|
24
|
50
|
|
|
|
48
|
next unless $c =~ m/\\x\{08(..)}/; |
1154
|
0
|
|
|
|
|
0
|
$c .= "='" .chr(hex($1)) ."'" |
1155
|
|
|
|
|
|
|
} |
1156
|
12
|
|
|
|
|
86
|
return sprintf "Strings differ at index $i: a[$i]=$desc[0], b[$i]=$desc[1]"; |
1157
|
|
|
|
|
|
|
} |
1158
|
32
|
100
|
|
|
|
85
|
return "String a truncated after $i characters" if @b_chars; |
1159
|
28
|
100
|
|
|
|
76
|
return "String b truncated after $i characters" if @a_chars; |
1160
|
24
|
|
|
|
|
70
|
return ""; |
1161
|
|
|
|
|
|
|
} |
1162
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
sub data_string_desc { # describe a data string |
1165
|
72
|
|
|
72
|
1
|
19102
|
my ($a) = @_; |
1166
|
72
|
|
|
|
|
2729
|
require bytes; |
1167
|
72
|
|
|
|
|
1419
|
require utf8; |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
# hacks to cater for perl 5.6 |
1170
|
72
|
50
|
|
0
|
|
184
|
*utf8::is_utf8 = sub { (DBI::neat(shift)=~/^"/) } unless defined &utf8::is_utf8; |
|
0
|
|
|
|
|
0
|
|
1171
|
72
|
50
|
|
0
|
|
136
|
*utf8::valid = sub { 1 } unless defined &utf8::valid; |
|
0
|
|
|
|
|
0
|
|
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
# Give sufficient info to help diagnose at least these kinds of situations: |
1174
|
|
|
|
|
|
|
# - valid UTF8 byte sequence but UTF8 flag not set |
1175
|
|
|
|
|
|
|
# (might be ascii so also need to check for hibit to make it worthwhile) |
1176
|
|
|
|
|
|
|
# - UTF8 flag set but invalid UTF8 byte sequence |
1177
|
|
|
|
|
|
|
# could do better here, but this'll do for now |
1178
|
72
|
100
|
100
|
|
|
424
|
my $utf8 = sprintf "UTF8 %s%s", |
|
|
50
|
|
|
|
|
|
1179
|
|
|
|
|
|
|
utf8::is_utf8($a) ? "on" : "off", |
1180
|
|
|
|
|
|
|
utf8::valid($a||'') ? "" : " but INVALID encoding"; |
1181
|
72
|
100
|
|
|
|
209
|
return "$utf8, undef" unless defined $a; |
1182
|
56
|
|
|
|
|
231
|
my $is_ascii = $a =~ m/^[\000-\177]*$/; |
1183
|
56
|
100
|
|
|
|
181
|
return sprintf "%s, %s, %d characters %d bytes", |
1184
|
|
|
|
|
|
|
$utf8, $is_ascii ? "ASCII" : "non-ASCII", |
1185
|
|
|
|
|
|
|
length($a), bytes::length($a); |
1186
|
|
|
|
|
|
|
} |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
sub connect_test_perf { |
1190
|
0
|
|
|
0
|
0
|
0
|
my($class, $dsn,$dbuser,$dbpass, $attr) = @_; |
1191
|
0
|
0
|
|
|
|
0
|
Carp::croak("connect_test_perf needs hash ref as fourth arg") unless ref $attr; |
1192
|
|
|
|
|
|
|
# these are non standard attributes just for this special method |
1193
|
0
|
|
0
|
|
|
0
|
my $loops ||= $attr->{dbi_loops} || 5; |
|
|
|
0
|
|
|
|
|
1194
|
0
|
|
0
|
|
|
0
|
my $par ||= $attr->{dbi_par} || 1; # parallelism |
|
|
|
0
|
|
|
|
|
1195
|
0
|
|
0
|
|
|
0
|
my $verb ||= $attr->{dbi_verb} || 1; |
|
|
|
0
|
|
|
|
|
1196
|
0
|
|
0
|
|
|
0
|
my $meth ||= $attr->{dbi_meth} || 'connect'; |
|
|
|
0
|
|
|
|
|
1197
|
0
|
|
|
|
|
0
|
print "$dsn: testing $loops sets of $par connections:\n"; |
1198
|
0
|
|
|
|
|
0
|
require "FileHandle.pm"; # don't let toke.c create empty FileHandle package |
1199
|
0
|
|
|
|
|
0
|
local $| = 1; |
1200
|
0
|
0
|
|
|
|
0
|
my $drh = $class->install_driver($dsn) or Carp::croak("Can't install $dsn driver\n"); |
1201
|
|
|
|
|
|
|
# test the connection and warm up caches etc |
1202
|
0
|
0
|
|
|
|
0
|
$drh->connect($dsn,$dbuser,$dbpass) or Carp::croak("connect failed: $DBI::errstr"); |
1203
|
0
|
|
|
|
|
0
|
my $t1 = dbi_time(); |
1204
|
0
|
|
|
|
|
0
|
my $loop; |
1205
|
0
|
|
|
|
|
0
|
for $loop (1..$loops) { |
1206
|
0
|
|
|
|
|
0
|
my @cons; |
1207
|
0
|
0
|
|
|
|
0
|
print "Connecting... " if $verb; |
1208
|
0
|
|
|
|
|
0
|
for (1..$par) { |
1209
|
0
|
|
|
|
|
0
|
print "$_ "; |
1210
|
0
|
|
0
|
|
|
0
|
push @cons, ($drh->connect($dsn,$dbuser,$dbpass) |
1211
|
|
|
|
|
|
|
or Carp::croak("connect failed: $DBI::errstr\n")); |
1212
|
|
|
|
|
|
|
} |
1213
|
0
|
0
|
|
|
|
0
|
print "\nDisconnecting...\n" if $verb; |
1214
|
0
|
|
|
|
|
0
|
for (@cons) { |
1215
|
0
|
0
|
|
|
|
0
|
$_->disconnect or warn "disconnect failed: $DBI::errstr" |
1216
|
|
|
|
|
|
|
} |
1217
|
|
|
|
|
|
|
} |
1218
|
0
|
|
|
|
|
0
|
my $t2 = dbi_time(); |
1219
|
0
|
|
|
|
|
0
|
my $td = $t2 - $t1; |
1220
|
0
|
|
|
|
|
0
|
printf "$meth %d and disconnect them, %d times: %.4fs / %d = %.4fs\n", |
1221
|
|
|
|
|
|
|
$par, $loops, $td, $loops*$par, $td/($loops*$par); |
1222
|
0
|
|
|
|
|
0
|
return $td; |
1223
|
|
|
|
|
|
|
} |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
# Help people doing DBI->errstr, might even document it one day |
1227
|
|
|
|
|
|
|
# XXX probably best moved to cheaper XS code if this gets documented |
1228
|
0
|
|
|
0
|
1
|
0
|
sub err { $DBI::err } |
1229
|
0
|
|
|
0
|
1
|
0
|
sub errstr { $DBI::errstr } |
1230
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
# --- Private Internal Function for Creating New DBI Handles |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
# XXX move to PurePerl? |
1235
|
|
|
|
|
|
|
*DBI::dr::TIEHASH = \&DBI::st::TIEHASH; |
1236
|
|
|
|
|
|
|
*DBI::db::TIEHASH = \&DBI::st::TIEHASH; |
1237
|
|
|
|
|
|
|
|
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
# These three special constructors are called by the drivers |
1240
|
|
|
|
|
|
|
# The way they are called is likely to change. |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
our $shared_profile; |
1243
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
sub _new_drh { # called by DBD::::driver() |
1245
|
240
|
|
|
240
|
|
2249
|
my ($class, $initial_attr, $imp_data) = @_; |
1246
|
|
|
|
|
|
|
# Provide default storage for State,Err and Errstr. |
1247
|
|
|
|
|
|
|
# Note that these are shared by all child handles by default! XXX |
1248
|
|
|
|
|
|
|
# State must be undef to get automatic faking in DBI::var::FETCH |
1249
|
240
|
|
|
|
|
953
|
my ($h_state_store, $h_err_store, $h_errstr_store) = (undef, undef, ''); |
1250
|
240
|
|
|
|
|
2349
|
my $attr = { |
1251
|
|
|
|
|
|
|
# these attributes get copied down to child handles by default |
1252
|
|
|
|
|
|
|
'State' => \$h_state_store, # Holder for DBI::state |
1253
|
|
|
|
|
|
|
'Err' => \$h_err_store, # Holder for DBI::err |
1254
|
|
|
|
|
|
|
'Errstr' => \$h_errstr_store, # Holder for DBI::errstr |
1255
|
|
|
|
|
|
|
'TraceLevel' => 0, |
1256
|
|
|
|
|
|
|
FetchHashKeyName=> 'NAME', |
1257
|
|
|
|
|
|
|
%$initial_attr, |
1258
|
|
|
|
|
|
|
}; |
1259
|
240
|
|
|
|
|
5225
|
my ($h, $i) = _new_handle('DBI::dr', '', $attr, $imp_data, $class); |
1260
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
# XXX DBI_PROFILE unless DBI::PurePerl because for some reason |
1262
|
|
|
|
|
|
|
# it kills the t/zz_*_pp.t tests (they silently exit early) |
1263
|
240
|
100
|
66
|
|
|
2710
|
if (($ENV{DBI_PROFILE} && !$DBI::PurePerl) || $shared_profile) { |
|
|
|
66
|
|
|
|
|
1264
|
|
|
|
|
|
|
# The profile object created here when the first driver is loaded |
1265
|
|
|
|
|
|
|
# is shared by all drivers so we end up with just one set of profile |
1266
|
|
|
|
|
|
|
# data and thus the 'total time in DBI' is really the true total. |
1267
|
3
|
100
|
|
|
|
16
|
if (!$shared_profile) { # first time |
1268
|
2
|
|
|
|
|
262
|
$h->{Profile} = $ENV{DBI_PROFILE}; # write string |
1269
|
2
|
|
|
|
|
41
|
$shared_profile = $h->{Profile}; # read and record object |
1270
|
|
|
|
|
|
|
} |
1271
|
|
|
|
|
|
|
else { |
1272
|
1
|
|
|
|
|
28
|
$h->{Profile} = $shared_profile; |
1273
|
|
|
|
|
|
|
} |
1274
|
|
|
|
|
|
|
} |
1275
|
240
|
100
|
|
|
|
1057
|
return $h unless wantarray; |
1276
|
194
|
|
|
|
|
872
|
($h, $i); |
1277
|
|
|
|
|
|
|
} |
1278
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
sub _new_dbh { # called by DBD::::dr::connect() |
1280
|
3856
|
|
|
3856
|
|
26816
|
my ($drh, $attr, $imp_data) = @_; |
1281
|
|
|
|
|
|
|
my $imp_class = $drh->{ImplementorClass} |
1282
|
3856
|
50
|
|
|
|
12744
|
or Carp::croak("DBI _new_dbh: $drh has no ImplementorClass"); |
1283
|
3856
|
|
|
|
|
11694
|
substr($imp_class,-4,4) = '::db'; |
1284
|
3856
|
|
|
|
|
9312
|
my $app_class = ref $drh; |
1285
|
3856
|
|
|
|
|
7993
|
substr($app_class,-4,4) = '::db'; |
1286
|
3856
|
|
50
|
|
|
19524
|
$attr->{Err} ||= \my $err; |
1287
|
3856
|
|
50
|
|
|
18132
|
$attr->{Errstr} ||= \my $errstr; |
1288
|
3856
|
|
50
|
|
|
17992
|
$attr->{State} ||= \my $state; |
1289
|
3856
|
|
|
|
|
74422
|
_new_handle($app_class, $drh, $attr, $imp_data, $imp_class); |
1290
|
|
|
|
|
|
|
} |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
sub _new_sth { # called by DBD::::db::prepare) |
1293
|
7719
|
|
|
7719
|
|
17162
|
my ($dbh, $attr, $imp_data) = @_; |
1294
|
|
|
|
|
|
|
my $imp_class = $dbh->{ImplementorClass} |
1295
|
7719
|
50
|
|
|
|
20982
|
or Carp::croak("DBI _new_sth: $dbh has no ImplementorClass"); |
1296
|
7719
|
|
|
|
|
18606
|
substr($imp_class,-4,4) = '::st'; |
1297
|
7719
|
|
|
|
|
15848
|
my $app_class = ref $dbh; |
1298
|
7719
|
|
|
|
|
13182
|
substr($app_class,-4,4) = '::st'; |
1299
|
7719
|
|
|
|
|
120669
|
_new_handle($app_class, $dbh, $attr, $imp_data, $imp_class); |
1300
|
|
|
|
|
|
|
} |
1301
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
# end of DBI package |
1304
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
1308
|
|
|
|
|
|
|
# === The internal DBI Switch pseudo 'driver' class === |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
{ package # hide from PAUSE |
1311
|
|
|
|
|
|
|
DBD::Switch::dr; |
1312
|
|
|
|
|
|
|
DBI->setup_driver('DBD::Switch'); # sets up @ISA |
1313
|
|
|
|
|
|
|
|
1314
|
|
|
|
|
|
|
$DBD::Switch::dr::imp_data_size = 0; |
1315
|
|
|
|
|
|
|
$DBD::Switch::dr::imp_data_size = 0; # avoid typo warning |
1316
|
|
|
|
|
|
|
my $drh; |
1317
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
sub driver { |
1319
|
4
|
50
|
|
4
|
|
18
|
return $drh if $drh; # a package global |
1320
|
|
|
|
|
|
|
|
1321
|
4
|
|
|
|
|
10
|
my $inner; |
1322
|
4
|
|
|
|
|
71
|
($drh, $inner) = DBI::_new_drh('DBD::Switch::dr', { |
1323
|
|
|
|
|
|
|
'Name' => 'Switch', |
1324
|
|
|
|
|
|
|
'Version' => $DBI::VERSION, |
1325
|
|
|
|
|
|
|
'Attribution' => "DBI $DBI::VERSION by Tim Bunce", |
1326
|
|
|
|
|
|
|
}); |
1327
|
4
|
50
|
33
|
|
|
42
|
Carp::croak("DBD::Switch init failed!") unless ($drh && $inner); |
1328
|
4
|
|
|
|
|
13
|
return $drh; |
1329
|
|
|
|
|
|
|
} |
1330
|
|
|
|
|
|
|
sub CLONE { |
1331
|
0
|
|
|
0
|
|
0
|
undef $drh; |
1332
|
|
|
|
|
|
|
} |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
sub FETCH { |
1335
|
26
|
|
|
26
|
|
5523
|
my($drh, $key) = @_; |
1336
|
26
|
50
|
|
|
|
67
|
return DBI->trace if $key eq 'DebugDispatch'; |
1337
|
26
|
50
|
|
|
|
51
|
return undef if $key eq 'DebugLog'; # not worth fetching, sorry |
1338
|
26
|
|
|
|
|
184
|
return $drh->DBD::_::dr::FETCH($key); |
1339
|
0
|
|
|
|
|
0
|
undef; |
1340
|
|
|
|
|
|
|
} |
1341
|
|
|
|
|
|
|
sub STORE { |
1342
|
20
|
|
|
20
|
|
5673
|
my($drh, $key, $value) = @_; |
1343
|
20
|
100
|
|
|
|
67
|
if ($key eq 'DebugDispatch') { |
|
|
50
|
|
|
|
|
|
1344
|
4
|
|
|
|
|
48
|
DBI->trace($value); |
1345
|
|
|
|
|
|
|
} elsif ($key eq 'DebugLog') { |
1346
|
0
|
|
|
|
|
0
|
DBI->trace(-1, $value); |
1347
|
|
|
|
|
|
|
} else { |
1348
|
16
|
|
|
|
|
169
|
$drh->DBD::_::dr::STORE($key, $value); |
1349
|
|
|
|
|
|
|
} |
1350
|
|
|
|
|
|
|
} |
1351
|
|
|
|
|
|
|
} |
1352
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
# -------------------------------------------------------------------- |
1355
|
|
|
|
|
|
|
# === OPTIONAL MINIMAL BASE CLASSES FOR DBI SUBCLASSES === |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
# We only define default methods for harmless functions. |
1358
|
|
|
|
|
|
|
# We don't, for example, define a DBD::_::st::prepare() |
1359
|
|
|
|
|
|
|
|
1360
|
|
|
|
|
|
|
{ package # hide from PAUSE |
1361
|
|
|
|
|
|
|
DBD::_::common; # ====== Common base class methods ====== |
1362
|
194
|
|
|
194
|
|
1735
|
use strict; |
|
194
|
|
|
|
|
482
|
|
|
194
|
|
|
|
|
166919
|
|
1363
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
# methods common to all handle types: |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
# generic TIEHASH default methods: |
1367
|
|
|
|
66
|
|
|
sub FIRSTKEY { } |
1368
|
|
|
|
0
|
|
|
sub NEXTKEY { } |
1369
|
122
|
|
|
122
|
|
26051
|
sub EXISTS { defined($_[0]->FETCH($_[1])) } # XXX undef? |
1370
|
0
|
|
|
0
|
|
0
|
sub CLEAR { Carp::carp "Can't CLEAR $_[0] (DBI)" } |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
sub FETCH_many { # XXX should move to C one day |
1373
|
8268
|
|
|
8268
|
|
37419
|
my $h = shift; |
1374
|
|
|
|
|
|
|
# scalar is needed to workaround drivers that return an empty list |
1375
|
|
|
|
|
|
|
# for some attributes |
1376
|
8268
|
|
|
|
|
15924
|
return map { scalar $h->FETCH($_) } @_; |
|
42764
|
|
|
|
|
174604
|
|
1377
|
|
|
|
|
|
|
} |
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
*dump_handle = \&DBI::dump_handle; |
1380
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
sub install_method { |
1382
|
|
|
|
|
|
|
# special class method called directly by apps and/or drivers |
1383
|
|
|
|
|
|
|
# to install new methods into the DBI dispatcher |
1384
|
|
|
|
|
|
|
# DBD::Foo::db->install_method("foo_mumble", { usage => [...], options => '...' }); |
1385
|
628
|
|
|
628
|
|
1650
|
my ($class, $method, $attr) = @_; |
1386
|
628
|
50
|
|
|
|
3821
|
Carp::croak("Class '$class' must begin with DBD:: and end with ::db or ::st") |
1387
|
|
|
|
|
|
|
unless $class =~ /^DBD::(\w+)::(dr|db|st)$/; |
1388
|
628
|
|
|
|
|
2214
|
my ($driver, $subtype) = ($1, $2); |
1389
|
628
|
50
|
|
|
|
2658
|
Carp::croak("invalid method name '$method'") |
1390
|
|
|
|
|
|
|
unless $method =~ m/^([a-z][a-z0-9]*_)\w+$/; |
1391
|
628
|
|
|
|
|
1211
|
my $prefix = $1; |
1392
|
628
|
|
|
|
|
1309
|
my $reg_info = $dbd_prefix_registry->{$prefix}; |
1393
|
628
|
50
|
|
|
|
1332
|
Carp::carp("method name prefix '$prefix' is not associated with a registered driver") unless $reg_info; |
1394
|
|
|
|
|
|
|
|
1395
|
628
|
|
|
|
|
1491
|
my $full_method = "DBI::${subtype}::$method"; |
1396
|
628
|
|
|
|
|
1609
|
$DBI::installed_methods{$full_method} = $attr; |
1397
|
|
|
|
|
|
|
|
1398
|
628
|
|
|
|
|
2180
|
my (undef, $filename, $line) = caller; |
1399
|
|
|
|
|
|
|
# XXX reformat $attr as needed for _install_method |
1400
|
628
|
100
|
|
|
|
1048
|
my %attr = %{$attr||{}}; # copy so we can edit |
|
628
|
|
|
|
|
2989
|
|
1401
|
628
|
|
|
|
|
6946
|
DBI->_install_method("DBI::${subtype}::$method", "$filename at line $line", \%attr); |
1402
|
|
|
|
|
|
|
} |
1403
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
sub parse_trace_flags { |
1405
|
80
|
|
|
80
|
|
659002
|
my ($h, $spec) = @_; |
1406
|
80
|
|
|
|
|
145
|
my $level = 0; |
1407
|
80
|
|
|
|
|
141
|
my $flags = 0; |
1408
|
80
|
|
|
|
|
122
|
my @unknown; |
1409
|
80
|
|
|
|
|
422
|
for my $word (split /\s*[|&,]\s*/, $spec) { |
1410
|
124
|
50
|
33
|
|
|
1092
|
if (DBI::looks_like_number($word) && $word <= 0xF && $word >= 0) { |
|
|
100
|
33
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1411
|
0
|
|
|
|
|
0
|
$level = $word; |
1412
|
|
|
|
|
|
|
} elsif ($word eq 'ALL') { |
1413
|
4
|
|
|
|
|
15
|
$flags = 0x7FFFFFFF; # XXX last bit causes negative headaches |
1414
|
4
|
|
|
|
|
12
|
last; |
1415
|
|
|
|
|
|
|
} elsif (my $flag = $h->parse_trace_flag($word)) { |
1416
|
108
|
|
|
|
|
765
|
$flags |= $flag; |
1417
|
|
|
|
|
|
|
} |
1418
|
|
|
|
|
|
|
else { |
1419
|
12
|
|
|
|
|
151
|
push @unknown, $word; |
1420
|
|
|
|
|
|
|
} |
1421
|
|
|
|
|
|
|
} |
1422
|
80
|
50
|
66
|
|
|
465
|
if (@unknown && (ref $h ? $h->FETCH('Warn') : 1)) { |
|
|
50
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
Carp::carp("$h->parse_trace_flags($spec) ignored unknown trace flags: ". |
1424
|
8
|
|
|
|
|
130
|
join(" ", map { DBI::neat($_) } @unknown)); |
|
12
|
|
|
|
|
989
|
|
1425
|
|
|
|
|
|
|
} |
1426
|
80
|
|
|
|
|
933
|
$flags |= $level; |
1427
|
80
|
|
|
|
|
545
|
return $flags; |
1428
|
|
|
|
|
|
|
} |
1429
|
|
|
|
|
|
|
|
1430
|
|
|
|
|
|
|
sub parse_trace_flag { |
1431
|
96
|
|
|
96
|
|
206
|
my ($h, $name) = @_; |
1432
|
|
|
|
|
|
|
# 0xddDDDDrL (driver, DBI, reserved, Level) |
1433
|
96
|
100
|
|
|
|
371
|
return 0x00000100 if $name eq 'SQL'; |
1434
|
72
|
100
|
|
|
|
199
|
return 0x00000200 if $name eq 'CON'; |
1435
|
58
|
100
|
|
|
|
171
|
return 0x00000400 if $name eq 'ENC'; |
1436
|
44
|
100
|
|
|
|
144
|
return 0x00000800 if $name eq 'DBD'; |
1437
|
30
|
100
|
|
|
|
118
|
return 0x00001000 if $name eq 'TXN'; |
1438
|
16
|
|
|
|
|
261
|
return; |
1439
|
|
|
|
|
|
|
} |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
sub private_attribute_info { |
1442
|
3668
|
|
|
3668
|
|
43410
|
return undef; |
1443
|
|
|
|
|
|
|
} |
1444
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
sub visit_child_handles { |
1446
|
28
|
|
|
28
|
|
405
|
my ($h, $code, $info) = @_; |
1447
|
28
|
50
|
|
|
|
67
|
$info = {} if not defined $info; |
1448
|
28
|
100
|
|
|
|
41
|
for my $ch (@{ $h->{ChildHandles} || []}) { |
|
28
|
|
|
|
|
110
|
|
1449
|
384
|
100
|
|
|
|
609
|
next unless $ch; |
1450
|
16
|
50
|
|
|
|
43
|
my $child_info = $code->($ch, $info) |
1451
|
|
|
|
|
|
|
or next; |
1452
|
16
|
|
|
|
|
522
|
$ch->visit_child_handles($code, $child_info); |
1453
|
|
|
|
|
|
|
} |
1454
|
28
|
|
|
|
|
149
|
return $info; |
1455
|
|
|
|
|
|
|
} |
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
|
1458
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
{ package # hide from PAUSE |
1460
|
|
|
|
|
|
|
DBD::_::dr; # ====== DRIVER ====== |
1461
|
|
|
|
|
|
|
@DBD::_::dr::ISA = qw(DBD::_::common); |
1462
|
194
|
|
|
194
|
|
1612
|
use strict; |
|
194
|
|
|
|
|
447
|
|
|
194
|
|
|
|
|
90518
|
|
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
sub default_user { |
1465
|
1610
|
|
|
1610
|
|
55540
|
my ($drh, $user, $pass, $attr) = @_; |
1466
|
1610
|
100
|
|
|
|
5276
|
$user = $ENV{DBI_USER} unless defined $user; |
1467
|
1610
|
100
|
|
|
|
4695
|
$pass = $ENV{DBI_PASS} unless defined $pass; |
1468
|
1610
|
|
|
|
|
5726
|
return ($user, $pass); |
1469
|
|
|
|
|
|
|
} |
1470
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
sub connect { # normally overridden, but a handy default |
1472
|
118
|
|
|
118
|
|
6208
|
my ($drh, $dsn, $user, $auth) = @_; |
1473
|
118
|
|
|
|
|
585
|
my ($this) = DBI::_new_dbh($drh, { |
1474
|
|
|
|
|
|
|
'Name' => $dsn, |
1475
|
|
|
|
|
|
|
}); |
1476
|
|
|
|
|
|
|
# XXX debatable as there's no "server side" here |
1477
|
|
|
|
|
|
|
# (and now many uses would trigger warnings on DESTROY) |
1478
|
|
|
|
|
|
|
# $this->STORE(Active => 1); |
1479
|
|
|
|
|
|
|
# so drivers should set it in their own connect |
1480
|
118
|
|
|
|
|
768
|
$this; |
1481
|
|
|
|
|
|
|
} |
1482
|
|
|
|
|
|
|
|
1483
|
|
|
|
|
|
|
|
1484
|
|
|
|
|
|
|
sub connect_cached { |
1485
|
3146
|
|
|
3146
|
|
8357
|
my $drh = shift; |
1486
|
3146
|
|
|
|
|
6138
|
my ($dsn, $user, $auth, $attr) = @_; |
1487
|
|
|
|
|
|
|
|
1488
|
3146
|
|
100
|
|
|
7774
|
my $cache = $drh->{CachedKids} ||= {}; |
1489
|
3146
|
|
|
|
|
3918
|
my $key = do { local $^W; |
|
3146
|
|
|
|
|
9375
|
|
1490
|
3146
|
|
|
|
|
43893
|
join "!\001", $dsn, $user, $auth, DBI::_concat_hash_sorted($attr, "=\001", ",\001", 0, 0) |
1491
|
|
|
|
|
|
|
}; |
1492
|
3146
|
|
|
|
|
7566
|
my $dbh = $cache->{$key}; |
1493
|
3146
|
50
|
|
|
|
6717
|
$drh->trace_msg(sprintf(" connect_cached: key '$key', cached dbh $dbh\n", DBI::neat($key), DBI::neat($dbh))) |
1494
|
|
|
|
|
|
|
if (($DBI::dbi_debug & 0xF) >= 4); |
1495
|
|
|
|
|
|
|
|
1496
|
3146
|
|
|
|
|
4248
|
my $cb = $attr->{Callbacks}; # take care not to autovivify |
1497
|
3146
|
50
|
66
|
|
|
17931
|
if ($dbh && $dbh->FETCH('Active') && eval { $dbh->ping }) { |
|
3114
|
|
66
|
|
|
12195
|
|
1498
|
|
|
|
|
|
|
# If the caller has provided a callback then call it |
1499
|
3114
|
100
|
66
|
|
|
7483
|
if ($cb and $cb = $cb->{"connect_cached.reused"}) { |
1500
|
2
|
|
|
|
|
6
|
local $_ = "connect_cached.reused"; |
1501
|
2
|
|
|
|
|
10
|
$cb->($dbh, $dsn, $user, $auth, $attr); |
1502
|
|
|
|
|
|
|
} |
1503
|
3114
|
|
|
|
|
17316
|
return $dbh; |
1504
|
|
|
|
|
|
|
} |
1505
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
# If the caller has provided a callback then call it |
1507
|
32
|
100
|
66
|
|
|
119
|
if ($cb and (my $new_cb = $cb->{"connect_cached.new"})) { |
1508
|
2
|
|
|
|
|
4
|
local $_ = "connect_cached.new"; |
1509
|
2
|
|
|
|
|
33
|
$new_cb->($dbh, $dsn, $user, $auth, $attr); # $dbh is dead or undef |
1510
|
|
|
|
|
|
|
} |
1511
|
|
|
|
|
|
|
|
1512
|
32
|
|
|
|
|
4305
|
$dbh = $drh->connect(@_); |
1513
|
32
|
|
|
|
|
318
|
$cache->{$key} = $dbh; # replace prev entry, even if connect failed |
1514
|
32
|
100
|
66
|
|
|
126
|
if ($cb and (my $conn_cb = $cb->{"connect_cached.connected"})) { |
1515
|
2
|
|
|
|
|
4
|
local $_ = "connect_cached.connected"; |
1516
|
2
|
|
|
|
|
9
|
$conn_cb->($dbh, $dsn, $user, $auth, $attr); |
1517
|
|
|
|
|
|
|
} |
1518
|
32
|
|
|
|
|
5894
|
return $dbh; |
1519
|
|
|
|
|
|
|
} |
1520
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
} |
1522
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
{ package # hide from PAUSE |
1525
|
|
|
|
|
|
|
DBD::_::db; # ====== DATABASE ====== |
1526
|
|
|
|
|
|
|
@DBD::_::db::ISA = qw(DBD::_::common); |
1527
|
194
|
|
|
194
|
|
3112
|
use strict; |
|
194
|
|
|
|
|
509
|
|
|
194
|
|
|
|
|
450996
|
|
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
sub clone { |
1530
|
16
|
|
|
16
|
|
22929
|
my ($old_dbh, $attr) = @_; |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
my $closure = $old_dbh->{dbi_connect_closure} |
1533
|
16
|
50
|
|
|
|
57
|
or return $old_dbh->set_err($DBI::stderr, "Can't clone handle"); |
1534
|
|
|
|
|
|
|
|
1535
|
16
|
100
|
|
|
|
42
|
unless ($attr) { # XXX deprecated, caller should always pass a hash ref |
1536
|
|
|
|
|
|
|
# copy attributes visible in the attribute cache |
1537
|
8
|
|
|
|
|
23
|
keys %$old_dbh; # reset iterator |
1538
|
8
|
|
|
|
|
37
|
while ( my ($k, $v) = each %$old_dbh ) { |
1539
|
|
|
|
|
|
|
# ignore non-code refs, i.e., caches, handles, Err etc |
1540
|
198
|
100
|
100
|
|
|
399
|
next if ref $v && ref $v ne 'CODE'; # HandleError etc |
1541
|
158
|
|
|
|
|
363
|
$attr->{$k} = $v; |
1542
|
|
|
|
|
|
|
} |
1543
|
|
|
|
|
|
|
# explicitly set attributes which are unlikely to be in the |
1544
|
|
|
|
|
|
|
# attribute cache, i.e., boolean's and some others |
1545
|
8
|
|
|
|
|
43
|
$attr->{$_} = $old_dbh->FETCH($_) for (qw( |
1546
|
|
|
|
|
|
|
AutoCommit ChopBlanks InactiveDestroy AutoInactiveDestroy |
1547
|
|
|
|
|
|
|
LongTruncOk PrintError PrintWarn Profile RaiseError |
1548
|
|
|
|
|
|
|
ShowErrorStatement TaintIn TaintOut |
1549
|
|
|
|
|
|
|
)); |
1550
|
|
|
|
|
|
|
} |
1551
|
|
|
|
|
|
|
|
1552
|
|
|
|
|
|
|
# use Data::Dumper; warn Dumper([$old_dbh, $attr]); |
1553
|
16
|
|
|
|
|
214
|
my $new_dbh = &$closure($old_dbh, $attr); |
1554
|
16
|
50
|
|
|
|
39
|
unless ($new_dbh) { |
1555
|
|
|
|
|
|
|
# need to copy err/errstr from driver back into $old_dbh |
1556
|
0
|
|
|
|
|
0
|
my $drh = $old_dbh->{Driver}; |
1557
|
0
|
|
|
|
|
0
|
return $old_dbh->set_err($drh->err, $drh->errstr, $drh->state); |
1558
|
|
|
|
|
|
|
} |
1559
|
16
|
|
|
|
|
53
|
$new_dbh->{dbi_connect_closure} = $closure; |
1560
|
16
|
|
|
|
|
112
|
return $new_dbh; |
1561
|
|
|
|
|
|
|
} |
1562
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
sub quote_identifier { |
1564
|
114
|
|
|
114
|
|
5754
|
my ($dbh, @id) = @_; |
1565
|
114
|
50
|
33
|
|
|
296
|
my $attr = (@id > 3 && ref($id[-1])) ? pop @id : undef; |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
my $info = $dbh->{dbi_quote_identifier_cache} ||= [ |
1568
|
114
|
|
50
|
|
|
337
|
$dbh->get_info(29) || '"', # SQL_IDENTIFIER_QUOTE_CHAR |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
1569
|
|
|
|
|
|
|
$dbh->get_info(41) || '.', # SQL_CATALOG_NAME_SEPARATOR |
1570
|
|
|
|
|
|
|
$dbh->get_info(114) || 1, # SQL_CATALOG_LOCATION |
1571
|
|
|
|
|
|
|
]; |
1572
|
|
|
|
|
|
|
|
1573
|
114
|
|
|
|
|
274
|
my $quote = $info->[0]; |
1574
|
114
|
|
|
|
|
172
|
foreach (@id) { # quote the elements |
1575
|
322
|
100
|
|
|
|
457
|
next unless defined; |
1576
|
208
|
|
|
|
|
442
|
s/$quote/$quote$quote/g; # escape embedded quotes |
1577
|
208
|
|
|
|
|
363
|
$_ = qq{$quote$_$quote}; |
1578
|
|
|
|
|
|
|
} |
1579
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
# strip out catalog if present for special handling |
1581
|
114
|
100
|
|
|
|
236
|
my $catalog = (@id >= 3) ? shift @id : undef; |
1582
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
# join the dots, ignoring any null/undef elements (ie schema) |
1584
|
114
|
|
|
|
|
177
|
my $quoted_id = join '.', grep { defined } @id; |
|
220
|
|
|
|
|
420
|
|
1585
|
|
|
|
|
|
|
|
1586
|
114
|
100
|
|
|
|
200
|
if ($catalog) { # add catalog correctly |
1587
|
78
|
100
|
|
|
|
108
|
if ($quoted_id) { |
1588
|
70
|
100
|
|
|
|
162
|
$quoted_id = ($info->[2] == 2) # SQL_CL_END |
1589
|
|
|
|
|
|
|
? $quoted_id . $info->[1] . $catalog |
1590
|
|
|
|
|
|
|
: $catalog . $info->[1] . $quoted_id; |
1591
|
|
|
|
|
|
|
} else { |
1592
|
8
|
|
|
|
|
14
|
$quoted_id = $catalog; |
1593
|
|
|
|
|
|
|
} |
1594
|
|
|
|
|
|
|
} |
1595
|
114
|
|
|
|
|
340
|
return $quoted_id; |
1596
|
|
|
|
|
|
|
} |
1597
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
sub quote { |
1599
|
16
|
|
|
16
|
|
2549
|
my ($dbh, $str, $data_type) = @_; |
1600
|
|
|
|
|
|
|
|
1601
|
16
|
100
|
|
|
|
54
|
return "NULL" unless defined $str; |
1602
|
12
|
100
|
|
|
|
37
|
unless ($data_type) { |
1603
|
4
|
|
|
|
|
23
|
$str =~ s/'/''/g; # ISO SQL2 |
1604
|
4
|
|
|
|
|
29
|
return "'$str'"; |
1605
|
|
|
|
|
|
|
} |
1606
|
|
|
|
|
|
|
|
1607
|
8
|
|
100
|
|
|
45
|
my $dbi_literal_quote_cache = $dbh->{'dbi_literal_quote_cache'} ||= [ {} , {} ]; |
1608
|
8
|
|
|
|
|
21
|
my ($prefixes, $suffixes) = @$dbi_literal_quote_cache; |
1609
|
|
|
|
|
|
|
|
1610
|
8
|
|
|
|
|
19
|
my $lp = $prefixes->{$data_type}; |
1611
|
8
|
|
|
|
|
12
|
my $ls = $suffixes->{$data_type}; |
1612
|
|
|
|
|
|
|
|
1613
|
8
|
50
|
33
|
|
|
29
|
if ( ! defined $lp || ! defined $ls ) { |
1614
|
8
|
|
|
|
|
48
|
my $ti = $dbh->type_info($data_type); |
1615
|
8
|
50
|
100
|
|
|
88
|
$lp = $prefixes->{$data_type} = $ti ? $ti->{LITERAL_PREFIX} || "" : "'"; |
1616
|
8
|
50
|
100
|
|
|
53
|
$ls = $suffixes->{$data_type} = $ti ? $ti->{LITERAL_SUFFIX} || "" : "'"; |
1617
|
|
|
|
|
|
|
} |
1618
|
8
|
100
|
66
|
|
|
50
|
return $str unless $lp || $ls; # no quoting required |
1619
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
# XXX don't know what the standard says about escaping |
1621
|
|
|
|
|
|
|
# in the 'general case' (where $lp != "'"). |
1622
|
|
|
|
|
|
|
# So we just do this and hope: |
1623
|
4
|
50
|
33
|
|
|
107
|
$str =~ s/$lp/$lp$lp/g |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
1624
|
|
|
|
|
|
|
if $lp && $lp eq $ls && ($lp eq "'" || $lp eq '"'); |
1625
|
4
|
|
|
|
|
30
|
return "$lp$str$ls"; |
1626
|
|
|
|
|
|
|
} |
1627
|
|
|
|
|
|
|
|
1628
|
0
|
|
|
0
|
|
0
|
sub rows { -1 } # here so $DBI::rows 'works' after using $dbh |
1629
|
|
|
|
|
|
|
|
1630
|
|
|
|
|
|
|
sub do { |
1631
|
1693
|
|
|
1693
|
|
35137
|
my($dbh, $statement, $attr, @params) = @_; |
1632
|
1693
|
100
|
|
|
|
6902
|
my $sth = $dbh->prepare($statement, $attr) or return undef; |
1633
|
1689
|
100
|
|
|
|
9038
|
$sth->execute(@params) or return undef; |
1634
|
220
|
|
|
|
|
2913
|
my $rows = $sth->rows; |
1635
|
220
|
100
|
|
|
|
2873
|
($rows == 0) ? "0E0" : $rows; |
1636
|
|
|
|
|
|
|
} |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
sub _do_selectrow { |
1639
|
16
|
|
|
16
|
|
63
|
my ($method, $dbh, $stmt, $attr, @bind) = @_; |
1640
|
16
|
50
|
|
|
|
117
|
my $sth = ((ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr)) |
|
|
50
|
|
|
|
|
|
1641
|
|
|
|
|
|
|
or return undef; |
1642
|
16
|
100
|
|
|
|
224
|
$sth->execute(@bind) |
1643
|
|
|
|
|
|
|
or return undef; |
1644
|
8
|
50
|
|
|
|
119
|
my $row = $sth->$method() |
1645
|
|
|
|
|
|
|
and $sth->finish; |
1646
|
8
|
|
|
|
|
109
|
return $row; |
1647
|
|
|
|
|
|
|
} |
1648
|
|
|
|
|
|
|
|
1649
|
4
|
|
|
4
|
|
3677
|
sub selectrow_hashref { return _do_selectrow('fetchrow_hashref', @_); } |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
# XXX selectrow_array/ref also have C implementations in Driver.xst |
1652
|
8
|
|
|
8
|
|
261
|
sub selectrow_arrayref { return _do_selectrow('fetchrow_arrayref', @_); } |
1653
|
|
|
|
|
|
|
sub selectrow_array { |
1654
|
4
|
50
|
|
4
|
|
2153
|
my $row = _do_selectrow('fetchrow_arrayref', @_) or return; |
1655
|
4
|
50
|
|
|
|
46
|
return $row->[0] unless wantarray; |
1656
|
4
|
|
|
|
|
22
|
return @$row; |
1657
|
|
|
|
|
|
|
} |
1658
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
sub selectall_array { |
1660
|
4
|
50
|
|
4
|
|
10451
|
return @{ shift->selectall_arrayref(@_) || [] }; |
|
4
|
|
|
|
|
20
|
|
1661
|
|
|
|
|
|
|
} |
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
# XXX selectall_arrayref also has C implementation in Driver.xst |
1664
|
|
|
|
|
|
|
# which fallsback to this if a slice is given |
1665
|
|
|
|
|
|
|
sub selectall_arrayref { |
1666
|
126
|
|
|
126
|
|
66781
|
my ($dbh, $stmt, $attr, @bind) = @_; |
1667
|
126
|
100
|
|
|
|
1376
|
my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr) |
|
|
100
|
|
|
|
|
|
1668
|
|
|
|
|
|
|
or return; |
1669
|
122
|
50
|
|
|
|
2378
|
$sth->execute(@bind) || return; |
1670
|
122
|
|
|
|
|
2349
|
my $slice = $attr->{Slice}; # typically undef, else hash or array ref |
1671
|
122
|
100
|
100
|
|
|
1446
|
if (!$slice and $slice=$attr->{Columns}) { |
1672
|
8
|
100
|
|
|
|
25
|
if (ref $slice eq 'ARRAY') { # map col idx to perl array idx |
1673
|
4
|
|
|
|
|
9
|
$slice = [ @{$attr->{Columns}} ]; # take a copy |
|
4
|
|
|
|
|
12
|
|
1674
|
4
|
|
|
|
|
10
|
for (@$slice) { $_-- } |
|
8
|
|
|
|
|
15
|
|
1675
|
|
|
|
|
|
|
} |
1676
|
|
|
|
|
|
|
} |
1677
|
122
|
|
|
|
|
1012
|
my $rows = $sth->fetchall_arrayref($slice, my $MaxRows = $attr->{MaxRows}); |
1678
|
122
|
50
|
|
|
|
1211
|
$sth->finish if defined $MaxRows; |
1679
|
122
|
|
|
|
|
2339
|
return $rows; |
1680
|
|
|
|
|
|
|
} |
1681
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
sub selectall_hashref { |
1683
|
8
|
|
|
8
|
|
15582
|
my ($dbh, $stmt, $key_field, $attr, @bind) = @_; |
1684
|
8
|
50
|
|
|
|
58
|
my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr); |
1685
|
8
|
50
|
|
|
|
77
|
return unless $sth; |
1686
|
8
|
50
|
|
|
|
36
|
$sth->execute(@bind) || return; |
1687
|
8
|
|
|
|
|
118
|
return $sth->fetchall_hashref($key_field); |
1688
|
|
|
|
|
|
|
} |
1689
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
sub selectcol_arrayref { |
1691
|
8
|
|
|
8
|
|
8848
|
my ($dbh, $stmt, $attr, @bind) = @_; |
1692
|
8
|
50
|
|
|
|
55
|
my $sth = (ref $stmt) ? $stmt : $dbh->prepare($stmt, $attr); |
1693
|
8
|
50
|
|
|
|
94
|
return unless $sth; |
1694
|
8
|
50
|
|
|
|
37
|
$sth->execute(@bind) || return; |
1695
|
8
|
100
|
|
|
|
114
|
my @columns = ($attr->{Columns}) ? @{$attr->{Columns}} : (1); |
|
4
|
|
|
|
|
14
|
|
1696
|
8
|
|
|
|
|
35
|
my @values = (undef) x @columns; |
1697
|
8
|
|
|
|
|
16
|
my $idx = 0; |
1698
|
8
|
|
|
|
|
17
|
for (@columns) { |
1699
|
12
|
50
|
|
|
|
86
|
$sth->bind_col($_, \$values[$idx++]) || return; |
1700
|
|
|
|
|
|
|
} |
1701
|
8
|
|
|
|
|
253
|
my @col; |
1702
|
8
|
50
|
|
|
|
30
|
if (my $max = $attr->{MaxRows}) { |
1703
|
0
|
|
0
|
|
|
0
|
push @col, @values while 0 < $max-- && $sth->fetch; |
1704
|
|
|
|
|
|
|
} |
1705
|
|
|
|
|
|
|
else { |
1706
|
8
|
|
|
|
|
33
|
push @col, @values while $sth->fetch; |
1707
|
|
|
|
|
|
|
} |
1708
|
8
|
|
|
|
|
243
|
return \@col; |
1709
|
|
|
|
|
|
|
} |
1710
|
|
|
|
|
|
|
|
1711
|
|
|
|
|
|
|
sub prepare_cached { |
1712
|
48
|
|
|
48
|
|
12728
|
my ($dbh, $statement, $attr, $if_active) = @_; |
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
# Needs support at dbh level to clear cache before complaining about |
1715
|
|
|
|
|
|
|
# active children. The XS template code does this. Drivers not using |
1716
|
|
|
|
|
|
|
# the template must handle clearing the cache themselves. |
1717
|
48
|
|
100
|
|
|
221
|
my $cache = $dbh->{CachedKids} ||= {}; |
1718
|
48
|
|
|
|
|
81
|
my $key = do { local $^W; |
|
48
|
|
|
|
|
155
|
|
1719
|
48
|
|
|
|
|
276
|
join "!\001", $statement, DBI::_concat_hash_sorted($attr, "=\001", ",\001", 0, 0) |
1720
|
|
|
|
|
|
|
}; |
1721
|
48
|
|
|
|
|
103
|
my $sth = $cache->{$key}; |
1722
|
|
|
|
|
|
|
|
1723
|
48
|
100
|
|
|
|
113
|
if ($sth) { |
1724
|
12
|
50
|
|
|
|
66
|
return $sth unless $sth->FETCH('Active'); |
1725
|
12
|
100
|
100
|
|
|
1077
|
Carp::carp("prepare_cached($statement) statement handle $sth still Active") |
1726
|
|
|
|
|
|
|
unless ($if_active ||= 0); |
1727
|
12
|
100
|
|
|
|
323
|
$sth->finish if $if_active <= 1; |
1728
|
12
|
100
|
|
|
|
96
|
return $sth if $if_active <= 2; |
1729
|
|
|
|
|
|
|
} |
1730
|
|
|
|
|
|
|
|
1731
|
40
|
|
|
|
|
208
|
$sth = $dbh->prepare($statement, $attr); |
1732
|
40
|
50
|
|
|
|
406
|
$cache->{$key} = $sth if $sth; |
1733
|
|
|
|
|
|
|
|
1734
|
40
|
|
|
|
|
129
|
return $sth; |
1735
|
|
|
|
|
|
|
} |
1736
|
|
|
|
|
|
|
|
1737
|
|
|
|
|
|
|
sub ping { |
1738
|
12
|
|
|
12
|
|
2850
|
my $dbh = shift; |
1739
|
|
|
|
|
|
|
# "0 but true" is a special kind of true 0 that is used here so |
1740
|
|
|
|
|
|
|
# applications can check if the ping was a real ping or not |
1741
|
12
|
100
|
|
|
|
88
|
($dbh->FETCH('Active')) ? "0 but true" : 0; |
1742
|
|
|
|
|
|
|
} |
1743
|
|
|
|
|
|
|
|
1744
|
|
|
|
|
|
|
sub begin_work { |
1745
|
4
|
|
|
4
|
|
2139
|
my $dbh = shift; |
1746
|
4
|
50
|
|
|
|
16
|
return $dbh->set_err($DBI::stderr, "Already in a transaction") |
1747
|
|
|
|
|
|
|
unless $dbh->FETCH('AutoCommit'); |
1748
|
4
|
|
|
|
|
37
|
$dbh->STORE('AutoCommit', 0); # will croak if driver doesn't support it |
1749
|
4
|
|
|
|
|
27
|
$dbh->STORE('BegunWork', 1); # trigger post commit/rollback action |
1750
|
4
|
|
|
|
|
22
|
return 1; |
1751
|
|
|
|
|
|
|
} |
1752
|
|
|
|
|
|
|
|
1753
|
|
|
|
|
|
|
sub primary_key { |
1754
|
0
|
|
|
0
|
|
0
|
my ($dbh, @args) = @_; |
1755
|
0
|
0
|
|
|
|
0
|
my $sth = $dbh->primary_key_info(@args) or return; |
1756
|
0
|
|
|
|
|
0
|
my ($row, @col); |
1757
|
0
|
|
|
|
|
0
|
push @col, $row->[3] while ($row = $sth->fetch); |
1758
|
0
|
0
|
|
|
|
0
|
Carp::croak("primary_key method not called in list context") |
1759
|
|
|
|
|
|
|
unless wantarray; # leave us some elbow room |
1760
|
0
|
|
|
|
|
0
|
return @col; |
1761
|
|
|
|
|
|
|
} |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
sub tables { |
1764
|
32
|
|
|
32
|
|
5892
|
my ($dbh, @args) = @_; |
1765
|
32
|
50
|
|
|
|
196
|
my $sth = $dbh->table_info(@args[0,1,2,3,4]) or return; |
1766
|
32
|
50
|
|
|
|
483
|
my $tables = $sth->fetchall_arrayref or return; |
1767
|
32
|
|
|
|
|
251
|
my @tables; |
1768
|
32
|
100
|
100
|
|
|
338
|
if (defined($args[3]) && $args[3] eq '%' # special case for tables('','','','%') |
|
|
100
|
66
|
|
|
|
|
1769
|
12
|
50
|
|
|
|
47
|
&& grep {defined($_) && $_ eq ''} @args[0,1,2] |
1770
|
|
|
|
|
|
|
) { |
1771
|
4
|
|
|
|
|
10
|
@tables = map { $_->[3] } @$tables; |
|
12
|
|
|
|
|
22
|
|
1772
|
|
|
|
|
|
|
} elsif ($dbh->get_info(29)) { # SQL_IDENTIFIER_QUOTE_CHAR |
1773
|
16
|
|
|
|
|
132
|
@tables = map { $dbh->quote_identifier( @{$_}[0,1,2] ) } @$tables; |
|
92
|
|
|
|
|
467
|
|
|
92
|
|
|
|
|
249
|
|
1774
|
|
|
|
|
|
|
} |
1775
|
|
|
|
|
|
|
else { # temporary old style hack (yeach) |
1776
|
|
|
|
|
|
|
@tables = map { |
1777
|
12
|
|
|
|
|
374
|
my $name = $_->[2]; |
|
16
|
|
|
|
|
49
|
|
1778
|
16
|
50
|
|
|
|
61
|
if ($_->[1]) { |
1779
|
16
|
|
|
|
|
40
|
my $schema = $_->[1]; |
1780
|
|
|
|
|
|
|
# a sad hack (mostly for Informix I recall) |
1781
|
16
|
50
|
|
|
|
72
|
my $quote = ($schema eq uc($schema)) ? '' : '"'; |
1782
|
16
|
|
|
|
|
68
|
$name = "$quote$schema$quote.$name" |
1783
|
|
|
|
|
|
|
} |
1784
|
16
|
|
|
|
|
55
|
$name; |
1785
|
|
|
|
|
|
|
} @$tables; |
1786
|
|
|
|
|
|
|
} |
1787
|
32
|
|
|
|
|
518
|
return @tables; |
1788
|
|
|
|
|
|
|
} |
1789
|
|
|
|
|
|
|
|
1790
|
|
|
|
|
|
|
sub type_info { # this should be sufficient for all drivers |
1791
|
28
|
|
|
28
|
|
9895
|
my ($dbh, $data_type) = @_; |
1792
|
28
|
|
|
|
|
57
|
my $idx_hash; |
1793
|
28
|
|
|
|
|
56
|
my $tia = $dbh->{dbi_type_info_row_cache}; |
1794
|
28
|
100
|
|
|
|
83
|
if ($tia) { |
1795
|
18
|
|
|
|
|
36
|
$idx_hash = $dbh->{dbi_type_info_idx_cache}; |
1796
|
|
|
|
|
|
|
} |
1797
|
|
|
|
|
|
|
else { |
1798
|
10
|
|
|
|
|
67
|
my $temp = $dbh->type_info_all; |
1799
|
10
|
50
|
33
|
|
|
119
|
return unless $temp && @$temp; |
1800
|
|
|
|
|
|
|
# we cache here because type_info_all may be expensive to call |
1801
|
|
|
|
|
|
|
# (and we take a copy so the following shift can't corrupt |
1802
|
|
|
|
|
|
|
# the data that may be returned by future calls to type_info_all) |
1803
|
10
|
|
|
|
|
50
|
$tia = $dbh->{dbi_type_info_row_cache} = [ @$temp ]; |
1804
|
10
|
|
|
|
|
47
|
$idx_hash = $dbh->{dbi_type_info_idx_cache} = shift @$tia; |
1805
|
|
|
|
|
|
|
} |
1806
|
|
|
|
|
|
|
|
1807
|
28
|
|
33
|
|
|
82
|
my $dt_idx = $idx_hash->{DATA_TYPE} || $idx_hash->{data_type}; |
1808
|
28
|
50
|
33
|
|
|
161
|
Carp::croak("type_info_all returned non-standard DATA_TYPE index value ($dt_idx != 1)") |
1809
|
|
|
|
|
|
|
if $dt_idx && $dt_idx != 1; |
1810
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
# --- simple DATA_TYPE match filter |
1812
|
28
|
|
|
|
|
44
|
my @ti; |
1813
|
28
|
50
|
|
|
|
78
|
my @data_type_list = (ref $data_type) ? @$data_type : ($data_type); |
1814
|
28
|
|
|
|
|
64
|
foreach $data_type (@data_type_list) { |
1815
|
28
|
100
|
66
|
|
|
161
|
if (defined($data_type) && $data_type != DBI::SQL_ALL_TYPES()) { |
1816
|
24
|
|
|
|
|
54
|
push @ti, grep { $_->[$dt_idx] == $data_type } @$tia; |
|
48
|
|
|
|
|
140
|
|
1817
|
|
|
|
|
|
|
} |
1818
|
|
|
|
|
|
|
else { # SQL_ALL_TYPES |
1819
|
4
|
|
|
|
|
15
|
push @ti, @$tia; |
1820
|
|
|
|
|
|
|
} |
1821
|
28
|
50
|
|
|
|
78
|
last if @ti; # found at least one match |
1822
|
|
|
|
|
|
|
} |
1823
|
|
|
|
|
|
|
|
1824
|
|
|
|
|
|
|
# --- format results into list of hash refs |
1825
|
28
|
|
|
|
|
70
|
my $idx_fields = keys %$idx_hash; |
1826
|
28
|
|
|
|
|
102
|
my @idx_names = map { uc($_) } keys %$idx_hash; |
|
420
|
|
|
|
|
645
|
|
1827
|
28
|
|
|
|
|
101
|
my @idx_values = values %$idx_hash; |
1828
|
0
|
|
|
|
|
0
|
Carp::croak "type_info_all result has $idx_fields keys but ".(@{$ti[0]})." fields" |
1829
|
28
|
50
|
33
|
|
|
90
|
if @ti && @{$ti[0]} != $idx_fields; |
|
28
|
|
|
|
|
91
|
|
1830
|
|
|
|
|
|
|
my @out = map { |
1831
|
28
|
|
|
|
|
59
|
my %h; @h{@idx_names} = @{$_}[ @idx_values ]; \%h; |
|
32
|
|
|
|
|
42
|
|
|
32
|
|
|
|
|
47
|
|
|
32
|
|
|
|
|
223
|
|
|
32
|
|
|
|
|
89
|
|
1832
|
|
|
|
|
|
|
} @ti; |
1833
|
28
|
100
|
|
|
|
179
|
return $out[0] unless wantarray; |
1834
|
4
|
|
|
|
|
27
|
return @out; |
1835
|
|
|
|
|
|
|
} |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
sub data_sources { |
1838
|
4
|
|
|
4
|
|
4307
|
my ($dbh, @other) = @_; |
1839
|
4
|
|
|
|
|
10
|
my $drh = $dbh->{Driver}; # XXX proxy issues? |
1840
|
4
|
|
|
|
|
18
|
return $drh->data_sources(@other); |
1841
|
|
|
|
|
|
|
} |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
} |
1844
|
|
|
|
|
|
|
|
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
{ package # hide from PAUSE |
1847
|
|
|
|
|
|
|
DBD::_::st; # ====== STATEMENT ====== |
1848
|
|
|
|
|
|
|
@DBD::_::st::ISA = qw(DBD::_::common); |
1849
|
194
|
|
|
194
|
|
1787
|
use strict; |
|
194
|
|
|
|
|
1328
|
|
|
194
|
|
|
|
|
416981
|
|
1850
|
|
|
|
|
|
|
|
1851
|
0
|
|
|
0
|
|
0
|
sub bind_param { Carp::croak("Can't bind_param, not implement by driver") } |
1852
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
# |
1854
|
|
|
|
|
|
|
# ******************************************************** |
1855
|
|
|
|
|
|
|
# |
1856
|
|
|
|
|
|
|
# BEGIN ARRAY BINDING |
1857
|
|
|
|
|
|
|
# |
1858
|
|
|
|
|
|
|
# Array binding support for drivers which don't support |
1859
|
|
|
|
|
|
|
# array binding, but have sufficient interfaces to fake it. |
1860
|
|
|
|
|
|
|
# NOTE: mixing scalars and arrayrefs requires using bind_param_array |
1861
|
|
|
|
|
|
|
# for *all* params...unless we modify bind_param for the default |
1862
|
|
|
|
|
|
|
# case... |
1863
|
|
|
|
|
|
|
# |
1864
|
|
|
|
|
|
|
# 2002-Apr-10 D. Arnold |
1865
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
sub bind_param_array { |
1867
|
84
|
|
|
84
|
|
11792
|
my $sth = shift; |
1868
|
84
|
|
|
|
|
154
|
my ($p_id, $value_array, $attr) = @_; |
1869
|
|
|
|
|
|
|
|
1870
|
84
|
100
|
100
|
|
|
378
|
return $sth->set_err($DBI::stderr, "Value for parameter $p_id must be a scalar or an arrayref, not a ".ref($value_array)) |
|
|
|
100
|
|
|
|
|
1871
|
|
|
|
|
|
|
if defined $value_array and ref $value_array and ref $value_array ne 'ARRAY'; |
1872
|
|
|
|
|
|
|
|
1873
|
80
|
100
|
|
|
|
264
|
return $sth->set_err($DBI::stderr, "Can't use named placeholder '$p_id' for non-driver supported bind_param_array") |
1874
|
|
|
|
|
|
|
unless DBI::looks_like_number($p_id); # because we rely on execute(@ary) here |
1875
|
|
|
|
|
|
|
|
1876
|
76
|
50
|
|
|
|
140
|
return $sth->set_err($DBI::stderr, "Placeholder '$p_id' is out of range") |
1877
|
|
|
|
|
|
|
if $p_id <= 0; # can't easily/reliably test for too big |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
# get/create arrayref to hold params |
1880
|
76
|
|
50
|
|
|
160
|
my $hash_of_arrays = $sth->{ParamArrays} ||= { }; |
1881
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
# If the bind has attribs then we rely on the driver conforming to |
1883
|
|
|
|
|
|
|
# the DBI spec in that a single bind_param() call with those attribs |
1884
|
|
|
|
|
|
|
# makes them 'sticky' and apply to all later execute(@values) calls. |
1885
|
|
|
|
|
|
|
# Since we only call bind_param() if we're given attribs then |
1886
|
|
|
|
|
|
|
# applications using drivers that don't support bind_param can still |
1887
|
|
|
|
|
|
|
# use bind_param_array() so long as they don't pass any attribs. |
1888
|
|
|
|
|
|
|
|
1889
|
76
|
|
|
|
|
138
|
$$hash_of_arrays{$p_id} = $value_array; |
1890
|
76
|
50
|
|
|
|
136
|
return $sth->bind_param($p_id, undef, $attr) |
1891
|
|
|
|
|
|
|
if $attr; |
1892
|
76
|
|
|
|
|
226
|
1; |
1893
|
|
|
|
|
|
|
} |
1894
|
|
|
|
|
|
|
|
1895
|
|
|
|
|
|
|
sub bind_param_inout_array { |
1896
|
0
|
|
|
0
|
|
0
|
my $sth = shift; |
1897
|
|
|
|
|
|
|
# XXX not supported so we just call bind_param_array instead |
1898
|
|
|
|
|
|
|
# and then return an error |
1899
|
0
|
|
|
|
|
0
|
my ($p_num, $value_array, $attr) = @_; |
1900
|
0
|
|
|
|
|
0
|
$sth->bind_param_array($p_num, $value_array, $attr); |
1901
|
0
|
|
|
|
|
0
|
return $sth->set_err($DBI::stderr, "bind_param_inout_array not supported"); |
1902
|
|
|
|
|
|
|
} |
1903
|
|
|
|
|
|
|
|
1904
|
|
|
|
|
|
|
sub bind_columns { |
1905
|
116
|
|
|
116
|
|
25189
|
my $sth = shift; |
1906
|
116
|
|
50
|
|
|
658
|
my $fields = $sth->FETCH('NUM_OF_FIELDS') || 0; |
1907
|
116
|
50
|
33
|
|
|
1242
|
if ($fields <= 0 && !$sth->{Active}) { |
1908
|
0
|
|
|
|
|
0
|
return $sth->set_err($DBI::stderr, "Statement has no result columns to bind" |
1909
|
|
|
|
|
|
|
." (perhaps you need to successfully call execute first, or again)"); |
1910
|
|
|
|
|
|
|
} |
1911
|
|
|
|
|
|
|
# Backwards compatibility for old-style call with attribute hash |
1912
|
|
|
|
|
|
|
# ref as first arg. Skip arg if undef or a hash ref. |
1913
|
116
|
|
|
|
|
253
|
my $attr; |
1914
|
116
|
100
|
66
|
|
|
1403
|
$attr = shift if !defined $_[0] or ref($_[0]) eq 'HASH'; |
1915
|
|
|
|
|
|
|
|
1916
|
116
|
|
|
|
|
288
|
my $idx = 0; |
1917
|
116
|
|
100
|
|
|
2138
|
$sth->bind_col(++$idx, shift, $attr) or return |
|
|
|
50
|
|
|
|
|
1918
|
|
|
|
|
|
|
while (@_ and $idx < $fields); |
1919
|
|
|
|
|
|
|
|
1920
|
116
|
100
|
100
|
|
|
1623
|
return $sth->set_err($DBI::stderr, "bind_columns called with ".($idx+@_)." values but $fields are needed") |
1921
|
|
|
|
|
|
|
if @_ or $idx != $fields; |
1922
|
|
|
|
|
|
|
|
1923
|
108
|
|
|
|
|
446
|
return 1; |
1924
|
|
|
|
|
|
|
} |
1925
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
sub execute_array { |
1927
|
48
|
|
|
48
|
|
47034
|
my $sth = shift; |
1928
|
48
|
|
|
|
|
116
|
my ($attr, @array_of_arrays) = @_; |
1929
|
48
|
|
|
|
|
168
|
my $NUM_OF_PARAMS = $sth->FETCH('NUM_OF_PARAMS'); # may be undef at this point |
1930
|
|
|
|
|
|
|
|
1931
|
|
|
|
|
|
|
# get tuple status array or hash attribute |
1932
|
48
|
|
|
|
|
298
|
my $tuple_sts = $attr->{ArrayTupleStatus}; |
1933
|
48
|
100
|
100
|
|
|
263
|
return $sth->set_err($DBI::stderr, "ArrayTupleStatus attribute must be an arrayref") |
1934
|
|
|
|
|
|
|
if $tuple_sts and ref $tuple_sts ne 'ARRAY'; |
1935
|
|
|
|
|
|
|
|
1936
|
|
|
|
|
|
|
# bind all supplied arrays |
1937
|
44
|
100
|
|
|
|
96
|
if (@array_of_arrays) { |
1938
|
28
|
|
|
|
|
80
|
$sth->{ParamArrays} = { }; # clear out old params |
1939
|
28
|
100
|
66
|
|
|
184
|
return $sth->set_err($DBI::stderr, |
1940
|
|
|
|
|
|
|
@array_of_arrays." bind values supplied but $NUM_OF_PARAMS expected") |
1941
|
|
|
|
|
|
|
if defined ($NUM_OF_PARAMS) && @array_of_arrays != $NUM_OF_PARAMS; |
1942
|
|
|
|
|
|
|
$sth->bind_param_array($_, $array_of_arrays[$_-1]) or return |
1943
|
24
|
|
100
|
|
|
158
|
foreach (1..@array_of_arrays); |
1944
|
|
|
|
|
|
|
} |
1945
|
|
|
|
|
|
|
|
1946
|
36
|
|
|
|
|
128
|
my $fetch_tuple_sub; |
1947
|
|
|
|
|
|
|
|
1948
|
36
|
100
|
|
|
|
79
|
if ($fetch_tuple_sub = $attr->{ArrayTupleFetch}) { # fetch on demand |
1949
|
|
|
|
|
|
|
|
1950
|
8
|
50
|
|
|
|
25
|
return $sth->set_err($DBI::stderr, |
1951
|
|
|
|
|
|
|
"Can't use both ArrayTupleFetch and explicit bind values") |
1952
|
|
|
|
|
|
|
if @array_of_arrays; # previous bind_param_array calls will simply be ignored |
1953
|
|
|
|
|
|
|
|
1954
|
8
|
100
|
|
|
|
52
|
if (UNIVERSAL::isa($fetch_tuple_sub,'DBI::st')) { |
|
|
50
|
|
|
|
|
|
1955
|
4
|
|
|
|
|
12
|
my $fetch_sth = $fetch_tuple_sub; |
1956
|
|
|
|
|
|
|
return $sth->set_err($DBI::stderr, |
1957
|
|
|
|
|
|
|
"ArrayTupleFetch sth is not Active, need to execute() it first") |
1958
|
4
|
50
|
|
|
|
29
|
unless $fetch_sth->{Active}; |
1959
|
|
|
|
|
|
|
# check column count match to give more friendly message |
1960
|
4
|
|
|
|
|
43
|
my $NUM_OF_FIELDS = $fetch_sth->{NUM_OF_FIELDS}; |
1961
|
4
|
50
|
33
|
|
|
89
|
return $sth->set_err($DBI::stderr, |
|
|
|
33
|
|
|
|
|
1962
|
|
|
|
|
|
|
"$NUM_OF_FIELDS columns from ArrayTupleFetch sth but $NUM_OF_PARAMS expected") |
1963
|
|
|
|
|
|
|
if defined($NUM_OF_FIELDS) && defined($NUM_OF_PARAMS) |
1964
|
|
|
|
|
|
|
&& $NUM_OF_FIELDS != $NUM_OF_PARAMS; |
1965
|
4
|
|
|
16
|
|
26
|
$fetch_tuple_sub = sub { $fetch_sth->fetchrow_arrayref }; |
|
16
|
|
|
|
|
76
|
|
1966
|
|
|
|
|
|
|
} |
1967
|
|
|
|
|
|
|
elsif (!UNIVERSAL::isa($fetch_tuple_sub,'CODE')) { |
1968
|
0
|
|
|
|
|
0
|
return $sth->set_err($DBI::stderr, "ArrayTupleFetch '$fetch_tuple_sub' is not a code ref or statement handle"); |
1969
|
|
|
|
|
|
|
} |
1970
|
|
|
|
|
|
|
|
1971
|
|
|
|
|
|
|
} |
1972
|
|
|
|
|
|
|
else { |
1973
|
28
|
50
|
|
|
|
36
|
my $NUM_OF_PARAMS_given = keys %{ $sth->{ParamArrays} || {} }; |
|
28
|
|
|
|
|
99
|
|
1974
|
28
|
50
|
33
|
|
|
137
|
return $sth->set_err($DBI::stderr, |
1975
|
|
|
|
|
|
|
"$NUM_OF_PARAMS_given bind values supplied but $NUM_OF_PARAMS expected") |
1976
|
|
|
|
|
|
|
if defined($NUM_OF_PARAMS) && $NUM_OF_PARAMS != $NUM_OF_PARAMS_given; |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
# get the length of a bound array |
1979
|
28
|
|
|
|
|
44
|
my $maxlen; |
1980
|
28
|
|
|
|
|
37
|
my %hash_of_arrays = %{$sth->{ParamArrays}}; |
|
28
|
|
|
|
|
113
|
|
1981
|
28
|
|
|
|
|
89
|
foreach (keys(%hash_of_arrays)) { |
1982
|
100
|
|
|
|
|
132
|
my $ary = $hash_of_arrays{$_}; |
1983
|
100
|
100
|
|
|
|
183
|
next unless ref $ary eq 'ARRAY'; |
1984
|
48
|
100
|
66
|
|
|
140
|
$maxlen = @$ary if !$maxlen || @$ary > $maxlen; |
1985
|
|
|
|
|
|
|
} |
1986
|
|
|
|
|
|
|
# if there are no arrays then execute scalars once |
1987
|
28
|
100
|
|
|
|
66
|
$maxlen = 1 unless defined $maxlen; |
1988
|
28
|
|
|
|
|
73
|
my @bind_ids = 1..keys(%hash_of_arrays); |
1989
|
|
|
|
|
|
|
|
1990
|
28
|
|
|
|
|
40
|
my $tuple_idx = 0; |
1991
|
|
|
|
|
|
|
$fetch_tuple_sub = sub { |
1992
|
68
|
100
|
|
68
|
|
185
|
return if $tuple_idx >= $maxlen; |
1993
|
|
|
|
|
|
|
my @tuple = map { |
1994
|
40
|
|
|
|
|
76
|
my $a = $hash_of_arrays{$_}; |
|
160
|
|
|
|
|
212
|
|
1995
|
160
|
100
|
|
|
|
335
|
ref($a) ? $a->[$tuple_idx] : $a |
1996
|
|
|
|
|
|
|
} @bind_ids; |
1997
|
40
|
|
|
|
|
51
|
++$tuple_idx; |
1998
|
40
|
|
|
|
|
94
|
return \@tuple; |
1999
|
28
|
|
|
|
|
138
|
}; |
2000
|
|
|
|
|
|
|
} |
2001
|
|
|
|
|
|
|
# pass thru the callers scalar or list context |
2002
|
36
|
|
|
|
|
164
|
return $sth->execute_for_fetch($fetch_tuple_sub, $tuple_sts); |
2003
|
|
|
|
|
|
|
} |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
sub execute_for_fetch { |
2006
|
36
|
|
|
36
|
|
637
|
my ($sth, $fetch_tuple_sub, $tuple_status) = @_; |
2007
|
|
|
|
|
|
|
# start with empty status array |
2008
|
36
|
100
|
|
|
|
107
|
($tuple_status) ? @$tuple_status = () : $tuple_status = []; |
2009
|
|
|
|
|
|
|
|
2010
|
36
|
|
|
|
|
59
|
my $rc_total = 0; |
2011
|
36
|
|
|
|
|
55
|
my $err_count; |
2012
|
36
|
|
|
|
|
122
|
while ( my $tuple = &$fetch_tuple_sub() ) { |
2013
|
60
|
100
|
|
|
|
377
|
if ( my $rc = $sth->execute(@$tuple) ) { |
2014
|
56
|
|
|
|
|
311
|
push @$tuple_status, $rc; |
2015
|
56
|
50
|
33
|
|
|
274
|
$rc_total = ($rc >= 0 && $rc_total >= 0) ? $rc_total + $rc : -1; |
2016
|
|
|
|
|
|
|
} |
2017
|
|
|
|
|
|
|
else { |
2018
|
4
|
|
|
|
|
131
|
$err_count++; |
2019
|
4
|
|
|
|
|
74
|
push @$tuple_status, [ $sth->err, $sth->errstr, $sth->state ]; |
2020
|
|
|
|
|
|
|
# XXX drivers implementing execute_for_fetch could opt to "last;" here |
2021
|
|
|
|
|
|
|
# if they know the error code means no further executes will work. |
2022
|
|
|
|
|
|
|
} |
2023
|
|
|
|
|
|
|
} |
2024
|
36
|
|
|
|
|
82
|
my $tuples = @$tuple_status; |
2025
|
36
|
100
|
|
|
|
191
|
return $sth->set_err($DBI::stderr, "executing $tuples generated $err_count errors") |
2026
|
|
|
|
|
|
|
if $err_count; |
2027
|
32
|
|
100
|
|
|
104
|
$tuples ||= "0E0"; |
2028
|
32
|
100
|
|
|
|
177
|
return $tuples unless wantarray; |
2029
|
4
|
|
|
|
|
32
|
return ($tuples, $rc_total); |
2030
|
|
|
|
|
|
|
} |
2031
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
|
2033
|
|
|
|
|
|
|
sub fetchall_arrayref { # ALSO IN Driver.xst |
2034
|
2358
|
|
|
2358
|
|
27310
|
my ($sth, $slice, $max_rows) = @_; |
2035
|
|
|
|
|
|
|
|
2036
|
|
|
|
|
|
|
# when batch fetching with $max_rows were very likely to try to |
2037
|
|
|
|
|
|
|
# fetch the 'next batch' after the previous batch returned |
2038
|
|
|
|
|
|
|
# <=$max_rows. So don't treat that as an error. |
2039
|
2358
|
100
|
100
|
|
|
6928
|
return undef if $max_rows and not $sth->FETCH('Active'); |
2040
|
|
|
|
|
|
|
|
2041
|
2354
|
|
100
|
|
|
9143
|
my $mode = ref($slice) || 'ARRAY'; |
2042
|
2354
|
|
|
|
|
4821
|
my @rows; |
2043
|
|
|
|
|
|
|
|
2044
|
2354
|
100
|
|
|
|
5769
|
if ($mode eq 'ARRAY') { |
2045
|
2322
|
|
|
|
|
3250
|
my $row; |
2046
|
|
|
|
|
|
|
# we copy the array here because fetch (currently) always |
2047
|
|
|
|
|
|
|
# returns the same array ref. XXX |
2048
|
2322
|
100
|
100
|
|
|
7707
|
if ($slice && @$slice) { |
|
|
100
|
|
|
|
|
|
2049
|
16
|
100
|
|
|
|
45
|
$max_rows = -1 unless defined $max_rows; |
2050
|
16
|
|
100
|
|
|
84
|
push @rows, [ @{$row}[ @$slice] ] |
|
40
|
|
|
|
|
533
|
|
2051
|
|
|
|
|
|
|
while($max_rows-- and $row = $sth->fetch); |
2052
|
|
|
|
|
|
|
} |
2053
|
|
|
|
|
|
|
elsif (defined $max_rows) { |
2054
|
8
|
|
100
|
|
|
43
|
push @rows, [ @$row ] |
2055
|
|
|
|
|
|
|
while($max_rows-- and $row = $sth->fetch); |
2056
|
|
|
|
|
|
|
} |
2057
|
|
|
|
|
|
|
else { |
2058
|
2298
|
|
|
|
|
11108
|
push @rows, [ @$row ] while($row = $sth->fetch); |
2059
|
|
|
|
|
|
|
} |
2060
|
|
|
|
|
|
|
return \@rows |
2061
|
2321
|
|
|
|
|
17370
|
} |
2062
|
|
|
|
|
|
|
|
2063
|
32
|
|
|
|
|
45
|
my %row; |
2064
|
32
|
100
|
100
|
|
|
152
|
if ($mode eq 'REF' && ref($$slice) eq 'HASH') { # \{ $idx => $name } |
|
|
100
|
|
|
|
|
|
2065
|
12
|
|
|
|
|
29
|
keys %$$slice; # reset the iterator |
2066
|
12
|
|
|
|
|
44
|
while ( my ($idx, $name) = each %$$slice ) { |
2067
|
12
|
|
|
|
|
102
|
$sth->bind_col($idx+1, \$row{$name}); |
2068
|
|
|
|
|
|
|
} |
2069
|
|
|
|
|
|
|
} |
2070
|
|
|
|
|
|
|
elsif ($mode eq 'HASH') { |
2071
|
16
|
100
|
|
|
|
52
|
if (keys %$slice) { # resets the iterator |
2072
|
12
|
|
|
|
|
54
|
my $name2idx = $sth->FETCH('NAME_lc_hash'); |
2073
|
12
|
|
|
|
|
108
|
while ( my ($name, $unused) = each %$slice ) { |
2074
|
20
|
|
|
|
|
104
|
my $idx = $name2idx->{lc $name}; |
2075
|
20
|
100
|
|
|
|
89
|
return $sth->set_err($DBI::stderr, "Invalid column name '$name' for slice") |
2076
|
|
|
|
|
|
|
if not defined $idx; |
2077
|
16
|
|
|
|
|
93
|
$sth->bind_col($idx+1, \$row{$name}); |
2078
|
|
|
|
|
|
|
} |
2079
|
|
|
|
|
|
|
} |
2080
|
|
|
|
|
|
|
else { |
2081
|
4
|
|
|
|
|
8
|
my @column_names = @{ $sth->FETCH($sth->FETCH('FetchHashKeyName')) }; |
|
4
|
|
|
|
|
28
|
|
2082
|
4
|
50
|
|
|
|
51
|
return [] if !@column_names; |
2083
|
|
|
|
|
|
|
|
2084
|
4
|
|
|
|
|
33
|
$sth->bind_columns( \( @row{@column_names} ) ); |
2085
|
|
|
|
|
|
|
} |
2086
|
|
|
|
|
|
|
} |
2087
|
|
|
|
|
|
|
else { |
2088
|
4
|
|
|
|
|
51
|
return $sth->set_err($DBI::stderr, "fetchall_arrayref($mode) invalid"); |
2089
|
|
|
|
|
|
|
} |
2090
|
|
|
|
|
|
|
|
2091
|
20
|
50
|
|
|
|
117
|
if (not defined $max_rows) { |
2092
|
20
|
|
|
|
|
67
|
push @rows, { %row } while ($sth->fetch); # full speed ahead! |
2093
|
|
|
|
|
|
|
} |
2094
|
|
|
|
|
|
|
else { |
2095
|
0
|
|
0
|
|
|
0
|
push @rows, { %row } while ($max_rows-- and $sth->fetch); |
2096
|
|
|
|
|
|
|
} |
2097
|
|
|
|
|
|
|
|
2098
|
20
|
|
|
|
|
175
|
return \@rows; |
2099
|
|
|
|
|
|
|
} |
2100
|
|
|
|
|
|
|
|
2101
|
|
|
|
|
|
|
sub fetchall_hashref { |
2102
|
96
|
|
|
96
|
|
38781
|
my ($sth, $key_field) = @_; |
2103
|
|
|
|
|
|
|
|
2104
|
96
|
|
50
|
|
|
840
|
my $hash_key_name = $sth->{FetchHashKeyName} || 'NAME'; |
2105
|
96
|
|
|
|
|
1735
|
my $names_hash = $sth->FETCH("${hash_key_name}_hash"); |
2106
|
96
|
100
|
|
|
|
1294
|
my @key_fields = (ref $key_field) ? @$key_field : ($key_field); |
2107
|
96
|
|
|
|
|
272
|
my @key_indexes; |
2108
|
96
|
|
|
|
|
534
|
my $num_of_fields = $sth->FETCH('NUM_OF_FIELDS'); |
2109
|
96
|
|
|
|
|
859
|
foreach (@key_fields) { |
2110
|
100
|
|
|
|
|
315
|
my $index = $names_hash->{$_}; # perl index not column |
2111
|
100
|
50
|
66
|
|
|
719
|
$index = $_ - 1 if !defined $index && DBI::looks_like_number($_) && $_>=1 && $_ <= $num_of_fields; |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
2112
|
100
|
50
|
|
|
|
479
|
return $sth->set_err($DBI::stderr, "Field '$_' does not exist (not one of @{[keys %$names_hash]})") |
|
0
|
|
|
|
|
0
|
|
2113
|
|
|
|
|
|
|
unless defined $index; |
2114
|
100
|
|
|
|
|
482
|
push @key_indexes, $index; |
2115
|
|
|
|
|
|
|
} |
2116
|
96
|
|
|
|
|
341
|
my $rows = {}; |
2117
|
96
|
|
|
|
|
489
|
my $NAME = $sth->FETCH($hash_key_name); |
2118
|
96
|
|
|
|
|
881
|
my @row = (undef) x $num_of_fields; |
2119
|
96
|
|
|
|
|
987
|
$sth->bind_columns(\(@row)); |
2120
|
96
|
|
|
|
|
1349
|
while ($sth->fetch) { |
2121
|
248
|
|
|
|
|
2969
|
my $ref = $rows; |
2122
|
248
|
|
100
|
|
|
1974
|
$ref = $ref->{$row[$_]} ||= {} for @key_indexes; |
2123
|
248
|
|
|
|
|
585
|
@{$ref}{@$NAME} = @row; |
|
248
|
|
|
|
|
1248
|
|
2124
|
|
|
|
|
|
|
} |
2125
|
96
|
|
|
|
|
1150
|
return $rows; |
2126
|
|
|
|
|
|
|
} |
2127
|
|
|
|
|
|
|
|
2128
|
|
|
|
|
|
|
*dump_results = \&DBI::dump_results; |
2129
|
|
|
|
|
|
|
|
2130
|
|
|
|
|
|
|
sub blob_copy_to_file { # returns length or undef on error |
2131
|
0
|
|
|
0
|
|
0
|
my($self, $field, $filename_or_handleref, $blocksize) = @_; |
2132
|
0
|
|
|
|
|
0
|
my $fh = $filename_or_handleref; |
2133
|
0
|
|
|
|
|
0
|
my($len, $buf) = (0, ""); |
2134
|
0
|
|
0
|
|
|
0
|
$blocksize ||= 512; # not too ambitious |
2135
|
0
|
|
|
|
|
0
|
local(*FH); |
2136
|
0
|
0
|
|
|
|
0
|
unless(ref $fh) { |
2137
|
0
|
0
|
|
|
|
0
|
open(FH, ">$fh") || return undef; |
2138
|
0
|
|
|
|
|
0
|
$fh = \*FH; |
2139
|
|
|
|
|
|
|
} |
2140
|
0
|
|
|
|
|
0
|
while(defined($self->blob_read($field, $len, $blocksize, \$buf))) { |
2141
|
0
|
|
|
|
|
0
|
print $fh $buf; |
2142
|
0
|
|
|
|
|
0
|
$len += length $buf; |
2143
|
|
|
|
|
|
|
} |
2144
|
0
|
|
|
|
|
0
|
close(FH); |
2145
|
0
|
|
|
|
|
0
|
$len; |
2146
|
|
|
|
|
|
|
} |
2147
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
sub more_results { |
2149
|
2447
|
|
|
2447
|
|
31905
|
shift->{syb_more_results}; # handy grandfathering |
2150
|
|
|
|
|
|
|
} |
2151
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
} |
2153
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
unless ($DBI::PurePerl) { # See install_driver |
2155
|
|
|
|
|
|
|
{ @DBD::_mem::dr::ISA = qw(DBD::_mem::common); } |
2156
|
|
|
|
|
|
|
{ @DBD::_mem::db::ISA = qw(DBD::_mem::common); } |
2157
|
|
|
|
|
|
|
{ @DBD::_mem::st::ISA = qw(DBD::_mem::common); } |
2158
|
|
|
|
|
|
|
# DBD::_mem::common::DESTROY is implemented in DBI.xs |
2159
|
|
|
|
|
|
|
} |
2160
|
|
|
|
|
|
|
|
2161
|
|
|
|
|
|
|
1; |
2162
|
|
|
|
|
|
|
__END__ |