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   320 use strict;
  52         101  
  52         1412  
22 52     52   256 use warnings;
  52         102  
  52         1393  
23 52     52   243 use vars qw( $VERSION $versions );
  52         95  
  52         2291  
24              
25 52     52   276 use Carp qw(croak);
  52         95  
  52         7045  
26              
27             require DBI; # for looks_like_number()
28              
29             BEGIN
30             {
31 52     52   220 $VERSION = "1.015544";
32              
33 52         161 $versions->{nano_version} = $VERSION;
34 52 50 66     364 if ( $ENV{DBI_SQL_NANO} || !eval { require SQL::Statement; $SQL::Statement::VERSION ge '1.400' } )
  28         2215  
  0         0  
35             {
36 52         665 @DBI::SQL::Nano::Statement::ISA = qw(DBI::SQL::Nano::Statement_);
37 52         2099 @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   292 use Carp qw(croak);
  52         95  
  52         2071  
52 52     52   276 use Errno;
  52         103  
  52         208228  
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   1752 my ( $class, $sql ) = @_;
67 732         1339 my $self = {};
68 732         1297 bless $self, $class;
69 732         1985 return $self->prepare($sql);
70             }
71              
72             #####################################################################
73             # PREPARE
74             #####################################################################
75             sub prepare
76             {
77 732     732   1426 my ( $self, $sql ) = @_;
78 732         3159 $sql =~ s/\s+$//;
79 732         1476 $sql =~ s/\s*;$//;
80 732         1480 for ($sql)
81             {
82             /^\s*CREATE\s+TABLE\s+(.*?)\s*\((.+)\)\s*$/is
83             && do
84 732 100       3229 {
85 82         300 $self->{command} = 'CREATE';
86 82         264 $self->{table_name} = $1;
87             defined $2 and $2 ne "" and
88 82 50 33     760 $self->{column_names} = parse_coldef_list($2);
89 82 50       253 $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       2964 {
94 128         488 $self->{command} = 'DROP';
95 128         384 $self->{table_name} = $2;
96             defined $1 and $1 ne "" and
97 128 100 66     693 $self->{ignore_missing_table} = 1;
98             };
99             /^\s*SELECT\s+(.*?)\s+FROM\s+(\S+)((.*))?/is
100             && do
101 732 100       2628 {
102 158         516 $self->{command} = 'SELECT';
103             defined $1 and $1 ne "" and
104 158 50 33     1241 $self->{column_names} = parse_comma_list($1);
105 158 50       529 $self->{column_names} or croak "Can't find columns";
106 158         418 $self->{table_name} = $2;
107 158 100       1274 if ( my $clauses = $4 )
108             {
109 56 100       318 if ( $clauses =~ /^(.*)\s+ORDER\s+BY\s+(.*)$/is )
110             {
111 48         117 $clauses = $1;
112 48         362 $self->{order_clause} = $self->parse_order_clause($2);
113             }
114 56 100       221 $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       2805 {
120 208         643 $self->{command} = 'INSERT';
121 208         600 $self->{table_name} = $1;
122             defined $2 and $2 ne "" and
123 208 100 66     841 $self->{column_names} = parse_comma_list($2);
124             defined $4 and $4 ne "" and
125 208 50 33     2033 $self->{values} = $self->parse_values_list($4);
126 208 50       676 $self->{values} or croak "Can't parse values";
127             };
128             /^\s*DELETE\s+FROM\s+(\S+)((.*))?/is
129             && do
130 732 100       2151 {
131 64         224 $self->{command} = 'DELETE';
132 64         201 $self->{table_name} = $1;
133             defined $3 and $3 ne "" and
134 64 100 66     637 $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       2301 {
139 44         154 $self->{command} = 'UPDATE';
140 44         144 $self->{table_name} = $1;
141 44 50 33     531 defined $2 and $2 ne "" and
142             $self->parse_set_clause($2);
143             defined $3 and $3 ne "" and
144 44 50 33     406 $self->{where_clause} = $self->parse_where_clause($3);
145             };
146             }
147 732 100 66     10147 croak "Couldn't parse" unless ( $self->{command} and $self->{table_name} );
148 684         1960 return $self;
149             }
150              
151             sub parse_order_clause
152             {
153 48     48   161 my ( $self, $str ) = @_;
154 48         181 my @clause = split /\s+/, $str;
155 48 100       262 return { $clause[0] => 'ASC' } if ( @clause == 1 );
156 12 50       40 croak "Bad ORDER BY clause '$str'" if ( @clause > 2 );
157 12   50     36 $clause[1] ||= '';
158 12 50 33     185 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   175 my @col_defs;
167 82         389 for ( split ',', shift )
168             {
169 156         371 my $col = clean_parse_str($_);
170 156 50       633 if ( $col =~ /^(\S+?)\s+.+/ )
171             { # doesn't check what it is
172 156         347 $col = $1; # just checks if it exists
173             }
174             else
175             {
176 0         0 croak "No column definition for '$_'";
177             }
178 156         362 push @col_defs, $col;
179             }
180 82         250 return \@col_defs;
181             }
182              
183             sub parse_comma_list
184             {
185 190     190   792 [ map { clean_parse_str($_) } split( ',', shift ) ];
  282         641  
186             }
187 850     850   1456 sub clean_parse_str { local $_ = shift; s/\(//; s/\)//; s/^\s+//; s/\s+$//; $_; }
  850         1528  
  850         1241  
  850         1803  
  850         1671  
  850         3811  
188              
189             sub parse_values_list
190             {
191 208     208   806 my ( $self, $str ) = @_;
192 208         856 [ map { $self->parse_value( clean_parse_str($_) ) } split( ',', $str ) ];
  412         891  
193             }
194              
195             sub parse_set_clause
196             {
197 44     44   747 my $self = shift;
198 44         185 my @cols = split /,/, shift;
199 44         91 my $set_clause;
200 44         110 for my $col (@cols)
201             {
202 44         283 my ( $col_name, $value ) = $col =~ /^\s*(.+?)\s*=\s*(.+?)\s*$/s;
203 44         101 push @{ $self->{column_names} }, $col_name;
  44         154  
204 44         88 push @{ $self->{values} }, $self->parse_value($value);
  44         194  
205             }
206 44 50 33     295 croak "Can't parse set clause" unless ( $self->{column_names} and $self->{values} );
207             }
208              
209             sub parse_value
210             {
211 624     624   1304 my ( $self, $str ) = @_;
212 624 50       1315 return unless ( defined $str );
213 624         1076 $str =~ s/\s+$//;
214 624         1103 $str =~ s/^\s+//;
215 624 100       1435 if ( $str =~ /^\?$/ )
216             {
217 164         240 push @{ $self->{params} }, '?';
  164         398  
218             return {
219 164         830 value => '?',
220             type => 'placeholder'
221             };
222             }
223             return {
224 460 100       947 value => undef,
225             type => 'NULL'
226             } if ( $str =~ /^NULL$/i );
227             return {
228 448 100       1728 value => $1,
229             type => 'string'
230             } if ( $str =~ /^'(.+)'$/s );
231             return {
232 312 100       1207 value => $str,
233             type => 'number'
234             } if ( DBI::looks_like_number($str) );
235             return {
236 132         608 value => $str,
237             type => 'column'
238             };
239             }
240              
241             sub parse_where_clause
242             {
243 84     84   250 my ( $self, $str ) = @_;
244 84         294 $str =~ s/\s+$//;
245 84 50       326 if ( $str =~ /^\s*WHERE\s+(.*)/i )
246             {
247 84         201 $str = $1;
248             }
249             else
250             {
251 0         0 croak "Couldn't find WHERE clause in '$str'";
252             }
253 84         239 my ($neg) = $str =~ s/^\s*(NOT)\s+//is;
254 84         162 my $opexp = '=|<>|<=|>=|<|>|LIKE|CLIKE|IS';
255 84         1609 my ( $val1, $op, $val2 ) = $str =~ /^(.+?)\s*($opexp)\s*(.+)\s*$/iso;
256 84 50 33     562 croak "Couldn't parse WHERE expression '$str'" unless ( defined $val1 and defined $op and defined $val2 );
      33        
257             return {
258 84         251 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   1212 my ( $self, $data, $params ) = @_;
271 484         993 my $num_placeholders = $self->params;
272 484   100     1742 my $num_params = scalar @$params || 0;
273 484 50       1129 croak "Number of params '$num_params' does not match number of placeholders '$num_placeholders'"
274             unless ( $num_placeholders == $num_params );
275 484 100       1170 if ( scalar @$params )
276             {
277 64         123 for my $i ( 0 .. $#{ $self->{values} } )
  64         262  
278             {
279 120 50       316 if ( $self->{values}->[$i]->{type} eq 'placeholder' )
280             {
281 120         307 $self->{values}->[$i]->{value} = shift @$params;
282             }
283             }
284 64 50       200 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         971 my $command = $self->{command};
297 484         2716 ( $self->{'NUM_OF_ROWS'}, $self->{'NUM_OF_FIELDS'}, $self->{'data'}, ) = $self->$command( $data, $params );
298 452   66     2636 $self->{NAME} ||= $self->{column_names};
299 452   100     3469 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   319 my ( $self, $data, $params ) = @_;
308              
309 120         230 my $table;
310             my @err;
311 120         340 eval {
312 120     0   879 local $SIG{__WARN__} = sub { push @err, @_ };
  0         0  
313 120         483 ($table) = $self->open_tables( $data, 0, 1 );
314             };
315 120 100 66     3515 if ( $self->{ignore_missing_table} and ( $@ or @err ) and grep { $_ =~ $enoentrx } ( @err, $@ ) )
  40   100     463  
      66        
316             {
317 40         92 $@ = '';
318 40         179 return ( -1, 0 );
319             }
320              
321 80 100 33     1102 croak( $@ || $err[0] ) if ( $@ || @err );
      66        
322 72 50       1048 return ( -1, 0 ) unless $table;
323              
324 72         354 $table->drop($data);
325 72         361 ( -1, 0 );
326             }
327              
328             sub CREATE ($$$)
329             {
330 62     62   338 my ( $self, $data, $params ) = @_;
331 62         300 my $table = $self->open_tables( $data, 1, 1 );
332 62         330 $table->push_names( $data, $self->{column_names} );
333 62         568 ( 0, 0 );
334             }
335              
336             sub INSERT ($$$)
337             {
338 136     136   302 my ( $self, $data, $params ) = @_;
339 136         405 my $table = $self->open_tables( $data, 0, 1 );
340 128         672 $self->verify_columns($table);
341 128         238 my $all_columns = $table->{col_names};
342 128 50       969 $table->seek( $data, 0, 2 ) unless ( $table->can('insert_one_row') );
343 128         255 my ($array) = [];
344 128         222 my ( $val, $col, $i );
345 128 50       303 $self->{column_names} = $table->col_names() unless ( $self->{column_names} );
346 128 50       383 my $cNum = scalar( @{ $self->{column_names} } ) if ( $self->{column_names} );
  128         265  
347 128         216 my $param_num = 0;
348              
349 128 50       269 $cNum or
350             croak "Bad col names in INSERT";
351              
352 128         226 my $maxCol = $#$all_columns;
353              
354 128         376 for ( $i = 0; $i < $cNum; $i++ )
355             {
356 256         457 $col = $self->{column_names}->[$i];
357 256         647 $array->[ $self->column_nums( $table, $col ) ] = $self->row_values($i);
358             }
359              
360             # Extend row to put values in ALL fields
361 128 50       327 $#$array < $maxCol and $array->[$maxCol] = undef;
362              
363 128 50       781 $table->can('insert_new_row') ? $table->insert_new_row( $data, $array ) : $table->push_row( $data, $array );
364              
365 128         525 return ( 1, 0 );
366             }
367              
368             sub DELETE ($$$)
369             {
370 32     32   96 my ( $self, $data, $params ) = @_;
371 32         205 my $table = $self->open_tables( $data, 0, 1 );
372 24         99 $self->verify_columns($table);
373 24         54 my ($affected) = 0;
374 24         48 my ( @rows, $array );
375 24         100 my $can_dor = $table->can('delete_one_row');
376 24         106 while ( $array = $table->fetch_row($data) )
377             {
378 96 100       294 if ( $self->eval_where( $table, $array ) )
379             {
380 56         84 ++$affected;
381 56 100       127 if ( $self->{fetched_from_key} )
382             {
383 8         22 $array = $self->{fetched_value};
384 8         40 $table->delete_one_row( $data, $array );
385 8         51 return ( $affected, 0 );
386             }
387 48 50       163 push( @rows, $array ) if ($can_dor);
388             }
389             else
390             {
391 40 50       124 push( @rows, $array ) unless ($can_dor);
392             }
393             }
394 16 50       57 if ($can_dor)
395             {
396 16         38 foreach $array (@rows)
397             {
398 48         1038 $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         95 return ( $affected, 0 );
411             }
412              
413             sub _anycmp($$;$)
414             {
415 64     64   157 my ( $a, $b, $case_fold ) = @_;
416              
417 64 50 33     473 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         192 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   270 my ( $self, $data, $params ) = @_;
434 102         367 my $table = $self->open_tables( $data, 0, 0 );
435 94         424 $self->verify_columns($table);
436 94         218 my $tname = $self->{table_name};
437 94         192 my ($affected) = 0;
438 94         183 my ( @rows, %cols, $array, $val, $col, $i );
439 94         408 while ( $array = $table->fetch_row($data) )
440             {
441 200 50       839 if ( $self->eval_where( $table, $array ) )
442             {
443 200 50       592 $array = $self->{fetched_value} if ( $self->{fetched_from_key} );
444 200 100       449 unless ( keys %cols )
445             {
446 94         207 my $col_nums = $self->column_nums($table);
447 94         177 %cols = reverse %{$col_nums};
  94         408  
448             }
449              
450 200         348 my $rowhash;
451 200         679 for ( sort keys %cols )
452             {
453 376         966 $rowhash->{ $cols{$_} } = $array->[$_];
454             }
455 200         323 my @newarray;
456 200         320 for ( $i = 0; $i < @{ $self->{column_names} }; $i++ )
  576         1137  
457             {
458 376         547 $col = $self->{column_names}->[$i];
459 376         696 push @newarray, $rowhash->{$col};
460             }
461 200         361 push( @rows, \@newarray );
462 0         0 return ( scalar(@rows), scalar @{ $self->{column_names} }, \@rows )
463 200 50       794 if ( $self->{fetched_from_key} );
464             }
465             }
466 94 100       332 if ( $self->{order_clause} )
467             {
468 32         56 my ( $sort_col, $desc ) = each %{ $self->{order_clause} };
  32         124  
469 32         107 my @sortCols = ( $self->column_nums( $table, $sort_col, 1 ) );
470 32 100       115 $sortCols[1] = uc $desc eq 'DESC' ? 1 : 0;
471              
472             @rows = sort {
473 32         167 my ( $result, $colNum, $desc );
  64         118  
474 64         101 my $i = 0;
475             do
476 64   33     100 {
477 64         111 $colNum = $sortCols[ $i++ ];
478 64         99 $desc = $sortCols[ $i++ ];
479 64         176 $result = _anycmp( $a->[$colNum], $b->[$colNum] );
480 64 100       265 $result = -$result if ($desc);
481             } while ( !$result && $i < @sortCols );
482             $result;
483             } @rows;
484             }
485 94         212 ( scalar(@rows), scalar @{ $self->{column_names} }, \@rows );
  94         513  
486             }
487              
488             sub UPDATE ($$$)
489             {
490 32     32   146 my ( $self, $data, $params ) = @_;
491 32         115 my $table = $self->open_tables( $data, 0, 1 );
492 32         155 $self->verify_columns($table);
493 32 50       104 return undef unless $table;
494 32         66 my $affected = 0;
495 32         147 my $can_usr = $table->can('update_specific_row');
496 32         125 my $can_uor = $table->can('update_one_row');
497 32   33     104 my $can_rwu = $can_usr || $can_uor;
498 32         81 my ( @rows, $array, $f_array, $val, $col, $i );
499              
500 32         131 while ( $array = $table->fetch_row($data) )
501             {
502 56 50       165 if ( $self->eval_where( $table, $array ) )
503             {
504 56 100 66     198 $array = $self->{fetched_value} if ( $self->{fetched_from_key} and $can_rwu );
505 56 50       1376 my $orig_ary = clone($array) if ($can_usr);
506 56         144 for ( $i = 0; $i < @{ $self->{column_names} }; $i++ )
  112         289  
507             {
508 56         129 $col = $self->{column_names}->[$i];
509 56         160 $array->[ $self->column_nums( $table, $col ) ] = $self->row_values($i);
510             }
511 56         93 $affected++;
512 56 100       152 if ( $self->{fetched_value} )
513             {
514 8 50       29 if ($can_usr)
    0          
515             {
516 8         36 $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         52 return ( $affected, 0 );
523             }
524 48 50       278 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       72 if ($can_rwu)
532             {
533 24         63 foreach my $array (@rows)
534             {
535 48 50       112 if ($can_usr)
    0          
536             {
537 48         128 $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         133 return ( $affected, 0 );
556             }
557              
558             sub verify_columns
559             {
560 278     278   630 my ( $self, $table ) = @_;
561 278         442 my @cols = @{ $self->{column_names} };
  278         937  
562 278 100       776 if ( $self->{where_clause} )
563             {
564 48 50       170 if ( my $col = $self->{where_clause}->{arg1} )
565             {
566 48 50       200 push @cols, $col->{value} if $col->{type} eq 'column';
567             }
568 48 50       153 if ( my $col = $self->{where_clause}->{arg2} )
569             {
570 48 50       157 push @cols, $col->{value} if $col->{type} eq 'column';
571             }
572             }
573 278         610 for (@cols)
574             {
575 560         1294 $self->column_nums( $table, $_ );
576             }
577             }
578              
579             sub column_nums
580             {
581 998     998   1810 my ( $self, $table, $stmt_col_name, $find_in_stmt ) = @_;
582 998         1192 my %dbd_nums = %{ $table->col_nums() };
  998         1786  
583 998         1534 my @dbd_cols = @{ $table->col_names() };
  998         1615  
584 998         1326 my %stmt_nums;
585 998 100 100     2796 if ( $stmt_col_name and !$find_in_stmt )
586             {
587 872         2253 while ( my ( $k, $v ) = each %dbd_nums )
588             {
589 1293 100       4904 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     394 if ( $stmt_col_name and $find_in_stmt )
594             {
595 32         60 for my $i ( 0 .. @{ $self->{column_names} } )
  32         109  
596             {
597 32 50       182 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         284 for my $i ( 0 .. $#dbd_cols )
602             {
603 176         259 for my $stmt_col ( @{ $self->{column_names} } )
  176         351  
604             {
605 340 100       871 $stmt_nums{$stmt_col} = $i if uc $dbd_cols[$i] eq uc $stmt_col;
606             }
607             }
608 94         301 return \%stmt_nums;
609             }
610              
611             sub eval_where
612             {
613 352     352   645 my ( $self, $table, $rowary ) = @_;
614 352   100     1002 my $where = $self->{"where_clause"} || return 1;
615 120         238 my $col_nums = $table->col_nums();
616 120         171 my %cols = reverse %{$col_nums};
  120         393  
617 120         167 my $rowhash;
618 120         443 for ( sort keys %cols )
619             {
620 240         711 $rowhash->{ uc $cols{$_} } = $rowary->[$_];
621             }
622 120         441 return $self->process_predicate( $where, $table, $rowhash );
623             }
624              
625             sub process_predicate
626             {
627 120     120   237 my ( $self, $pred, $table, $rowhash ) = @_;
628 120         228 my $val1 = $pred->{arg1};
629 120 50       261 if ( $val1->{type} eq 'column' )
630             {
631 120         264 $val1 = $rowhash->{ uc $val1->{value} };
632             }
633             else
634             {
635 0         0 $val1 = $val1->{value};
636             }
637 120         191 my $val2 = $pred->{arg2};
638 120 50       266 if ( $val2->{type} eq 'column' )
639             {
640 0         0 $val2 = $rowhash->{ uc $val2->{value} };
641             }
642             else
643             {
644 120         191 $val2 = $val2->{value};
645             }
646 120         277 my $op = $pred->{op};
647 120         178 my $neg = $pred->{neg};
648 120 50 33     772 if ( $op eq '=' and !$neg and $table->can('fetch_one_row') )
      33        
649             {
650 120         321 my $key_col = $table->fetch_one_row( 1, 1 );
651 120 100       785 if ( $pred->{arg1}->{value} =~ /^$key_col$/i )
652             {
653 16         43 $self->{fetched_from_key} = 1;
654 16         52 $self->{fetched_value} = $table->fetch_one_row( 0, $pred->{arg2}->{value} );
655 16         85 return 1;
656             }
657             }
658 104   100     295 my $match = $self->is_matched( $val1, $op, $val2 ) || 0;
659 104 0       216 if ($neg) { $match = $match ? 0 : 1; }
  0 50       0  
660 104         381 return $match;
661             }
662              
663             sub is_matched
664             {
665 104     104   218 my ( $self, $val1, $op, $val2 ) = @_;
666 104 50       242 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       194 $val1 = '' unless ( defined $val1 );
672 104 50       184 $val2 = '' unless ( defined $val2 );
673 104 50       193 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       183 if ( $op eq 'LIKE' ) { return $val1 =~ /^$val2$/s; }
  0         0  
680 104 50       276 if ( $op eq 'CLIKE' ) { return $val1 =~ /^$val2$/si; }
  0         0  
681 104 50 33     448 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       211 if ( $op eq '<' ) { return $val1 lt $val2; }
  0         0  
693 104 50       199 if ( $op eq '>' ) { return $val1 gt $val2; }
  0         0  
694 104 50       200 if ( $op eq '=' ) { return $val1 eq $val2; }
  104         348  
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   2916 my ( $self, $val_num ) = @_;
704 1652 100       4487 if ( !$self->{"params"} ) { return 0; }
  1436         4055  
705 216 50       539 if ( defined $val_num )
706             {
707 0         0 return $self->{"params"}->[$val_num];
708             }
709              
710 216 50       506 return wantarray ? @{ $self->{"params"} } : scalar @{ $self->{"params"} };
  0         0  
  216         687  
711             }
712              
713             sub open_tables
714             {
715 484     484   1187 my ( $self, $data, $createMode, $lockMode ) = @_;
716 484         991 my $table_name = $self->{table_name};
717 484         651 my $table;
718 484         658 eval { $table = $self->open_table( $data, $table_name, $createMode, $lockMode ) };
  484         1612  
719 484 100       5702 if ($@)
720             {
721 72         175 chomp $@;
722 72         7088 croak $@;
723             }
724 412 50       1185 croak "Couldn't open table '$table_name'" unless $table;
725 412 100 100     1667 if ( !$self->{column_names} or $self->{column_names}->[0] eq '*' )
726             {
727 250         1016 $self->{column_names} = $table->col_names();
728             }
729 412         1280 return $table;
730             }
731              
732             sub row_values
733             {
734 312     312   559 my ( $self, $val_num ) = @_;
735 312 50       646 if ( !$self->{"values"} ) { return 0; }
  0         0  
736 312 50       583 if ( defined $val_num )
737             {
738 312         924 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   2401 my ($self) = @_;
753 1404         1699 my @col_names;
754 1404 100 100     4313 if ( $self->{column_names} and $self->{column_names}->[0] ne '*' )
755             {
756 462         670 @col_names = @{ $self->{column_names} };
  462         1149  
757             }
758 1404         3247 return @col_names;
759             }
760              
761             ###############################
762             package DBI::SQL::Nano::Table_;
763             ###############################
764              
765 52     52   490 use Carp qw(croak);
  52         108  
  52         24195  
766              
767             sub new ($$)
768             {
769 412     412   1111 my ( $proto, $attr ) = @_;
770 412         1609 my ($self) = {%$attr};
771              
772             defined( $self->{col_names} ) and "ARRAY" eq ref( $self->{col_names} )
773 412 50 33     2273 or croak("attribute 'col_names' must be defined as an array");
774 412 50       1656 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     1855 or croak("attribute 'col_nums' must be defined as a hash");
777              
778 412   33     1442 bless( $self, ( ref($proto) || $proto ) );
779 412         2053 return $self;
780             }
781              
782             sub _map_colnums
783             {
784 412     412   717 my $col_names = $_[0];
785 412         625 my %col_nums;
786 412         1281 for my $i ( 0 .. $#$col_names )
787             {
788 640 50       1310 next unless $col_names->[$i];
789 640         1575 $col_nums{ $col_names->[$i] } = $i;
790             }
791 412         1157 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   3150 sub col_nums() { $_[0]->{col_nums} }
798 1248     1248   2822 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__