File Coverage

blib/lib/DBD/Mock/st.pm
Criterion Covered Total %
statement 193 220 87.7
branch 104 122 85.2
condition 13 20 65.0
subroutine 19 19 100.0
pod 0 14 0.0
total 329 395 83.2


line stmt bran cond sub pod time code
1             package DBD::Mock::st;
2              
3 40     40   301 use strict;
  40         81  
  40         1270  
4 40     40   206 use warnings;
  40         80  
  40         96681  
5              
6             our $imp_data_size = 0;
7              
8             sub bind_col {
9 13     13 0 593 my ( $sth, $param_num, $ref, $attr ) = @_;
10              
11 13         35 my $tracker = $sth->FETCH('mock_my_history');
12 13         42 $tracker->bind_col( $param_num, $ref );
13 13         24 return 1;
14             }
15              
16             sub bind_param {
17 14     14 0 520 my ( $sth, $param_num, $val, $attr ) = @_;
18 14         42 my $tracker = $sth->FETCH('mock_my_history');
19 14         47 $tracker->bound_param( $param_num, $val, $attr );
20 14         29 return 1;
21             }
22              
23             sub bind_param_array {
24 2     2 0 18 bind_param(@_);
25             }
26              
27             sub bind_param_inout {
28 2     2 0 21 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         9 $tracker->bound_param( $param_num, $val );
41 2         5 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         4  
53 1         3 foreach my $p (@bound) {
54 2         9 my $result = $sth->execute( @$p );
55             # store the result from execute() if ArrayTupleStatus attribute is
56             # passed
57 2         7 push @{ $attr->{ArrayTupleStatus} }, $result
58 2 50       6 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         5 return scalar @bound;
74             }
75              
76             sub execute {
77 152     152 0 27065 my ( $sth, @params ) = @_;
78 152         312 my $dbh = $sth->{Database};
79              
80 152 100       417 unless ( $dbh->{mock_can_connect} ) {
81 1         34 $dbh->set_err( 1, "No connection present" );
82 0         0 return 0;
83             }
84 151 100       367 unless ( $dbh->{mock_can_execute} ) {
85 2         24 $dbh->set_err( 1, "Cannot execute" );
86 0         0 return 0;
87             }
88 149 100       379 $dbh->{mock_can_execute}++ if $dbh->{mock_can_execute} < 0;
89              
90 149         562 my $tracker = $sth->FETCH('mock_my_history');
91              
92 149 100       474 if ( $tracker->has_failure() ) {
93 3         10 $dbh->set_err( $tracker->get_failure() );
94 0         0 return 0;
95             }
96              
97 146 100       383 if (@params) {
98 46         151 $tracker->bind_params(@params);
99             }
100              
101 146 100       766 if ( my $session = $dbh->{mock_session} ) {
102 49         94 eval {
103 49         151 my $state = $session->current_state;
104 49         162 $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         58 my @results = @{ $state->{results} };
  40         95  
110 40         63 shift @results;
111 40         107 $tracker->{return_data} = \@results;
112             };
113 49 100       117 if ($@) {
114 9         18 my $session_error = $@;
115 9         25 chomp $session_error;
116 9         142 $sth->set_err( 1, "Session Error: ${session_error}" );
117 9         140 return;
118             }
119             }
120              
121 137         445 $tracker->mark_executed;
122 137         438 my $fields = $tracker->fields;
123 137 50       260 $sth->STORE( NUM_OF_FIELDS => scalar @{ $fields ? $fields : [] } );
  137         618  
124 137         479 $sth->STORE( NAME => $fields );
125              
126 137         456 $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 137 100       696 if ( $dbh->{Statement} =~ /^\s*?insert(?:\s+ignore)?\s+into\s+(\S+)/i ) {
134 23 100 66     149 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         19 $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 137 100       581 if ( $dbh->{Statement} =~ /^\s*?select/i ) {
151 101         392 return '0E0';
152             }
153 36   100     153 return ( $sth->rows() || '0E0' );
154             }
155              
156             sub fetch {
157 146     146 0 2983 my ($sth) = @_;
158 146         212 my $dbh = $sth->{Database};
159 146 100       307 unless ( $dbh->{mock_can_connect} ) {
160 1         16 $dbh->set_err( 1, "No connection present" );
161 0         0 return;
162             }
163 145 100       296 unless ( $dbh->{mock_can_fetch} ) {
164 3         42 $dbh->set_err( 1, "Cannot fetch" );
165 0         0 return;
166             }
167 142 100       267 $dbh->{mock_can_fetch}++ if $dbh->{mock_can_fetch} < 0;
168              
169 142         359 my $tracker = $sth->FETCH('mock_my_history');
170              
171 142 100       352 my $record = $tracker->next_record
172             or return;
173              
174 123 100       279 if ( my @cols = $tracker->bind_cols() ) {
175 6         18 for my $i ( grep { ref $cols[$_] } 0 .. $#cols ) {
  14         28  
176 14         22 ${ $cols[$i] } = $record->[$i];
  14         36  
177             }
178             }
179              
180 123         315 return $record;
181             }
182              
183             sub fetchrow_array {
184 33     33 0 17582 my ($sth) = @_;
185 33         104 my $row = $sth->DBD::Mock::st::fetch();
186 32 100       102 return unless ref($row) eq 'ARRAY';
187 30         45 return @{$row};
  30         95  
188             }
189              
190             sub fetchrow_arrayref {
191 87     87 0 3191 my ($sth) = @_;
192 87         166 return $sth->DBD::Mock::st::fetch();
193             }
194              
195             sub fetchrow_hashref {
196 10     10 0 2177 my ( $sth, $name ) = @_;
197 10         26 my $dbh = $sth->{Database};
198              
199             # handle any errors since we are grabbing
200             # from the tracker directly
201 10 50       34 unless ( $dbh->{mock_can_connect} ) {
202 0         0 $dbh->set_err( 1, "No connection present" );
203 0         0 return;
204             }
205 10 100       22 unless ( $dbh->{mock_can_fetch} ) {
206 1         14 $dbh->set_err( 1, "Cannot fetch" );
207 0         0 return;
208             }
209 9 100       24 $dbh->{mock_can_fetch}++ if $dbh->{mock_can_fetch} < 0;
210              
211             # first handle the $name, it will default to NAME
212 9   50     41 $name ||= 'NAME';
213              
214             # then fetch the names from the $sth (per DBI spec)
215 9         32 my $fields = $sth->FETCH($name);
216              
217             # now check the tracker ...
218 9         27 my $tracker = $sth->FETCH('mock_my_history');
219              
220             # and collect the results
221 9 100       30 if ( my $record = $tracker->next_record() ) {
222 6         7 my @values = @{$record};
  6         14  
223 6         10 return { map { $_ => shift(@values) } @{$fields} };
  12         74  
  6         10  
224             }
225              
226 3         15 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 33 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       25 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       12 $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     24 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         20 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         8  
256              
257 5         13 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         9 my @key_indexes;
262 5         10 foreach my $field (@key_fields) {
263 6 100 33     58 if (defined $names_hash->{$field}) {
    50 33        
264 3         9 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         10 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         22 my $tracker = $sth->FETCH('mock_my_history');
280 5         10 my $rethash = {};
281              
282             # now loop through all the records ...
283 5         14 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         14 my $ref = $rethash;
288 10         17 foreach my $index (@key_indexes) {
289 12         17 my $value = $record->[$index];
290 12 50       34 $ref->{$value} = {} if ! defined $ref->{$value};
291 12         52 $ref = $ref->{$value};
292             }
293              
294             # copy all of the returned data into the most-nested level of the hash
295 10         13 foreach my $field (keys %{$names_hash}) {
  10         27  
296 30         35 my $index = $names_hash->{$field};
297 30         68 $ref->{$field} = $record->[$index];
298             }
299             }
300              
301 5         35 return $rethash;
302             }
303              
304             sub last_insert_id {
305 6     6 0 13 my ( $sth, @params ) = @_;
306 6         22 return $sth->{Database}->last_insert_id( @params );
307             }
308              
309             sub finish {
310 38     38 0 12162 my ($sth) = @_;
311 38         182 $sth->FETCH('mock_my_history')->is_finished('yes');
312             }
313              
314             sub rows {
315 43     43 0 1225 my ($sth) = @_;
316 43         170 $sth->FETCH('mock_num_rows');
317             }
318              
319             sub FETCH {
320 131     131   52878 my ( $sth, $attrib ) = @_;
321 131         551 $sth->trace_msg("Fetching ST attribute '$attrib'\n");
322 131         243 my $tracker = $sth->{mock_my_history};
323 131         541 $sth->trace_msg( "Retrieved tracker: " . ref($tracker) . "\n" );
324              
325             # NAME attributes
326 131 100       1306 if ( $attrib eq 'NAME' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
327 12         20 return [ @{ $tracker->fields } ];
  12         34  
328             }
329             elsif ( $attrib eq 'NAME_lc' ) {
330 2         5 return [ map { lc($_) } @{ $tracker->fields } ];
  6         30  
  2         14  
331             }
332             elsif ( $attrib eq 'NAME_uc' ) {
333 1         3 return [ map { uc($_) } @{ $tracker->fields } ];
  3         11  
  1         3  
334             }
335              
336             # NAME_hash attributes
337             elsif ( $attrib eq 'NAME_hash' ) {
338 6         13 my $i = 0;
339 6         8 return { map { $_ => $i++ } @{ $tracker->fields } };
  18         52  
  6         15  
340             }
341             elsif ( $attrib eq 'NAME_hash_lc' ) {
342 1         3 my $i = 0;
343 1         3 return { map { lc($_) => $i++ } @{ $tracker->fields } };
  3         11  
  1         4  
344             }
345             elsif ( $attrib eq 'NAME_hash_uc' ) {
346 1         3 my $i = 0;
347 1         2 return { map { uc($_) => $i++ } @{ $tracker->fields } };
  3         11  
  1         3  
348             }
349              
350             # others
351             elsif ( $attrib eq 'NUM_OF_FIELDS' ) {
352 2         11 return $tracker->num_fields;
353             }
354             elsif ( $attrib eq 'NUM_OF_PARAMS' ) {
355 1         6 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         18 return $tracker->is_active;
363             }
364             elsif ( exists $tracker->{driver_attributes}->{$attrib} ) {
365 8         37 return $tracker->{driver_attributes}->{$attrib};
366             }
367             elsif ( $attrib !~ /^mock/ ) {
368 4 50       32 if ( $sth->{Database}->{mock_attribute_aliases} ) {
369 0 0       0 if (
370 0         0 exists ${ $sth->{Database}->{mock_attribute_aliases}->{st} }
371             {$attrib} )
372             {
373             my $mock_attrib =
374 0         0 $sth->{Database}->{mock_attribute_aliases}->{st}->{$attrib};
375 0 0       0 if ( ref($mock_attrib) eq 'CODE' ) {
376 0         0 return $mock_attrib->($sth);
377             }
378             else {
379 0         0 return $sth->FETCH($mock_attrib);
380             }
381             }
382             }
383 4         50 return $sth->SUPER::FETCH($attrib);
384             }
385              
386             # now do our stuff...
387              
388 88 50 100     694 if ( $attrib eq 'mock_my_history' ) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
389 0         0 return $tracker;
390             }
391             elsif ( $attrib eq 'mock_execution_history' ) {
392 1         6 return $tracker->execution_history();
393             }
394             elsif ( $attrib eq 'mock_statement' ) {
395 2         11 return $tracker->statement;
396             }
397             elsif ( $attrib eq 'mock_params' ) {
398 5         18 return $tracker->bound_params;
399             }
400             elsif ( $attrib eq 'mock_param_attrs' ) {
401 3         13 return $tracker->bound_param_attrs;
402             }
403             elsif ( $attrib eq 'mock_records' ) {
404 1         6 return $tracker->return_data;
405             }
406             elsif ( $attrib eq 'mock_num_records' || $attrib eq 'mock_num_rows' ) {
407 48         146 return $tracker->num_rows;
408             }
409             elsif ( $attrib eq 'mock_current_record_num' ) {
410 11         35 return $tracker->current_record_num;
411             }
412             elsif ( $attrib eq 'mock_fields' ) {
413 1         4 return $tracker->fields;
414             }
415             elsif ( $attrib eq 'mock_is_executed' ) {
416 4         17 return $tracker->is_executed;
417             }
418             elsif ( $attrib eq 'mock_is_finished' ) {
419 5         20 return $tracker->is_finished;
420             }
421             elsif ( $attrib eq 'mock_is_depleted' ) {
422 7         26 return $tracker->is_depleted;
423             }
424             else {
425 0         0 die "I don't know how to retrieve statement attribute '$attrib'\n";
426             }
427             }
428              
429             sub STORE {
430 717     717   1292 my ( $sth, $attrib, $value ) = @_;
431 717         2365 $sth->trace_msg("Storing ST attribute '$attrib'\n");
432 717 100       2553 if ( $attrib =~ /^mock/ ) {
    100          
433 144         666 return $sth->{$attrib} = $value;
434             }
435             elsif ( $attrib =~ /^NAME/ ) {
436              
437             # no-op...
438 218         472 return;
439             }
440             else {
441 355   100     1037 $value ||= 0;
442 355         1895 return $sth->SUPER::STORE( $attrib, $value );
443             }
444             }
445              
446 144     144   44257 sub DESTROY { undef }
447              
448             1;