File Coverage

blib/lib/DBIx/LogAny/db.pm
Criterion Covered Total %
statement 141 254 55.5
branch 47 142 33.1
condition 22 78 28.2
subroutine 18 29 62.0
pod 15 16 93.7
total 243 519 46.8


line stmt bran cond sub pod time code
1             # $Id: db.pm 245 2006-07-25 14:20:59Z martin $
2 2     2   11 use strict;
  2         4  
  2         44  
3 2     2   7 use warnings;
  2         4  
  2         35  
4 2     2   2329 use DBI;
  2         24600  
  2         122  
5 2     2   21 use Data::Dumper;
  2         6  
  2         107  
6 2     2   1223 use Module::Loaded;
  2         1379  
  2         142  
7              
8             package DBIx::LogAny::db;
9 2     2   28 use Log::Any;
  2         4  
  2         15  
10             @DBIx::LogAny::db::ISA = qw(DBI::db DBIx::LogAny);
11 2     2   120 use DBIx::LogAny::Constants qw (:masks $LogMask);
  2         4  
  2         432  
12              
13             # $_glogger is not relied upon - it is just a fallback
14             my $_glogger;
15              
16             my $_counter; # to hold sub to count
17              
18             BEGIN {
19             my $x = sub {
20 2         6 my $start = shift;
21 2     2   14 return sub {$start++}};
  2         6287  
  1         4  
22 2         9 $_counter = &$x(0); # used to count dbh connections
23             }
24              
25              
26             sub STORE{
27 9     9   2127 my $dbh = shift;
28 9         27 my @args = @_;
29              
30 9         14 my $h = $dbh->{private_DBIx_LogAny};
31             # as we don't set private_DBIx_LogAny until the connect method sometimes
32             # $h will not be set
33             $dbh->_dbix_la_debug($h, 2, "STORE($h->{dbh_no})", @args)
34 9 50 66     44 if ($h && ($h->{logmask} & DBIX_LA_LOG_STORE));
35              
36 9         58 return $dbh->SUPER::STORE(@args);
37             }
38              
39             sub get_info
40             {
41 0     0 1 0 my ($dbh, @args) = @_;
42              
43 0         0 my $h = $dbh->{private_DBIx_LogAny};
44 0         0 my $value = $dbh->SUPER::get_info(@args);
45              
46             $dbh->_dbix_la_debug($h, 2, "get_info($h->{dbh_no})", @args, $value)
47 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_INPUT);
48 0         0 return $value;
49             }
50             sub prepare {
51 5     5 1 850 my($dbh, @args) = @_;
52              
53 5         19 my $h = $dbh->{private_DBIx_LogAny};
54 5         14 my $ctr = $h->{new_stmt_no}(); # get a new unique stmt counter in this dbh
55 5 100 33     46 if (($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL)) &&
      66        
56             (caller !~ /^DBIx::LogAny/o) &&
57             (caller !~ /^DBD::/o)) { # e.g. from selectall_arrayref
58 2         11 $dbh->_dbix_la_debug($h, 2, "prepare($h->{dbh_no}.$ctr)", $args[0]);
59             }
60              
61 5         28 my $sth = $dbh->SUPER::prepare(@args);
62 5 50       1099 if ($sth) {
63 5         23 $sth->{private_DBIx_LogAny} = $h;
64 5         55 $sth->{private_DBIx_st_no} = $ctr;
65             }
66              
67 5         60 return $sth;
68             }
69              
70             sub prepare_cached {
71 0     0 1 0 my($dbh, @args) = @_;
72              
73 0         0 my $h = $dbh->{private_DBIx_LogAny};
74 0         0 my $ctr = $h->{new_stmt_no}();
75 0 0 0     0 if (($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL)) &&
      0        
76             (caller !~ /^DBIx::LogAny/o) &&
77             (caller !~ /^DBD::/o)) { # e.g. from selectall_arrayref
78 0         0 $dbh->_dbix_la_debug($h, 2,
79             "prepare_cached($h->{dbh_no}.$ctr)", $args[0]);
80             }
81              
82 0         0 my $sth = $dbh->SUPER::prepare_cached(@args);
83 0 0       0 if ($sth) {
84 0         0 $sth->{private_DBIx_LogAny} = $h;
85 0         0 $sth->{private_DBIx_st_no} = $ctr;
86             }
87 0         0 return $sth;
88             }
89              
90             sub do {
91 3     3 1 465 my ($dbh, @args) = @_;
92 3         17 my $h = $dbh->{private_DBIx_LogAny};
93              
94 3         9 $h->{Statement} = $args[0];
95             $dbh->_dbix_la_debug($h, 2, "do($h->{dbh_no})", @args)
96 3 50       29 if ($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL));
97              
98 3         23 my $affected = $dbh->SUPER::do(@args);
99              
100 3 100 66     84 if (!defined($affected)) {
    50 66        
    100 66        
101             $dbh->_dbix_la_error(2, 'do error for ', @args)
102             if (($h->{logmask} & DBIX_LA_LOG_ERRCAPTURE) &&
103 1 50 33     8 !($h->{logmask} & DBIX_LA_LOG_INPUT)); # not already logged
104             } elsif (defined($affected) && $affected eq '0E0' &&
105             ($h->{logmask} & DBIX_LA_LOG_WARNINGS)) {
106 0         0 $dbh->_dbix_la_warning(2, 'no effect from ', @args);
107             } elsif (($affected ne '0E0') && ($h->{logmask} & DBIX_LA_LOG_INPUT)) {
108 1         7 $dbh->_dbix_la_debug($h, 2, "affected($h->{dbh_no})", $affected);
109 1 50       5 $dbh->_dbix_la_debug($h, 2, "\t" . $dbh->SUPER::errstr)
110             if (!defined($affected));
111             }
112 3         17 return $affected;
113             }
114              
115             sub selectrow_array {
116 0     0 1 0 my ($dbh, @args) = @_;
117              
118 0         0 my $h = $dbh->{private_DBIx_LogAny};
119              
120 0 0       0 if ($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL)) {
121 0 0 0     0 if ((scalar(@args) > 0) && (ref $args[0])) {
122             $dbh->_dbix_la_debug($h,
123             2,
124             "selectrow_array($h->{dbh_no}." .
125 0         0 $args[0]->{private_DBIx_st_no} . ")", @args);
126             } else {
127 0         0 $dbh->_dbix_la_debug($h, 2,
128             "selectrow_array($h->{dbh_no})", @args);
129             }
130             }
131              
132 0 0       0 if (wantarray) {
133 0         0 my @ret = $dbh->SUPER::selectrow_array(@args);
134             $dbh->_dbix_la_debug($h, 2, "result($h->{dbh_no})", @ret)
135 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_OUTPUT);
136 0         0 return @ret;
137              
138             } else {
139 0         0 my $ret = $dbh->SUPER::selectrow_array(@args);
140             $dbh->_dbix_la_debug($h, 2, "result($h->{dbh_no})", $ret)
141 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_OUTPUT);
142 0         0 return $ret;
143             }
144             }
145              
146             sub selectrow_arrayref {
147 0     0 1 0 my ($dbh, @args) = @_;
148              
149 0         0 my $h = $dbh->{private_DBIx_LogAny};
150              
151 0 0       0 if ($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL)) {
152 0 0 0     0 if ((scalar(@args) > 0) && (ref $args[0])) {
153             $dbh->_dbix_la_debug(
154             $h, 2,
155             "selectrow_arrayref($h->{dbh_no}." .
156 0         0 $args[0]->{private_DBIx_st_no} . ")", @args);
157             } else {
158 0         0 $dbh->_dbix_la_debug(
159             $h, 2, "selectrow_arrayref($h->{dbh_no})", @args);
160             }
161             }
162              
163 0         0 my $ref = $dbh->SUPER::selectrow_arrayref(@args);
164             $dbh->_dbix_la_debug($h, 2, "result($h->{dbh_no})", $ref)
165 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_OUTPUT);
166 0         0 return $ref;
167             }
168              
169             sub selectrow_hashref {
170 0     0 1 0 my ($dbh, @args) = @_;
171              
172 0         0 my $h = $dbh->{private_DBIx_LogAny};
173              
174 0 0       0 if ($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL)) {
175 0 0 0     0 if ((scalar(@args) > 0) && (ref $args[0])){
176             $dbh->_dbix_la_debug(
177             $h, 2,
178             "selectrow_hashref($h->{dbh_no}." .
179 0         0 $args[0]->{private_DBIx_st_no} . ")", @args)
180             } else {
181 0         0 $dbh->_dbix_la_debug($h, 2,
182             "selectrow_hashref($h->{dbh_no})", @args);
183             }
184             }
185              
186 0         0 my $ref = $dbh->SUPER::selectrow_hashref(@args);
187             # no need to show result - fetch will do this
188 0         0 return $ref;
189              
190             }
191              
192             sub selectall_arrayref {
193 1     1 1 441 my ($dbh, @args) = @_;
194              
195 1         7 my $h = $dbh->{private_DBIx_LogAny};
196 1 50       6 if ($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL)) {
197 1 50 33     8 if ((scalar(@args) > 0) && (ref $args[0])) {
198             $dbh->_dbix_la_debug(
199             $h, 2,
200             "selectall_arrayref($h->{dbh_no}." .
201 1         10 $args[0]->{private_DBIx_st_no} . ")", @args);
202             } else {
203 0         0 $dbh->_dbix_la_debug(
204             $h, 2, "selectall_arrayref($h->{dbh_no})", @args);
205             }
206             }
207              
208 1         18 my $ref = $dbh->SUPER::selectall_arrayref(@args);
209             $dbh->_dbix_la_debug($h, 2, "result($h->{dbh_no})", $ref)
210 1 50       13 if ($h->{logmask} & DBIX_LA_LOG_OUTPUT);
211 1         3 return $ref;
212             }
213              
214             sub selectall_hashref {
215 0     0 1 0 my ($dbh, @args) = @_;
216              
217 0         0 my $h = $dbh->{private_DBIx_LogAny};
218 0 0       0 if ($h->{logmask} & (DBIX_LA_LOG_INPUT|DBIX_LA_LOG_SQL)) {
219 0 0 0     0 if ((scalar(@args) > 0) && (ref $args[0])) {
220             $dbh->_dbix_la_debug(
221             $h, 2,
222             "selectall_hashref($h->{dbh_no}." .
223 0         0 $args[0]->{private_DBIx_st_no} . ")", @args);
224             } else {
225 0         0 $dbh->_dbix_la_debug($h, 2,
226             "selectall_hashref($h->{dbh_no})", @args);
227             }
228             }
229              
230 0         0 my $ref = $dbh->SUPER::selectall_hashref(@args);
231             # no need to show result - fetch will do this
232 0         0 return $ref;
233              
234             }
235              
236             sub _make_counter {
237 1     1   3 my $start = shift;
238 5     5   10 return sub {$start++}
239 1         6 };
240              
241             sub connected {
242              
243 1     1 0 35533 my ($dbh, $dsn, $user, $pass, $attr) = @_;
244              
245 1         3 my %h = ();
246 1         7 $h{dbh_no} = &$_counter();
247 1         7 $h{new_stmt_no} = _make_counter(0); # get a new stmt count for this dbh
248              
249             # if passed a Log4perl log handle use that
250 1 50       24 if (exists($attr->{dbix_la_logger})) {
    50          
251 0         0 $h{logger} = $attr->{dbix_la_logger};
252             } elsif (exists($attr->{dbix_la_category})) {
253 0         0 $h{category} = $attr->{dbix_la_category};
254 0         0 $h{logger} = Log::Any->get_logger(category => $h{category});
255             } else {
256 1         10 $h{logger} = Log::Any->get_logger(category => __PACKAGE__);
257             }
258              
259             # save log mask
260 1 50       303 $h{logmask} = $attr->{dbix_la_logmask} if (exists($attr->{dbix_la_logmask}));
261             # save error regexp
262             $h{err_regexp} = $attr->{dbix_la_ignore_err_regexp}
263 1 50       4 if (exists($attr->{dbix_la_ignore_err_regexp}));
264              
265             # take global log mask if non defined
266 1 50       7 $h{logmask} = $LogMask unless (exists($h{logmask}));
267              
268 1         3 $_glogger = $h{logger};
269              
270              
271 1         2 $h{dbd_specific} = 0;
272 1         25 $h{driver} = $dbh->{Driver}->{Name};
273              
274 1         49 $dbh->{private_DBIx_LogAny} = \%h;
275              
276 1         20 $h{ll_loaded} = Module::Loaded::is_loaded('Log::Log4perl');
277 1 50       28 if ($h{ll_loaded}) {
278             # register all our packages so Log::Log4perl skips them
279 0         0 Log::Log4perl->wrapper_register('DBIx::LogAny');
280 0         0 Log::Log4perl->wrapper_register('DBIx::LogAny::db');
281 0         0 Log::Log4perl->wrapper_register('DBIx::LogAny::st')
282             }
283              
284             #
285             # If capturing errors then save any error handler and set_err Handler
286             # passed to us and replace with our own.
287             #
288 1 50       8 if ($h{logmask} & DBIX_LA_LOG_ERRCAPTURE) {
289             $h{HandleError} = $attr->{HandleError}
290 1 50       4 if (exists($attr->{HandleError}));
291             $h{HandleSetErr} = $attr->{HandleSetErr}
292 1 50       4 if (exists($attr->{HandleSetErr}));
293 1         5 $dbh->{HandleError} = \&_error_handler;
294 1         12 $dbh->{HandleSetErr} = \&_set_err_handler;
295             }
296 1         12 return;
297              
298             }
299             sub clone {
300 0     0 1 0 my ($dbh, @args) = @_;
301              
302 0         0 my $h = $dbh->{private_DBIx_LogAny};
303 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_CONNECT) {
304 0         0 $dbh->_dbix_la_debug($h, 2, "clone($h->{dbh_no})", @args);
305             }
306              
307 0         0 return $dbh->SUPER::clone(@args);
308             }
309              
310             sub disconnect {
311 1     1 1 17 my $dbh = shift;
312              
313 1 50       3 if ($dbh) {
314 1         3 my $h;
315 1         2 eval {
316             # Avoid
317             # (in cleanup) Can't call method "FETCH" on an undefined value
318 1         5 $h = $dbh->{private_DBIx_LogAny};
319             };
320 1 50 33     9 if (!$@ && $h && defined($h->{logger})) {
      33        
321 1 50       4 if ($h->{logmask} & DBIX_LA_LOG_CONNECT) {
322 1         5 $dbh->_dbix_la_debug($h, 2, "disconnect($h->{dbh_no})");
323             }
324             }
325             }
326 1         15 return $dbh->SUPER::disconnect;
327              
328             }
329              
330             sub begin_work {
331 0     0 1 0 my $dbh = shift;
332 0         0 my $h = $dbh->{private_DBIx_LogAny};
333              
334             $dbh->_dbix_la_debug($h, 2, "start transaction($h->{dbh_no})")
335 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_TXN);
336              
337 0         0 return $dbh->SUPER::begin_work;
338             }
339              
340             sub rollback {
341 0     0 1 0 my $dbh = shift;
342 0         0 my $h = $dbh->{private_DBIx_LogAny};
343              
344             $dbh->_dbix_la_debug($h, 2, "roll back($h->{dbh_no})")
345 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_TXN);
346              
347 0         0 return $dbh->SUPER::rollback;
348             }
349              
350             sub commit {
351 0     0 1 0 my $dbh = shift;
352              
353 0         0 my $h = $dbh->{private_DBIx_LogAny};
354             $dbh->_dbix_la_debug($h, 2, "commit($h->{dbh_no})")
355 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_TXN);
356              
357 0         0 return $dbh->SUPER::commit;
358             }
359              
360             sub last_insert_id {
361 0     0 1 0 my ($dbh, @args) = @_;
362 0         0 my $h = $dbh->{private_DBIx_LogAny};
363              
364             $dbh->_dbix_la_debug(
365             $h, 2, Data::Dumper->Dump([\@args], ["last_insert_id($h->{dbh_no})"]))
366 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_INPUT);
367              
368 0         0 my $ret = $dbh->SUPER::last_insert_id(@args);
369             $dbh->_dbix_la_debug($h, 2, "\t" . DBI::neat($ret))
370 0 0       0 if ($h->{logmask} & DBIX_LA_LOG_INPUT);
371 0         0 return $ret;
372             }
373              
374              
375             #
376             # Error handler to capture errors and log them
377             # Whatever, errors are passed on.
378             # if the user of DBIx::LogAny passed in an error handler that is called
379             # before returning.
380             #
381             sub _error_handler {
382 1     1   55 my ($msg, $handle, $method_ret) = @_;
383              
384 1         2 my $dbh = $handle;
385 1         2 my $lh;
386 1         6 my $h = $handle->{private_DBIx_LogAny};
387 1         3 my $out = '';
388              
389 1         2 $lh = $_glogger;
390 1 50 33     7 $lh = $h->{logger} if ($h && exists($h->{logger}));
391 1 50       3 return 0 if (!$lh);
392              
393 1 50       5 if (!$lh->is_fatal) {
394 0         0 goto FINISH;
395             }
396              
397 1 50 33     22 if ($h && exists($h->{err_regexp})) {
398 0 0       0 if ($dbh->err =~ $h->{err_regexp}) {
399 0         0 goto FINISH;
400             }
401             }
402             # start with error message, state and err
403 1         6 $out .= ' ' . '=' x 60 . "\n $msg\n";
404 1         15 $out .= "err() = " . $handle->err . "\n";
405 1         11 $out .= "state() = " . $handle->state . "\n";
406              
407 1 50       7 if ($DBI::lasth) {
408             $out .= " lasth type: $DBI::lasth->{Type}\n"
409 1 50       7 if ($DBI::lasth->{Type});
410             $out .= " lasth Statement ($DBI::lasth):\n " .
411             "$DBI::lasth->{Statement}\n"
412 1 50       10 if ($DBI::lasth->{Statement});
413             }
414             # get db handle if we have an st
415 1         5 my $type = $handle->{Type};
416 1         13 my $sql;
417 1 50       5 if ($type eq 'st') { # given statement handle
418 0         0 $dbh = $handle->{Database};
419 0         0 $sql = $handle->{Statement};
420             } else {
421             # given db handle
422             # We've got other stmts under this db but we'll deal with those later
423 1         2 $sql = 'Possible SQL: ';
424 1 50       5 $sql .= "/$h->{Statement}/" if (exists($h->{Statement}));
425             $sql .= "/$dbh->{Statement}/"
426             if ($dbh->{Statement} &&
427             (exists($h->{Statement}) &&
428 1 50 33     31 ($dbh->{Statement} ne $h->{Statement})));
      33        
429             }
430              
431 1 50       8 my $dbname = exists($dbh->{Name}) ? $dbh->{Name} : "";
432 1 50       15 my $username = exists($dbh->{Username}) ? $dbh->{Username} : "";
433 1         16 $out .= " DB: $dbname, Username: $username\n";
434 1         11 $out .= " handle type: $type\n SQL: " . DBI::neat($sql) . "\n";
435             $out .= ' db Kids=' . $dbh->{Kids} .
436 1         5 ', ActiveKids=' . $dbh->{ActiveKids} . "\n";
437 1 50 33     46 $out .= " DB errstr: " . $handle->errstr . "\n"
438             if ($handle->errstr && ($handle->errstr ne $msg));
439              
440 1 0 33     5 if (exists($h->{ParamValues}) && $h->{ParamValues}) {
441 0         0 $out .= " ParamValues captured in HandleSetErr:\n ";
442 0         0 foreach (sort keys %{$h->{ParamValues}}) {
  0         0  
443 0         0 $out .= "$_=" . DBI::neat($h->{ParamValues}->{$_}) . ",";
444             }
445 0         0 $out .= "\n";
446             }
447 1 50       4 if ($type eq 'st') {
448 0         0 my $str = "";
449 0 0       0 if ($handle->{ParamValues}) {
450 0         0 foreach (sort keys %{$handle->{ParamValues}}) {
  0         0  
451 0         0 $str .= "$_=" . DBI::neat($handle->{ParamValues}->{$_}) . ",";
452             }
453             }
454 0         0 $out .= " ParamValues: $str\n";
455             $out .= " " .
456             Data::Dumper->Dump([$handle->{ParamArrays}], ['ParamArrays'])
457 0 0       0 if ($handle->{ParamArrays});
458             }
459 1         3 my @substmts;
460             # get list of statements under the db
461 1         2 push @substmts, $_ for (grep { defined } @{$dbh->{ChildHandles}});
  1         5  
  1         10  
462 1         10 $out .= " " . scalar(@substmts) . " sub statements:\n";
463 1 50       4 if (scalar(@substmts)) {
464 0         0 foreach my $stmt (@substmts) {
465 0         0 $out .= " stmt($stmt):\n";
466             $out .= ' SQL(' . $stmt->{Statement} . ")\n "
467             if ($stmt->{Statement} &&
468             (exists($h->{Statement}) &&
469 0 0 0     0 ($h->{Statement} ne $stmt->{Statement})));
      0        
470 0 0 0     0 if (exists($stmt->{ParamValues}) && $stmt->{ParamValues}) {
471 0         0 $out .= ' Params(';
472 0         0 foreach (sort keys %{$stmt->{ParamValues}}) {
  0         0  
473 0         0 $out .= "$_=" . DBI::neat($stmt->{ParamValues}->{$_}) . ",";
474             }
475 0         0 $out .= ")\n";
476             }
477             }
478             }
479              
480 1 50       5 if (exists($dbh->{Callbacks})) {
481             $out .= " Callbacks exist for " .
482 0         0 join(",", keys(%{$dbh->{Callbacks}})) . "\n";
  0         0  
483             }
484 1         18 local $Carp::MaxArgLen = 256;
485 1         96 $out .= " " .Carp::longmess("DBI error trap");
486 1         113 $out .= " " . "=" x 60 . "\n";
487              
488 1         6 $lh->fatal($out);
489              
490             FINISH:
491 1 50 33     98 if ($h && exists($h->{ErrorHandler})) {
492 0         0 return $h->{ErrorHandler}($msg, $handle, $method_ret);
493             } else {
494 1         5 return 0; # pass error on
495             }
496             }
497              
498             #
499             # set_err handler so we can capture ParamValues before a statement
500             # is destroyed.
501             # If the use of DBIx::LogAny passed in an error handler that is
502             # called before returning.
503             #
504             sub _set_err_handler {
505 1     1   2478 my ($handle, $err, $errstr, $state, $method) = @_;
506              
507             # Capture ParamValues
508 1 50       4 if ($handle) {
509 1         7 my $h = $handle->{private_DBIx_LogAny};
510             $h->{ParamValues} = $handle->{ParamValues}
511 1 50       9 if (exists($handle->{ParamValues}));
512 1 50       45 return $h->{HandleSetErr}(@_) if (exists($h->{HandleSetErr}));
513             }
514 1         5 return 0;
515             }
516              
517              
518             1;