File Coverage

blib/lib/DBIx/LogAny/db.pm
Criterion Covered Total %
statement 25 254 9.8
branch 0 142 0.0
condition 0 78 0.0
subroutine 8 29 27.5
pod 15 16 93.7
total 48 519 9.2


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