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