line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Additional methods for DBI. |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package UR::DBI; |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=pod |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 NAME |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
UR::DBI - methods for interacting with a database. |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 SYNOPSIS |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
##- use UR::DBI; |
14
|
|
|
|
|
|
|
UR::DBI->monitor_sql(1); |
15
|
|
|
|
|
|
|
my $dbh = UR::DBI->connect(...); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 DESCRIPTION |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
This module subclasses DBI, and provides a few extra methods useful when using a database. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 METHODS |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=over 4 |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=cut |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# set up package |
28
|
|
|
|
|
|
|
require 5.006_000; |
29
|
266
|
|
|
21254
|
|
1039
|
use warnings; |
|
266
|
|
|
|
|
306
|
|
|
266
|
|
|
|
|
8499
|
|
30
|
266
|
|
|
266
|
|
901
|
use strict; |
|
266
|
|
|
|
|
306
|
|
|
266
|
|
|
|
|
8581
|
|
31
|
|
|
|
|
|
|
our $VERSION = "0.46"; # UR $VERSION;; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# set up module |
34
|
266
|
|
|
266
|
|
877
|
use base qw(Exporter DBI); |
|
266
|
|
|
|
|
322
|
|
|
266
|
|
|
|
|
329158
|
|
35
|
|
|
|
|
|
|
our (@EXPORT, @EXPORT_OK); |
36
|
|
|
|
|
|
|
@EXPORT = qw(); |
37
|
|
|
|
|
|
|
@EXPORT_OK = qw(); |
38
|
|
|
|
|
|
|
|
39
|
266
|
|
|
266
|
|
3286789
|
use IO::Handle; |
|
266
|
|
|
|
|
401
|
|
|
266
|
|
|
|
|
9500
|
|
40
|
266
|
|
|
266
|
|
134110
|
use IO::File; |
|
266
|
|
|
|
|
384950
|
|
|
266
|
|
|
|
|
22906
|
|
41
|
266
|
|
|
266
|
|
1365
|
use Time::HiRes; |
|
266
|
|
|
|
|
330
|
|
|
266
|
|
|
|
|
1797
|
|
42
|
|
|
|
|
|
|
# do not use UR::ModuleBase as base class because it does not play nice with DBI |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# |
45
|
|
|
|
|
|
|
# UR::DBI control flags |
46
|
|
|
|
|
|
|
# |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Build a few class methods to manipulate the environment variables |
49
|
|
|
|
|
|
|
# that control SQL monitoring |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
my %sub_env_map = ( monitor_sql => 'UR_DBI_MONITOR_SQL', |
52
|
|
|
|
|
|
|
monitor_dml => 'UR_DBI_MONITOR_DML', |
53
|
|
|
|
|
|
|
explain_sql_if => 'UR_DBI_EXPLAIN_SQL_IF', |
54
|
|
|
|
|
|
|
explain_sql_slow => 'UR_DBI_EXPLAIN_SQL_SLOW', |
55
|
|
|
|
|
|
|
explain_sql_match => 'UR_DBI_EXPLAIN_SQL_MATCH', |
56
|
|
|
|
|
|
|
explain_sql_callstack => 'UR_DBI_EXPLAIN_SQL_CALLSTACK', |
57
|
|
|
|
|
|
|
no_commit => 'UR_DBI_NO_COMMIT', |
58
|
|
|
|
|
|
|
monitor_every_fetch => 'UR_DBI_MONITOR_EVERY_FETCH', |
59
|
|
|
|
|
|
|
dump_stack_on_connect => 'UR_DBI_DUMP_STACK_ON_CONNECT', |
60
|
|
|
|
|
|
|
); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
our ($monitor_sql,$monitor_dml,$no_commit,$monitor_every_fetch,$dump_stack_on_connect, |
63
|
|
|
|
|
|
|
$explain_sql_slow,$explain_sql_if,$explain_sql_match,$explain_sql_callstack); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
while ( my($subname, $envname) = each ( %sub_env_map ) ) { |
66
|
266
|
|
|
266
|
|
39280
|
no strict 'refs'; |
|
266
|
|
|
|
|
351
|
|
|
266
|
|
|
|
|
333058
|
|
67
|
|
|
|
|
|
|
# There's a scalar of the same name as the sub to hold the value, hook them together |
68
|
|
|
|
|
|
|
*{$subname} = \$ENV{$envname}; |
69
|
|
|
|
|
|
|
my $subref = sub { |
70
|
34
|
50
|
|
34
|
|
16054
|
if (@_ > 1) { |
71
|
34
|
|
|
|
|
239
|
$$subname = $_[1]; |
72
|
|
|
|
|
|
|
} |
73
|
34
|
|
|
|
|
136
|
return $$subname; |
74
|
|
|
|
|
|
|
}; |
75
|
|
|
|
|
|
|
if ($subname =~ /explain/) { |
76
|
|
|
|
|
|
|
eval "\$$subname = '' if not defined \$$subname"; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
else { |
79
|
|
|
|
|
|
|
eval "\$$subname = 0 if not defined \$$subname"; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
die $@ if $@; |
82
|
|
|
|
|
|
|
*$subname = $subref; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# by default, monitored SQL goes to STDOUT |
86
|
|
|
|
|
|
|
# FIXME change this 'our' back to a 'my' after we're transisitioned off of the old App API |
87
|
|
|
|
|
|
|
our $sql_fh = IO::Handle->new; |
88
|
|
|
|
|
|
|
$sql_fh->fdopen(fileno(STDERR), 'w'); |
89
|
|
|
|
|
|
|
$sql_fh->autoflush(1); |
90
|
|
|
|
|
|
|
sub sql_fh |
91
|
|
|
|
|
|
|
{ |
92
|
0
|
0
|
|
0
|
0
|
0
|
$sql_fh = $_[1] if @_ > 1; |
93
|
0
|
|
|
|
|
0
|
return $sql_fh; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# |
97
|
|
|
|
|
|
|
# Logging methods |
98
|
|
|
|
|
|
|
# |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
our $log_file; |
101
|
|
|
|
|
|
|
sub log_file { |
102
|
0
|
0
|
|
0
|
0
|
0
|
$log_file = pop if @_ > 1; |
103
|
0
|
|
|
|
|
0
|
return $log_file; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
our $log_fh; |
107
|
|
|
|
|
|
|
my $create_time=0; |
108
|
|
|
|
|
|
|
sub start_logging { |
109
|
0
|
0
|
|
0
|
0
|
0
|
return 1 if(defined($log_fh)); |
110
|
0
|
0
|
|
|
|
0
|
return 0 if(-e "$log_file"); |
111
|
0
|
|
|
|
|
0
|
$log_fh = new IO::File("> ${log_file}"); |
112
|
0
|
0
|
|
|
|
0
|
unless(defined($log_fh)) { |
113
|
0
|
|
|
|
|
0
|
warn "Logging File $log_file Could not be created\n"; |
114
|
0
|
|
|
|
|
0
|
return 0; |
115
|
|
|
|
|
|
|
} |
116
|
0
|
|
|
|
|
0
|
$create_time=Time::HiRes::time(); |
117
|
0
|
|
|
|
|
0
|
return 1; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub stop_logging { |
121
|
0
|
0
|
|
0
|
0
|
0
|
return 1 unless(defined($log_fh)); |
122
|
0
|
|
|
|
|
0
|
$log_fh->close; |
123
|
0
|
|
|
|
|
0
|
undef $log_fh; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub log_sql { |
127
|
7082
|
50
|
|
7082
|
0
|
14541
|
return 1 unless(defined($log_fh)); |
128
|
0
|
|
|
|
|
0
|
my $sql=pop; |
129
|
0
|
|
|
|
|
0
|
my $no_timestamp=pop; |
130
|
0
|
0
|
|
|
|
0
|
print $log_fh '=' x 10, "\n" unless($no_timestamp); |
131
|
0
|
0
|
|
|
|
0
|
print $log_fh Time::HiRes::time()-$create_time, "\n" unless($no_timestamp); |
132
|
0
|
|
|
|
|
0
|
print $log_fh $sql; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# |
136
|
|
|
|
|
|
|
# Standard DBI overrides |
137
|
|
|
|
|
|
|
# |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub connect |
140
|
|
|
|
|
|
|
{ |
141
|
172
|
|
|
172
|
1
|
694
|
my $self = shift; |
142
|
172
|
|
|
|
|
425
|
my @params = @_; |
143
|
|
|
|
|
|
|
|
144
|
172
|
50
|
33
|
|
|
1423
|
if ($monitor_sql or $dump_stack_on_connect) { |
145
|
0
|
|
|
|
|
0
|
my $time = time; |
146
|
0
|
|
|
|
|
0
|
my $time_string = join(' ', $time, '[' . localtime($time) . ']'); |
147
|
0
|
|
|
|
|
0
|
$sql_fh->print("DB CONNECT AT: $time_string"); |
148
|
|
|
|
|
|
|
} |
149
|
172
|
50
|
|
|
|
572
|
if ($dump_stack_on_connect) { |
150
|
0
|
|
|
|
|
0
|
$sql_fh->print(Carp::longmess()); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
172
|
|
|
|
|
383
|
$params[2] = 'xxx'; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Param 3 is usually a hashref of connection modifiers |
156
|
172
|
50
|
33
|
|
|
1837
|
if (ref($params[3]) and ref($params[3]) =~ m/HASH/) { |
157
|
|
|
|
|
|
|
my $string = join(', ', |
158
|
394
|
|
|
|
|
1392
|
map { $_ . ' => ' . $params[3]->{$_} } |
159
|
172
|
|
|
|
|
334
|
keys(%{$params[3]}) |
|
172
|
|
|
|
|
782
|
|
160
|
|
|
|
|
|
|
); |
161
|
172
|
|
|
|
|
660
|
$params[3] = "{ $string }"; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
172
|
100
|
|
|
|
393
|
my $params_stringified = join(",", map { defined($_) ? "'$_'" : 'undef' } @params); |
|
688
|
|
|
|
|
1793
|
|
165
|
172
|
|
|
|
|
973
|
UR::DBI::before_execute("connecting with params: ($params_stringified)"); |
166
|
|
|
|
|
|
|
|
167
|
172
|
|
|
|
|
1976
|
my $rv = $self->SUPER::connect(@_); |
168
|
172
|
|
|
|
|
160577
|
UR::DBI::after_execute(); |
169
|
172
|
|
|
|
|
721
|
return $rv; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
# |
173
|
|
|
|
|
|
|
# UR::Object hooks |
174
|
|
|
|
|
|
|
# |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub commit_all_app_db_objects { |
177
|
103
|
|
|
103
|
0
|
255
|
my $this_class = shift; |
178
|
103
|
|
|
|
|
200
|
my $handle = shift; |
179
|
|
|
|
|
|
|
|
180
|
103
|
|
|
|
|
180
|
my $data_source; |
181
|
103
|
50
|
|
|
|
1435
|
if ($handle->isa("UR::DBI::db")) { |
|
|
0
|
|
|
|
|
|
182
|
103
|
|
|
|
|
15582
|
$data_source = UR::DataSource::RDBMS->get_for_dbh($handle); |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
elsif ($handle->isa("UR::DBI::st")) { |
185
|
0
|
|
|
|
|
0
|
$data_source = UR::DataSource::RDBMS->get_for_dbh($handle->{Database}); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
else { |
188
|
0
|
|
|
|
|
0
|
Carp::confess("No handle passed to method!?") |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
103
|
50
|
|
|
|
383
|
unless ($data_source) { |
192
|
0
|
|
|
|
|
0
|
return; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
103
|
|
|
|
|
1135
|
return $data_source->_set_all_objects_saved_committed(); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub rollback_all_app_db_objects { |
199
|
22
|
|
|
22
|
0
|
28
|
my $this_class = shift; |
200
|
22
|
|
|
|
|
25
|
my $handle = shift; |
201
|
|
|
|
|
|
|
|
202
|
22
|
|
|
|
|
24
|
my $data_source; |
203
|
22
|
50
|
|
|
|
114
|
if ($handle->isa("UR::DBI::db")) { |
|
|
0
|
|
|
|
|
|
204
|
22
|
|
|
|
|
832
|
$data_source = UR::DataSource::RDBMS->get_for_dbh($handle); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
elsif ($handle->isa("UR::DBI::st")) { |
207
|
0
|
|
|
|
|
0
|
$data_source = UR::DataSource::RDBMS->get_for_dbh($handle->{Database}); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
else { |
210
|
0
|
|
|
|
|
0
|
Carp::confess("No handle passed to method!?") |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
22
|
50
|
|
|
|
67
|
unless ($data_source) { |
214
|
0
|
|
|
|
|
0
|
Carp::confess("No data source found for database handle! $handle") |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
22
|
|
|
|
|
185
|
return $data_source->_set_all_objects_saved_rolled_back(); |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
my @disable_dump_and_explain; |
221
|
|
|
|
|
|
|
sub _disable_dump_explain |
222
|
|
|
|
|
|
|
{ |
223
|
5518
|
|
|
5518
|
|
13729
|
push @disable_dump_and_explain, |
224
|
|
|
|
|
|
|
[$monitor_sql,$explain_sql_slow,$explain_sql_match]; |
225
|
5518
|
|
|
|
|
17398
|
$monitor_sql = 0; |
226
|
5518
|
|
|
|
|
8264
|
$explain_sql_slow = ''; |
227
|
5518
|
|
|
|
|
7983
|
$explain_sql_match = ''; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub _restore_dump_explain |
231
|
|
|
|
|
|
|
{ |
232
|
5518
|
50
|
|
5518
|
|
9117
|
if (@disable_dump_and_explain) { |
233
|
5518
|
|
|
|
|
5696
|
my $vars = pop @disable_dump_and_explain; |
234
|
5518
|
|
|
|
|
23297
|
($monitor_sql,$explain_sql_slow,$explain_sql_match) = @$vars; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
else { |
237
|
0
|
|
|
|
|
0
|
Carp::confess("No state saved for disabled dump/explain"); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# The before_execute/after_execute subroutine pair |
242
|
|
|
|
|
|
|
# are callbacks called by execute() and by other |
243
|
|
|
|
|
|
|
# methods which implicitly execute a statement. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# They use these three varaibles to track state, |
246
|
|
|
|
|
|
|
# presuming that the callback pair cannot be nested.
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
our ($start_time, $elapsed_time); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# This gets around a bug which prevents variables |
251
|
|
|
|
|
|
|
# which are strings internally utf8 encoded from working with DBI |
252
|
|
|
|
|
|
|
# as execution parameters. |
253
|
|
|
|
|
|
|
if ($^O eq "MSWin32" || $^O eq 'cygwin') { |
254
|
|
|
|
|
|
|
*normalize_parameter = sub { $_[0] = substr($_[0],0) }; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
elsif ($^V le v5.8.0) { |
257
|
|
|
|
|
|
|
# perl 5.6.1 utf8 module does not have a downgrade function |
258
|
|
|
|
|
|
|
*normalize_parameter = sub { $_[0] = substr($_[0],0) }; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
else { |
261
|
|
|
|
|
|
|
require utf8; |
262
|
|
|
|
|
|
|
*normalize_parameter = \&utf8::downgrade; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub before_execute |
266
|
|
|
|
|
|
|
{ |
267
|
|
|
|
|
|
|
#my ($dbh,$sql,@params) = @_; |
268
|
|
|
|
|
|
|
# $dbh is optional |
269
|
|
|
|
|
|
|
|
270
|
3541
|
|
|
3541
|
0
|
4197
|
my $dbh; |
271
|
3541
|
100
|
|
|
|
15801
|
$dbh = shift if ref($_[0]); |
272
|
|
|
|
|
|
|
|
273
|
3541
|
|
|
|
|
8590
|
my $sql = shift; |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# Odd errors occur sometimes with values which have not gone through |
276
|
|
|
|
|
|
|
# updgrade, downgrade or $_ = substr($_,0). The query fails w/o error. |
277
|
|
|
|
|
|
|
# This has some connection to a language/encoding problem, and has so |
278
|
|
|
|
|
|
|
# far only been seen with Tk, Gtk2, and XML parser derived data. |
279
|
|
|
|
|
|
|
# Note: when this error occurs it happens with a seeminly normal Perl variable. |
280
|
3541
|
|
|
|
|
6932
|
for (@_) { |
281
|
4816
|
|
|
|
|
7954
|
normalize_parameter($_); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
3541
|
50
|
66
|
|
|
17732
|
if ($dbh and length($explain_sql_match)) { |
285
|
0
|
|
|
|
|
0
|
for my $val ($sql,@_) { |
286
|
0
|
0
|
|
|
|
0
|
if ($val =~ /$explain_sql_match/gi) { |
287
|
0
|
0
|
|
|
|
0
|
$sql_fh->print("\nEXPLAIN QUERY MATCHING /$explain_sql_match/gi" |
288
|
|
|
|
|
|
|
. ($val ne $sql ? " (on value '$val') " : "") |
289
|
|
|
|
|
|
|
); |
290
|
0
|
0
|
|
|
|
0
|
if ($monitor_sql) { |
291
|
0
|
|
|
|
|
0
|
$sql_fh->print("\n"); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
else { |
294
|
0
|
|
|
|
|
0
|
_print_sql_and_params($sql,@_); |
295
|
|
|
|
|
|
|
} |
296
|
0
|
0
|
|
|
|
0
|
if ($explain_sql_callstack) { |
297
|
0
|
|
|
|
|
0
|
$sql_fh->print(Carp::longmess("callstack begins"),"\n"); |
298
|
|
|
|
|
|
|
} |
299
|
0
|
0
|
|
|
|
0
|
if ($UR::DBI::explained_queries{$sql}) { |
300
|
0
|
|
|
|
|
0
|
$sql_fh->print("(query explained above)\n"); |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
else { |
303
|
0
|
|
|
|
|
0
|
UR::DBI::_print_query_plan($sql,$dbh); |
304
|
0
|
|
|
|
|
0
|
$UR::DBI::explained_queries{$sql} = 1; |
305
|
|
|
|
|
|
|
} |
306
|
0
|
|
|
|
|
0
|
last; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
3541
|
|
|
|
|
7372
|
my $start_time = _set_start_time(); |
312
|
3541
|
50
|
33
|
|
|
16352
|
if ($monitor_sql){ |
|
|
50
|
|
|
|
|
|
313
|
0
|
|
|
|
|
0
|
_print_sql_and_params($sql,@_); |
314
|
0
|
0
|
|
|
|
0
|
if ($monitor_sql > 1) { |
315
|
0
|
|
|
|
|
0
|
$sql_fh->print(Carp::longmess("callstack begins"),"\n"); |
316
|
|
|
|
|
|
|
} |
317
|
0
|
|
|
|
|
0
|
_print_monitor_label("EXECUTE"); |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
elsif($monitor_dml && $sql !~ /^\s*select/i){ |
320
|
0
|
|
|
|
|
0
|
_print_sql_and_params($sql,@_); |
321
|
0
|
|
|
|
|
0
|
_print_monitor_label("EXECUTE"); |
322
|
0
|
|
|
|
|
0
|
$monitor_dml=2; |
323
|
|
|
|
|
|
|
} |
324
|
266
|
|
|
266
|
|
1429
|
no warnings; |
|
266
|
|
|
|
|
367
|
|
|
266
|
|
|
|
|
180785
|
|
325
|
|
|
|
|
|
|
|
326
|
3541
|
|
|
|
|
8112
|
UR::DBI::log_sql_for_summary($sql); # $ENV{UR_DBI_SUMMARIZE_SQL} |
327
|
|
|
|
|
|
|
|
328
|
3541
|
|
|
|
|
7953
|
my $log_sql_str = _generate_sql_and_params_log_entry($sql, @_); |
329
|
3541
|
|
|
|
|
8011
|
UR::DBI::log_sql($log_sql_str); |
330
|
3541
|
|
|
|
|
3813
|
return $start_time; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub after_execute |
334
|
|
|
|
|
|
|
{ |
335
|
|
|
|
|
|
|
#my ($sql,@params) = @_; |
336
|
3541
|
|
|
3541
|
0
|
7254
|
my $elapsed_time = _set_elapsed_time(); |
337
|
3541
|
50
|
|
|
|
11913
|
if ($monitor_sql){ |
|
|
50
|
|
|
|
|
|
338
|
0
|
|
|
|
|
0
|
_print_elapsed_time(); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
elsif($monitor_dml == 2){ |
341
|
0
|
|
|
|
|
0
|
_print_elapsed_time(); |
342
|
0
|
|
|
|
|
0
|
$monitor_dml = 1; |
343
|
|
|
|
|
|
|
} |
344
|
3541
|
|
|
|
|
34082
|
UR::DBI::log_sql(1, ($elapsed_time)."\n"); |
345
|
3541
|
|
|
|
|
4460
|
return $elapsed_time; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# The before_fetch/after_fetch pair are callback |
349
|
|
|
|
|
|
|
# called by fetch() and by other methods which implicitly |
350
|
|
|
|
|
|
|
# fetch data w/o explicitly calling fetch(). |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
our $_fetching = 0; |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub before_fetch { |
355
|
6831
|
|
|
6831
|
0
|
5912
|
my $sth = shift; |
356
|
6831
|
100
|
|
|
|
11533
|
return if @disable_dump_and_explain; |
357
|
5518
|
50
|
|
|
|
8996
|
if ($_fetching) { |
358
|
0
|
|
|
|
|
0
|
Carp::cluck("before_fetch called after another before_fetch w/o intervening after_fetch!"); |
359
|
|
|
|
|
|
|
} |
360
|
5518
|
|
|
|
|
4936
|
$_fetching = 1; |
361
|
5518
|
|
|
|
|
9327
|
my $fetch_timing_arrayref = $sth->fetch_timing_arrayref; |
362
|
5518
|
50
|
|
|
|
12635
|
if ($monitor_sql) { |
363
|
0
|
0
|
0
|
|
|
0
|
if ($fetch_timing_arrayref and @$fetch_timing_arrayref == 0) { |
|
|
0
|
|
|
|
|
|
364
|
0
|
|
|
|
|
0
|
UR::DBI::_print_monitor_label('FIRST FETCH'); |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
elsif ($monitor_every_fetch) { |
367
|
0
|
|
|
|
|
0
|
UR::DBI::_print_monitor_label('NTH FETCH'); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
} |
370
|
5518
|
|
|
|
|
9516
|
return UR::DBI::_set_start_time(); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
sub after_fetch { |
374
|
6831
|
|
|
6831
|
0
|
5828
|
my $sth = shift; |
375
|
6831
|
100
|
|
|
|
11245
|
return if @disable_dump_and_explain; |
376
|
5518
|
|
|
|
|
5223
|
$_fetching = 0; |
377
|
5518
|
|
|
|
|
8329
|
my $fetch_timing_arrayref = $sth->fetch_timing_arrayref; |
378
|
5518
|
|
|
|
|
6708
|
my $time; |
379
|
5518
|
|
|
|
|
9275
|
push @$fetch_timing_arrayref, UR::DBI::_set_elapsed_time(); |
380
|
5518
|
50
|
|
|
|
9803
|
if ($monitor_sql) { |
381
|
0
|
0
|
0
|
|
|
0
|
if ($monitor_every_fetch || @$fetch_timing_arrayref == 1) { |
382
|
0
|
|
|
|
|
0
|
$time = UR::DBI::_print_elapsed_time(); |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
} |
385
|
5518
|
100
|
|
|
|
9751
|
if (@$fetch_timing_arrayref == 1) { |
386
|
2094
|
|
|
|
|
4356
|
my $time = $sth->execute_time + $fetch_timing_arrayref->[0]; |
387
|
2094
|
|
|
|
|
9217
|
UR::DBI::_check_query_timing($sth->{Statement},$time,$sth->{Database},$sth->last_params); |
388
|
|
|
|
|
|
|
} |
389
|
5518
|
|
|
|
|
7126
|
return $time; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub after_all_fetches_with_sth { |
393
|
6738
|
|
|
6738
|
0
|
6324
|
my $sth = shift; |
394
|
|
|
|
|
|
|
|
395
|
6738
|
|
|
|
|
9270
|
my $fetch_timing_arrayref = $sth->fetch_timing_arrayref; |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# This arrayref is set when it goes through the subclass' execute(), |
398
|
|
|
|
|
|
|
# and is removed when we finish all fetches(). |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# Since a variety of things attempt to call this from the various "final" |
401
|
|
|
|
|
|
|
# positions of an $sth we delete this so the final callback operates only once. |
402
|
|
|
|
|
|
|
# Also, internally generated $sths which do not get executed() normally |
403
|
|
|
|
|
|
|
# will be skipped by this check. |
404
|
|
|
|
|
|
|
|
405
|
6738
|
100
|
|
|
|
13229
|
if (!$fetch_timing_arrayref) { |
406
|
|
|
|
|
|
|
# internal sth which did not go through prepare() |
407
|
|
|
|
|
|
|
#print $sql_fh "SKIP STH\n"; |
408
|
4020
|
|
|
|
|
4386
|
return; |
409
|
|
|
|
|
|
|
} |
410
|
2718
|
|
|
|
|
4749
|
$sth->fetch_timing_arrayref(undef); |
411
|
|
|
|
|
|
|
|
412
|
2718
|
|
|
|
|
3588
|
my $print_fetch_summary; |
413
|
2718
|
50
|
33
|
|
|
7158
|
if ($monitor_sql and $sth->{Statement} =~ /select/i) { |
414
|
0
|
|
|
|
|
0
|
$print_fetch_summary = 1; |
415
|
0
|
|
|
|
|
0
|
UR::DBI::_print_monitor_label('TOTAL EXECUTE-FETCH'); |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
2718
|
|
|
|
|
4923
|
my $time = $sth->execute_time; |
419
|
|
|
|
|
|
|
|
420
|
2718
|
100
|
|
|
|
6074
|
if (@$fetch_timing_arrayref) { |
421
|
2093
|
|
|
|
|
3776
|
for my $fetch_time (@$fetch_timing_arrayref ) { |
422
|
5517
|
|
|
|
|
5318
|
$time += $fetch_time; |
423
|
|
|
|
|
|
|
} |
424
|
2093
|
50
|
|
|
|
4037
|
if ($print_fetch_summary) { |
425
|
0
|
|
|
|
|
0
|
UR::DBI::_print_monitor_time($time); |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
# since there WERE fetches, we already checked query timing |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
else { |
430
|
625
|
50
|
|
|
|
1115
|
if ($print_fetch_summary) { |
431
|
0
|
|
|
|
|
0
|
UR::DBI::_print_monitor_time($time); |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
# since there were NOT fetches, we check query timing now |
434
|
625
|
|
|
|
|
1766
|
UR::DBI::_check_query_timing($sth->{Statement},$time,$sth->{Database},$sth->last_params); |
435
|
|
|
|
|
|
|
} |
436
|
2718
|
|
|
|
|
4186
|
return $time; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub after_all_fetches_no_sth { |
440
|
40
|
|
|
40
|
0
|
114
|
my ($sql, $time, $dbh, @params) = @_; |
441
|
40
|
50
|
|
|
|
129
|
$time = _set_elapsed_time() unless defined $time; |
442
|
40
|
50
|
33
|
|
|
143
|
if ($monitor_sql and $sql =~ /select/i) { |
443
|
0
|
|
|
|
|
0
|
UR::DBI::_print_monitor_label('TOTAL EXECUTE-FETCH'); |
444
|
0
|
|
|
|
|
0
|
UR::DBI::_print_monitor_time($time); |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
# no sth = no fetches = no query timing check done yet... |
447
|
40
|
|
|
|
|
105
|
UR::DBI::_check_query_timing($sql,$time,$dbh,@params); |
448
|
40
|
|
|
|
|
54
|
return $time; |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
my $__SQL_SUMMARY__ = {}; |
453
|
|
|
|
|
|
|
sub log_sql_for_summary { |
454
|
3541
|
|
|
3541
|
0
|
4719
|
my ($sql) = @_; |
455
|
3541
|
|
|
|
|
9466
|
$__SQL_SUMMARY__->{$sql}++; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub print_sql_summary { |
459
|
0
|
|
|
0
|
0
|
0
|
for my $sql (sort {$__SQL_SUMMARY__->{$b} <=> $__SQL_SUMMARY__->{$a}} keys %$__SQL_SUMMARY__) { |
|
0
|
|
|
|
|
0
|
|
460
|
0
|
|
|
|
|
0
|
print STDERR join('',"********************\n", $__SQL_SUMMARY__->{$sql}, " instances of query: $sql\n"); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# These methods are called by the above. |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
sub _generate_sql_and_params_log_entry |
467
|
|
|
|
|
|
|
{ |
468
|
|
|
|
|
|
|
|
469
|
3541
|
|
|
3541
|
|
4143
|
my $sql = shift; |
470
|
|
|
|
|
|
|
|
471
|
266
|
|
|
266
|
|
1348
|
no warnings; |
|
266
|
|
|
|
|
345
|
|
|
266
|
|
|
|
|
41450
|
|
472
|
3541
|
|
|
|
|
8002
|
my $sql_log_str = "\nSQL: $sql\n"; |
473
|
3541
|
100
|
|
|
|
7412
|
if (@_) { |
474
|
2396
|
|
|
|
|
4086
|
$sql_log_str .= "PARAMS: "; |
475
|
|
|
|
|
|
|
$sql_log_str .= join(", ", |
476
|
4816
|
100
|
|
|
|
12353
|
map { defined($_) ? "'$_'" : "NULL" } |
477
|
2396
|
50
|
|
|
|
4328
|
map { scalar(grep { $_ } map { 128 & ord $_ } split(//, substr($_, 0, 64))) ? '' : $_ } |
|
4816
|
|
|
|
|
11823
|
|
|
22281
|
|
|
|
|
22300
|
|
|
22281
|
|
|
|
|
19968
|
|
478
|
|
|
|
|
|
|
@_ ) |
479
|
|
|
|
|
|
|
. "\n"; |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
3541
|
|
|
|
|
6705
|
return $sql_log_str; |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
sub _print_sql_and_params |
486
|
|
|
|
|
|
|
{ |
487
|
0
|
|
|
0
|
|
0
|
my $sql = shift; |
488
|
0
|
|
|
|
|
0
|
my $entry = _generate_sql_and_params_log_entry($sql, @_); |
489
|
266
|
|
|
266
|
|
1174
|
no warnings; |
|
266
|
|
|
|
|
374
|
|
|
266
|
|
|
|
|
138112
|
|
490
|
0
|
|
|
|
|
0
|
print $sql_fh $entry; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
sub _set_start_time |
494
|
|
|
|
|
|
|
{ |
495
|
9059
|
|
|
9059
|
|
23588
|
$start_time=&Time::HiRes::time(); |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
our $_print_monitor_label_or_time_is_ready_for = "label"; |
499
|
|
|
|
|
|
|
sub _print_monitor_label |
500
|
|
|
|
|
|
|
{ |
501
|
|
|
|
|
|
|
#Carp::cluck() unless $_print_monitor_label_or_time_is_ready_for eq "label"; |
502
|
0
|
|
|
0
|
|
0
|
my $time_label = shift; |
503
|
0
|
|
|
|
|
0
|
$sql_fh->print("$time_label TIME: "); |
504
|
0
|
|
|
|
|
0
|
$_print_monitor_label_or_time_is_ready_for = "time"; |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
sub _print_monitor_time |
508
|
|
|
|
|
|
|
{ |
509
|
|
|
|
|
|
|
#Carp::cluck() unless $_print_monitor_label_or_time_is_ready_for eq "time"; |
510
|
0
|
|
|
0
|
|
0
|
$sql_fh->printf( "%.4f s\n", shift); |
511
|
0
|
|
|
|
|
0
|
$_print_monitor_label_or_time_is_ready_for = "label"; |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
sub _set_elapsed_time |
515
|
|
|
|
|
|
|
{ |
516
|
9059
|
|
|
9059
|
|
24276
|
$elapsed_time = &Time::HiRes::time()-$start_time; |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
sub _print_elapsed_time |
520
|
|
|
|
|
|
|
{ |
521
|
0
|
|
|
0
|
|
0
|
_print_monitor_time($elapsed_time); |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
our $_print_check_for_slow_query = 0; |
525
|
|
|
|
|
|
|
sub _check_query_timing |
526
|
|
|
|
|
|
|
{ |
527
|
2759
|
|
|
2759
|
|
17270
|
my ($sql,$time,$dbh,@params) = @_; |
528
|
2759
|
50
|
|
|
|
6374
|
return if @disable_dump_and_explain; |
529
|
2759
|
100
|
|
|
|
11063
|
return unless $sql =~ /select/i; |
530
|
1649
|
50
|
|
|
|
3909
|
print $sql_fh "CHECK FOR SLOW QUERY:\n" if $_print_check_for_slow_query; # used only by a test case |
531
|
1649
|
50
|
33
|
|
|
6041
|
if (length($explain_sql_slow) and $time >= $explain_sql_slow) { |
532
|
0
|
|
|
|
|
0
|
$sql_fh->print("EXPLAIN QUERY SLOWER THAN $explain_sql_slow seconds ($time):"); |
533
|
0
|
0
|
0
|
|
|
0
|
if ($monitor_sql |
|
|
|
0
|
|
|
|
|
534
|
|
|
|
|
|
|
|| ($monitor_dml && $sql !~ /^\s*select/i)) { |
535
|
0
|
|
|
|
|
0
|
$sql_fh->print("\n"); |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
else { |
538
|
0
|
|
|
|
|
0
|
_print_sql_and_params($sql,@params); |
539
|
|
|
|
|
|
|
} |
540
|
0
|
0
|
|
|
|
0
|
if ($explain_sql_callstack) { |
541
|
0
|
|
|
|
|
0
|
$sql_fh->print(Carp::longmess("callstack begins"),"\n"); |
542
|
|
|
|
|
|
|
} |
543
|
0
|
0
|
|
|
|
0
|
if ($UR::DBI::explained_queries{$sql}) { |
544
|
0
|
|
|
|
|
0
|
$sql_fh->print("(query explained above)\n"); |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
else { |
547
|
0
|
|
|
|
|
0
|
$UR::DBI::explained_queries{$sql} = 1; |
548
|
0
|
|
|
|
|
0
|
UR::DBI::_print_query_plan($sql,$dbh); |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
sub _print_query_plan |
554
|
|
|
|
|
|
|
{ |
555
|
0
|
|
|
0
|
|
0
|
my ($sql,$dbh,%params) = @_; |
556
|
0
|
|
|
|
|
0
|
UR::DBI::_disable_dump_explain(); |
557
|
0
|
|
|
|
|
0
|
$dbh->do($UR::DBI::EXPLAIN_PLAN_CLEANUP_DML); |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
# placeholders in explain plan queries on windows |
560
|
|
|
|
|
|
|
# results in Oracle throwing an ORA-00600 error, |
561
|
|
|
|
|
|
|
# likely due to interaction with DBI. Replace with |
562
|
|
|
|
|
|
|
# literals. |
563
|
|
|
|
|
|
|
|
564
|
0
|
0
|
0
|
|
|
0
|
if ($^O eq "MSWin32" || $^O eq 'cygwin') { |
565
|
0
|
|
|
|
|
0
|
$sql =~ s/\?/'1'/g; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
0
|
0
|
|
|
|
0
|
$dbh->do($UR::DBI::EXPLAIN_PLAN_DML . "\n" . $sql) |
569
|
|
|
|
|
|
|
or die "Failed to produce query plan! " . $dbh->errstr; |
570
|
0
|
|
|
|
|
0
|
UR::DBI::Report->generate( |
571
|
|
|
|
|
|
|
sql => [$UR::DBI::EXPLAIN_PLAN_SQL], |
572
|
|
|
|
|
|
|
dbh => $dbh, |
573
|
|
|
|
|
|
|
count => 0, |
574
|
|
|
|
|
|
|
outfh => $sql_fh, |
575
|
|
|
|
|
|
|
%params, |
576
|
|
|
|
|
|
|
"explain-sql" => 0, |
577
|
|
|
|
|
|
|
"echo" => 0, |
578
|
|
|
|
|
|
|
); |
579
|
0
|
|
|
|
|
0
|
$sql_fh->print("\n"); |
580
|
0
|
|
|
|
|
0
|
$dbh->do($UR::DBI::EXPLAIN_PLAN_CLEANUP_DML); |
581
|
0
|
|
|
|
|
0
|
UR::DBI::_restore_dump_explain(); |
582
|
|
|
|
|
|
|
|
583
|
0
|
|
|
|
|
0
|
return 1; |
584
|
|
|
|
|
|
|
} |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
############ |
588
|
|
|
|
|
|
|
# |
589
|
|
|
|
|
|
|
# Database handle subclass |
590
|
|
|
|
|
|
|
# |
591
|
|
|
|
|
|
|
############ |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
package UR::DBI::db; |
595
|
|
|
|
|
|
|
|
596
|
266
|
|
|
266
|
|
1307
|
use strict; |
|
266
|
|
|
|
|
394
|
|
|
266
|
|
|
|
|
4723
|
|
597
|
266
|
|
|
266
|
|
855
|
use warnings; |
|
266
|
|
|
|
|
336
|
|
|
266
|
|
|
|
|
237476
|
|
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
our @ISA = qw(DBI::db); |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
sub commit |
602
|
|
|
|
|
|
|
{ |
603
|
166
|
|
|
166
|
|
32571
|
my $self = shift; |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
# unless ($no_commit) { |
606
|
|
|
|
|
|
|
# print "\n\n\n************* FORCIBLY SETTING NO-COMMIT FOR TESTING. This would have committeed!!!! **********\n\n\n"; |
607
|
|
|
|
|
|
|
# $no_commit = 1; |
608
|
|
|
|
|
|
|
# } |
609
|
|
|
|
|
|
|
|
610
|
166
|
100
|
|
|
|
480
|
if ($no_commit) |
611
|
|
|
|
|
|
|
{ |
612
|
|
|
|
|
|
|
# Respect the ->no_commit(1) setting. |
613
|
63
|
|
|
|
|
121
|
UR::DBI::before_execute("commit (ignored)"); |
614
|
63
|
|
|
|
|
106
|
UR::DBI::after_execute; |
615
|
63
|
|
|
|
|
166
|
return 1; |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
else |
618
|
|
|
|
|
|
|
{ |
619
|
103
|
50
|
|
|
|
473
|
if(UR::DataSource->use_dummy_autogenerated_ids) { |
620
|
|
|
|
|
|
|
# Not cool...you shouldn't have dummy-ids on and no-commit off |
621
|
|
|
|
|
|
|
# Don't commit, and notify the authorities |
622
|
0
|
|
|
|
|
0
|
UR::DBI::before_execute("commit (ignored)"); |
623
|
0
|
|
|
|
|
0
|
$UR::Context::current->error_message('Tried to commit with dummy-ids on and no-commit off'); |
624
|
0
|
|
|
|
|
0
|
UR::DBI::after_execute; |
625
|
|
|
|
|
|
|
#$UR::Context::current->send_email( |
626
|
|
|
|
|
|
|
# To => 'example@example.edu', |
627
|
|
|
|
|
|
|
# Subject => 'attempt to commit with dummy-ids on and no-commit off '. |
628
|
|
|
|
|
|
|
# "by $ENV{USER} on $ENV{HOST} running ". |
629
|
|
|
|
|
|
|
# UR::Context::Process->original_program_path." as pid $$", |
630
|
|
|
|
|
|
|
# Message => "Call stack:\n" .Carp::longmess() |
631
|
|
|
|
|
|
|
#); |
632
|
|
|
|
|
|
|
} else { |
633
|
|
|
|
|
|
|
# Commit and update the associated objects. |
634
|
103
|
|
|
|
|
319
|
UR::DBI::before_execute("commit"); |
635
|
103
|
|
|
|
|
3922032
|
my $rv = $self->SUPER::commit(@_); |
636
|
103
|
|
|
|
|
724
|
UR::DBI::after_execute; |
637
|
103
|
50
|
|
|
|
463
|
if ($rv) { |
638
|
103
|
|
|
|
|
704
|
UR::DBI->commit_all_app_db_objects($self) |
639
|
|
|
|
|
|
|
} |
640
|
103
|
|
|
|
|
610
|
return $rv; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
sub commit_without_object_update |
646
|
|
|
|
|
|
|
{ |
647
|
0
|
|
|
0
|
|
0
|
UR::DBI::before_execute("commit (no object updates)"); |
648
|
0
|
|
|
|
|
0
|
my $rv = shift->SUPER::commit(@_); |
649
|
0
|
|
|
|
|
0
|
UR::DBI::after_execute(); |
650
|
0
|
|
|
|
|
0
|
return $rv; |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
sub rollback |
654
|
|
|
|
|
|
|
{ |
655
|
22
|
|
|
22
|
|
23
|
my $self = shift; |
656
|
22
|
|
|
|
|
62
|
UR::DBI::before_execute("rollback"); |
657
|
22
|
|
|
|
|
2757
|
my $rv = $self->SUPER::rollback(@_); |
658
|
22
|
|
|
|
|
53
|
UR::DBI::after_execute(); |
659
|
22
|
50
|
|
|
|
54
|
if ($rv) { |
660
|
22
|
|
|
|
|
104
|
UR::DBI->rollback_all_app_db_objects($self) |
661
|
|
|
|
|
|
|
} |
662
|
22
|
|
|
|
|
69
|
return $rv; |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
sub rollback_without_object_update |
666
|
|
|
|
|
|
|
{ |
667
|
0
|
|
|
0
|
|
0
|
UR::DBI::before_execute("rollback (w/o object updates)"); |
668
|
0
|
|
|
|
|
0
|
my $rv = shift->SUPER::commit(@_); |
669
|
0
|
|
|
|
|
0
|
UR::DBI::after_execute(); |
670
|
0
|
|
|
|
|
0
|
return $rv; |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
sub disconnect |
674
|
|
|
|
|
|
|
{ |
675
|
5
|
|
|
5
|
|
14
|
my $self = shift; |
676
|
|
|
|
|
|
|
# Rollback if AutoCommit is 0. Oracle commits by default on disconnect. |
677
|
|
|
|
|
|
|
# Rolling back when AutoCommit is on will generate a DBI warning. |
678
|
5
|
50
|
|
|
|
33
|
if ($self->{'AutoCommit'} == 0) { |
679
|
5
|
|
|
|
|
18
|
$self->rollback; |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
# Msg and disconnect. |
683
|
5
|
|
|
|
|
19
|
UR::DBI::before_execute("disconnecting"); |
684
|
5
|
|
|
|
|
714
|
my $rv = $self->SUPER::disconnect(@_); |
685
|
5
|
|
|
|
|
14
|
UR::DBI::after_execute(); |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
# There doesn't seem to be anything less which |
688
|
|
|
|
|
|
|
# sets this, but legacy tools did |
689
|
5
|
50
|
33
|
|
|
37
|
if ( |
690
|
|
|
|
|
|
|
(defined $UR::DBI::common_dbh) |
691
|
|
|
|
|
|
|
and |
692
|
|
|
|
|
|
|
($self eq $UR::DBI::common_dbh) |
693
|
|
|
|
|
|
|
) |
694
|
|
|
|
|
|
|
{ |
695
|
0
|
|
|
|
|
0
|
UR::DBI::before_execute("common dbh removed"); |
696
|
0
|
|
|
|
|
0
|
$UR::DBI::common_dbh = undef; |
697
|
0
|
|
|
|
|
0
|
UR::DBI::after_execute("common dbh removed"); |
698
|
|
|
|
|
|
|
} |
699
|
5
|
|
|
|
|
25
|
return $rv; |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
sub prepare |
703
|
|
|
|
|
|
|
{ |
704
|
2317
|
|
|
2317
|
|
90381
|
my $self = shift; |
705
|
2317
|
|
|
|
|
3291
|
my $sql = $_[0]; |
706
|
2317
|
|
|
|
|
2579
|
my $sth; |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
#print $sql_fh "PREPARE: $sql\n"; |
709
|
|
|
|
|
|
|
|
710
|
2317
|
50
|
|
|
|
11823
|
if ($sql =~ /^\s*(commit|rollback)\s*$/i) |
711
|
|
|
|
|
|
|
{ |
712
|
0
|
0
|
|
|
|
0
|
unless ($sql =~ /^(commit|rollback)$/i) { |
713
|
0
|
|
|
|
|
0
|
Carp::confess("Executing a statement with an embedded commit/rollback?\n$sql\n"); |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
0
|
0
|
|
|
|
0
|
if ($sth = $self->SUPER::prepare(@_)) |
717
|
|
|
|
|
|
|
{ |
718
|
0
|
0
|
|
|
|
0
|
if ($1 =~ /commit/i) |
|
|
0
|
|
|
|
|
|
719
|
|
|
|
|
|
|
{ |
720
|
0
|
|
|
|
|
0
|
$UR::DBI::prepared_commit{$sth} = 1; |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
elsif ($1 =~ /rollback/) |
723
|
|
|
|
|
|
|
{ |
724
|
0
|
|
|
|
|
0
|
$UR::DBI::prepared_rollback{$sth} = 1; |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
} |
728
|
|
|
|
|
|
|
else |
729
|
|
|
|
|
|
|
{ |
730
|
2317
|
50
|
|
|
|
15313
|
$sth = $self->SUPER::prepare(@_) or return; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
2317
|
|
|
|
|
275509
|
return $sth; |
734
|
|
|
|
|
|
|
} |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
# For newer versions of DBI, some of the $dbh->select* methods do not |
737
|
|
|
|
|
|
|
# call execute internally, so SQL dumping and logging will not occur. |
738
|
|
|
|
|
|
|
# These are listed below, and the bad ones are overridden. |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
# selectall_hashref ok |
741
|
|
|
|
|
|
|
# selectcol_arrayref ok |
742
|
|
|
|
|
|
|
# selectrow_hashref ok |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
# selectall_arrayref bad |
745
|
|
|
|
|
|
|
# selectrow_arrayref bad |
746
|
|
|
|
|
|
|
# selectrow_array bad |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
sub selectall_arrayref |
749
|
|
|
|
|
|
|
{ |
750
|
29
|
|
|
29
|
|
992
|
my $self = shift; |
751
|
29
|
|
|
|
|
135
|
my @p = ($_[0],@_[2..$#_]); |
752
|
29
|
|
|
|
|
97
|
UR::DBI::before_execute($self,@p); |
753
|
29
|
|
|
|
|
526
|
my $ar = $self->SUPER::selectall_arrayref(@_); |
754
|
29
|
|
|
|
|
112
|
my $time = UR::DBI::after_execute($self,@p); |
755
|
29
|
|
|
|
|
124
|
UR::DBI::after_all_fetches_no_sth($_[0],$time,$self,@p); |
756
|
29
|
|
|
|
|
81
|
return $ar; |
757
|
|
|
|
|
|
|
} |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
sub selectcol_arrayref |
761
|
|
|
|
|
|
|
{ |
762
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
763
|
0
|
|
|
|
|
0
|
my @p = ($_[0],@_[2..$#_]); |
764
|
0
|
|
|
|
|
0
|
UR::DBI::before_execute($self,@p); |
765
|
0
|
|
|
|
|
0
|
UR::DBI::_disable_dump_explain(); |
766
|
0
|
|
|
|
|
0
|
my $ar = $self->SUPER::selectcol_arrayref(@_); |
767
|
0
|
|
|
|
|
0
|
UR::DBI::_restore_dump_explain(); |
768
|
0
|
|
|
|
|
0
|
my $time = UR::DBI::after_execute($self,@p); |
769
|
0
|
|
|
|
|
0
|
UR::DBI::after_all_fetches_no_sth($_[0],$time,$self,@p); |
770
|
0
|
|
|
|
|
0
|
return $ar; |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
sub selectall_hashref |
775
|
|
|
|
|
|
|
{ |
776
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
777
|
0
|
|
|
|
|
0
|
my @p = ($_[0],@_[3..$#_]); |
778
|
0
|
|
|
|
|
0
|
UR::DBI::before_execute($self,@p); |
779
|
0
|
|
|
|
|
0
|
UR::DBI::_disable_dump_explain(); |
780
|
0
|
|
|
|
|
0
|
my $ar = $self->SUPER::selectall_hashref(@_); |
781
|
0
|
|
|
|
|
0
|
UR::DBI::_restore_dump_explain(); |
782
|
0
|
|
|
|
|
0
|
my $time = UR::DBI::after_execute($self,@p); |
783
|
0
|
|
|
|
|
0
|
UR::DBI::after_all_fetches_no_sth($_[0],$time,$self,@p); |
784
|
0
|
|
|
|
|
0
|
return $ar; |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
sub selectrow_arrayref |
788
|
|
|
|
|
|
|
{ |
789
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
790
|
1
|
|
|
|
|
5
|
my @p = ($_[0],@_[2..$#_]); |
791
|
1
|
|
|
|
|
5
|
UR::DBI::before_execute($self,@p); |
792
|
1
|
|
|
|
|
18
|
my $ar = $self->SUPER::selectrow_arrayref(@_); |
793
|
1
|
|
|
|
|
5
|
my $time = UR::DBI::after_execute($self,@p); |
794
|
1
|
|
|
|
|
6
|
UR::DBI::after_all_fetches_no_sth($_[0],$time,$self,@p); |
795
|
1
|
|
|
|
|
4
|
return $ar; |
796
|
|
|
|
|
|
|
} |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
sub selectrow_array |
799
|
|
|
|
|
|
|
{ |
800
|
10
|
|
|
10
|
|
5398
|
my $self = shift; |
801
|
10
|
|
|
|
|
35
|
my @p = ($_[0],@_[2..$#_]); |
802
|
10
|
|
|
|
|
29
|
UR::DBI::before_execute($self,@p); |
803
|
10
|
|
|
|
|
92
|
my @a = $self->SUPER::selectrow_array(@_); |
804
|
10
|
|
|
|
|
53
|
my $time = UR::DBI::after_execute($self,@p); |
805
|
10
|
|
|
|
|
30
|
UR::DBI::after_all_fetches_no_sth($_[0],$time,$self,@p); |
806
|
10
|
50
|
|
|
|
50
|
return @a if wantarray; |
807
|
0
|
|
|
|
|
0
|
return $a[0]; |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
sub DESTROY |
811
|
|
|
|
|
|
|
{ |
812
|
4
|
|
|
4
|
|
1741
|
UR::DBI::before_execute("destroying connection"); |
813
|
4
|
|
|
|
|
38
|
shift->SUPER::DESTROY(@_); |
814
|
4
|
|
|
|
|
9
|
UR::DBI::after_execute("destroying connection"); |
815
|
|
|
|
|
|
|
} |
816
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
######### |
818
|
|
|
|
|
|
|
# |
819
|
|
|
|
|
|
|
# Statement handle subclass |
820
|
|
|
|
|
|
|
# |
821
|
|
|
|
|
|
|
######### |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
package UR::DBI::st; |
824
|
|
|
|
|
|
|
|
825
|
266
|
|
|
266
|
|
1313
|
use strict; |
|
266
|
|
|
|
|
374
|
|
|
266
|
|
|
|
|
4666
|
|
826
|
266
|
|
|
266
|
|
879
|
use warnings; |
|
266
|
|
|
|
|
377
|
|
|
266
|
|
|
|
|
5648
|
|
827
|
|
|
|
|
|
|
|
828
|
266
|
|
|
266
|
|
867
|
use Time::HiRes; |
|
266
|
|
|
|
|
313
|
|
|
266
|
|
|
|
|
1009
|
|
829
|
266
|
|
|
266
|
|
137527
|
use Sys::Hostname; |
|
266
|
|
|
|
|
215448
|
|
|
266
|
|
|
|
|
11540
|
|
830
|
266
|
|
|
266
|
|
103925
|
use Devel::GlobalDestruction; |
|
266
|
|
|
|
|
396554
|
|
|
266
|
|
|
|
|
1272
|
|
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
our @ISA = qw(DBI::st); |
833
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
sub _mk_mutator { |
835
|
798
|
|
|
798
|
|
891
|
my ($class, $method) = @_; |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
# Make a more specific key based on the package |
838
|
|
|
|
|
|
|
# to try not to conflict with anything else. |
839
|
|
|
|
|
|
|
# This must start with 'private_'. See DBI docs on subclassing. |
840
|
798
|
|
|
|
|
2004
|
my $hash_key = join('_', 'private', lc $class, lc $method); |
841
|
798
|
|
|
|
|
1969
|
$hash_key =~ s/::/_/g; |
842
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
my $sub = sub { |
844
|
40137
|
50
|
|
40137
|
|
687251
|
return if Devel::GlobalDestruction::in_global_destruction; |
845
|
40137
|
|
|
|
|
129279
|
my $sth = shift; |
846
|
40137
|
100
|
|
|
|
55990
|
if (@_) { |
847
|
266
|
|
|
266
|
|
33660
|
no warnings 'uninitialized'; |
|
266
|
|
|
|
|
379
|
|
|
266
|
|
|
|
|
9836
|
|
848
|
11700
|
|
|
|
|
69848
|
$sth->{$hash_key} = shift; |
849
|
|
|
|
|
|
|
} |
850
|
266
|
|
|
266
|
|
898
|
no warnings; |
|
266
|
|
|
|
|
324
|
|
|
266
|
|
|
|
|
10797
|
|
851
|
40137
|
|
|
|
|
158315
|
return $sth->{$hash_key}; |
852
|
798
|
|
|
|
|
2248
|
}; |
853
|
|
|
|
|
|
|
|
854
|
266
|
|
|
266
|
|
925
|
no strict; |
|
266
|
|
|
|
|
349
|
|
|
266
|
|
|
|
|
186186
|
|
855
|
798
|
|
|
|
|
706
|
*{$class . '::' . $method} = $sub; |
|
798
|
|
|
|
|
2927
|
|
856
|
|
|
|
|
|
|
} |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
for my $method (qw(execute_time fetch_timing_arrayref last_params_arrayref)) { |
859
|
|
|
|
|
|
|
__PACKAGE__->_mk_mutator($method); |
860
|
|
|
|
|
|
|
} |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
sub last_params |
863
|
|
|
|
|
|
|
{ |
864
|
2719
|
|
|
2719
|
|
5607
|
my $ret = shift->last_params_arrayref; |
865
|
2719
|
50
|
|
|
|
7079
|
unless (defined $ret) { |
866
|
0
|
|
|
|
|
0
|
$ret = []; |
867
|
|
|
|
|
|
|
} |
868
|
2719
|
|
|
|
|
2885
|
@{ $ret }; |
|
2719
|
|
|
|
|
8162
|
|
869
|
|
|
|
|
|
|
} |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
sub execute |
872
|
|
|
|
|
|
|
{ |
873
|
3132
|
|
|
3132
|
|
25041
|
my $sth = shift; |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
# (re)-initialize the timing array |
876
|
3132
|
100
|
|
|
|
7943
|
if (my $a = $sth->fetch_timing_arrayref()) { |
877
|
|
|
|
|
|
|
# re-executing on a previously used $sth. |
878
|
414
|
|
|
|
|
736
|
UR::DBI::after_all_fetches_with_sth($sth); |
879
|
|
|
|
|
|
|
} |
880
|
|
|
|
|
|
|
else { |
881
|
|
|
|
|
|
|
# initialize the $sth on first execute. |
882
|
2718
|
|
|
|
|
5815
|
$sth->fetch_timing_arrayref([]); |
883
|
|
|
|
|
|
|
} |
884
|
|
|
|
|
|
|
|
885
|
3132
|
|
|
|
|
10283
|
$sth->last_params_arrayref([@_]); |
886
|
|
|
|
|
|
|
|
887
|
3132
|
|
|
|
|
12608
|
UR::DBI::before_execute($sth->{Database},$sth->{Statement},@_); |
888
|
3132
|
|
|
|
|
115588
|
my $rv = $sth->SUPER::execute(@_); |
889
|
3132
|
|
|
|
|
12666
|
UR::DBI::after_execute($sth->{Database},$sth->{Statement},@_); |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
# record the elapsed time for execution. |
892
|
3132
|
|
|
|
|
8666
|
$sth->execute_time($UR::DBI::elapsed_time); |
893
|
|
|
|
|
|
|
|
894
|
3132
|
50
|
|
|
|
6976
|
if ($rv) |
895
|
|
|
|
|
|
|
{ |
896
|
3132
|
50
|
|
|
|
8781
|
if (my $prev = $UR::DBI::prepared_commit{$sth}) |
897
|
|
|
|
|
|
|
{ |
898
|
0
|
|
|
|
|
0
|
UR::DBI->commit_all_app_db_objects($sth); |
899
|
|
|
|
|
|
|
} |
900
|
3132
|
50
|
|
|
|
7951
|
if (my $prev = $UR::DBI::prepared_rollback{$sth}) |
901
|
|
|
|
|
|
|
{ |
902
|
0
|
|
|
|
|
0
|
UR::DBI->rollback_all_app_db_objects($sth); |
903
|
|
|
|
|
|
|
} |
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
} |
906
|
3132
|
|
|
|
|
8981
|
return $rv; |
907
|
|
|
|
|
|
|
} |
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
sub fetchrow_array |
911
|
|
|
|
|
|
|
{ |
912
|
8
|
|
|
8
|
|
60
|
my $sth = shift; |
913
|
8
|
|
|
|
|
11
|
UR::DBI::before_fetch($sth,@_); |
914
|
8
|
|
|
|
|
9
|
UR::DBI::_disable_dump_explain(); |
915
|
8
|
|
|
|
|
50
|
my @a = $sth->SUPER::fetchrow_array(@_); |
916
|
8
|
|
|
|
|
10
|
UR::DBI::_restore_dump_explain(); |
917
|
8
|
|
|
|
|
13
|
UR::DBI::after_fetch($sth,@_); |
918
|
8
|
50
|
|
|
|
37
|
return @a if wantarray; |
919
|
0
|
|
|
|
|
0
|
return $a[0]; |
920
|
|
|
|
|
|
|
} |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
sub fetchrow_arrayref |
923
|
|
|
|
|
|
|
{ |
924
|
4305
|
|
|
4305
|
|
4168
|
my $sth = shift; |
925
|
4305
|
|
|
|
|
8695
|
UR::DBI::before_fetch($sth,@_); |
926
|
4305
|
|
|
|
|
8024
|
UR::DBI::_disable_dump_explain(); |
927
|
4305
|
|
|
|
|
46061
|
my $ar = $sth->SUPER::fetchrow_arrayref(@_); |
928
|
4305
|
|
|
|
|
8073
|
UR::DBI::_restore_dump_explain(); |
929
|
4305
|
|
|
|
|
8254
|
UR::DBI::after_fetch($sth,@_); |
930
|
4305
|
|
|
|
|
7893
|
return $ar; |
931
|
|
|
|
|
|
|
} |
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
sub fetchall_arrayref |
935
|
|
|
|
|
|
|
{ |
936
|
65
|
|
|
65
|
|
326
|
my $sth = shift; |
937
|
65
|
|
|
|
|
180
|
UR::DBI::before_fetch($sth,@_); |
938
|
65
|
|
|
|
|
153
|
UR::DBI::_disable_dump_explain(); |
939
|
65
|
|
|
|
|
798
|
my $ar = $sth->SUPER::fetchall_arrayref(@_); |
940
|
65
|
|
|
|
|
433
|
UR::DBI::_restore_dump_explain(); |
941
|
65
|
|
|
|
|
164
|
UR::DBI::after_fetch($sth,@_); |
942
|
65
|
|
|
|
|
167
|
UR::DBI::after_all_fetches_with_sth($sth,@_); |
943
|
65
|
|
|
|
|
168
|
return $ar; |
944
|
|
|
|
|
|
|
} |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
sub fetchall_hashref |
947
|
|
|
|
|
|
|
{ |
948
|
1
|
|
|
1
|
|
8
|
my $sth = shift; |
949
|
1
|
|
|
|
|
8
|
my @p = @_[1,$#_]; |
950
|
1
|
|
|
|
|
6
|
UR::DBI::before_fetch($sth,@p); |
951
|
1
|
|
|
|
|
5
|
UR::DBI::_disable_dump_explain(); |
952
|
1
|
|
|
|
|
23
|
my $ar = $sth->SUPER::fetchall_hashref(@_); |
953
|
1
|
|
|
|
|
8
|
UR::DBI::_restore_dump_explain(); |
954
|
1
|
|
|
|
|
4
|
UR::DBI::after_fetch($sth,@p); |
955
|
1
|
|
|
|
|
5
|
UR::DBI::after_all_fetches_with_sth($sth,@_[1,$#_]); |
956
|
1
|
|
|
|
|
4
|
return $ar; |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
sub fetchrow_hashref |
960
|
|
|
|
|
|
|
{ |
961
|
1139
|
|
|
1139
|
|
2586
|
my $sth = shift; |
962
|
1139
|
|
|
|
|
1668
|
UR::DBI::before_fetch($sth,@_); |
963
|
1139
|
|
|
|
|
1532
|
UR::DBI::_disable_dump_explain(); |
964
|
1139
|
|
|
|
|
8734
|
my $ar = $sth->SUPER::fetchrow_hashref(@_); |
965
|
1139
|
|
|
|
|
2498
|
UR::DBI::_restore_dump_explain(); |
966
|
1139
|
|
|
|
|
1515
|
UR::DBI::after_fetch($sth,@_); |
967
|
1139
|
|
|
|
|
2632
|
return $ar; |
968
|
|
|
|
|
|
|
} |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
sub fetch { |
972
|
1313
|
|
|
1313
|
|
5836
|
my $sth = shift; |
973
|
1313
|
|
|
|
|
1602
|
UR::DBI::before_fetch($sth,@_); |
974
|
1313
|
|
|
|
|
6322
|
my $rv = $sth->SUPER::fetch(@_); |
975
|
1313
|
|
|
|
|
1857
|
UR::DBI::after_fetch($sth,@_); |
976
|
1313
|
|
|
|
|
4047
|
return $rv; |
977
|
|
|
|
|
|
|
} |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
sub finish { |
980
|
1624
|
|
|
1624
|
|
4812
|
my $sth = shift; |
981
|
1624
|
|
|
|
|
4100
|
UR::DBI::after_all_fetches_with_sth($sth); |
982
|
1624
|
|
|
|
|
8317
|
return $sth->SUPER::finish(@_); |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
sub DESTROY |
986
|
|
|
|
|
|
|
{ |
987
|
4634
|
|
|
4634
|
|
33636
|
delete $UR::DBI::prepared_commit{$_[0]}; |
988
|
4634
|
|
|
|
|
4928
|
delete $UR::DBI::prepared_rollback{$_[0]}; |
989
|
|
|
|
|
|
|
#print $sql_fh "DESTROY1\n"; |
990
|
4634
|
|
|
|
|
6827
|
UR::DBI::after_all_fetches_with_sth(@_); # does nothing if called previously by finish() |
991
|
|
|
|
|
|
|
#print $sql_fh "DESTROY2\n"; |
992
|
|
|
|
|
|
|
#Carp::cluck(); |
993
|
4634
|
|
|
|
|
48440
|
shift->SUPER::DESTROY(@_); |
994
|
|
|
|
|
|
|
} |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
$UR::DBI::STATEMENT_ID = $$ . '@' . hostname(); |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
$UR::DBI::EXPLAIN_PLAN_DML = "explain plan set statement_id = '$UR::DBI::STATEMENT_ID' into plan_table for "; |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
$UR::DBI::EXPLAIN_PLAN_SQL = qq/ |
1003
|
|
|
|
|
|
|
select |
1004
|
|
|
|
|
|
|
LPAD(' ',p.LVL-1) || OPERATION OPERATION, |
1005
|
|
|
|
|
|
|
OPTIONS, |
1006
|
|
|
|
|
|
|
--(case when p.OBJECT_OWNER is null then '' else p.OBJECT_OWNER || '.' end) |
1007
|
|
|
|
|
|
|
-- || |
1008
|
|
|
|
|
|
|
p.OBJECT_NAME |
1009
|
|
|
|
|
|
|
|| |
1010
|
|
|
|
|
|
|
(case when p.OBJECT_TYPE is null then '' else ' (' || p.OBJECT_TYPE || ')' end) |
1011
|
|
|
|
|
|
|
"OBJECT", |
1012
|
|
|
|
|
|
|
(case |
1013
|
|
|
|
|
|
|
when i.table_name is not null then i.table_name |
1014
|
|
|
|
|
|
|
|| '(' |
1015
|
|
|
|
|
|
|
|| index_column_names |
1016
|
|
|
|
|
|
|
|| ')' |
1017
|
|
|
|
|
|
|
else '' |
1018
|
|
|
|
|
|
|
end) "OBJECT_IS_ON", |
1019
|
|
|
|
|
|
|
p.COST, |
1020
|
|
|
|
|
|
|
p.CARDINALITY CARD, |
1021
|
|
|
|
|
|
|
p.BYTES, |
1022
|
|
|
|
|
|
|
p.OPTIMIZER, |
1023
|
|
|
|
|
|
|
p.CPU_COST CPU, |
1024
|
|
|
|
|
|
|
p.IO_COST IO, |
1025
|
|
|
|
|
|
|
p.TEMP_SPACE TEMP, |
1026
|
|
|
|
|
|
|
i.index_type "index_type", |
1027
|
|
|
|
|
|
|
i.last_analyzed "index_analyzed" |
1028
|
|
|
|
|
|
|
from |
1029
|
|
|
|
|
|
|
( |
1030
|
|
|
|
|
|
|
SELECT plan_table.*, level lvl |
1031
|
|
|
|
|
|
|
FROM PLAN_TABLE |
1032
|
|
|
|
|
|
|
CONNECT BY prior id = parent_id AND prior statement_id = statement_id |
1033
|
|
|
|
|
|
|
START WITH id = 0 |
1034
|
|
|
|
|
|
|
AND statement_id = '$UR::DBI::STATEMENT_ID' |
1035
|
|
|
|
|
|
|
) p |
1036
|
|
|
|
|
|
|
full join dual on dummy = dummy |
1037
|
|
|
|
|
|
|
left join all_indexes i |
1038
|
|
|
|
|
|
|
on i.index_name = p.object_name |
1039
|
|
|
|
|
|
|
and i.owner = p.object_owner |
1040
|
|
|
|
|
|
|
left join |
1041
|
|
|
|
|
|
|
( |
1042
|
|
|
|
|
|
|
select |
1043
|
|
|
|
|
|
|
index_owner, |
1044
|
|
|
|
|
|
|
index_name, |
1045
|
|
|
|
|
|
|
LTRIM(MAX(SYS_CONNECT_BY_PATH(ic.column_name,',')) KEEP (DENSE_RANK LAST ORDER BY ic.column_position),',') index_column_names |
1046
|
|
|
|
|
|
|
from ( |
1047
|
|
|
|
|
|
|
select ic.index_owner, ic.index_name, ic.column_name, ic.column_position |
1048
|
|
|
|
|
|
|
from all_ind_columns ic |
1049
|
|
|
|
|
|
|
) ic |
1050
|
|
|
|
|
|
|
group by ic.index_owner, ic.index_name |
1051
|
|
|
|
|
|
|
connect by |
1052
|
|
|
|
|
|
|
index_owner = prior index_owner |
1053
|
|
|
|
|
|
|
and index_name = prior index_name |
1054
|
|
|
|
|
|
|
and column_position = PRIOR column_position + 1 |
1055
|
|
|
|
|
|
|
start with column_position = 1 |
1056
|
|
|
|
|
|
|
) index_columns_stringified |
1057
|
|
|
|
|
|
|
on index_columns_stringified.index_owner = i.owner |
1058
|
|
|
|
|
|
|
and index_columns_stringified.index_name = i.index_name |
1059
|
|
|
|
|
|
|
where p.object_name is not null |
1060
|
|
|
|
|
|
|
ORDER BY p.id |
1061
|
|
|
|
|
|
|
/; |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
$UR::DBI::EXPLAIN_PLAN_CLEANUP_DML = "delete from plan_table where statement_id = '$UR::DBI::STATEMENT_ID'"; |
1064
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
1; |
1067
|
|
|
|
|
|
|
__END__ |