File Coverage

blib/lib/DBI/SQL/Nano.pm
Criterion Covered Total %
statement 374 450 83.1
branch 147 252 58.3
condition 63 121 52.0
subroutine 39 49 79.5
pod n/a
total 623 872 71.4


line stmt bran cond sub pod time code
1             #######################################################################
2             #
3             # DBI::SQL::Nano - a very tiny SQL engine
4             #
5             # Copyright (c) 2010 by Jens Rehsack < rehsack AT cpan.org >
6             # Copyright (c) 2004 by Jeff Zucker < jzucker AT cpan.org >
7             #
8             # All rights reserved.
9             #
10             # You may freely distribute and/or modify this module under the terms
11             # of either the GNU General Public License (GPL) or the Artistic License,
12             # as specified in the Perl README file.
13             #
14             # See the pod at the bottom of this file for help information
15             #
16             #######################################################################
17              
18             #######################
19             package DBI::SQL::Nano;
20             #######################
21 52     52   293 use strict;
  52         96  
  52         1287  
22 52     52   233 use warnings;
  52         82  
  52         1330  
23 52     52   229 use vars qw( $VERSION $versions );
  52         82  
  52         2066  
24              
25 52     52   270 use Carp qw(croak);
  52         86  
  52         6495  
26              
27             require DBI; # for looks_like_number()
28              
29             BEGIN
30             {
31 52     52   185 $VERSION = "1.015544";
32              
33 52         145 $versions->{nano_version} = $VERSION;
34 52 50 66     313 if ( $ENV{DBI_SQL_NANO} || !eval { require SQL::Statement; $SQL::Statement::VERSION ge '1.400' } )
  28         1867  
  0         0  
35             {
36 52         597 @DBI::SQL::Nano::Statement::ISA = qw(DBI::SQL::Nano::Statement_);
37 52         1874 @DBI::SQL::Nano::Table::ISA = qw(DBI::SQL::Nano::Table_);
38             }
39             else
40             {
41 0         0 @DBI::SQL::Nano::Statement::ISA = qw( SQL::Statement );
42 0         0 @DBI::SQL::Nano::Table::ISA = qw( SQL::Eval::Table);
43 0         0 $versions->{statement_version} = $SQL::Statement::VERSION;
44             }
45             }
46              
47             ###################################
48             package DBI::SQL::Nano::Statement_;
49             ###################################
50              
51 52     52   266 use Carp qw(croak);
  52         96  
  52         2011  
52 52     52   253 use Errno;
  52         97  
  52         194521  
53              
54             if ( eval { require Clone; } )
55             {
56             Clone->import("clone");
57             }
58             else
59             {
60             require Storable; # in CORE since 5.7.3
61             *clone = \&Storable::dclone;
62             }
63              
64             sub new
65             {
66 732     732   1601 my ( $class, $sql ) = @_;
67 732         1245 my $self = {};
68 732         1551 bless $self, $class;
69 732         1796 return $self->prepare($sql);
70             }
71              
72             #####################################################################
73             # PREPARE
74             #####################################################################
75             sub prepare
76             {
77 732     732   1286 my ( $self, $sql ) = @_;
78 732         2895 $sql =~ s/\s+$//;
79 732         1422 $sql =~ s/\s*;$//;
80 732         1372 for ($sql)
81             {
82             /^\s*CREATE\s+TABLE\s+(.*?)\s*\((.+)\)\s*$/is
83             && do
84 732 100       3027 {
85 82         266 $self->{command} = 'CREATE';
86 82         255 $self->{table_name} = $1;
87             defined $2 and $2 ne "" and
88 82 50 33     677 $self->{column_names} = parse_coldef_list($2);
89 82 50       263 $self->{column_names} or croak "Can't find columns";
90             };
91             /^\s*DROP\s+TABLE\s+(IF\s+EXISTS\s+)?(.*?)\s*$/is
92             && do
93 732 100       2773 {
94 128         490 $self->{command} = 'DROP';
95 128         442 $self->{table_name} = $2;
96             defined $1 and $1 ne "" and
97 128 100 66     654 $self->{ignore_missing_table} = 1;
98             };
99             /^\s*SELECT\s+(.*?)\s+FROM\s+(\S+)((.*))?/is
100             && do
101 732 100       2497 {
102 158         530 $self->{command} = 'SELECT';
103             defined $1 and $1 ne "" and
104 158 50 33     1223 $self->{column_names} = parse_comma_list($1);
105 158 50       485 $self->{column_names} or croak "Can't find columns";
106 158         409 $self->{table_name} = $2;
107 158 100       1184 if ( my $clauses = $4 )
108             {
109 56 100       322 if ( $clauses =~ /^(.*)\s+ORDER\s+BY\s+(.*)$/is )
110             {
111 48         106 $clauses = $1;
112 48         322 $self->{order_clause} = $self->parse_order_clause($2);
113             }
114 56 100       211 $self->{where_clause} = $self->parse_where_clause($clauses) if ($clauses);
115             }
116             };
117             /^\s*INSERT\s+(?:INTO\s+)?(\S+)\s*(\((.*?)\))?\s*VALUES\s*\((.+)\)/is
118             && do
119 732 100       2384 {
120 208         595 $self->{command} = 'INSERT';
121 208         553 $self->{table_name} = $1;
122             defined $2 and $2 ne "" and
123 208 100 66     774 $self->{column_names} = parse_comma_list($2);
124             defined $4 and $4 ne "" and
125 208 50 33     1680 $self->{values} = $self->parse_values_list($4);
126 208 50       631 $self->{values} or croak "Can't parse values";
127             };
128             /^\s*DELETE\s+FROM\s+(\S+)((.*))?/is
129             && do
130 732 100       1995 {
131 64         193 $self->{command} = 'DELETE';
132 64         176 $self->{table_name} = $1;
133             defined $3 and $3 ne "" and
134 64 100 66     577 $self->{where_clause} = $self->parse_where_clause($3);
135             };
136             /^\s*UPDATE\s+(\S+)\s+SET\s+(.+)(\s+WHERE\s+.+)/is
137             && do
138 732 100       2179 {
139 44         158 $self->{command} = 'UPDATE';
140 44         137 $self->{table_name} = $1;
141 44 50 33     1143 defined $2 and $2 ne "" and
142             $self->parse_set_clause($2);
143             defined $3 and $3 ne "" and
144 44 50 33     399 $self->{where_clause} = $self->parse_where_clause($3);
145             };
146             }
147 732 100 66     8964 croak "Couldn't parse" unless ( $self->{command} and $self->{table_name} );
148 684         1918 return $self;
149             }
150              
151             sub parse_order_clause
152             {
153 48     48   149 my ( $self, $str ) = @_;
154 48         164 my @clause = split /\s+/, $str;
155 48 100       232 return { $clause[0] => 'ASC' } if ( @clause == 1 );
156 12 50       30 croak "Bad ORDER BY clause '$str'" if ( @clause > 2 );
157 12   50     32 $clause[1] ||= '';
158 12 50 33     110 return { $clause[0] => uc $clause[1] }
159             if $clause[1] =~ /^ASC$/i
160             or $clause[1] =~ /^DESC$/i;
161 0         0 croak "Bad ORDER BY clause '$clause[1]'";
162             }
163              
164             sub parse_coldef_list
165             { # check column definitions
166 82     82   156 my @col_defs;
167 82         363 for ( split ',', shift )
168             {
169 156         345 my $col = clean_parse_str($_);
170 156 50       1237 if ( $col =~ /^(\S+?)\s+.+/ )
171             { # doesn't check what it is
172 156         330 $col = $1; # just checks if it exists
173             }
174             else
175             {
176 0         0 croak "No column definition for '$_'";
177             }
178 156         352 push @col_defs, $col;
179             }
180 82         243 return \@col_defs;
181             }
182              
183             sub parse_comma_list
184             {
185 190     190   759 [ map { clean_parse_str($_) } split( ',', shift ) ];
  282         587  
186             }
187 850     850   1340 sub clean_parse_str { local $_ = shift; s/\(//; s/\)//; s/^\s+//; s/\s+$//; $_; }
  850         1440  
  850         1173  
  850         1651  
  850         1596  
  850         2515  
188              
189             sub parse_values_list
190             {
191 208     208   682 my ( $self, $str ) = @_;
192 208         832 [ map { $self->parse_value( clean_parse_str($_) ) } split( ',', $str ) ];
  412         821  
193             }
194              
195             sub parse_set_clause
196             {
197 44     44   94 my $self = shift;
198 44         170 my @cols = split /,/, shift;
199 44         81 my $set_clause;
200 44         111 for my $col (@cols)
201             {
202 44         297 my ( $col_name, $value ) = $col =~ /^\s*(.+?)\s*=\s*(.+?)\s*$/s;
203 44         90 push @{ $self->{column_names} }, $col_name;
  44         154  
204 44         80 push @{ $self->{values} }, $self->parse_value($value);
  44         196  
205             }
206 44 50 33     279 croak "Can't parse set clause" unless ( $self->{column_names} and $self->{values} );
207             }
208              
209             sub parse_value
210             {
211 624     624   1219 my ( $self, $str ) = @_;
212 624 50       1248 return unless ( defined $str );
213 624         1025 $str =~ s/\s+$//;
214 624         1008 $str =~ s/^\s+//;
215 624 100       1309 if ( $str =~ /^\?$/ )
216             {
217 164         211 push @{ $self->{params} }, '?';
  164         375  
218             return {
219 164         725 value => '?',
220             type => 'placeholder'
221             };
222             }
223             return {
224 460 100       939 value => undef,
225             type => 'NULL'
226             } if ( $str =~ /^NULL$/i );
227             return {
228 448 100       1580 value => $1,
229             type => 'string'
230             } if ( $str =~ /^'(.+)'$/s );
231             return {
232 312 100       1196 value => $str,
233             type => 'number'
234             } if ( DBI::looks_like_number($str) );
235             return {
236 132         604 value => $str,
237             type => 'column'
238             };
239             }
240              
241             sub parse_where_clause
242             {
243 84     84   234 my ( $self, $str ) = @_;
244 84         271 $str =~ s/\s+$//;
245 84 50       312 if ( $str =~ /^\s*WHERE\s+(.*)/i )
246             {
247 84         198 $str = $1;
248             }
249             else
250             {
251 0         0 croak "Couldn't find WHERE clause in '$str'";
252             }
253 84         236 my ($neg) = $str =~ s/^\s*(NOT)\s+//is;
254 84         164 my $opexp = '=|<>|<=|>=|<|>|LIKE|CLIKE|IS';
255 84         1566 my ( $val1, $op, $val2 ) = $str =~ /^(.+?)\s*($opexp)\s*(.+)\s*$/iso;
256 84 50 33     515 croak "Couldn't parse WHERE expression '$str'" unless ( defined $val1 and defined $op and defined $val2 );
      33        
257             return {
258 84         224 arg1 => $self->parse_value($val1),
259             arg2 => $self->parse_value($val2),
260             op => $op,
261             neg => $neg,
262             };
263             }
264              
265             #####################################################################
266             # EXECUTE
267             #####################################################################
268             sub execute
269             {
270 484     484   1109 my ( $self, $data, $params ) = @_;
271 484         893 my $num_placeholders = $self->params;
272 484   100     1628 my $num_params = scalar @$params || 0;
273 484 50       1040 croak "Number of params '$num_params' does not match number of placeholders '$num_placeholders'"
274             unless ( $num_placeholders == $num_params );
275 484 100       1153 if ( scalar @$params )
276             {
277 64         109 for my $i ( 0 .. $#{ $self->{values} } )
  64         227  
278             {
279 120 50       307 if ( $self->{values}->[$i]->{type} eq 'placeholder' )
280             {
281 120         298 $self->{values}->[$i]->{value} = shift @$params;
282             }
283             }
284 64 50       202 if ( $self->{where_clause} )
285             {
286 0 0       0 if ( $self->{where_clause}->{arg1}->{type} eq 'placeholder' )
287             {
288 0         0 $self->{where_clause}->{arg1}->{value} = shift @$params;
289             }
290 0 0       0 if ( $self->{where_clause}->{arg2}->{type} eq 'placeholder' )
291             {
292 0         0 $self->{where_clause}->{arg2}->{value} = shift @$params;
293             }
294             }
295             }
296 484         868 my $command = $self->{command};
297 484         2445 ( $self->{'NUM_OF_ROWS'}, $self->{'NUM_OF_FIELDS'}, $self->{'data'}, ) = $self->$command( $data, $params );
298 452   66     2454 $self->{NAME} ||= $self->{column_names};
299 452   100     3232 return $self->{'NUM_OF_ROWS'} || '0E0';
300             }
301              
302             my $enoentstr = "Cannot open .*\(" . Errno::ENOENT . "\)";
303             my $enoentrx = qr/$enoentstr/;
304              
305             sub DROP ($$$)
306             {
307 120     120   289 my ( $self, $data, $params ) = @_;
308              
309 120         224 my $table;
310             my @err;
311 120         337 eval {
312 120     0   779 local $SIG{__WARN__} = sub { push @err, @_ };
  0         0  
313 120         417 ($table) = $self->open_tables( $data, 0, 1 );
314             };
315 120 100 66     3317 if ( $self->{ignore_missing_table} and ( $@ or @err ) and grep { $_ =~ $enoentrx } ( @err, $@ ) )
  40   100     443  
      66        
316             {
317 40         88 $@ = '';
318 40         179 return ( -1, 0 );
319             }
320              
321 80 100 33     945 croak( $@ || $err[0] ) if ( $@ || @err );
      66        
322 72 50       187 return ( -1, 0 ) unless $table;
323              
324 72         1222 $table->drop($data);
325 72         333 ( -1, 0 );
326             }
327              
328             sub CREATE ($$$)
329             {
330 62     62   279 my ( $self, $data, $params ) = @_;
331 62         260 my $table = $self->open_tables( $data, 1, 1 );
332 62         299 $table->push_names( $data, $self->{column_names} );
333 62         547 ( 0, 0 );
334             }
335              
336             sub INSERT ($$$)
337             {
338 136     136   291 my ( $self, $data, $params ) = @_;
339 136         344 my $table = $self->open_tables( $data, 0, 1 );
340 128         630 $self->verify_columns($table);
341 128         321 my $all_columns = $table->{col_names};
342 128 50       857 $table->seek( $data, 0, 2 ) unless ( $table->can('insert_one_row') );
343 128         242 my ($array) = [];
344 128         240 my ( $val, $col, $i );
345 128 50       319 $self->{column_names} = $table->col_names() unless ( $self->{column_names} );
346 128 50       355 my $cNum = scalar( @{ $self->{column_names} } ) if ( $self->{column_names} );
  128         246  
347 128         190 my $param_num = 0;
348              
349 128 50       275 $cNum or
350             croak "Bad col names in INSERT";
351              
352 128         199 my $maxCol = $#$all_columns;
353              
354 128         345 for ( $i = 0; $i < $cNum; $i++ )
355             {
356 256         453 $col = $self->{column_names}->[$i];
357 256         623 $array->[ $self->column_nums( $table, $col ) ] = $self->row_values($i);
358             }
359              
360             # Extend row to put values in ALL fields
361 128 50       309 $#$array < $maxCol and $array->[$maxCol] = undef;
362              
363 128 50       729 $table->can('insert_new_row') ? $table->insert_new_row( $data, $array ) : $table->push_row( $data, $array );
364              
365 128         493 return ( 1, 0 );
366             }
367              
368             sub DELETE ($$$)
369             {
370 32     32   96 my ( $self, $data, $params ) = @_;
371 32         177 my $table = $self->open_tables( $data, 0, 1 );
372 24         85 $self->verify_columns($table);
373 24         46 my ($affected) = 0;
374 24         38 my ( @rows, $array );
375 24         96 my $can_dor = $table->can('delete_one_row');
376 24         86 while ( $array = $table->fetch_row($data) )
377             {
378 96 100       270 if ( $self->eval_where( $table, $array ) )
379             {
380 56         84 ++$affected;
381 56 100       119 if ( $self->{fetched_from_key} )
382             {
383 8         21 $array = $self->{fetched_value};
384 8         31 $table->delete_one_row( $data, $array );
385 8         43 return ( $affected, 0 );
386             }
387 48 50       138 push( @rows, $array ) if ($can_dor);
388             }
389             else
390             {
391 40 50       117 push( @rows, $array ) unless ($can_dor);
392             }
393             }
394 16 50       42 if ($can_dor)
395             {
396 16         35 foreach $array (@rows)
397             {
398 48         988 $table->delete_one_row( $data, $array );
399             }
400             }
401             else
402             {
403 0         0 $table->seek( $data, 0, 0 );
404 0         0 foreach $array (@rows)
405             {
406 0         0 $table->push_row( $data, $array );
407             }
408 0         0 $table->truncate($data);
409             }
410 16         78 return ( $affected, 0 );
411             }
412              
413             sub _anycmp($$;$)
414             {
415 64     64   140 my ( $a, $b, $case_fold ) = @_;
416              
417 64 50 33     389 if ( !defined($a) || !defined($b) )
    50 33        
418             {
419 0         0 return defined($a) - defined($b);
420             }
421             elsif ( DBI::looks_like_number($a) && DBI::looks_like_number($b) )
422             {
423 64         145 return $a <=> $b;
424             }
425             else
426             {
427 0 0 0     0 return $case_fold ? lc($a) cmp lc($b) || $a cmp $b : $a cmp $b;
428             }
429             }
430              
431             sub SELECT ($$$)
432             {
433 102     102   240 my ( $self, $data, $params ) = @_;
434 102         329 my $table = $self->open_tables( $data, 0, 0 );
435 94         385 $self->verify_columns($table);
436 94         209 my $tname = $self->{table_name};
437 94         174 my ($affected) = 0;
438 94         158 my ( @rows, %cols, $array, $val, $col, $i );
439 94         385 while ( $array = $table->fetch_row($data) )
440             {
441 200 50       806 if ( $self->eval_where( $table, $array ) )
442             {
443 200 50       488 $array = $self->{fetched_value} if ( $self->{fetched_from_key} );
444 200 100       440 unless ( keys %cols )
445             {
446 94         196 my $col_nums = $self->column_nums($table);
447 94         156 %cols = reverse %{$col_nums};
  94         386  
448             }
449              
450 200         348 my $rowhash;
451 200         623 for ( sort keys %cols )
452             {
453 376         936 $rowhash->{ $cols{$_} } = $array->[$_];
454             }
455 200         308 my @newarray;
456 200         317 for ( $i = 0; $i < @{ $self->{column_names} }; $i++ )
  576         1063  
457             {
458 376         558 $col = $self->{column_names}->[$i];
459 376         674 push @newarray, $rowhash->{$col};
460             }
461 200         330 push( @rows, \@newarray );
462 0         0 return ( scalar(@rows), scalar @{ $self->{column_names} }, \@rows )
463 200 50       728 if ( $self->{fetched_from_key} );
464             }
465             }
466 94 100       378 if ( $self->{order_clause} )
467             {
468 32         50 my ( $sort_col, $desc ) = each %{ $self->{order_clause} };
  32         102  
469 32         98 my @sortCols = ( $self->column_nums( $table, $sort_col, 1 ) );
470 32 100       109 $sortCols[1] = uc $desc eq 'DESC' ? 1 : 0;
471              
472             @rows = sort {
473 32         161 my ( $result, $colNum, $desc );
  64         103  
474 64         88 my $i = 0;
475             do
476 64   33     86 {
477 64         99 $colNum = $sortCols[ $i++ ];
478 64         97 $desc = $sortCols[ $i++ ];
479 64         148 $result = _anycmp( $a->[$colNum], $b->[$colNum] );
480 64 100       235 $result = -$result if ($desc);
481             } while ( !$result && $i < @sortCols );
482             $result;
483             } @rows;
484             }
485 94         176 ( scalar(@rows), scalar @{ $self->{column_names} }, \@rows );
  94         477  
486             }
487              
488             sub UPDATE ($$$)
489             {
490 32     32   89 my ( $self, $data, $params ) = @_;
491 32         99 my $table = $self->open_tables( $data, 0, 1 );
492 32         128 $self->verify_columns($table);
493 32 50       92 return undef unless $table;
494 32         55 my $affected = 0;
495 32         136 my $can_usr = $table->can('update_specific_row');
496 32         119 my $can_uor = $table->can('update_one_row');
497 32   33     100 my $can_rwu = $can_usr || $can_uor;
498 32         67 my ( @rows, $array, $f_array, $val, $col, $i );
499              
500 32         116 while ( $array = $table->fetch_row($data) )
501             {
502 56 50       156 if ( $self->eval_where( $table, $array ) )
503             {
504 56 100 66     186 $array = $self->{fetched_value} if ( $self->{fetched_from_key} and $can_rwu );
505 56 50       1301 my $orig_ary = clone($array) if ($can_usr);
506 56         151 for ( $i = 0; $i < @{ $self->{column_names} }; $i++ )
  112         294  
507             {
508 56         118 $col = $self->{column_names}->[$i];
509 56         153 $array->[ $self->column_nums( $table, $col ) ] = $self->row_values($i);
510             }
511 56         91 $affected++;
512 56 100       135 if ( $self->{fetched_value} )
513             {
514 8 50       32 if ($can_usr)
    0          
515             {
516 8         37 $table->update_specific_row( $data, $array, $orig_ary );
517             }
518             elsif ($can_uor)
519             {
520 0         0 $table->update_one_row( $data, $array );
521             }
522 8         48 return ( $affected, 0 );
523             }
524 48 50       211 push( @rows, $can_usr ? [ $array, $orig_ary ] : $array );
525             }
526             else
527             {
528 0 0       0 push( @rows, $array ) unless ($can_rwu);
529             }
530             }
531 24 50       68 if ($can_rwu)
532             {
533 24         62 foreach my $array (@rows)
534             {
535 48 50       128 if ($can_usr)
    0          
536             {
537 48         133 $table->update_specific_row( $data, @$array );
538             }
539             elsif ($can_uor)
540             {
541 0         0 $table->update_one_row( $data, $array );
542             }
543             }
544             }
545             else
546             {
547 0         0 $table->seek( $data, 0, 0 );
548 0         0 foreach my $array (@rows)
549             {
550 0         0 $table->push_row( $data, $array );
551             }
552 0         0 $table->truncate($data);
553             }
554              
555 24         129 return ( $affected, 0 );
556             }
557              
558             sub verify_columns
559             {
560 278     278   579 my ( $self, $table ) = @_;
561 278         414 my @cols = @{ $self->{column_names} };
  278         779  
562 278 100       727 if ( $self->{where_clause} )
563             {
564 48 50       154 if ( my $col = $self->{where_clause}->{arg1} )
565             {
566 48 50       189 push @cols, $col->{value} if $col->{type} eq 'column';
567             }
568 48 50       142 if ( my $col = $self->{where_clause}->{arg2} )
569             {
570 48 50       142 push @cols, $col->{value} if $col->{type} eq 'column';
571             }
572             }
573 278         581 for (@cols)
574             {
575 560         1190 $self->column_nums( $table, $_ );
576             }
577             }
578              
579             sub column_nums
580             {
581 998     998   1698 my ( $self, $table, $stmt_col_name, $find_in_stmt ) = @_;
582 998         1151 my %dbd_nums = %{ $table->col_nums() };
  998         1654  
583 998         1421 my @dbd_cols = @{ $table->col_names() };
  998         1507  
584 998         1316 my %stmt_nums;
585 998 100 100     2732 if ( $stmt_col_name and !$find_in_stmt )
586             {
587 872         2090 while ( my ( $k, $v ) = each %dbd_nums )
588             {
589 1308 100       4596 return $v if uc $k eq uc $stmt_col_name;
590             }
591 0         0 croak "No such column '$stmt_col_name'";
592             }
593 126 100 66     387 if ( $stmt_col_name and $find_in_stmt )
594             {
595 32         56 for my $i ( 0 .. @{ $self->{column_names} } )
  32         95  
596             {
597 32 50       175 return $i if uc $stmt_col_name eq uc $self->{column_names}->[$i];
598             }
599 0         0 croak "No such column '$stmt_col_name'";
600             }
601 94         272 for my $i ( 0 .. $#dbd_cols )
602             {
603 176         249 for my $stmt_col ( @{ $self->{column_names} } )
  176         413  
604             {
605 340 100       959 $stmt_nums{$stmt_col} = $i if uc $dbd_cols[$i] eq uc $stmt_col;
606             }
607             }
608 94         278 return \%stmt_nums;
609             }
610              
611             sub eval_where
612             {
613 352     352   602 my ( $self, $table, $rowary ) = @_;
614 352   100     967 my $where = $self->{"where_clause"} || return 1;
615 120         217 my $col_nums = $table->col_nums();
616 120         168 my %cols = reverse %{$col_nums};
  120         374  
617 120         177 my $rowhash;
618 120         441 for ( sort keys %cols )
619             {
620 240         696 $rowhash->{ uc $cols{$_} } = $rowary->[$_];
621             }
622 120         408 return $self->process_predicate( $where, $table, $rowhash );
623             }
624              
625             sub process_predicate
626             {
627 120     120   232 my ( $self, $pred, $table, $rowhash ) = @_;
628 120         195 my $val1 = $pred->{arg1};
629 120 50       261 if ( $val1->{type} eq 'column' )
630             {
631 120         254 $val1 = $rowhash->{ uc $val1->{value} };
632             }
633             else
634             {
635 0         0 $val1 = $val1->{value};
636             }
637 120         189 my $val2 = $pred->{arg2};
638 120 50       217 if ( $val2->{type} eq 'column' )
639             {
640 0         0 $val2 = $rowhash->{ uc $val2->{value} };
641             }
642             else
643             {
644 120         215 $val2 = $val2->{value};
645             }
646 120         168 my $op = $pred->{op};
647 120         172 my $neg = $pred->{neg};
648 120 50 33     740 if ( $op eq '=' and !$neg and $table->can('fetch_one_row') )
      33        
649             {
650 120         311 my $key_col = $table->fetch_one_row( 1, 1 );
651 120 100       817 if ( $pred->{arg1}->{value} =~ /^$key_col$/i )
652             {
653 16         35 $self->{fetched_from_key} = 1;
654 16         46 $self->{fetched_value} = $table->fetch_one_row( 0, $pred->{arg2}->{value} );
655 16         79 return 1;
656             }
657             }
658 104   100     296 my $match = $self->is_matched( $val1, $op, $val2 ) || 0;
659 104 0       203 if ($neg) { $match = $match ? 0 : 1; }
  0 50       0  
660 104         373 return $match;
661             }
662              
663             sub is_matched
664             {
665 104     104   224 my ( $self, $val1, $op, $val2 ) = @_;
666 104 50       209 if ( $op eq 'IS' )
667             {
668 0 0 0     0 return 1 if ( !defined $val1 or $val1 eq '' );
669 0         0 return 0;
670             }
671 104 50       209 $val1 = '' unless ( defined $val1 );
672 104 50       212 $val2 = '' unless ( defined $val2 );
673 104 50       207 if ( $op =~ /LIKE|CLIKE/i )
674             {
675 0         0 $val2 = quotemeta($val2);
676 0         0 $val2 =~ s/\\%/.*/g;
677 0         0 $val2 =~ s/_/./g;
678             }
679 104 50       186 if ( $op eq 'LIKE' ) { return $val1 =~ /^$val2$/s; }
  0         0  
680 104 50       199 if ( $op eq 'CLIKE' ) { return $val1 =~ /^$val2$/si; }
  0         0  
681 104 50 33     305 if ( DBI::looks_like_number($val1) && DBI::looks_like_number($val2) )
682             {
683 0 0       0 if ( $op eq '<' ) { return $val1 < $val2; }
  0         0  
684 0 0       0 if ( $op eq '>' ) { return $val1 > $val2; }
  0         0  
685 0 0       0 if ( $op eq '=' ) { return $val1 == $val2; }
  0         0  
686 0 0       0 if ( $op eq '<>' ) { return $val1 != $val2; }
  0         0  
687 0 0       0 if ( $op eq '<=' ) { return $val1 <= $val2; }
  0         0  
688 0 0       0 if ( $op eq '>=' ) { return $val1 >= $val2; }
  0         0  
689             }
690             else
691             {
692 104 50       195 if ( $op eq '<' ) { return $val1 lt $val2; }
  0         0  
693 104 50       192 if ( $op eq '>' ) { return $val1 gt $val2; }
  0         0  
694 104 50       195 if ( $op eq '=' ) { return $val1 eq $val2; }
  104         365  
695 0 0       0 if ( $op eq '<>' ) { return $val1 ne $val2; }
  0         0  
696 0 0       0 if ( $op eq '<=' ) { return $val1 ge $val2; }
  0         0  
697 0 0       0 if ( $op eq '>=' ) { return $val1 le $val2; }
  0         0  
698             }
699             }
700              
701             sub params
702             {
703 1652     1652   2703 my ( $self, $val_num ) = @_;
704 1652 100       4266 if ( !$self->{"params"} ) { return 0; }
  1436         3787  
705 216 50       514 if ( defined $val_num )
706             {
707 0         0 return $self->{"params"}->[$val_num];
708             }
709              
710 216 50       468 return wantarray ? @{ $self->{"params"} } : scalar @{ $self->{"params"} };
  0         0  
  216         636  
711             }
712              
713             sub open_tables
714             {
715 484     484   1019 my ( $self, $data, $createMode, $lockMode ) = @_;
716 484         860 my $table_name = $self->{table_name};
717 484         627 my $table;
718 484         607 eval { $table = $self->open_table( $data, $table_name, $createMode, $lockMode ) };
  484         1433  
719 484 100       5407 if ($@)
720             {
721 72         203 chomp $@;
722 72         7030 croak $@;
723             }
724 412 50       1123 croak "Couldn't open table '$table_name'" unless $table;
725 412 100 100     1496 if ( !$self->{column_names} or $self->{column_names}->[0] eq '*' )
726             {
727 250         929 $self->{column_names} = $table->col_names();
728             }
729 412         1181 return $table;
730             }
731              
732             sub row_values
733             {
734 312     312   531 my ( $self, $val_num ) = @_;
735 312 50       603 if ( !$self->{"values"} ) { return 0; }
  0         0  
736 312 50       553 if ( defined $val_num )
737             {
738 312         841 return $self->{"values"}->[$val_num]->{value};
739             }
740 0 0       0 if (wantarray)
741             {
742 0         0 return map { $_->{"value"} } @{ $self->{"values"} };
  0         0  
  0         0  
743             }
744             else
745             {
746 0         0 return scalar @{ $self->{"values"} };
  0         0  
747             }
748             }
749              
750             sub column_names
751             {
752 1404     1404   2250 my ($self) = @_;
753 1404         1659 my @col_names;
754 1404 100 100     4192 if ( $self->{column_names} and $self->{column_names}->[0] ne '*' )
755             {
756 462         624 @col_names = @{ $self->{column_names} };
  462         1078  
757             }
758 1404         3221 return @col_names;
759             }
760              
761             ###############################
762             package DBI::SQL::Nano::Table_;
763             ###############################
764              
765 52     52   459 use Carp qw(croak);
  52         104  
  52         22283  
766              
767             sub new ($$)
768             {
769 412     412   1012 my ( $proto, $attr ) = @_;
770 412         1450 my ($self) = {%$attr};
771              
772             defined( $self->{col_names} ) and "ARRAY" eq ref( $self->{col_names} )
773 412 50 33     2193 or croak("attribute 'col_names' must be defined as an array");
774 412 50       1418 exists( $self->{col_nums} ) or $self->{col_nums} = _map_colnums( $self->{col_names} );
775             defined( $self->{col_nums} ) and "HASH" eq ref( $self->{col_nums} )
776 412 50 33     1690 or croak("attribute 'col_nums' must be defined as a hash");
777              
778 412   33     1223 bless( $self, ( ref($proto) || $proto ) );
779 412         1840 return $self;
780             }
781              
782             sub _map_colnums
783             {
784 412     412   663 my $col_names = $_[0];
785 412         613 my %col_nums;
786 412         1171 for my $i ( 0 .. $#$col_names )
787             {
788 640 50       1246 next unless $col_names->[$i];
789 640         1438 $col_nums{ $col_names->[$i] } = $i;
790             }
791 412         980 return \%col_nums;
792             }
793              
794 0     0   0 sub row() { return $_[0]->{row}; }
795 0     0   0 sub column($) { return $_[0]->{row}->[ $_[0]->column_num( $_[1] ) ]; }
796 0     0   0 sub column_num($) { $_[0]->{col_nums}->{ $_[1] }; }
797 1118     1118   2827 sub col_nums() { $_[0]->{col_nums} }
798 1248     1248   2574 sub col_names() { $_[0]->{col_names}; }
799              
800 0     0     sub drop ($$) { croak "Abstract method " . ref( $_[0] ) . "::drop called" }
801 0     0     sub fetch_row ($$$) { croak "Abstract method " . ref( $_[0] ) . "::fetch_row called" }
802 0     0     sub push_row ($$$) { croak "Abstract method " . ref( $_[0] ) . "::push_row called" }
803 0     0     sub push_names ($$$) { croak "Abstract method " . ref( $_[0] ) . "::push_names called" }
804 0     0     sub truncate ($$) { croak "Abstract method " . ref( $_[0] ) . "::truncate called" }
805 0     0     sub seek ($$$$) { croak "Abstract method " . ref( $_[0] ) . "::seek called" }
806              
807             1;
808             __END__