File Coverage

blib/lib/DBD/Mock/st.pm
Criterion Covered Total %
statement 192 219 87.6
branch 102 120 85.0
condition 13 20 65.0
subroutine 19 19 100.0
pod 0 14 0.0
total 326 392 83.1


line stmt bran cond sub pod time code
1             package DBD::Mock::st;
2              
3 39     39   286 use strict;
  39         84  
  39         1210  
4 39     39   205 use warnings;
  39         87  
  39         95511  
5              
6             our $imp_data_size = 0;
7              
8             sub bind_col {
9 13     13 0 742 my ( $sth, $param_num, $ref, $attr ) = @_;
10              
11 13         36 my $tracker = $sth->FETCH('mock_my_history');
12 13         43 $tracker->bind_col( $param_num, $ref );
13 13         27 return 1;
14             }
15              
16             sub bind_param {
17 14     14 0 393 my ( $sth, $param_num, $val, $attr ) = @_;
18 14         46 my $tracker = $sth->FETCH('mock_my_history');
19 14         42 $tracker->bound_param( $param_num, $val, $attr );
20 14         32 return 1;
21             }
22              
23             sub bind_param_array {
24 2     2 0 17 bind_param(@_);
25             }
26              
27             sub bind_param_inout {
28 2     2 0 23 my ( $sth, $param_num, $val, $max_len ) = @_;
29              
30             # check that $val is a scalar ref
31             ( UNIVERSAL::isa( $val, 'SCALAR' ) )
32             || $sth->{Database}
33 2 50       7 ->set_err( 1, "need a scalar ref to bind_param_inout, not $val" );
34              
35             # check for positive $max_len
36             ( $max_len > 0 )
37             || $sth->{Database}
38 2 50       6 ->set_err( 1, "need to specify a maximum length to bind_param_inout" );
39 2         7 my $tracker = $sth->FETCH('mock_my_history');
40 2         7 $tracker->bound_param( $param_num, $val );
41 2         4 return 1;
42             }
43              
44             sub execute_array {
45 1     1 0 11 my ( $sth, $attr, @bind_values ) = @_;
46              
47             # no bind values means we're relying on prior calls to bind_param_array()
48             # for our data
49 1         4 my $tracker = $sth->FETCH('mock_my_history');
50             # don't use a reference; there's some magic attached to it somewhere
51             # so make it a lovely, simple array as soon as possible
52 1         2 my @bound = @{ $tracker->bound_params() };
  1         3  
53 1         3 foreach my $p (@bound) {
54 2         8 my $result = $sth->execute( @$p );
55             # store the result from execute() if ArrayTupleStatus attribute is
56             # passed
57 2         6 push @{ $attr->{ArrayTupleStatus} }, $result
58 2 50       5 if (exists $attr->{ArrayTupleStatus});
59             }
60              
61             # TODO: the docs say:
62             # When called in scalar context the execute_array() method returns the
63             # number of tuples executed, or undef if an error occurred. Like
64             # execute(), a successful execute_array() always returns true regardless
65             # of the number of tuples executed, even if it's zero. If there were any
66             # errors the ArrayTupleStatus array can be used to discover which tuples
67             # failed and with what errors.
68             # When called in list context the execute_array() method returns two
69             # scalars; $tuples is the same as calling execute_array() in scalar
70             # context and $rows is the number of rows affected for each tuple, if
71             # available or -1 if the driver cannot determine this.
72             # We have glossed over this...
73 1         4 return scalar @bound;
74             }
75              
76             sub execute {
77 148     148 0 23026 my ( $sth, @params ) = @_;
78 148         301 my $dbh = $sth->{Database};
79              
80 148 100       414 unless ( $dbh->{mock_can_connect} ) {
81 1         35 $dbh->set_err( 1, "No connection present" );
82 0         0 return 0;
83             }
84 147 100       328 unless ( $dbh->{mock_can_execute} ) {
85 2         27 $dbh->set_err( 1, "Cannot execute" );
86 0         0 return 0;
87             }
88 145 100       459 $dbh->{mock_can_execute}++ if $dbh->{mock_can_execute} < 0;
89              
90 145         562 my $tracker = $sth->FETCH('mock_my_history');
91              
92 145 100       463 if ( $tracker->has_failure() ) {
93 3         7 $dbh->set_err( $tracker->get_failure() );
94 0         0 return 0;
95             }
96              
97 142 100       365 if (@params) {
98 46         192 $tracker->bind_params(@params);
99             }
100              
101 142 100       402 if ( my $session = $dbh->{mock_session} ) {
102 49         93 eval {
103 49         139 my $state = $session->current_state;
104 49         165 $session->verify_statement( $sth->{Statement});
105 43         123 $session->verify_bound_params( $tracker->bound_params() );
106              
107             # Load a copy of the results to return (minus the field
108             # names) into the tracker
109 40         64 my @results = @{ $state->{results} };
  40         102  
110 40         69 shift @results;
111 40         137 $tracker->{return_data} = \@results;
112             };
113 49 100       133 if ($@) {
114 9         21 my $session_error = $@;
115 9         32 chomp $session_error;
116 9         138 $sth->set_err( 1, "Session Error: ${session_error}" );
117 9         203 return;
118             }
119             }
120              
121 133         425 $tracker->mark_executed;
122 133         366 my $fields = $tracker->fields;
123 133 50       246 $sth->STORE( NUM_OF_FIELDS => scalar @{ $fields ? $fields : [] } );
  133         577  
124 133         471 $sth->STORE( NAME => $fields );
125              
126 133         511 $sth->STORE( NUM_OF_PARAMS => $tracker->num_params );
127              
128             # handle INSERT statements and the mock_last_insert_ids
129             # We should only increment these things after the last successful INSERT.
130             # -RobK, 2007-10-12
131             #use Data::Dumper;warn Dumper $dbh->{mock_last_insert_ids};
132              
133 133 100       703 if ( $dbh->{Statement} =~ /^\s*?insert(?:\s+ignore)?\s+into\s+(\S+)/i ) {
134 23 100 66     179 if ( $tracker->{last_insert_id} ) {
    100          
135 1         3 $dbh->{mock_last_insert_id} = $tracker->{last_insert_id};
136              
137             } elsif ( $dbh->{mock_last_insert_ids}
138             && exists $dbh->{mock_last_insert_ids}{$1} )
139             {
140 7         20 $dbh->{mock_last_insert_id} = $dbh->{mock_last_insert_ids}{$1}++;
141             }
142             else {
143 15         49 $dbh->{mock_last_insert_id}++;
144             }
145             }
146              
147             #warn "$dbh->{mock_last_insert_id}\n";
148              
149             # always return 0E0 for Selects
150 133 100       539 if ( $dbh->{Statement} =~ /^\s*?select/i ) {
151 97         425 return '0E0';
152             }
153 36   100     151 return ( $sth->rows() || '0E0' );
154             }
155              
156             sub fetch {
157 146     146 0 1759 my ($sth) = @_;
158 146         241 my $dbh = $sth->{Database};
159 146 100       324 unless ( $dbh->{mock_can_connect} ) {
160 1         16 $dbh->set_err( 1, "No connection present" );
161 0         0 return;
162             }
163 145 100       272 unless ( $dbh->{mock_can_fetch} ) {
164 3         42 $dbh->set_err( 1, "Cannot fetch" );
165 0         0 return;
166             }
167 142 100       323 $dbh->{mock_can_fetch}++ if $dbh->{mock_can_fetch} < 0;
168              
169 142         391 my $tracker = $sth->FETCH('mock_my_history');
170              
171 142 100       383 my $record = $tracker->next_record
172             or return;
173              
174 123 100       274 if ( my @cols = $tracker->bind_cols() ) {
175 6         19 for my $i ( grep { ref $cols[$_] } 0 .. $#cols ) {
  14         31  
176 14         17 ${ $cols[$i] } = $record->[$i];
  14         29  
177             }
178             }
179              
180 123         303 return $record;
181             }
182              
183             sub fetchrow_array {
184 33     33 0 15157 my ($sth) = @_;
185 33         97 my $row = $sth->DBD::Mock::st::fetch();
186 32 100       97 return unless ref($row) eq 'ARRAY';
187 30         42 return @{$row};
  30         100  
188             }
189              
190             sub fetchrow_arrayref {
191 87     87 0 3757 my ($sth) = @_;
192 87         161 return $sth->DBD::Mock::st::fetch();
193             }
194              
195             sub fetchrow_hashref {
196 10     10 0 2495 my ( $sth, $name ) = @_;
197 10         18 my $dbh = $sth->{Database};
198              
199             # handle any errors since we are grabbing
200             # from the tracker directly
201 10 50       30 unless ( $dbh->{mock_can_connect} ) {
202 0         0 $dbh->set_err( 1, "No connection present" );
203 0         0 return;
204             }
205 10 100       28 unless ( $dbh->{mock_can_fetch} ) {
206 1         33 $dbh->set_err( 1, "Cannot fetch" );
207 0         0 return;
208             }
209 9 100       35 $dbh->{mock_can_fetch}++ if $dbh->{mock_can_fetch} < 0;
210              
211             # first handle the $name, it will default to NAME
212 9   50     55 $name ||= 'NAME';
213              
214             # then fetch the names from the $sth (per DBI spec)
215 9         37 my $fields = $sth->FETCH($name);
216              
217             # now check the tracker ...
218 9         28 my $tracker = $sth->FETCH('mock_my_history');
219              
220             # and collect the results
221 9 100       24 if ( my $record = $tracker->next_record() ) {
222 6         8 my @values = @{$record};
  6         14  
223 6         10 return { map { $_ => shift(@values) } @{$fields} };
  12         64  
  6         12  
224             }
225              
226 3         14 return undef;
227             }
228              
229             #XXX Isn't this supposed to return an array of hashrefs? -RobK, 2007-10-15
230             sub fetchall_hashref {
231 5     5 0 30 my ( $sth, $keyfield ) = @_;
232 5         9 my $dbh = $sth->{Database};
233              
234             # handle any errors since we are grabbing
235             # from the tracker directly
236 5 50       14 unless ( $dbh->{mock_can_connect} ) {
237 0         0 $dbh->set_err( 1, "No connection present" );
238 0         0 return;
239             }
240 5 50       10 unless ( $dbh->{mock_can_fetch} ) {
241 0         0 $dbh->set_err( 1, "Cannot fetch" );
242 0         0 return;
243             }
244 5 50       11 $dbh->{mock_can_fetch}++ if $dbh->{mock_can_fetch} < 0;
245              
246             # get the case conversion to use for hash key names (NAME/NAME_lc/NAME_uc)
247 5   50     21 my $hash_key_name = $sth->{Database}->FETCH('FetchHashKeyName') || 'NAME';
248              
249             # get a hashref mapping field names to their corresponding indexes. indexes
250             # start at zero
251 5         19 my $names_hash = $sth->FETCH("${hash_key_name}_hash");
252              
253             # as of DBI v1.48, the $keyfield argument can be either an arrayref of field
254             # names/indexes or a single field name/index
255 5 100       13 my @key_fields = ref $keyfield ? @{$keyfield} : $keyfield;
  3         7  
256              
257 5         16 my $num_fields = $sth->FETCH('NUM_OF_FIELDS');
258              
259             # get the index(es) of the given key field(s). a key field can be specified
260             # as either the name of a field or an integer column number
261 5         7 my @key_indexes;
262 5         11 foreach my $field (@key_fields) {
263 6 100 33     44 if (defined $names_hash->{$field}) {
    50 33        
264 3         6 push @key_indexes, $names_hash->{$field};
265             }
266             elsif (DBI::looks_like_number($field) && $field >= 1 && $field <= $num_fields) {
267             # convert from column number to array index. column numbers start at
268             # one, while indexes start at zero
269 3         18 push @key_indexes, $field - 1;
270             }
271             else {
272             my $err = "Could not find key field '$field' (not one of " .
273 0         0 join(' ', keys %{$names_hash}) . ')';
  0         0  
274 0         0 $dbh->set_err( 1, $err );
275 0         0 return;
276             }
277             }
278              
279 5         15 my $tracker = $sth->FETCH('mock_my_history');
280 5         9 my $rethash = {};
281              
282             # now loop through all the records ...
283 5         15 while ( my $record = $tracker->next_record() ) {
284              
285             # populate the hash, adding a layer of nesting for each key field
286             # specified by the user
287 10         13 my $ref = $rethash;
288 10         16 foreach my $index (@key_indexes) {
289 12         16 my $value = $record->[$index];
290 12 50       40 $ref->{$value} = {} if ! defined $ref->{$value};
291 12         28 $ref = $ref->{$value};
292             }
293              
294             # copy all of the returned data into the most-nested level of the hash
295 10         12 foreach my $field (keys %{$names_hash}) {
  10         26  
296 30         40 my $index = $names_hash->{$field};
297 30         64 $ref->{$field} = $record->[$index];
298             }
299             }
300              
301 5         36 return $rethash;
302             }
303              
304             sub last_insert_id {
305 6     6 0 16 my ( $sth, @params ) = @_;
306 6         26 return $sth->{Database}->last_insert_id( @params );
307             }
308              
309             sub finish {
310 38     38 0 10341 my ($sth) = @_;
311 38         181 $sth->FETCH('mock_my_history')->is_finished('yes');
312             }
313              
314             sub rows {
315 43     43 0 1693 my ($sth) = @_;
316 43         144 $sth->FETCH('mock_num_rows');
317             }
318              
319             sub FETCH {
320 121     121   45303 my ( $sth, $attrib ) = @_;
321 121         528 $sth->trace_msg("Fetching ST attribute '$attrib'\n");
322 121         225 my $tracker = $sth->{mock_my_history};
323 121         450 $sth->trace_msg( "Retrieved tracker: " . ref($tracker) . "\n" );
324              
325             # NAME attributes
326 121 100       1115 if ( $attrib eq 'NAME' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
327 12         19 return [ @{ $tracker->fields } ];
  12         37  
328             }
329             elsif ( $attrib eq 'NAME_lc' ) {
330 2         6 return [ map { lc($_) } @{ $tracker->fields } ];
  6         37  
  2         8  
331             }
332             elsif ( $attrib eq 'NAME_uc' ) {
333 1         3 return [ map { uc($_) } @{ $tracker->fields } ];
  3         10  
  1         4  
334             }
335              
336             # NAME_hash attributes
337             elsif ( $attrib eq 'NAME_hash' ) {
338 6         11 my $i = 0;
339 6         11 return { map { $_ => $i++ } @{ $tracker->fields } };
  18         53  
  6         15  
340             }
341             elsif ( $attrib eq 'NAME_hash_lc' ) {
342 1         2 my $i = 0;
343 1         3 return { map { lc($_) => $i++ } @{ $tracker->fields } };
  3         12  
  1         3  
344             }
345             elsif ( $attrib eq 'NAME_hash_uc' ) {
346 1         2 my $i = 0;
347 1         2 return { map { uc($_) => $i++ } @{ $tracker->fields } };
  3         11  
  1         5  
348             }
349              
350             # others
351             elsif ( $attrib eq 'NUM_OF_FIELDS' ) {
352 2         8 return $tracker->num_fields;
353             }
354             elsif ( $attrib eq 'NUM_OF_PARAMS' ) {
355 1         5 return $tracker->num_params;
356             }
357             elsif ( $attrib eq 'TYPE' ) {
358 0         0 my $num_fields = $tracker->num_fields;
359 0         0 return [ map { $DBI::SQL_VARCHAR } ( 0 .. $num_fields ) ];
  0         0  
360             }
361             elsif ( $attrib eq 'Active' ) {
362 5         17 return $tracker->is_active;
363             }
364             elsif ( $attrib !~ /^mock/ ) {
365 2 50       8 if ( $sth->{Database}->{mock_attribute_aliases} ) {
366 0 0       0 if (
367 0         0 exists ${ $sth->{Database}->{mock_attribute_aliases}->{st} }
368             {$attrib} )
369             {
370             my $mock_attrib =
371 0         0 $sth->{Database}->{mock_attribute_aliases}->{st}->{$attrib};
372 0 0       0 if ( ref($mock_attrib) eq 'CODE' ) {
373 0         0 return $mock_attrib->($sth);
374             }
375             else {
376 0         0 return $sth->FETCH($mock_attrib);
377             }
378             }
379             }
380 2         43 return $sth->SUPER::FETCH($attrib);
381             }
382              
383             # now do our stuff...
384              
385 88 50 100     768 if ( $attrib eq 'mock_my_history' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
386 0         0 return $tracker;
387             }
388             elsif ( $attrib eq 'mock_execution_history' ) {
389 1         5 return $tracker->execution_history();
390             }
391             elsif ( $attrib eq 'mock_statement' ) {
392 2         8 return $tracker->statement;
393             }
394             elsif ( $attrib eq 'mock_params' ) {
395 5         18 return $tracker->bound_params;
396             }
397             elsif ( $attrib eq 'mock_param_attrs' ) {
398 3         11 return $tracker->bound_param_attrs;
399             }
400             elsif ( $attrib eq 'mock_records' ) {
401 1         5 return $tracker->return_data;
402             }
403             elsif ( $attrib eq 'mock_num_records' || $attrib eq 'mock_num_rows' ) {
404 48         169 return $tracker->num_rows;
405             }
406             elsif ( $attrib eq 'mock_current_record_num' ) {
407 11         38 return $tracker->current_record_num;
408             }
409             elsif ( $attrib eq 'mock_fields' ) {
410 1         5 return $tracker->fields;
411             }
412             elsif ( $attrib eq 'mock_is_executed' ) {
413 4         16 return $tracker->is_executed;
414             }
415             elsif ( $attrib eq 'mock_is_finished' ) {
416 5         19 return $tracker->is_finished;
417             }
418             elsif ( $attrib eq 'mock_is_depleted' ) {
419 7         25 return $tracker->is_depleted;
420             }
421             else {
422 0         0 die "I don't know how to retrieve statement attribute '$attrib'\n";
423             }
424             }
425              
426             sub STORE {
427 693     693   1312 my ( $sth, $attrib, $value ) = @_;
428 693         2310 $sth->trace_msg("Storing ST attribute '$attrib'\n");
429 693 100       2493 if ( $attrib =~ /^mock/ ) {
    100          
430 140         591 return $sth->{$attrib} = $value;
431             }
432             elsif ( $attrib =~ /^NAME/ ) {
433              
434             # no-op...
435 210         468 return;
436             }
437             else {
438 343   100     988 $value ||= 0;
439 343         1906 return $sth->SUPER::STORE( $attrib, $value );
440             }
441             }
442              
443 140     140   40657 sub DESTROY { undef }
444              
445             1;