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