File Coverage

blib/lib/DBD/Log/Sth.pm
Criterion Covered Total %
statement 68 106 64.1
branch 17 52 32.6
condition 3 14 21.4
subroutine 12 16 75.0
pod 0 5 0.0
total 100 193 51.8


line stmt bran cond sub pod time code
1             package DBD::Log::Sth;
2              
3             # hartog/20041208
4             # hartog/20050525 - 0.11 - backtracing added
5              
6 3     3   16 use base 'DBD::Log';
  3         5  
  3         419  
7              
8             BEGIN {
9 3     3   49 $DBD::Log::Sth::VERSION = "0.11";
10             }
11              
12 3     3   14 use strict;
  3         5  
  3         94  
13 3     3   17 no strict 'refs';
  3         4  
  3         165  
14              
15             use Class::AccessorMaker {
16 3         46 dbi => "",
17             sth => "",
18              
19             statement => "",
20             rest => [],
21             bound => [],
22              
23             logFH => "",
24             logThis => [],
25              
26             dbiLogging => 0,
27             fullLogging => 0,
28              
29 3     3   1928 }, "new_init";
  3         1725  
30              
31 3     3   444 use Carp qw(croak);
  3         5  
  3         4709  
32              
33             sub init {
34 4     4 0 454 my ( $self, $command, @rest ) = @_;
35              
36 4         12 $self->sth( $self->dbi->prepare( $self->statement, @{$self->rest}) );
  4         44  
37             }
38              
39             sub logCall {
40 0     0 0 0 my ( $function, $self, @rest ) = @_;
41              
42             # are we logging this?
43 0 0       0 return undef if !$self->dbiLogging;
44              
45 0         0 my ($command) = lc($self->statement) =~ /^(\w+)/;
46 0 0 0     0 if ( $self->logThis->[0] ne "all"
  0         0  
47 0         0 && !grep { $_ eq $command } @{$self->logThis}
48             ) {
49 0         0 return undef;
50             }
51              
52 0         0 $self->printLog("[$function]", $self->statement, @rest);
53             }
54              
55             sub logAction {
56 2     2 0 6 my ( $function, $self, @rest ) = @_;
57              
58             # define logging
59 2 50       8 @rest = () if !$self->fullLogging;
60              
61 2         31 my ($command) = lc($self->statement) =~ /^(\w+)/;
62 2 50 33     37 if ( $self->logThis->[0] ne "all"
  12         40  
63 2         38 && !grep { $_ eq $command } @{$self->logThis}
64             ) {
65 0         0 return undef;
66             }
67              
68 2 50       8 if ( $function eq "execute" ) {
    0          
69 2         4 $self->printLog( $self->composeStatement(@{$self->bound}), @rest );
  2         6  
70              
71             } elsif ( $function eq "execute_array" ) {
72 0 0       0 if ( ref($self->bound->[0]) ) {
73 0         0 foreach my $bound ( @{$self->bound} ) {
  0         0  
74 0         0 my @print = $self->composeStatement(@$bound);
75 0         0 $self->printLog( @print, @rest );
76             }
77              
78             } else {
79 0         0 $self->printLog( $self->composeStatement(@{$self->bound}), @rest );
  0         0  
80             }
81             }
82              
83             }
84              
85             sub composeStatement {
86 2     2 0 20 my ( $self, @bound ) = @_;
87              
88 2         7 my $statement = $self->statement;
89              
90 2 50       20 if ( $statement =~ /\?/ ) {
    0          
91 2         9 my @parts = split(/\?/, $statement);
92              
93 2         8 for ( 0..$#parts ) {
94             # skip the parts that are not bound.
95 2 50       8 next if !defined $bound[$_];
96              
97             # if the bound value is NaN, wrap it in quotes.
98 2         4 my $val = $bound[$_];
99 2 50       10 $val =~ /\D+/ && ( $val = "'$val'" );
100              
101 2         6 $parts[$_] .= $val;
102             }
103              
104 2         5 $statement = join("", @parts);
105 2 50       10 if ( ($#parts+1) < $#bound ) {
106 0         0 @bound = splice(@bound, $#parts+1, $#bound);
107             } else {
108 2         5 @bound = ();
109             }
110              
111             } elsif ( $statement =~ /\:\w+/ ) {
112             # oracle style replacement
113              
114 0         0 $statement =~ s/(\:\w+)/&oracleSubstitute($1, \@bound)/eg;
  0         0  
115 0         0 @bound = ();
116             }
117              
118 2         26 return $statement, @bound
119             }
120              
121             sub oracleSubstitute{
122 0     0 0 0 my ( $subst, $bound ) = @_;
123 0         0 my $var = "";
124              
125 0         0 my @list = grep { $_->[0] eq $subst } @$bound;
  0         0  
126 0 0       0 @list && ( $var = $list[0]->[1] );
127              
128 0 0       0 ref($var) =~ /scalar/i && ( $var = $$var );
129 0 0       0 $var =~ /\D+/ && ( $var = "'$var'" );
130 0   0     0 $var ||= "''";
131              
132 0         0 return $var;
133             }
134              
135             ## make multiple routines
136              
137             # logging actions
138             foreach my $sub ( qw( execute bind_param execute_array bind_param_array bind_param_inout ) ) {
139              
140             *{"DBD::Log::Sth::$sub"} = sub {
141 2     2   35 my ( $self, @rest ) = @_;
142              
143 2         3 my @bound = @{$self->bound};
  2         9  
144              
145 2 50       41 if ( $#rest >= 0 ) {
146              
147 2 50 0     9 if ( $sub eq "execute" ) {
    0          
    0          
148             # bind litteral
149 2         7 @bound = @rest;
150             } elsif ( $sub eq "execute_array" ) {
151 0 0       0 if ( $#rest >= 1 ) {
152             # bind the array
153 0         0 @bound = @rest[1..$#rest];
154             }
155              
156             } elsif ( $#rest >= 1 && $rest[0] =~ /\D+/ ) {
157             # oracle style binding
158             # rest[0] = :key
159             # rest[1] = value
160 0         0 push @bound, [@rest];
161              
162             } else {
163             # rest[0] = index (start at 1).
164             # rest[1] = value.
165 0         0 $bound[$rest[0]-1] = $rest[1];
166              
167             }
168              
169             }
170              
171 2         10 $self->bound( [ @bound ] );
172              
173 2 50       34 logAction($sub, $self, @bound) if $sub =~ /execute/;
174 2 50       12 logCall($sub, @_) if $sub !~ /execute/;
175              
176 2         20 my $res = $self->sth->$sub(@rest);
177              
178 2 100 66     244 if ( my $error = ( $self->dbi->errstr || $self->sth->errstr ) ) {
179              
180 1         21 my @backtrace;
181              
182             # walk through the backtrace trying to find the error.
183 1         7 for ( 0..5 ) {
184 2         11 my ( $package, $filename, $line, @xtra ) = caller($_);
185              
186 2 100       8 last if !caller($_);
187              
188 1 50       8 if ( $package =~ /dbd/i ) {
    50          
189             # this is me - ignore.
190              
191             } elsif ( $package =~ /dbi/i ) {
192             # this is the dbi - ignore
193              
194             } else {
195 1         6 $self->dbi->{dbd_log_error} = "$error in $filename at line $line\n";
196              
197             }
198              
199 1         10 unshift @backtrace, ( "$xtra[0](" .
200 1         36 join(", ", @{$xtra[1]}) .
201             ") at $filename line $line."
202             );
203             }
204              
205 1         5 $self->dbi->{dbd_log_backtrace} = join("\n", @backtrace);
206             }
207              
208 2         84 return $res;
209             };
210              
211             }
212              
213             # non-logging actions
214             foreach my $sub ( qw( bind_col bind_columns fetchrow_array fetchrow_arrayref
215             fetchall_arrayref fetchrow_hashref fetchall_hashref
216             rows )
217             ) {
218              
219             *{"DBD::Log::Sth::$sub"} = sub {
220 0     0   0 my ( $self, @rest ) = @_;
221 0         0 return $self->sth->$sub(@rest);
222             };
223              
224             }
225              
226             sub DESTROY {
227             # kill the object and return the real sth.
228 4     4   805 my $self = shift;
229 4         15 $self->dbi("");
230 4         40 $self->sth("");
231             }
232              
233             sub AUTOLOAD {
234              
235             # any of the DBI routines we missed, or want not logged, are
236             # autoloaded.
237              
238 3     3   49 no strict;
  3         6  
  3         439  
239              
240 0     0     my ($routine) = $AUTOLOAD =~ /\:\:(\w+)$/;
241 0           my ( $self, @rest ) = @_;
242              
243 0           return $self->sth->$routine(@rest);
244             }
245              
246             1;
247              
248             __END__