line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DBIx::QueryLog; |
2
|
|
|
|
|
|
|
|
3
|
23
|
|
|
23
|
|
2901087
|
use strict; |
|
23
|
|
|
|
|
257
|
|
|
23
|
|
|
|
|
696
|
|
4
|
23
|
|
|
23
|
|
123
|
use warnings; |
|
23
|
|
|
|
|
44
|
|
|
23
|
|
|
|
|
627
|
|
5
|
23
|
|
|
23
|
|
486
|
use 5.008_001; |
|
23
|
|
|
|
|
83
|
|
6
|
|
|
|
|
|
|
|
7
|
23
|
|
|
23
|
|
4892
|
use DBI; |
|
23
|
|
|
|
|
53055
|
|
|
23
|
|
|
|
|
1353
|
|
8
|
23
|
|
|
23
|
|
1842
|
use Time::HiRes qw(gettimeofday tv_interval); |
|
23
|
|
|
|
|
3786
|
|
|
23
|
|
|
|
|
203
|
|
9
|
23
|
|
|
23
|
|
17048
|
use Term::ANSIColor qw(colored); |
|
23
|
|
|
|
|
198602
|
|
|
23
|
|
|
|
|
39176
|
|
10
|
23
|
|
|
23
|
|
14070
|
use Text::ASCIITable; |
|
23
|
|
|
|
|
179356
|
|
|
23
|
|
|
|
|
1222
|
|
11
|
23
|
|
|
23
|
|
1940
|
use Data::Dumper (); |
|
23
|
|
|
|
|
19979
|
|
|
23
|
|
|
|
|
1331
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
$ENV{ANSI_COLORS_DISABLED} = 1 if $^O eq 'MSWin32'; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.42'; |
16
|
|
|
|
|
|
|
|
17
|
23
|
|
|
23
|
|
145
|
use constant _ORG_EXECUTE => \&DBI::st::execute; |
|
23
|
|
|
|
|
46
|
|
|
23
|
|
|
|
|
1787
|
|
18
|
23
|
|
|
23
|
|
147
|
use constant _ORG_BIND_PARAM => \&DBI::st::bind_param; |
|
23
|
|
|
|
|
46
|
|
|
23
|
|
|
|
|
1279
|
|
19
|
23
|
|
|
23
|
|
135
|
use constant _ORG_DB_DO => \&DBI::db::do; |
|
23
|
|
|
|
|
41
|
|
|
23
|
|
|
|
|
1318
|
|
20
|
23
|
|
|
23
|
|
130
|
use constant _ORG_DB_SELECTALL_ARRAYREF => \&DBI::db::selectall_arrayref; |
|
23
|
|
|
|
|
45
|
|
|
23
|
|
|
|
|
1132
|
|
21
|
23
|
|
|
23
|
|
121
|
use constant _ORG_DB_SELECTROW_ARRAYREF => \&DBI::db::selectrow_arrayref; |
|
23
|
|
|
|
|
55
|
|
|
23
|
|
|
|
|
1410
|
|
22
|
23
|
|
|
23
|
|
149
|
use constant _ORG_DB_SELECTROW_ARRAY => \&DBI::db::selectrow_array; |
|
23
|
|
|
|
|
41
|
|
|
23
|
|
|
|
|
1936
|
|
23
|
|
|
|
|
|
|
|
24
|
23
|
50
|
|
23
|
|
176
|
use constant _HAS_MYSQL => eval { require DBD::mysql; 1 } ? 1 : 0; |
|
23
|
|
|
|
|
62
|
|
|
23
|
|
|
|
|
46
|
|
|
23
|
|
|
|
|
4809
|
|
|
0
|
|
|
|
|
0
|
|
25
|
23
|
50
|
|
23
|
|
182
|
use constant _HAS_PG => eval { require DBD::Pg; 1 } ? 1 : 0; |
|
23
|
|
|
|
|
61
|
|
|
23
|
|
|
|
|
74
|
|
|
23
|
|
|
|
|
4397
|
|
|
0
|
|
|
|
|
0
|
|
26
|
23
|
50
|
|
23
|
|
177
|
use constant _HAS_SQLITE => eval { require DBD::SQLite; DBD::SQLite->VERSION(1.48); 1 } ? 1 : 0; |
|
23
|
|
|
|
|
52
|
|
|
23
|
|
|
|
|
41
|
|
|
23
|
|
|
|
|
2337
|
|
|
23
|
|
|
|
|
33622
|
|
|
23
|
|
|
|
|
1725
|
|
27
|
23
|
50
|
|
23
|
|
155
|
use constant _PP_MODE => $INC{'DBI/PurePerl.pm'} ? 1 : 0; |
|
23
|
|
|
|
|
53
|
|
|
23
|
|
|
|
|
5025
|
|
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
|
|
11670
|
my ($class) = @_; |
46
|
|
|
|
|
|
|
|
47
|
24
|
|
66
|
|
|
165
|
$st_execute ||= $class->_st_execute(_ORG_EXECUTE); |
48
|
24
|
|
66
|
|
|
131
|
$st_bind_param ||= $class->_st_bind_param(_ORG_BIND_PARAM); |
49
|
24
|
|
66
|
|
|
128
|
$db_do ||= $class->_db_do(_ORG_DB_DO) if _HAS_MYSQL or _HAS_PG or _HAS_SQLITE; |
50
|
24
|
|
|
|
|
35
|
unless (_PP_MODE) { |
51
|
24
|
|
66
|
|
|
128
|
$selectall_arrayref ||= $class->_select_array(_ORG_DB_SELECTALL_ARRAYREF); |
52
|
24
|
|
66
|
|
|
125
|
$selectrow_arrayref ||= $class->_select_array(_ORG_DB_SELECTROW_ARRAYREF); |
53
|
24
|
|
66
|
|
|
197
|
$selectrow_array ||= $class->_select_array(_ORG_DB_SELECTROW_ARRAY, 1); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
23
|
|
|
23
|
|
169
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
45
|
|
|
23
|
|
|
|
|
3202
|
|
57
|
24
|
|
|
|
|
112
|
*DBI::st::execute = $st_execute; |
58
|
24
|
|
|
|
|
59
|
*DBI::st::bind_param = $st_bind_param; |
59
|
24
|
|
|
|
|
69
|
*DBI::db::do = $db_do if _HAS_MYSQL or _HAS_PG or _HAS_SQLITE; |
60
|
24
|
|
|
|
|
39
|
unless (_PP_MODE) { |
61
|
24
|
|
|
|
|
100
|
*DBI::db::selectall_arrayref = $selectall_arrayref; |
62
|
24
|
|
|
|
|
45
|
*DBI::db::selectrow_arrayref = $selectrow_arrayref; |
63
|
24
|
|
|
|
|
48
|
*DBI::db::selectrow_array = $selectrow_array; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
24
|
|
|
|
|
25067
|
$is_enabled = 1; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub unimport { |
70
|
23
|
|
|
23
|
|
171
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
44
|
|
|
23
|
|
|
|
|
6199
|
|
71
|
5
|
|
|
5
|
|
45193
|
*DBI::st::execute = _ORG_EXECUTE; |
72
|
5
|
|
|
|
|
15
|
*DBI::st::bind_param = _ORG_BIND_PARAM; |
73
|
5
|
|
|
|
|
15
|
*DBI::db::do = _ORG_DB_DO if _HAS_MYSQL or _HAS_PG or _HAS_SQLITE; |
74
|
5
|
|
|
|
|
10
|
unless (_PP_MODE) { |
75
|
5
|
|
|
|
|
29
|
*DBI::db::selectall_arrayref = _ORG_DB_SELECTALL_ARRAYREF; |
76
|
5
|
|
|
|
|
16
|
*DBI::db::selectrow_arrayref = _ORG_DB_SELECTROW_ARRAYREF; |
77
|
5
|
|
|
|
|
12
|
*DBI::db::selectrow_array = _ORG_DB_SELECTROW_ARRAY; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
5
|
|
|
|
|
18
|
$is_enabled = 0; |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
*enable = *begin = \&import; |
84
|
|
|
|
|
|
|
*disable = *end = \&unimport; |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub guard { |
87
|
1
|
|
|
1
|
1
|
4881
|
my $org_is_enabled = DBIx::QueryLog->is_enabled; |
88
|
1
|
|
|
|
|
5
|
DBIx::QueryLog->enable(); |
89
|
1
|
|
|
|
|
8
|
return DBIx::QueryLog::Guard->new($org_is_enabled); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub ignore_trace { |
93
|
1
|
|
|
1
|
1
|
10
|
my $org_is_enabled = DBIx::QueryLog->is_enabled; |
94
|
1
|
|
|
|
|
11
|
DBIx::QueryLog->disable(); |
95
|
1
|
|
|
|
|
7
|
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
|
|
633
|
no strict 'refs'; |
|
23
|
|
|
|
|
66
|
|
|
23
|
|
|
|
|
1366
|
|
106
|
|
|
|
|
|
|
*{__PACKAGE__."::$accessor"} = sub { |
107
|
23
|
|
|
23
|
|
140
|
use strict 'refs'; |
|
23
|
|
|
|
|
40
|
|
|
23
|
|
|
|
|
15211
|
|
108
|
53
|
|
|
53
|
|
68202
|
my ($class, $args) = @_; |
109
|
53
|
100
|
|
|
|
271
|
return $container->{$accessor} unless @_ > 1; |
110
|
36
|
|
|
|
|
156
|
$container->{$accessor} = $args; |
111
|
|
|
|
|
|
|
}; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub _st_execute { |
115
|
22
|
|
|
22
|
|
56
|
my ($class, $org) = @_; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
return sub { |
118
|
17
|
50
|
|
17
|
|
8224
|
my $wantarray = wantarray ? 1 : 0; |
119
|
17
|
|
|
|
|
46
|
my $sth = shift; |
120
|
17
|
|
|
|
|
44
|
my @params = @_; |
121
|
17
|
|
|
|
|
33
|
my @types; |
122
|
|
|
|
|
|
|
|
123
|
17
|
|
33
|
|
|
95
|
my $probability = $container->{probability} || $ENV{DBIX_QUERYLOG_PROBABILITY}; |
124
|
17
|
50
|
33
|
|
|
69
|
if ($probability && int(rand() * $probability) % $probability != 0) { |
125
|
0
|
|
|
|
|
0
|
return $org->($sth, @params); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
17
|
|
|
|
|
137
|
my $dbh = $sth->{Database}; |
129
|
17
|
|
|
|
|
100
|
my $ret = $sth->{Statement}; |
130
|
17
|
100
|
|
|
|
130
|
if (my $attrs = $sth->{private_DBIx_QueryLog_attrs}) { |
131
|
7
|
|
|
|
|
25
|
my $bind_params = $sth->{private_DBIx_QueryLog_params}; |
132
|
7
|
|
|
|
|
30
|
for my $i (1..@$attrs) { |
133
|
10
|
|
|
|
|
28
|
push @types, $attrs->[$i - 1]{TYPE}; |
134
|
10
|
50
|
|
|
|
32
|
push @params, $bind_params->[$i - 1] if $bind_params; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
# DBD::Pg::st warns "undef in subroutine" |
138
|
17
|
50
|
|
|
|
271
|
$sth->{private_DBIx_QueryLog_params} = $dbh->{Driver}{Name} eq 'Pg' ? '' : undef; |
139
|
|
|
|
|
|
|
|
140
|
17
|
|
|
|
|
57
|
my $explain; |
141
|
17
|
100
|
100
|
|
|
108
|
if ($container->{explain} || $ENV{DBIX_QUERYLOG_EXPLAIN}) { |
142
|
2
|
|
|
|
|
9
|
$explain = _explain($dbh, $ret, \@params, \@types); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
17
|
100
|
100
|
|
|
118
|
unless (($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) && @params) { |
|
|
|
66
|
|
|
|
|
146
|
9
|
|
|
|
|
43
|
$ret = _bind($dbh, $ret, \@params, \@types); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
17
|
|
|
|
|
117
|
my $begin = [gettimeofday]; |
150
|
17
|
50
|
|
|
|
988
|
my $res = $wantarray ? [$org->($sth, @_)] : scalar $org->($sth, @_); |
151
|
17
|
|
|
|
|
167
|
my $time = sprintf '%.6f', tv_interval $begin, [gettimeofday]; |
152
|
|
|
|
|
|
|
|
153
|
17
|
|
|
|
|
550
|
$class->_logging($dbh, $ret, $time, \@params, $explain); |
154
|
|
|
|
|
|
|
|
155
|
17
|
50
|
|
|
|
2454
|
return $wantarray ? @$res : $res; |
156
|
22
|
|
|
|
|
206
|
}; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub _st_bind_param { |
160
|
22
|
|
|
22
|
|
59
|
my ($class, $org) = @_; |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
return sub { |
163
|
10
|
|
|
10
|
|
19483
|
my ($sth, $p_num, $value, $attr) = @_; |
164
|
10
|
|
100
|
|
|
175
|
$sth->{private_DBIx_QueryLog_params} ||= []; |
165
|
10
|
|
100
|
|
|
100
|
$sth->{private_DBIx_QueryLog_attrs } ||= []; |
166
|
10
|
50
|
50
|
|
|
60
|
$attr = +{ TYPE => $attr || 0 } unless ref $attr eq 'HASH'; |
167
|
10
|
|
|
|
|
49
|
$sth->{private_DBIx_QueryLog_params}[$p_num - 1] = $value; |
168
|
10
|
|
|
|
|
41
|
$sth->{private_DBIx_QueryLog_attrs }[$p_num - 1] = $attr; |
169
|
10
|
|
|
|
|
60
|
$org->(@_); |
170
|
22
|
|
|
|
|
142
|
}; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub _select_array { |
174
|
66
|
|
|
66
|
|
157
|
my ($class, $org, $is_selectrow_array) = @_; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
return sub { |
177
|
12
|
|
|
12
|
|
34333
|
my $wantarray = wantarray; |
178
|
12
|
|
|
|
|
43
|
my ($dbh, $stmt, $attr, @bind) = @_; |
179
|
|
|
|
|
|
|
|
180
|
23
|
|
|
23
|
|
174
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
50
|
|
|
23
|
|
|
|
|
17386
|
|
181
|
12
|
|
|
|
|
46
|
local *DBI::st::execute = _ORG_EXECUTE; # suppress duplicate logging |
182
|
|
|
|
|
|
|
|
183
|
12
|
|
33
|
|
|
79
|
my $probability = $container->{probability} || $ENV{DBIX_QUERYLOG_PROBABILITY}; |
184
|
12
|
50
|
33
|
|
|
55
|
if ($probability && int(rand() * $probability) % $probability != 0) { |
185
|
0
|
|
|
|
|
0
|
return $org->($dbh, $stmt, $attr, @bind); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
12
|
50
|
|
|
|
39
|
my $ret = ref $stmt ? $stmt->{Statement} : $stmt; |
189
|
|
|
|
|
|
|
|
190
|
12
|
|
|
|
|
20
|
my $explain; |
191
|
12
|
100
|
100
|
|
|
66
|
if ($container->{explain} || $ENV{DBIX_QUERYLOG_EXPLAIN}) { |
192
|
6
|
|
|
|
|
15
|
$explain = _explain($dbh, $ret, \@bind); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
12
|
100
|
66
|
|
|
81
|
unless (($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) && @bind) { |
|
|
|
66
|
|
|
|
|
196
|
11
|
|
|
|
|
41
|
$ret = _bind($dbh, $ret, \@bind); |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
12
|
|
|
|
|
80
|
my $begin = [gettimeofday]; |
200
|
12
|
|
|
|
|
22
|
my $res; |
201
|
12
|
100
|
|
|
|
34
|
if ($is_selectrow_array) { |
202
|
5
|
50
|
|
|
|
67
|
$res = $wantarray ? [$org->($dbh, $stmt, $attr, @bind)] : $org->($dbh, $stmt, $attr, @bind); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
else { |
205
|
7
|
|
|
|
|
98
|
$res = $org->($dbh, $stmt, $attr, @bind); |
206
|
|
|
|
|
|
|
} |
207
|
12
|
|
|
|
|
2197
|
my $time = sprintf '%.6f', tv_interval $begin, [gettimeofday]; |
208
|
|
|
|
|
|
|
|
209
|
12
|
|
|
|
|
351
|
$class->_logging($dbh, $ret, $time, \@bind, $explain); |
210
|
|
|
|
|
|
|
|
211
|
12
|
100
|
|
|
|
6679
|
if ($is_selectrow_array) { |
212
|
5
|
50
|
|
|
|
72
|
return $wantarray ? @$res : $res; |
213
|
|
|
|
|
|
|
} |
214
|
7
|
|
|
|
|
102
|
return $res; |
215
|
66
|
|
|
|
|
617
|
}; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub _db_do { |
219
|
22
|
|
|
22
|
|
56
|
my ($class, $org) = @_; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
return sub { |
222
|
332
|
50
|
|
332
|
|
102205
|
my $wantarray = wantarray ? 1 : 0; |
223
|
332
|
|
|
|
|
757
|
my ($dbh, $stmt, $attr, @bind) = @_; |
224
|
|
|
|
|
|
|
|
225
|
332
|
100
|
33
|
|
|
7499
|
if ($dbh->{Driver}{Name} ne 'mysql' && $dbh->{Driver}{Name} ne 'Pg' && !($dbh->{Driver}{Name} eq 'SQLite' && _HAS_SQLITE && !@bind)) { |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
226
|
8
|
|
|
|
|
65
|
return $org->($dbh, $stmt, $attr, @bind); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
324
|
|
100
|
|
|
1691
|
my $probability = $container->{probability} || $ENV{DBIX_QUERYLOG_PROBABILITY}; |
230
|
324
|
100
|
100
|
|
|
1284
|
if ($probability && int(rand() * $probability) % $probability != 0) { |
231
|
176
|
|
|
|
|
656
|
return $org->($dbh, $stmt, $attr, @bind); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
148
|
|
|
|
|
213
|
my $ret = $stmt; |
235
|
|
|
|
|
|
|
|
236
|
148
|
|
|
|
|
213
|
my $explain; |
237
|
148
|
100
|
100
|
|
|
542
|
if ($container->{explain} || $ENV{DBIX_QUERYLOG_EXPLAIN}) { |
238
|
8
|
|
|
|
|
22
|
$explain = _explain($dbh, $ret, \@bind); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
148
|
50
|
33
|
|
|
639
|
unless (($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) && @bind) { |
|
|
|
33
|
|
|
|
|
242
|
148
|
|
|
|
|
358
|
$ret = _bind($dbh, $ret, \@bind); |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
148
|
|
|
|
|
612
|
my $begin = [gettimeofday]; |
246
|
148
|
50
|
|
|
|
693
|
my $res = $wantarray ? [$org->($dbh, $stmt, $attr, @bind)] : scalar $org->($dbh, $stmt, $attr, @bind); |
247
|
146
|
|
|
|
|
14952
|
my $time = sprintf '%.6f', tv_interval $begin, [gettimeofday]; |
248
|
|
|
|
|
|
|
|
249
|
146
|
|
|
|
|
3972
|
$class->_logging($dbh, $ret, $time, \@bind, $explain); |
250
|
|
|
|
|
|
|
|
251
|
146
|
50
|
|
|
|
3143
|
return $wantarray ? @$res : $res; |
252
|
22
|
|
|
|
|
128
|
}; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub _explain { |
256
|
16
|
|
|
16
|
|
37
|
my ($dbh, $ret, $params, $types) = @_; |
257
|
16
|
|
100
|
|
|
59
|
$types ||= []; |
258
|
|
|
|
|
|
|
|
259
|
16
|
100
|
|
|
|
105
|
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
|
|
187
|
no warnings qw(redefine prototype); |
|
23
|
|
|
|
|
51
|
|
|
23
|
|
|
|
|
35110
|
|
275
|
14
|
|
|
|
|
36
|
local *DBI::st::execute = _ORG_EXECUTE; # suppress duplicate logging |
276
|
|
|
|
|
|
|
|
277
|
14
|
|
|
|
|
17
|
my $sth; |
278
|
14
|
50
|
33
|
|
|
249
|
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
|
|
|
|
|
37
|
my $sql = 'EXPLAIN QUERY PLAN ' . _bind($dbh, $ret, $params, $types); |
284
|
14
|
|
|
|
|
61
|
$sth = $dbh->prepare($sql); |
285
|
14
|
|
|
|
|
1034
|
$sth->execute; |
286
|
|
|
|
|
|
|
} else { |
287
|
|
|
|
|
|
|
# not supported |
288
|
0
|
|
|
|
|
0
|
return; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
14
|
50
|
|
|
|
155
|
return if $DBI::err; # skip if maybe statement error |
292
|
|
|
|
|
|
|
return sub { |
293
|
14
|
|
|
14
|
|
39
|
my %args = @_; |
294
|
|
|
|
|
|
|
|
295
|
14
|
100
|
66
|
|
|
92
|
return $sth->fetchall_arrayref(+{}) unless defined $args{print} and $args{print}; |
296
|
|
|
|
|
|
|
|
297
|
10
|
|
|
|
|
55
|
my $t = Text::ASCIITable->new(); |
298
|
10
|
|
|
|
|
254
|
$t->setCols(@{$sth->{NAME}}); |
|
10
|
|
|
|
|
150
|
|
299
|
10
|
50
|
|
|
|
951
|
$t->addRow(map { defined($_) ? $_ : 'NULL' } @$_) for @{$sth->fetchall_arrayref}; |
|
10
|
|
|
|
|
238
|
|
|
40
|
|
|
|
|
180
|
|
300
|
|
|
|
|
|
|
|
301
|
10
|
|
|
|
|
1453
|
return $t; |
302
|
14
|
|
|
|
|
145
|
}; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub _bind { |
306
|
182
|
|
|
182
|
|
385
|
my ($dbh, $ret, $params, $types) = @_; |
307
|
182
|
|
100
|
|
|
659
|
$types ||= []; |
308
|
182
|
|
|
|
|
273
|
my $i = 0; |
309
|
182
|
50
|
33
|
|
|
2109
|
if ($dbh->{Driver}{Name} eq 'mysql' or $dbh->{Driver}{Name} eq 'Pg') { |
310
|
0
|
|
|
|
|
0
|
my $limit_flag = 0; |
311
|
0
|
|
|
|
|
0
|
$ret =~ s{([?)])}{ |
312
|
0
|
0
|
|
|
|
0
|
if ($1 eq '?') { |
|
|
0
|
|
|
|
|
|
313
|
0
|
|
0
|
|
|
0
|
$limit_flag ||= do { |
314
|
0
|
|
|
|
|
0
|
my $pos = pos $ret; |
315
|
0
|
0
|
0
|
|
|
0
|
($pos >= 6 && substr($ret, $pos - 6, 6) =~ /\A[Ll](?:IMIT|imit) \z/) ? 1 : 0; |
316
|
|
|
|
|
|
|
}; |
317
|
0
|
0
|
|
|
|
0
|
if ($limit_flag) { |
318
|
0
|
|
|
|
|
0
|
$params->[$i++] |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
else { |
321
|
0
|
|
|
|
|
0
|
my $type = $types->[$i]; |
322
|
0
|
0
|
0
|
|
|
0
|
if (defined $type and $dbh->{Driver}{Name} eq 'Pg' and $type == 0) { |
|
|
|
0
|
|
|
|
|
323
|
0
|
|
|
|
|
0
|
$type = undef; |
324
|
|
|
|
|
|
|
} |
325
|
0
|
0
|
|
|
|
0
|
$dbh->quote($params->[$i++], defined $type ? $type : ()); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
elsif ($1 eq ')') { |
329
|
0
|
|
|
|
|
0
|
$limit_flag = 0; |
330
|
0
|
|
|
|
|
0
|
')'; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
}eg; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
else { |
335
|
182
|
|
|
|
|
569
|
$ret =~ s/\?/$dbh->quote($params->[$i], $types->[$i++])/eg; |
|
16
|
|
|
|
|
230
|
|
336
|
|
|
|
|
|
|
} |
337
|
182
|
|
|
|
|
777
|
return $ret; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub _logging { |
341
|
175
|
|
|
175
|
|
452
|
my ($class, $dbh, $ret, $time, $bind_params, $explain) = @_; |
342
|
|
|
|
|
|
|
|
343
|
175
|
|
100
|
|
|
826
|
my $threshold = $container->{threshold} || $ENV{DBIX_QUERYLOG_THRESHOLD}; |
344
|
175
|
100
|
66
|
|
|
464
|
return unless !$threshold || $time > $threshold; |
345
|
|
|
|
|
|
|
|
346
|
173
|
|
50
|
|
|
381
|
$bind_params ||= []; |
347
|
|
|
|
|
|
|
|
348
|
173
|
|
|
|
|
290
|
my $i = 0; |
349
|
173
|
|
|
|
|
696
|
my $caller = { pkg => '???', line => '???', file => '???' }; |
350
|
173
|
|
|
|
|
1536
|
while (my @c = caller(++$i)) { |
351
|
189
|
100
|
100
|
|
|
997
|
if (!$SKIP_PKG_MAP{$c[0]} and $c[0] !~ /^DB[DI]::/) { |
352
|
173
|
|
|
|
|
724
|
$caller = { pkg => $c[0], file => $c[1], line => $c[2] }; |
353
|
173
|
|
|
|
|
465
|
last; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
173
|
|
|
|
|
347
|
my $sql = $ret; |
358
|
173
|
100
|
100
|
|
|
722
|
if ($container->{skip_bind} || $ENV{DBIX_QUERYLOG_SKIP_BIND}) { |
359
|
9
|
|
|
|
|
21
|
local $" = ', '; |
360
|
9
|
50
|
|
|
|
20
|
if (@$bind_params) { |
361
|
9
|
100
|
|
|
|
21
|
my @bind_data = map { defined $_ ? $_ : 'NULL' } @$bind_params; |
|
11
|
|
|
|
|
86
|
|
362
|
9
|
|
|
|
|
41
|
$ret .= " : [@bind_data]"; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
173
|
100
|
66
|
|
|
648
|
if ($container->{compact} || $ENV{DBIX_QUERYLOG_COMPACT}) { |
367
|
2
|
|
|
|
|
7
|
my ($buff, $i) = ('', 0); |
368
|
2
|
|
|
|
|
4
|
my $skip_space = 0; |
369
|
2
|
|
|
|
|
4
|
my $before_escape = 0; |
370
|
2
|
|
|
|
|
4
|
my $quote_char = ''; |
371
|
2
|
|
|
|
|
23
|
for (my ($i, $l) = (0, length $ret); $i < $l; ++$i) { |
372
|
284
|
|
|
|
|
381
|
my $s = substr $ret, $i, 1; |
373
|
284
|
100
|
100
|
|
|
1924
|
if (!$quote_char && ($s eq q{ }||$s eq "\n"||$s eq "\t"||$s eq "\r")) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
374
|
97
|
100
|
|
|
|
193
|
next if $skip_space; |
375
|
46
|
|
|
|
|
84
|
$buff .= q{ }; |
376
|
46
|
|
|
|
|
53
|
$skip_space = 1; |
377
|
46
|
|
|
|
|
85
|
next; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
elsif ($s eq q{'} || $s eq q{"} || $s eq q{`}) { |
380
|
20
|
100
|
|
|
|
56
|
unless ($quote_char) { |
|
|
100
|
|
|
|
|
|
381
|
8
|
|
|
|
|
11
|
$quote_char = $s; |
382
|
|
|
|
|
|
|
} |
383
|
0
|
100
|
|
|
|
0
|
elsif (!$before_escape && $s eq $quote_char) { |
384
|
7
|
|
|
|
|
10
|
$quote_char = ''; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
else { |
387
|
5
|
|
|
|
|
6
|
$before_escape = 0; |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
elsif (!$before_escape && $quote_char && $s eq q{\\}) { |
391
|
1
|
|
|
|
|
2
|
$before_escape = 1; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
elsif (!$quote_char) { |
394
|
133
|
100
|
100
|
|
|
457
|
if ($s eq q{(}) { |
|
|
100
|
66
|
|
|
|
|
395
|
2
|
|
|
|
|
5
|
$buff .= $s; |
396
|
2
|
|
|
|
|
2
|
$skip_space = 1; |
397
|
2
|
|
|
|
|
5
|
next; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
elsif (($s eq q{)}||$s eq q{,}) && substr($buff, -1, 1) eq q{ }) { |
400
|
4
|
|
|
|
|
6
|
substr($buff, -1, 1) = ''; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
} |
403
|
185
|
|
|
|
|
240
|
$buff .= $s; |
404
|
185
|
|
|
|
|
320
|
$skip_space = 0; |
405
|
|
|
|
|
|
|
} |
406
|
2
|
|
|
|
|
51
|
($ret = $buff) =~ s/^\s|\s$//g; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
173
|
100
|
66
|
|
|
651
|
if ($container->{useqq} || $ENV{DBIX_QUERYLOG_USEQQ}) { |
410
|
2
|
|
|
|
|
6
|
local $Data::Dumper::Useqq = 1; |
411
|
2
|
|
|
|
|
6
|
local $Data::Dumper::Terse = 1; |
412
|
2
|
|
|
|
|
7
|
local $Data::Dumper::Indent = 0; |
413
|
2
|
|
|
|
|
12
|
$ret = Data::Dumper::Dumper($ret); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
173
|
|
66
|
|
|
719
|
my $color = $container->{color} || $ENV{DBIX_QUERYLOG_COLOR}; |
417
|
173
|
|
|
|
|
340
|
my $localtime = do { |
418
|
173
|
|
|
|
|
4214
|
my ($sec, $min, $hour, $day, $mon, $year) = localtime; |
419
|
173
|
|
|
|
|
1337
|
sprintf '%d-%02d-%02dT%02d:%02d:%02d', $year + 1900, $mon + 1, $day, $hour, $min, $sec; |
420
|
|
|
|
|
|
|
}; |
421
|
173
|
|
|
|
|
2447
|
my $data_source = "$dbh->{Driver}{Name}:$dbh->{Name}"; |
422
|
|
|
|
|
|
|
my $message = sprintf "[%s] [%s] [%s] %s%s at %s line %s\n", |
423
|
|
|
|
|
|
|
$localtime, $caller->{pkg}, $time, |
424
|
|
|
|
|
|
|
$container->{show_data_source} || $ENV{DBIX_QUERYLOG_SHOW_DATASOURCE} ? "[$data_source] " : '', |
425
|
|
|
|
|
|
|
$color ? colored([$color], $ret) : $ret, |
426
|
173
|
100
|
100
|
|
|
1783
|
$caller->{file}, $caller->{line}; |
|
|
100
|
|
|
|
|
|
427
|
|
|
|
|
|
|
|
428
|
173
|
100
|
|
|
|
674
|
if (my $logger = $container->{logger}) { |
429
|
3
|
100
|
|
|
|
41
|
my %explain = $explain ? (explain => $explain->()) : (); |
430
|
3
|
|
|
|
|
242
|
$logger->log( |
431
|
|
|
|
|
|
|
level => $LOG_LEVEL, |
432
|
|
|
|
|
|
|
message => $message, |
433
|
|
|
|
|
|
|
params => { |
434
|
|
|
|
|
|
|
dbh => $dbh, |
435
|
|
|
|
|
|
|
localtime => $localtime, |
436
|
|
|
|
|
|
|
time => $time, |
437
|
|
|
|
|
|
|
sql => $sql, |
438
|
|
|
|
|
|
|
bind_params => $bind_params, |
439
|
|
|
|
|
|
|
data_source => $data_source, |
440
|
|
|
|
|
|
|
%explain, |
441
|
|
|
|
|
|
|
%$caller, |
442
|
|
|
|
|
|
|
}, |
443
|
|
|
|
|
|
|
); |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
else { |
446
|
170
|
100
|
|
|
|
580
|
if (ref $OUTPUT eq 'CODE') { |
447
|
11
|
100
|
|
|
|
41
|
my %explain = $explain ? (explain => $explain->()) : (); |
448
|
11
|
|
|
|
|
225
|
$OUTPUT->( |
449
|
|
|
|
|
|
|
dbh => $dbh, |
450
|
|
|
|
|
|
|
level => $LOG_LEVEL, |
451
|
|
|
|
|
|
|
message => $message, |
452
|
|
|
|
|
|
|
localtime => $localtime, |
453
|
|
|
|
|
|
|
time => $time, |
454
|
|
|
|
|
|
|
sql => $sql, |
455
|
|
|
|
|
|
|
bind_params => $bind_params, |
456
|
|
|
|
|
|
|
data_source => $data_source, |
457
|
|
|
|
|
|
|
%explain, |
458
|
|
|
|
|
|
|
%$caller, |
459
|
|
|
|
|
|
|
); |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
else { |
462
|
159
|
100
|
|
|
|
251
|
print {$OUTPUT} $message, $explain ? $explain->(print => 1) : (); |
|
159
|
|
|
|
|
1045
|
|
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
{ |
468
|
|
|
|
|
|
|
package # hide from pause |
469
|
|
|
|
|
|
|
DBIx::QueryLog::Guard; |
470
|
|
|
|
|
|
|
sub new { |
471
|
2
|
|
|
2
|
|
8
|
my ($class, $org_is_enabled) = @_; |
472
|
2
|
|
|
|
|
9
|
bless [$org_is_enabled], shift; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
sub DESTROY { |
475
|
2
|
100
|
|
2
|
|
2596
|
if (shift->[0]) { |
476
|
1
|
|
|
|
|
6
|
DBIx::QueryLog->enable(); |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
else { |
479
|
1
|
|
|
|
|
6
|
DBIx::QueryLog->disable(); |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
1; |
485
|
|
|
|
|
|
|
__END__ |