File Coverage

blib/lib/Test/MockDBI/Db.pm
Criterion Covered Total %
statement 123 129 95.3
branch 45 58 77.5
condition 2 4 50.0
subroutine 14 14 100.0
pod n/a
total 184 205 89.7


line stmt bran cond sub pod time code
1             package Test::MockDBI::Db;
2              
3 50     50   273 use strict;
  50         149  
  50         2240  
4 50     50   254 use warnings;
  50         90  
  50         1763  
5 50     50   24345 use Test::MockDBI::Base;
  50         122  
  50         1603  
6              
7 50     50   278 use base qw(Test::MockDBI::Base);
  50         87  
  50         87080  
8              
9             my $mockdbi = undef;
10              
11 101     101   2322 sub import{ $mockdbi = $_[1]; }
12              
13             sub _dbi_prepare{
14 91     91   28177 my ($self, $statement, $attr) = @_;
15            
16             # Reset both errors as per DBI Rule
17 91         6870 $mockdbi->_clear_dbi_err_errstr($self);
18            
19 91         321 my ($status, $retval) = $mockdbi->_has_fake_retval($statement);
20 91 100       308 if($status){
21 7         238 $mockdbi->_set_fake_dbi_err_errstr($self);
22            
23 7 100       32 if(ref($retval) eq 'CODE'){
24 1         4 return $retval->($self);
25             }
26 6         35 return $retval;
27             }
28            
29             #Seems like DBI dies if nothing is passed as a statement
30             #We replicate the same behaviour, but is this wrong?
31             #Doesnt DBI->prepare honor RaiseError \ PrintError ?
32 84 50       312 unless( $statement ){
33 0         0 die('DBI prepare: invalid number of arguments: got handle + 0, expected handle + between 1 and 2
34             Usage: $h->prepare($statement [, \%attr])');
35             }
36              
37             #dbh->{Statment} should contain the most recent string
38             #passed to prepare or do event if that call failed
39 84         192 $self->{Statement} = $statement;
40              
41 84         260 my $num_of_params = ($statement =~ tr/?//);
42            
43 84         3319 my $o_retval = bless {
44             NUM_OF_FIELDS => undef,
45             NUM_OF_PARAMS => $num_of_params,
46             NAME => undef,
47             NAME_lc => undef,
48             NAME_uc => undef,
49             NAME_hash => undef,
50             NAME_lc_hash => undef,
51             NAME_uc_hash => undef,
52             TYPE => undef,
53             PRECISION => undef,
54             SCALE => undef,
55             NULLABLE => undef,
56             CursorName => undef,
57             Database => $self,
58             Statement => $statement,
59             ParamValues => {},
60             ParamTypes => {},
61             ParamArray => undef,
62             RowsInCache => undef,
63             _fake => {
64             InoutParams => []
65             },
66            
67             #Common
68             Warn => undef,
69             Active => undef,
70             Executed => undef,
71             Kids => 0, #Should always be zero for a statementhandler see DBI documentation
72             ActiveKids => undef,
73             CachedKids => undef,
74             Type => 'st',
75             ChildHandles => undef,
76             CompatMode => undef,
77             InactiveDestroy => undef,
78             AutoInactiveDestroy => undef,
79             PrintWarn => undef,
80             PrintError => undef,
81             RaiseError => undef,
82             HandleError => undef,
83             HandleSetErr => undef,
84             ErrCount => undef,
85             ShowErrorStatement => undef,
86             TraceLevel => undef,
87             FetchHashKeyName => undef,
88             ChopBlanks => undef,
89             LongReadLen => undef,
90             LongTruncOk => undef,
91             TaintIn => undef,
92             TaintOut => undef,
93             Taint => undef,
94             Profile => undef,
95             ReadOnly => undef,
96             Callbacks => undef,
97             }, 'DBI::st';
98            
99 84         194 push( @{ $self->{ChildHandles} }, $o_retval);
  84         259  
100 84         133 $self->{Kids} = scalar( @{ $self->{ChildHandles} } );
  84         251  
101 84         422 $self->{ActiveKids} = Test::MockDBI::Db::_update_active_kids($self);
102 84         277 return $o_retval;
103             }
104              
105             sub _dbi_prepare_cached{
106 12     12   6321 my ($self, $statement, $attr, $if_active) = @_;
107            
108 12 100       41 $attr = {} if !$attr;
109             # Reset both errors as per DBI Rule
110 12         44 $mockdbi->_clear_dbi_err_errstr($self);
111            
112 12         111 my ($status, $retval) = $mockdbi->_has_fake_retval($statement);
113 12 100       34 if($status){
114 6         26 $mockdbi->_set_fake_dbi_err_errstr($self);
115            
116 6 100       23 if(ref($retval) eq 'CODE'){
117 1         4 return $retval->($self);
118             }
119 5         32 return $retval;
120             }
121            
122 6   100     21 my $cache = $self->{CachedKids} ||= {};
123 6         8 my $key = do { local $^W;
  6         19  
124 6         18 join "!\001", $statement, DBI::_concat_hash_sorted($attr, "=\001", ",\001", 0, 0)
125             };
126 6         44 my $sth = $cache->{$key};
127            
128 6 100       14 if($sth){
129 2 50       12 return $sth unless ($sth->{Active});
130 0 0 0     0 Carp::carp("prepare_cached($statement) statement handle $sth still Active")
131             unless ($if_active ||= 0);
132 0 0       0 $sth->finish if $if_active <= 1;
133 0 0       0 return $sth if $if_active <= 2;
134             }
135 4         13 $sth = $self->prepare($statement, $attr);
136 4 50       16 $cache->{$key} = $sth if $sth;
137              
138 4         12 return $sth;
139             }
140              
141             sub _dbi_do{
142 7     7   1426 my($self, $statement, $attr, @bind_values) = @_;
143              
144             # Reset both errors as per DBI Rule
145 7         27 $mockdbi->_clear_dbi_err_errstr($self);
146            
147 7         25 my ($status, $retval) = $mockdbi->_has_fake_retval($statement);
148 7 100       26 if($status){
149 6         21 $mockdbi->_set_fake_dbi_err_errstr($self);
150            
151 6 100       93 if(ref($retval) eq 'CODE'){
152 1         5 return $retval->($self);
153             }
154 5         29 return $retval;
155             }
156            
157 1 50       4 my $sth = $self->prepare($statement, $attr) or return;
158 1 50       5 $sth->execute(@bind_values) or return;
159              
160             #Updating dbh attributes
161 1         2 $self->{Executed} = 1;
162              
163            
164 1         11 my $rows = $sth->rows;
165 1 50       7 ($rows == 0) ? "0E0" : $rows; # always return true if no error
166             }
167              
168             sub _dbi_commit{
169 8     8   2090 my ($self) = @_;
170              
171             # Reset both errors as per DBI Rule
172 8         30 $mockdbi->_clear_dbi_err_errstr($self);
173            
174            
175            
176             #The executed attribute is updated even if the
177             #call fails
178 8         87 $self->{Executed} = undef;
179            
180             #Warning is displayed even if the method fails
181 8 100       49 warn "commit ineffective with AutoCommit enabled" if $self->{AutoCommit};
182            
183 8         104 my ($status, $retval) = $mockdbi->_has_fake_retval($self->{Statement});
184 8 100       107 if($status){
185 6         120 $mockdbi->_set_fake_dbi_err_errstr($self);
186            
187 6 100       19 if(ref($retval) eq 'CODE'){
188 1         3 return $retval->($self);
189             }
190 5         26 return $retval;
191             }
192            
193             #Updating dbh attributes
194 2         5 $self->{AutoCommit} = 1;
195              
196 2         8 return 1;
197             }
198              
199             sub _dbi_rollback{
200 8     8   2761 my ($self) = @_;
201             # Reset both errors as per DBI Rule
202 8         32 $mockdbi->_clear_dbi_err_errstr($self);
203            
204             #The executed attribute is updated even if the
205             #call fails
206 8         15 $self->{Executed} = undef;
207            
208             #Warning is displayed even if the method fails
209 8 100       38 warn "rollback ineffective with AutoCommit enabled" if $self->{AutoCommit};
210            
211 8         90 my ($status, $retval) = $mockdbi->_has_fake_retval($self->{Statement});
212 8 100       27 if($status){
213 6         34 $mockdbi->_set_fake_dbi_err_errstr($self);
214            
215 6 100       22 if(ref($retval) eq 'CODE'){
216 1         4 return $retval->($self);
217             }
218 5         26 return $retval;
219             }
220            
221 2         5 $self->{AutoCommit} = 1;
222 2         8 return 1;
223             }
224              
225             sub _dbi_begin_work{
226 5     5   1733 my ($self) = @_;
227            
228             # Reset both errors as per DBI Rule
229 5         22 $mockdbi->_clear_dbi_err_errstr($self);
230            
231 5         33 my ($status, $retval) = $mockdbi->_has_fake_retval($self->{Statement});
232 5 100       18 if($status){
233 3         12 $mockdbi->_set_fake_dbi_err_errstr($self);
234            
235 3 100       11 if(ref($retval) eq 'CODE'){
236 1         4 return $retval->($self);
237             }
238 2         6 return $retval;
239             }
240            
241 2         4 $self->{AutoCommit} = 0;
242 2         5 return 1;
243             }
244              
245             sub _dbi_ping{
246 3     3   19 my ($self) = @_;
247            
248             # Reset both errors as per DBI Rule
249 3         11 $mockdbi->_clear_dbi_err_errstr($self);
250            
251 3         12 my ($status, $retval) = $mockdbi->_has_fake_retval();
252 3 50       11 if($status){
253 3         12 $mockdbi->_set_fake_dbi_err_errstr($self);
254            
255 3 100       46 if(ref($retval) eq 'CODE'){
256 1         4 return $retval->($self);
257             }
258 2         8 return $retval;
259             }
260              
261 0         0 return 1;
262             }
263              
264             sub _dbi_disconnect{
265 7     7   2947 my ($self) = @_;
266              
267             # Reset both errors as per DBI Rule
268 7         34 $mockdbi->_clear_dbi_err_errstr($self);
269            
270 7         27 my ($status, $retval) = $mockdbi->_has_fake_retval();
271 7 100       29 if($status){
272 6         23 $mockdbi->_set_fake_dbi_err_errstr($self);
273            
274 6 100       21 if(ref($retval) eq 'CODE'){
275 1         4 return $retval->($self);
276             }
277 5         31 return $retval;
278             }
279              
280             #Set the Active flag to false for all childhandlers
281 1         2 foreach my $ch ( @{ $self->{ChildHandlers} } ){
  1         19  
282 0         0 $ch->{Active} = undef;
283             }
284 1         4 Test::MockDBI::Db::_update_active_kids($self);
285              
286 1         5 return 1;
287             }
288              
289              
290             #This is a helper method, and not a part of the DBI specification
291             sub _update_active_kids{
292 182     182   294 my ($self) = @_;
293 182         320 my $cnt = scalar(grep{ $_->{Active} } @{$self->{ChildHandles}});
  316         853  
  182         386  
294 182         312 $self->{ActiveKids} = $cnt;
295 182         365 return 1;
296             }
297             1;