line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DBIx::QueryLog; |
2
|
|
|
|
|
|
|
|
3
|
23
|
|
|
23
|
|
1746029
|
use strict; |
|
23
|
|
|
|
|
52
|
|
|
23
|
|
|
|
|
918
|
|
4
|
23
|
|
|
23
|
|
99
|
use warnings; |
|
23
|
|
|
|
|
36
|
|
|
23
|
|
|
|
|
609
|
|
5
|
23
|
|
|
23
|
|
565
|
use 5.008_001; |
|
23
|
|
|
|
|
80
|
|
|
23
|
|
|
|
|
828
|
|
6
|
|
|
|
|
|
|
|
7
|
23
|
|
|
23
|
|
4644
|
use DBI; |
|
23
|
|
|
|
|
45569
|
|
|
23
|
|
|
|
|
1103
|
|
8
|
23
|
|
|
23
|
|
2329
|
use Time::HiRes qw(gettimeofday tv_interval); |
|
23
|
|
|
|
|
5181
|
|
|
23
|
|
|
|
|
170
|
|
9
|
23
|
|
|
23
|
|
20558
|
use Term::ANSIColor qw(colored); |
|
23
|
|
|
|
|
145772
|
|
|
23
|
|
|
|
|
10771
|
|
10
|
23
|
|
|
23
|
|
17826
|
use Text::ASCIITable; |
|
23
|
|
|
|
|
339938
|
|
|
23
|
|
|
|
|
1335
|
|
11
|
23
|
|
|
23
|
|
2252
|
use Data::Dumper (); |
|
23
|
|
|
|
|
14564
|
|
|
23
|
|
|
|
|
1215
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
$ENV{ANSI_COLORS_DISABLED} = 1 if $^O eq 'MSWin32'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.40'; |
16
|
|
|
|
|
|
|
|
17
|
23
|
|
|
23
|
|
125
|
use constant _ORG_EXECUTE => \&DBI::st::execute; |
|
23
|
|
|
|
|
42
|
|
|
23
|
|
|
|
|
1820
|
|
18
|
23
|
|
|
23
|
|
308
|
use constant _ORG_BIND_PARAM => \&DBI::st::bind_param; |
|
23
|
|
|
|
|
39
|
|
|
23
|
|
|
|
|
1167
|
|
19
|
23
|
|
|
23
|
|
104
|
use constant _ORG_DB_DO => \&DBI::db::do; |
|
23
|
|
|
|
|
29
|
|
|
23
|
|
|
|
|
1135
|
|
20
|
23
|
|
|
23
|
|
111
|
use constant _ORG_DB_SELECTALL_ARRAYREF => \&DBI::db::selectall_arrayref; |
|
23
|
|
|
|
|
33
|
|
|
23
|
|
|
|
|
1326
|
|
21
|
23
|
|
|
23
|
|
108
|
use constant _ORG_DB_SELECTROW_ARRAYREF => \&DBI::db::selectrow_arrayref; |
|
23
|
|
|
|
|
31
|
|
|
23
|
|
|
|
|
1129
|
|
22
|
23
|
|
|
23
|
|
108
|
use constant _ORG_DB_SELECTROW_ARRAY => \&DBI::db::selectrow_array; |
|
23
|
|
|
|
|
30
|
|
|
23
|
|
|
|
|
1332
|
|
23
|
|
|
|
|
|
|
|
24
|
23
|
50
|
|
23
|
|
105
|
use constant _HAS_MYSQL => eval { require DBD::mysql; 1 } ? 1 : 0; |
|
23
|
|
|
|
|
28
|
|
|
23
|
|
|
|
|
36
|
|
|
23
|
|
|
|
|
6732
|
|
|
0
|
|
|
|
|
0
|
|
25
|
23
|
50
|
|
23
|
|
104
|
use constant _HAS_PG => eval { require DBD::Pg; 1 } ? 1 : 0; |
|
23
|
|
|
|
|
31
|
|
|
23
|
|
|
|
|
30
|
|
|
23
|
|
|
|
|
5971
|
|
|
0
|
|
|
|
|
0
|
|
26
|
23
|
50
|
|
23
|
|
117
|
use constant _HAS_SQLITE => eval { require DBD::SQLite; DBD::SQLite->VERSION(1.48); 1 } ? 1 : 0; |
|
23
|
|
|
|
|
33
|
|
|
23
|
|
|
|
|
33
|
|
|
23
|
|
|
|
|
2497
|
|
|
23
|
|
|
|
|
22604
|
|
|
23
|
|
|
|
|
1785
|
|
27
|
23
|
50
|
|
23
|
|
145
|
use constant _PP_MODE => $INC{'DBI/PurePerl.pm'} ? 1 : 0; |
|
23
|
|
|
|
|
47
|
|
|
23
|
|
|
|
|
5804
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
our %SKIP_PKG_MAP = ( |
30
|
|
|
|
|
|
|
'DBIx::QueryLog' => 1, |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
our $LOG_LEVEL = 'debug'; |
33
|
|
|
|
|
|
|
our $OUTPUT = *STDERR; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my $st_execute; |
36
|
|
|
|
|
|
|
my $st_bind_param; |
37
|
|
|
|
|
|
|
my $db_do; |
38
|
|
|
|
|
|
|
my $selectall_arrayref; |
39
|
|
|
|
|
|
|
my $selectrow_arrayref; |
40
|
|
|
|
|
|
|
my $selectrow_array; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $is_enabled = 0; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub import { |
45
|
24
|
|
|
24
|
|
8288
|
my ($class) = @_; |
46
|
|
|
|
|
|
|
|
47
|
24
|
|
66
|
|
|
177
|
$st_execute ||= $class->_st_execute(_ORG_EXECUTE); |
48
|
24
|
|
66
|
|
|
139
|
$st_bind_param ||= $class->_st_bind_param(_ORG_BIND_PARAM); |
49
|
24
|
|
66
|
|
|
136
|
$db_do ||= $class->_db_do(_ORG_DB_DO) if _HAS_MYSQL or _HAS_PG or _HAS_SQLITE; |
50
|
24
|
|
|
|
|
23
|
unless (_PP_MODE) { |
51
|
24
|
|
66
|
|
|
123
|
$selectall_arrayref ||= $class->_select_array(_ORG_DB_SELECTALL_ARRAYREF); |
52
|
24
|
|
66
|
|
|
109
|
$selectrow_arrayref ||= $class->_select_array(_ORG_DB_SELECTROW_ARRAYREF); |
53
|
24
|
|
66
|
|
|
136
|
$selectrow_array ||= $class->_select_array(_ORG_DB_SELECTROW_ARRAY, 1); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
23
|
|
|
23
|
|
124
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
32
|
|
|
23
|
|
|
|
|
3358
|
|
57
|
24
|
|
|
|
|
79
|
*DBI::st::execute = $st_execute; |
58
|
24
|
|
|
|
|
49
|
*DBI::st::bind_param = $st_bind_param; |
59
|
24
|
|
|
|
|
67
|
*DBI::db::do = $db_do if _HAS_MYSQL or _HAS_PG or _HAS_SQLITE; |
60
|
24
|
|
|
|
|
34
|
unless (_PP_MODE) { |
61
|
24
|
|
|
|
|
42
|
*DBI::db::selectall_arrayref = $selectall_arrayref; |
62
|
24
|
|
|
|
|
54
|
*DBI::db::selectrow_arrayref = $selectrow_arrayref; |
63
|
24
|
|
|
|
|
57
|
*DBI::db::selectrow_array = $selectrow_array; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
24
|
|
|
|
|
26379
|
$is_enabled = 1; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub unimport { |
70
|
23
|
|
|
23
|
|
104
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
33
|
|
|
23
|
|
|
|
|
6370
|
|
71
|
5
|
|
|
5
|
|
32736
|
*DBI::st::execute = _ORG_EXECUTE; |
72
|
5
|
|
|
|
|
10
|
*DBI::st::bind_param = _ORG_BIND_PARAM; |
73
|
5
|
|
|
|
|
16
|
*DBI::db::do = _ORG_DB_DO if _HAS_MYSQL or _HAS_PG or _HAS_SQLITE; |
74
|
5
|
|
|
|
|
5
|
unless (_PP_MODE) { |
75
|
5
|
|
|
|
|
10
|
*DBI::db::selectall_arrayref = _ORG_DB_SELECTALL_ARRAYREF; |
76
|
5
|
|
|
|
|
8
|
*DBI::db::selectrow_arrayref = _ORG_DB_SELECTROW_ARRAYREF; |
77
|
5
|
|
|
|
|
14
|
*DBI::db::selectrow_array = _ORG_DB_SELECTROW_ARRAY; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
5
|
|
|
|
|
14
|
$is_enabled = 0; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
*enable = *begin = \&import; |
84
|
|
|
|
|
|
|
*disable = *end = \&unimport; |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub guard { |
87
|
1
|
|
|
1
|
1
|
4050
|
my $org_is_enabled = DBIx::QueryLog->is_enabled; |
88
|
1
|
|
|
|
|
4
|
DBIx::QueryLog->enable(); |
89
|
1
|
|
|
|
|
5
|
return DBIx::QueryLog::Guard->new($org_is_enabled); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub ignore_trace { |
93
|
1
|
|
|
1
|
1
|
8
|
my $org_is_enabled = DBIx::QueryLog->is_enabled; |
94
|
1
|
|
|
|
|
4
|
DBIx::QueryLog->disable(); |
95
|
1
|
|
|
|
|
6
|
return DBIx::QueryLog::Guard->new($org_is_enabled); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
2
|
|
|
2
|
1
|
5
|
sub is_enabled { $is_enabled } |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
my $container = {}; |
101
|
|
|
|
|
|
|
for my $accessor (qw{ |
102
|
|
|
|
|
|
|
logger threshold probability skip_bind |
103
|
|
|
|
|
|
|
color useqq compact explain show_data_source |
104
|
|
|
|
|
|
|
}) { |
105
|
23
|
|
|
23
|
|
123
|
no strict 'refs'; |
|
23
|
|
|
|
|
34
|
|
|
23
|
|
|
|
|
1288
|
|
106
|
|
|
|
|
|
|
*{__PACKAGE__."::$accessor"} = sub { |
107
|
23
|
|
|
23
|
|
98
|
use strict 'refs'; |
|
23
|
|
|
|
|
28
|
|
|
23
|
|
|
|
|
12661
|
|
108
|
53
|
|
|
53
|
|
38925
|
my ($class, $args) = @_; |
109
|
53
|
100
|
|
|
|
277
|
return $container->{$accessor} unless @_ > 1; |
110
|
36
|
|
|
|
|
159
|
$container->{$accessor} = $args; |
111
|
|
|
|
|
|
|
}; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub _st_execute { |
115
|
22
|
|
|
22
|
|
43
|
my ($class, $org) = @_; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
return sub { |
118
|
15
|
50
|
|
15
|
|
5289
|
my $wantarray = wantarray ? 1 : 0; |
119
|
15
|
|
|
|
|
27
|
my $sth = shift; |
120
|
15
|
|
|
|
|
61
|
my @params = @_; |
121
|
15
|
|
|
|
|
18
|
my @types; |
122
|
|
|
|
|
|
|
|
123
|
15
|
|
33
|
|
|
81
|
my $probability = $container->{probability} || $ENV{DBIX_QUERYLOG_PROBABILITY}; |
124
|
15
|
50
|
33
|
|
|
44
|
if ($probability && int(rand() * $probability) % $probability != 0) { |
125
|
0
|
|
|
|
|
0
|
return $org->($sth, @params); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
15
|
|
|
|
|
72
|
my $dbh = $sth->{Database}; |
129
|
15
|
|
|
|
|
68
|
my $ret = $sth->{Statement}; |
130
|
15
|
100
|
|
|
|
302
|
if (my $attrs = $sth->{private_DBIx_QueryLog_attrs}) { |
131
|
5
|
|
|
|
|
13
|
my $bind_params = $sth->{private_DBIx_QueryLog_params}; |
132
|
5
|
|
|
|
|
14
|
for my $i (1..@$attrs) { |
133
|
6
|
|
|
|
|
13
|
push @types, $attrs->[$i - 1]{TYPE}; |
134
|
6
|
50
|
|
|
|
21
|
push @params, $bind_params->[$i - 1] if $bind_params; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
# DBD::Pg::st warns "undef in subroutine" |
138
|
15
|
50
|
|
|
|
247
|
$sth->{private_DBIx_QueryLog_params} = $dbh->{Driver}{Name} eq 'Pg' ? '' : undef; |
139
|
|
|
|
|
|
|
|
140
|
15
|
|
|
|
|
33
|
my $explain; |
141
|
15
|
100
|
100
|
|
|
87
|
if ($container->{explain} || $ENV{DBIX_QUERYLOG_EXPLAIN}) { |
142
|
2
|
|
|
|
|
7
|
$explain = _explain($dbh, $ret, \@params, \@types); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
15
|
100
|
100
|
|
|
113
|
unless (($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) && @params) { |
|
|
|
66
|
|
|
|
|
146
|
9
|
|
|
|
|
30
|
$ret = _bind($dbh, $ret, \@params, \@types); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
15
|
|
|
|
|
81
|
my $begin = [gettimeofday]; |
150
|
15
|
50
|
|
|
|
717
|
my $res = $wantarray ? [$org->($sth, @_)] : scalar $org->($sth, @_); |
151
|
15
|
|
|
|
|
96
|
my $time = sprintf '%.6f', tv_interval $begin, [gettimeofday]; |
152
|
|
|
|
|
|
|
|
153
|
15
|
|
|
|
|
413
|
$class->_logging($dbh, $ret, $time, \@params, $explain); |
154
|
|
|
|
|
|
|
|
155
|
15
|
50
|
|
|
|
2064
|
return $wantarray ? @$res : $res; |
156
|
22
|
|
|
|
|
187
|
}; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub _st_bind_param { |
160
|
22
|
|
|
22
|
|
36
|
my ($class, $org) = @_; |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
return sub { |
163
|
6
|
|
|
6
|
|
7567
|
my ($sth, $p_num, $value, $attr) = @_; |
164
|
6
|
|
100
|
|
|
110
|
$sth->{private_DBIx_QueryLog_params} ||= []; |
165
|
6
|
|
100
|
|
|
52
|
$sth->{private_DBIx_QueryLog_attrs } ||= []; |
166
|
6
|
50
|
50
|
|
|
41
|
$attr = +{ TYPE => $attr || 0 } unless ref $attr eq 'HASH'; |
167
|
6
|
|
|
|
|
29
|
$sth->{private_DBIx_QueryLog_params}[$p_num - 1] = $value; |
168
|
6
|
|
|
|
|
24
|
$sth->{private_DBIx_QueryLog_attrs }[$p_num - 1] = $attr; |
169
|
6
|
|
|
|
|
32
|
$org->(@_); |
170
|
22
|
|
|
|
|
105
|
}; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub _select_array { |
174
|
66
|
|
|
66
|
|
100
|
my ($class, $org, $is_selectrow_array) = @_; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
return sub { |
177
|
12
|
|
|
12
|
|
18917
|
my $wantarray = wantarray; |
178
|
12
|
|
|
|
|
28
|
my ($dbh, $stmt, $attr, @bind) = @_; |
179
|
|
|
|
|
|
|
|
180
|
23
|
|
|
23
|
|
123
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
33
|
|
|
23
|
|
|
|
|
15506
|
|
181
|
12
|
|
|
|
|
28
|
local *DBI::st::execute = _ORG_EXECUTE; # suppress duplicate logging |
182
|
|
|
|
|
|
|
|
183
|
12
|
|
33
|
|
|
66
|
my $probability = $container->{probability} || $ENV{DBIX_QUERYLOG_PROBABILITY}; |
184
|
12
|
50
|
33
|
|
|
109
|
if ($probability && int(rand() * $probability) % $probability != 0) { |
185
|
0
|
|
|
|
|
0
|
return $org->($dbh, $stmt, $attr, @bind); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
12
|
50
|
|
|
|
29
|
my $ret = ref $stmt ? $stmt->{Statement} : $stmt; |
189
|
|
|
|
|
|
|
|
190
|
12
|
|
|
|
|
13
|
my $explain; |
191
|
12
|
100
|
100
|
|
|
57
|
if ($container->{explain} || $ENV{DBIX_QUERYLOG_EXPLAIN}) { |
192
|
6
|
|
|
|
|
13
|
$explain = _explain($dbh, $ret, \@bind); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
12
|
100
|
66
|
|
|
71
|
unless (($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) && @bind) { |
|
|
|
66
|
|
|
|
|
196
|
11
|
|
|
|
|
31
|
$ret = _bind($dbh, $ret, \@bind); |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
12
|
|
|
|
|
51
|
my $begin = [gettimeofday]; |
200
|
12
|
|
|
|
|
16
|
my $res; |
201
|
12
|
100
|
|
|
|
28
|
if ($is_selectrow_array) { |
202
|
5
|
50
|
|
|
|
47
|
$res = $wantarray ? [$org->($dbh, $stmt, $attr, @bind)] : $org->($dbh, $stmt, $attr, @bind); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
else { |
205
|
7
|
|
|
|
|
49
|
$res = $org->($dbh, $stmt, $attr, @bind); |
206
|
|
|
|
|
|
|
} |
207
|
12
|
|
|
|
|
1797
|
my $time = sprintf '%.6f', tv_interval $begin, [gettimeofday]; |
208
|
|
|
|
|
|
|
|
209
|
12
|
|
|
|
|
280
|
$class->_logging($dbh, $ret, $time, \@bind, $explain); |
210
|
|
|
|
|
|
|
|
211
|
12
|
100
|
|
|
|
5888
|
if ($is_selectrow_array) { |
212
|
5
|
50
|
|
|
|
60
|
return $wantarray ? @$res : $res; |
213
|
|
|
|
|
|
|
} |
214
|
7
|
|
|
|
|
83
|
return $res; |
215
|
66
|
|
|
|
|
290
|
}; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub _db_do { |
219
|
22
|
|
|
22
|
|
41
|
my ($class, $org) = @_; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
return sub { |
222
|
330
|
50
|
|
330
|
|
179004
|
my $wantarray = wantarray ? 1 : 0; |
223
|
330
|
|
|
|
|
601
|
my ($dbh, $stmt, $attr, @bind) = @_; |
224
|
|
|
|
|
|
|
|
225
|
330
|
100
|
33
|
|
|
9089
|
if ($dbh->{Driver}{Name} ne 'mysql' && $dbh->{Driver}{Name} ne 'Pg' && !($dbh->{Driver}{Name} eq 'SQLite' && _HAS_SQLITE && !@bind)) { |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
226
|
8
|
|
|
|
|
45
|
return $org->($dbh, $stmt, $attr, @bind); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
322
|
|
100
|
|
|
1886
|
my $probability = $container->{probability} || $ENV{DBIX_QUERYLOG_PROBABILITY}; |
230
|
322
|
100
|
100
|
|
|
1310
|
if ($probability && int(rand() * $probability) % $probability != 0) { |
231
|
176
|
|
|
|
|
667
|
return $org->($dbh, $stmt, $attr, @bind); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
146
|
|
|
|
|
251
|
my $ret = $stmt; |
235
|
|
|
|
|
|
|
|
236
|
146
|
|
|
|
|
140
|
my $explain; |
237
|
146
|
100
|
100
|
|
|
612
|
if ($container->{explain} || $ENV{DBIX_QUERYLOG_EXPLAIN}) { |
238
|
6
|
|
|
|
|
12
|
$explain = _explain($dbh, $ret, \@bind); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
146
|
50
|
33
|
|
|
672
|
unless (($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) && @bind) { |
|
|
|
33
|
|
|
|
|
242
|
146
|
|
|
|
|
340
|
$ret = _bind($dbh, $ret, \@bind); |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
146
|
|
|
|
|
537
|
my $begin = [gettimeofday]; |
246
|
146
|
50
|
|
|
|
717
|
my $res = $wantarray ? [$org->($dbh, $stmt, $attr, @bind)] : scalar $org->($dbh, $stmt, $attr, @bind); |
247
|
146
|
|
|
|
|
14407
|
my $time = sprintf '%.6f', tv_interval $begin, [gettimeofday]; |
248
|
|
|
|
|
|
|
|
249
|
146
|
|
|
|
|
3216
|
$class->_logging($dbh, $ret, $time, \@bind, $explain); |
250
|
|
|
|
|
|
|
|
251
|
146
|
50
|
|
|
|
2786
|
return $wantarray ? @$res : $res; |
252
|
22
|
|
|
|
|
118
|
}; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub _explain { |
256
|
14
|
|
|
14
|
|
22
|
my ($dbh, $ret, $params, $types) = @_; |
257
|
14
|
|
100
|
|
|
49
|
$types ||= []; |
258
|
|
|
|
|
|
|
|
259
|
14
|
50
|
|
|
|
85
|
return unless $ret =~ m| |
260
|
|
|
|
|
|
|
\A # at start of string |
261
|
|
|
|
|
|
|
(?: |
262
|
|
|
|
|
|
|
\s* # white space |
263
|
|
|
|
|
|
|
(?: /\* .*? \*/ )* # /* ... */ |
264
|
|
|
|
|
|
|
\s* # while space |
265
|
|
|
|
|
|
|
)* |
266
|
|
|
|
|
|
|
SELECT |
267
|
|
|
|
|
|
|
\s* # white space |
268
|
|
|
|
|
|
|
.+? # columns |
269
|
|
|
|
|
|
|
\s* # white space |
270
|
|
|
|
|
|
|
FROM |
271
|
|
|
|
|
|
|
\s* # white space |
272
|
|
|
|
|
|
|
|ixms; |
273
|
|
|
|
|
|
|
|
274
|
23
|
|
|
23
|
|
130
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
35
|
|
|
23
|
|
|
|
|
30917
|
|
275
|
14
|
|
|
|
|
22
|
local *DBI::st::execute = _ORG_EXECUTE; # suppress duplicate logging |
276
|
|
|
|
|
|
|
|
277
|
14
|
|
|
|
|
9
|
my $sth; |
278
|
14
|
50
|
33
|
|
|
257
|
if ($dbh->{Driver}{Name} eq 'mysql' || $dbh->{Driver}{Name} eq 'Pg') { |
|
|
50
|
|
|
|
|
|
279
|
0
|
|
|
|
|
0
|
my $sql = 'EXPLAIN ' . _bind($dbh, $ret, $params, $types); |
280
|
0
|
|
|
|
|
0
|
$sth = $dbh->prepare($sql); |
281
|
0
|
|
|
|
|
0
|
$sth->execute; |
282
|
|
|
|
|
|
|
} elsif ($dbh->{Driver}{Name} eq 'SQLite') { |
283
|
14
|
|
|
|
|
25
|
my $sql = 'EXPLAIN QUERY PLAN ' . _bind($dbh, $ret, $params, $types); |
284
|
14
|
|
|
|
|
61
|
$sth = $dbh->prepare($sql); |
285
|
14
|
|
|
|
|
864
|
$sth->execute; |
286
|
|
|
|
|
|
|
} else { |
287
|
|
|
|
|
|
|
# not supported |
288
|
0
|
|
|
|
|
0
|
return; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
return sub { |
292
|
14
|
|
|
14
|
|
29
|
my %args = @_; |
293
|
|
|
|
|
|
|
|
294
|
14
|
100
|
66
|
|
|
84
|
return $sth->fetchall_arrayref(+{}) unless defined $args{print} and $args{print}; |
295
|
|
|
|
|
|
|
|
296
|
10
|
|
|
|
|
47
|
my $t = Text::ASCIITable->new(); |
297
|
10
|
|
|
|
|
265
|
$t->setCols(@{$sth->{NAME}}); |
|
10
|
|
|
|
|
123
|
|
298
|
10
|
50
|
|
|
|
861
|
$t->addRow(map { defined($_) ? $_ : 'NULL' } @$_) for @{$sth->fetchall_arrayref}; |
|
10
|
|
|
|
|
153
|
|
|
40
|
|
|
|
|
75
|
|
299
|
|
|
|
|
|
|
|
300
|
10
|
|
|
|
|
1687
|
return $t; |
301
|
14
|
|
|
|
|
105
|
}; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
sub _bind { |
305
|
180
|
|
|
180
|
|
233
|
my ($dbh, $ret, $params, $types) = @_; |
306
|
180
|
|
100
|
|
|
580
|
$types ||= []; |
307
|
180
|
|
|
|
|
184
|
my $i = 0; |
308
|
180
|
50
|
33
|
|
|
2174
|
if ($dbh->{Driver}{Name} eq 'mysql' or $dbh->{Driver}{Name} eq 'Pg') { |
309
|
0
|
|
|
|
|
0
|
my $limit_flag = 0; |
310
|
0
|
|
|
|
|
0
|
$ret =~ s{([?)])}{ |
311
|
0
|
0
|
|
|
|
0
|
if ($1 eq '?') { |
|
|
0
|
|
|
|
|
|
312
|
0
|
|
0
|
|
|
0
|
$limit_flag ||= do { |
313
|
0
|
|
|
|
|
0
|
my $pos = pos $ret; |
314
|
0
|
0
|
0
|
|
|
0
|
($pos >= 6 && substr($ret, $pos - 6, 6) =~ /\A[Ll](?:IMIT|imit) \z/) ? 1 : 0; |
315
|
|
|
|
|
|
|
}; |
316
|
0
|
0
|
|
|
|
0
|
if ($limit_flag) { |
317
|
0
|
|
|
|
|
0
|
$params->[$i++] |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
else { |
320
|
0
|
|
|
|
|
0
|
my $type = $types->[$i]; |
321
|
0
|
0
|
0
|
|
|
0
|
if (defined $type and $dbh->{Driver}{Name} eq 'Pg' and $type == 0) { |
|
|
|
0
|
|
|
|
|
322
|
0
|
|
|
|
|
0
|
$type = undef; |
323
|
|
|
|
|
|
|
} |
324
|
0
|
0
|
|
|
|
0
|
$dbh->quote($params->[$i++], defined $type ? $type : ()); |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
elsif ($1 eq ')') { |
328
|
0
|
|
|
|
|
0
|
$limit_flag = 0; |
329
|
0
|
|
|
|
|
0
|
')'; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
}eg; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
else { |
334
|
180
|
|
|
|
|
423
|
$ret =~ s/\?/$dbh->quote($params->[$i], $types->[$i++])/eg; |
|
16
|
|
|
|
|
159
|
|
335
|
|
|
|
|
|
|
} |
336
|
180
|
|
|
|
|
635
|
return $ret; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub _logging { |
340
|
173
|
|
|
173
|
|
346
|
my ($class, $dbh, $ret, $time, $bind_params, $explain) = @_; |
341
|
|
|
|
|
|
|
|
342
|
173
|
|
100
|
|
|
867
|
my $threshold = $container->{threshold} || $ENV{DBIX_QUERYLOG_THRESHOLD}; |
343
|
173
|
100
|
66
|
|
|
438
|
return unless !$threshold || $time > $threshold; |
344
|
|
|
|
|
|
|
|
345
|
171
|
|
50
|
|
|
310
|
$bind_params ||= []; |
346
|
|
|
|
|
|
|
|
347
|
171
|
|
|
|
|
206
|
my $i = 0; |
348
|
171
|
|
|
|
|
572
|
my $caller = { pkg => '???', line => '???', file => '???' }; |
349
|
171
|
|
|
|
|
1533
|
while (my @c = caller(++$i)) { |
350
|
187
|
100
|
66
|
|
|
809
|
if (!$SKIP_PKG_MAP{$c[0]} and $c[0] !~ /^DB[DI]::/) { |
351
|
171
|
|
|
|
|
505
|
$caller = { pkg => $c[0], file => $c[1], line => $c[2] }; |
352
|
171
|
|
|
|
|
627
|
last; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
171
|
|
|
|
|
227
|
my $sql = $ret; |
357
|
171
|
100
|
100
|
|
|
729
|
if ($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) { |
358
|
7
|
|
|
|
|
9
|
local $" = ', '; |
359
|
7
|
50
|
|
|
|
24
|
$ret .= " : [@$bind_params]" if @$bind_params; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
171
|
100
|
66
|
|
|
643
|
if ($container->{compact} || $ENV{DBIX_QUERYLOG_COMPACT}) { |
363
|
2
|
|
|
|
|
6
|
my ($buff, $i) = ('', 0); |
364
|
2
|
|
|
|
|
9
|
my $skip_space = 0; |
365
|
2
|
|
|
|
|
8
|
my $before_escape = 0; |
366
|
2
|
|
|
|
|
4
|
my $quote_char = ''; |
367
|
2
|
|
|
|
|
14
|
for (my ($i, $l) = (0, length $ret); $i < $l; ++$i) { |
368
|
284
|
|
|
|
|
256
|
my $s = substr $ret, $i, 1; |
369
|
284
|
100
|
100
|
|
|
2319
|
if (!$quote_char && ($s eq q{ }||$s eq "\n"||$s eq "\t"||$s eq "\r")) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
370
|
97
|
100
|
|
|
|
165
|
next if $skip_space; |
371
|
46
|
|
|
|
|
42
|
$buff .= q{ }; |
372
|
46
|
|
|
|
|
35
|
$skip_space = 1; |
373
|
46
|
|
|
|
|
68
|
next; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
elsif ($s eq q{'} || $s eq q{"} || $s eq q{`}) { |
376
|
20
|
100
|
100
|
|
|
44
|
unless ($quote_char) { |
|
|
100
|
|
|
|
|
|
377
|
8
|
|
|
|
|
10
|
$quote_char = $s; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
elsif (!$before_escape && $s eq $quote_char) { |
380
|
7
|
|
|
|
|
8
|
$quote_char = ''; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
else { |
383
|
5
|
|
|
|
|
6
|
$before_escape = 0; |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
elsif (!$before_escape && $quote_char && $s eq q{\\}) { |
387
|
1
|
|
|
|
|
1
|
$before_escape = 1; |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
elsif (!$quote_char) { |
390
|
133
|
100
|
100
|
|
|
565
|
if ($s eq q{(}) { |
|
|
100
|
66
|
|
|
|
|
391
|
2
|
|
|
|
|
1
|
$buff .= $s; |
392
|
2
|
|
|
|
|
2
|
$skip_space = 1; |
393
|
2
|
|
|
|
|
3
|
next; |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
elsif (($s eq q{)}||$s eq q{,}) && substr($buff, -1, 1) eq q{ }) { |
396
|
4
|
|
|
|
|
4
|
substr($buff, -1, 1) = ''; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
} |
399
|
185
|
|
|
|
|
141
|
$buff .= $s; |
400
|
185
|
|
|
|
|
273
|
$skip_space = 0; |
401
|
|
|
|
|
|
|
} |
402
|
2
|
|
|
|
|
34
|
($ret = $buff) =~ s/^\s|\s$//g; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
171
|
100
|
66
|
|
|
659
|
if ($container->{useqq} || $ENV{DBIX_QUERYLOG_USEQQ}) { |
406
|
2
|
|
|
|
|
6
|
local $Data::Dumper::Useqq = 1; |
407
|
2
|
|
|
|
|
4
|
local $Data::Dumper::Terse = 1; |
408
|
2
|
|
|
|
|
7
|
local $Data::Dumper::Indent = 0; |
409
|
2
|
|
|
|
|
14
|
$ret = Data::Dumper::Dumper($ret); |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
171
|
|
66
|
|
|
743
|
my $color = $container->{color} || $ENV{DBIX_QUERYLOG_COLOR}; |
413
|
171
|
|
|
|
|
197
|
my $localtime = do { |
414
|
171
|
|
|
|
|
4631
|
my ($sec, $min, $hour, $day, $mon, $year) = localtime; |
415
|
171
|
|
|
|
|
958
|
sprintf '%d-%02d-%02dT%02d:%02d:%02d', $year + 1900, $mon + 1, $day, $hour, $min, $sec; |
416
|
|
|
|
|
|
|
}; |
417
|
171
|
|
|
|
|
2147
|
my $data_source = "$dbh->{Driver}{Name}:$dbh->{Name}"; |
418
|
171
|
100
|
100
|
|
|
1694
|
my $message = sprintf "[%s] [%s] [%s] %s%s at %s line %s\n", |
|
|
100
|
|
|
|
|
|
419
|
|
|
|
|
|
|
$localtime, $caller->{pkg}, $time, |
420
|
|
|
|
|
|
|
$container->{show_data_source} || $ENV{DBIX_QUERYLOG_SHOW_DATASOURCE} ? "[$data_source] " : '', |
421
|
|
|
|
|
|
|
$color ? colored([$color], $ret) : $ret, |
422
|
|
|
|
|
|
|
$caller->{file}, $caller->{line}; |
423
|
|
|
|
|
|
|
|
424
|
171
|
100
|
|
|
|
401
|
if (my $logger = $container->{logger}) { |
425
|
3
|
100
|
|
|
|
15
|
my %explain = $explain ? (explain => $explain->()) : (); |
426
|
3
|
|
|
|
|
197
|
$logger->log( |
427
|
|
|
|
|
|
|
level => $LOG_LEVEL, |
428
|
|
|
|
|
|
|
message => $message, |
429
|
|
|
|
|
|
|
params => { |
430
|
|
|
|
|
|
|
dbh => $dbh, |
431
|
|
|
|
|
|
|
localtime => $localtime, |
432
|
|
|
|
|
|
|
time => $time, |
433
|
|
|
|
|
|
|
sql => $sql, |
434
|
|
|
|
|
|
|
bind_params => $bind_params, |
435
|
|
|
|
|
|
|
data_source => $data_source, |
436
|
|
|
|
|
|
|
%explain, |
437
|
|
|
|
|
|
|
%$caller, |
438
|
|
|
|
|
|
|
}, |
439
|
|
|
|
|
|
|
); |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
else { |
442
|
168
|
100
|
|
|
|
390
|
if (ref $OUTPUT eq 'CODE') { |
443
|
11
|
100
|
|
|
|
27
|
my %explain = $explain ? (explain => $explain->()) : (); |
444
|
11
|
|
|
|
|
171
|
$OUTPUT->( |
445
|
|
|
|
|
|
|
dbh => $dbh, |
446
|
|
|
|
|
|
|
level => $LOG_LEVEL, |
447
|
|
|
|
|
|
|
message => $message, |
448
|
|
|
|
|
|
|
localtime => $localtime, |
449
|
|
|
|
|
|
|
time => $time, |
450
|
|
|
|
|
|
|
sql => $sql, |
451
|
|
|
|
|
|
|
bind_params => $bind_params, |
452
|
|
|
|
|
|
|
data_source => $data_source, |
453
|
|
|
|
|
|
|
%explain, |
454
|
|
|
|
|
|
|
%$caller, |
455
|
|
|
|
|
|
|
); |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
else { |
458
|
157
|
100
|
|
|
|
164
|
print {$OUTPUT} $message, $explain ? $explain->(print => 1) : (); |
|
157
|
|
|
|
|
1069
|
|
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
{ |
464
|
|
|
|
|
|
|
package # hide from pause |
465
|
|
|
|
|
|
|
DBIx::QueryLog::Guard; |
466
|
|
|
|
|
|
|
sub new { |
467
|
2
|
|
|
2
|
|
3
|
my ($class, $org_is_enabled) = @_; |
468
|
2
|
|
|
|
|
7
|
bless [$org_is_enabled], shift; |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
sub DESTROY { |
471
|
2
|
100
|
|
2
|
|
2972
|
if (shift->[0]) { |
472
|
1
|
|
|
|
|
5
|
DBIx::QueryLog->enable(); |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
else { |
475
|
1
|
|
|
|
|
5
|
DBIx::QueryLog->disable(); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
1; |
481
|
|
|
|
|
|
|
__END__ |