File Coverage

blib/lib/DBI/SQL/Nano.pm
Criterion Covered Total %
statement 374 450 83.1
branch 147 252 58.3
condition 62 121 51.2
subroutine 39 49 79.5
pod n/a
total 622 872 71.3


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 48     48   210 use strict;
  48         64  
  48         1601  
22 48     48   183 use warnings;
  48         63  
  48         1229  
23 48     48   185 use vars qw( $VERSION $versions );
  48         62  
  48         2084  
24              
25 48     48   217 use Carp qw(croak);
  48         65  
  48         6244  
26              
27             require DBI; # for looks_like_number()
28              
29             BEGIN
30             {
31 48     48   98 $VERSION = "1.015544";
32              
33 48         108 $versions->{nano_version} = $VERSION;
34 48 50 66     346 if ( $ENV{DBI_SQL_NANO} || !eval { require SQL::Statement; $SQL::Statement::VERSION ge '1.400' } )
  24         4773  
  0         0  
35             {
36 48         639 @DBI::SQL::Nano::Statement::ISA = qw(DBI::SQL::Nano::Statement_);
37 48         1834 @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 48     48   238 use Carp qw(croak);
  48         84  
  48         2107  
52 48     48   211 use Errno;
  48         58  
  48         199006  
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 724     724   1188 my ( $class, $sql ) = @_;
67 724         1243 my $self = {};
68 724         1430 bless $self, $class;
69 724         2096 return $self->prepare($sql);
70             }
71              
72             #####################################################################
73             # PREPARE
74             #####################################################################
75             sub prepare
76             {
77 724     724   993 my ( $self, $sql ) = @_;
78 724         3166 $sql =~ s/\s+$//;
79 724         1461 for ($sql)
80             {
81             /^\s*CREATE\s+TABLE\s+(.*?)\s*\((.+)\)\s*$/is
82             && do
83 724 100       2669 {
84 80         300 $self->{command} = 'CREATE';
85 80         261 $self->{table_name} = $1;
86 80 50 33     1513 defined $2 and $2 ne "" and
87             $self->{column_names} = parse_coldef_list($2);
88 80 50       278 $self->{column_names} or croak "Can't find columns";
89             };
90             /^\s*DROP\s+TABLE\s+(IF\s+EXISTS\s+)?(.*?)\s*$/is
91             && do
92 724 100       3199 {
93 128         544 $self->{command} = 'DROP';
94 128         391 $self->{table_name} = $2;
95 128 100 66     843 defined $1 and $1 ne "" and
96             $self->{ignore_missing_table} = 1;
97             };
98             /^\s*SELECT\s+(.*?)\s+FROM\s+(\S+)((.*))?/is
99             && do
100 724 100       2638 {
101 156         506 $self->{command} = 'SELECT';
102 156 50 33     1398 defined $1 and $1 ne "" and
103             $self->{column_names} = parse_comma_list($1);
104 156 50       520 $self->{column_names} or croak "Can't find columns";
105 156         417 $self->{table_name} = $2;
106 156 100       563 if ( my $clauses = $4 )
107             {
108 56 100       345 if ( $clauses =~ /^(.*)\s+ORDER\s+BY\s+(.*)$/is )
109             {
110 48         82 $clauses = $1;
111 48         399 $self->{order_clause} = $self->parse_order_clause($2);
112             }
113 56 100       264 $self->{where_clause} = $self->parse_where_clause($clauses) if ($clauses);
114             }
115             };
116             /^\s*INSERT\s+(?:INTO\s+)?(\S+)\s*(\((.*?)\))?\s*VALUES\s*\((.+)\)/is
117             && do
118 724 100       2691 {
119 204         610 $self->{command} = 'INSERT';
120 204         623 $self->{table_name} = $1;
121 204 100 66     841 defined $2 and $2 ne "" and
122             $self->{column_names} = parse_comma_list($2);
123 204 50 33     2323 defined $4 and $4 ne "" and
124             $self->{values} = $self->parse_values_list($4);
125 204 50       640 $self->{values} or croak "Can't parse values";
126             };
127             /^\s*DELETE\s+FROM\s+(\S+)((.*))?/is
128             && do
129 724 100       2290 {
130 64         194 $self->{command} = 'DELETE';
131 64         212 $self->{table_name} = $1;
132 64 100 66     683 defined $3 and $3 ne "" and
133             $self->{where_clause} = $self->parse_where_clause($3);
134             };
135             /^\s*UPDATE\s+(\S+)\s+SET\s+(.+)(\s+WHERE\s+.+)/is
136             && do
137 724 100       2689 {
138 44         149 $self->{command} = 'UPDATE';
139 44         138 $self->{table_name} = $1;
140 44 50 33     881 defined $2 and $2 ne "" and
141             $self->parse_set_clause($2);
142 44 50 33     447 defined $3 and $3 ne "" and
143             $self->{where_clause} = $self->parse_where_clause($3);
144             };
145             }
146 724 100 66     12146 croak "Couldn't parse" unless ( $self->{command} and $self->{table_name} );
147 676         2485 return $self;
148             }
149              
150             sub parse_order_clause
151             {
152 48     48   103 my ( $self, $str ) = @_;
153 48         158 my @clause = split /\s+/, $str;
154 48 100       269 return { $clause[0] => 'ASC' } if ( @clause == 1 );
155 12 50       38 croak "Bad ORDER BY clause '$str'" if ( @clause > 2 );
156 12   50     38 $clause[1] ||= '';
157 12 50 33     154 return { $clause[0] => uc $clause[1] }
158             if $clause[1] =~ /^ASC$/i
159             or $clause[1] =~ /^DESC$/i;
160 0         0 croak "Bad ORDER BY clause '$clause[1]'";
161             }
162              
163             sub parse_coldef_list
164             { # check column definitions
165 80     80   112 my @col_defs;
166 80         396 for ( split ',', shift )
167             {
168 152         365 my $col = clean_parse_str($_);
169 152 50       601 if ( $col =~ /^(\S+?)\s+.+/ )
170             { # doesn't check what it is
171 152         280 $col = $1; # just checks if it exists
172             }
173             else
174             {
175 0         0 croak "No column definition for '$_'";
176             }
177 152         336 push @col_defs, $col;
178             }
179 80         275 return \@col_defs;
180             }
181              
182             sub parse_comma_list
183             {
184 184     184   860 [ map { clean_parse_str($_) } split( ',', shift ) ];
  272         1336  
185             }
186 828     828   1239 sub clean_parse_str { local $_ = shift; s/\(//; s/\)//; s/^\s+//; s/\s+$//; $_; }
  828         1337  
  828         950  
  828         1573  
  828         1417  
  828         2544  
187              
188             sub parse_values_list
189             {
190 204     204   385 my ( $self, $str ) = @_;
191 204         850 [ map { $self->parse_value( clean_parse_str($_) ) } split( ',', $str ) ];
  404         777  
192             }
193              
194             sub parse_set_clause
195             {
196 44     44   79 my $self = shift;
197 44         252 my @cols = split /,/, shift;
198 44         63 my $set_clause;
199 44         100 for my $col (@cols)
200             {
201 44         287 my ( $col_name, $value ) = $col =~ /^\s*(.+?)\s*=\s*(.+?)\s*$/s;
202 44         83 push @{ $self->{column_names} }, $col_name;
  44         151  
203 44         66 push @{ $self->{values} }, $self->parse_value($value);
  44         208  
204             }
205 44 50 33     398 croak "Can't parse set clause" unless ( $self->{column_names} and $self->{values} );
206             }
207              
208             sub parse_value
209             {
210 616     616   843 my ( $self, $str ) = @_;
211 616 50       1227 return unless ( defined $str );
212 616         974 $str =~ s/\s+$//;
213 616         1261 $str =~ s/^\s+//;
214 616 100       1638 if ( $str =~ /^\?$/ )
215             {
216 164         164 push @{ $self->{params} }, '?';
  164         391  
217             return {
218 164         781 value => '?',
219             type => 'placeholder'
220             };
221             }
222             return {
223 452 100       1045 value => undef,
224             type => 'NULL'
225             } if ( $str =~ /^NULL$/i );
226             return {
227 440 100       1859 value => $1,
228             type => 'string'
229             } if ( $str =~ /^'(.+)'$/s );
230             return {
231 304 100       1364 value => $str,
232             type => 'number'
233             } if ( DBI::looks_like_number($str) );
234             return {
235 132         757 value => $str,
236             type => 'column'
237             };
238             }
239              
240             sub parse_where_clause
241             {
242 84     84   171 my ( $self, $str ) = @_;
243 84         270 $str =~ s/\s+$//;
244 84 50       358 if ( $str =~ /^\s*WHERE\s+(.*)/i )
245             {
246 84         192 $str = $1;
247             }
248             else
249             {
250 0         0 croak "Couldn't find WHERE clause in '$str'";
251             }
252 84         248 my ($neg) = $str =~ s/^\s*(NOT)\s+//is;
253 84         137 my $opexp = '=|<>|<=|>=|<|>|LIKE|CLIKE|IS';
254 84         2108 my ( $val1, $op, $val2 ) = $str =~ /^(.+?)\s*($opexp)\s*(.+)\s*$/iso;
255 84 50 33     676 croak "Couldn't parse WHERE expression '$str'" unless ( defined $val1 and defined $op and defined $val2 );
      33        
256             return {
257 84         245 arg1 => $self->parse_value($val1),
258             arg2 => $self->parse_value($val2),
259             op => $op,
260             neg => $neg,
261             };
262             }
263              
264             #####################################################################
265             # EXECUTE
266             #####################################################################
267             sub execute
268             {
269 476     476   713 my ( $self, $data, $params ) = @_;
270 476         1064 my $num_placeholders = $self->params;
271 476   100     2021 my $num_params = scalar @$params || 0;
272 476 50       1096 croak "Number of params '$num_params' does not match number of placeholders '$num_placeholders'"
273             unless ( $num_placeholders == $num_params );
274 476 100       1208 if ( scalar @$params )
275             {
276 64         133 for my $i ( 0 .. $#{ $self->{values} } )
  64         227  
277             {
278 120 50       365 if ( $self->{values}->[$i]->{type} eq 'placeholder' )
279             {
280 120         306 $self->{values}->[$i]->{value} = shift @$params;
281             }
282             }
283 64 50       217 if ( $self->{where_clause} )
284             {
285 0 0       0 if ( $self->{where_clause}->{arg1}->{type} eq 'placeholder' )
286             {
287 0         0 $self->{where_clause}->{arg1}->{value} = shift @$params;
288             }
289 0 0       0 if ( $self->{where_clause}->{arg2}->{type} eq 'placeholder' )
290             {
291 0         0 $self->{where_clause}->{arg2}->{value} = shift @$params;
292             }
293             }
294             }
295 476         932 my $command = $self->{command};
296 476         3293 ( $self->{'NUM_OF_ROWS'}, $self->{'NUM_OF_FIELDS'}, $self->{'data'}, ) = $self->$command( $data, $params );
297 444   66     2726 $self->{NAME} ||= $self->{column_names};
298 444   100     4108 return $self->{'NUM_OF_ROWS'} || '0E0';
299             }
300              
301             my $enoentstr = "Cannot open .*\(" . Errno::ENOENT . "\)";
302             my $enoentrx = qr/$enoentstr/;
303              
304             sub DROP ($$$)
305             {
306 120     120   326 my ( $self, $data, $params ) = @_;
307              
308 120         155 my $table;
309             my @err;
310 120         162 eval {
311 120     0   808 local $SIG{__WARN__} = sub { push @err, @_ };
  0         0  
312 120         504 ($table) = $self->open_tables( $data, 0, 1 );
313             };
314 120 100 66     3929 if ( $self->{ignore_missing_table} and ( $@ or @err ) and grep { $_ =~ $enoentrx } ( @err, $@ ) )
  40   66     536  
      66        
315             {
316 40         74 $@ = '';
317 40         212 return ( -1, 0 );
318             }
319              
320 80 100 33     1239 croak( $@ || $err[0] ) if ( $@ || @err );
      66        
321 72 50       219 return ( -1, 0 ) unless $table;
322              
323 72         289 $table->drop($data);
324 72         381 ( -1, 0 );
325             }
326              
327             sub CREATE ($$$)
328             {
329 60     60   362 my ( $self, $data, $params ) = @_;
330 60         432 my $table = $self->open_tables( $data, 1, 1 );
331 60         399 $table->push_names( $data, $self->{column_names} );
332 60         630 ( 0, 0 );
333             }
334              
335             sub INSERT ($$$)
336             {
337 132     132   224 my ( $self, $data, $params ) = @_;
338 132         523 my $table = $self->open_tables( $data, 0, 1 );
339 124         583 $self->verify_columns($table);
340 124         216 my $all_columns = $table->{col_names};
341 124 50       1153 $table->seek( $data, 0, 2 ) unless ( $table->can('insert_one_row') );
342 124         235 my ($array) = [];
343 124         170 my ( $val, $col, $i );
344 124 50       409 $self->{column_names} = $table->col_names() unless ( $self->{column_names} );
345 124 50       312 my $cNum = scalar( @{ $self->{column_names} } ) if ( $self->{column_names} );
  124         246  
346 124         235 my $param_num = 0;
347              
348 124 50       282 $cNum or
349             croak "Bad col names in INSERT";
350              
351 124         209 my $maxCol = $#$all_columns;
352              
353 124         369 for ( $i = 0; $i < $cNum; $i++ )
354             {
355 248         379 $col = $self->{column_names}->[$i];
356 248         658 $array->[ $self->column_nums( $table, $col ) ] = $self->row_values($i);
357             }
358              
359             # Extend row to put values in ALL fields
360 124 50       333 $#$array < $maxCol and $array->[$maxCol] = undef;
361              
362 124 50       815 $table->can('insert_new_row') ? $table->insert_new_row( $data, $array ) : $table->push_row( $data, $array );
363              
364 124         553 return ( 1, 0 );
365             }
366              
367             sub DELETE ($$$)
368             {
369 32     32   60 my ( $self, $data, $params ) = @_;
370 32         109 my $table = $self->open_tables( $data, 0, 1 );
371 24         92 $self->verify_columns($table);
372 24         47 my ($affected) = 0;
373 24         33 my ( @rows, $array );
374 24         97 my $can_dor = $table->can('delete_one_row');
375 24         105 while ( $array = $table->fetch_row($data) )
376             {
377 96 100       284 if ( $self->eval_where( $table, $array ) )
378             {
379 56         72 ++$affected;
380 56 100       135 if ( $self->{fetched_from_key} )
381             {
382 8         20 $array = $self->{fetched_value};
383 8         34 $table->delete_one_row( $data, $array );
384 8         46 return ( $affected, 0 );
385             }
386 48 50       167 push( @rows, $array ) if ($can_dor);
387             }
388             else
389             {
390 40 50       143 push( @rows, $array ) unless ($can_dor);
391             }
392             }
393 16 50       54 if ($can_dor)
394             {
395 16         33 foreach $array (@rows)
396             {
397 48         159 $table->delete_one_row( $data, $array );
398             }
399             }
400             else
401             {
402 0         0 $table->seek( $data, 0, 0 );
403 0         0 foreach $array (@rows)
404             {
405 0         0 $table->push_row( $data, $array );
406             }
407 0         0 $table->truncate($data);
408             }
409 16         99 return ( $affected, 0 );
410             }
411              
412             sub _anycmp($$;$)
413             {
414 64     64   100 my ( $a, $b, $case_fold ) = @_;
415              
416 64 50 33     525 if ( !defined($a) || !defined($b) )
    50 33        
417             {
418 0         0 return defined($a) - defined($b);
419             }
420             elsif ( DBI::looks_like_number($a) && DBI::looks_like_number($b) )
421             {
422 64         150 return $a <=> $b;
423             }
424             else
425             {
426 0 0 0     0 return $case_fold ? lc($a) cmp lc($b) || $a cmp $b : $a cmp $b;
427             }
428             }
429              
430             sub SELECT ($$$)
431             {
432 100     100   177 my ( $self, $data, $params ) = @_;
433 100         426 my $table = $self->open_tables( $data, 0, 0 );
434 92         483 $self->verify_columns($table);
435 92         195 my $tname = $self->{table_name};
436 92         162 my ($affected) = 0;
437 92         267 my ( @rows, %cols, $array, $val, $col, $i );
438 92         464 while ( $array = $table->fetch_row($data) )
439             {
440 196 50       918 if ( $self->eval_where( $table, $array ) )
441             {
442 196 50       652 $array = $self->{fetched_value} if ( $self->{fetched_from_key} );
443 196 100       595 unless ( keys %cols )
444             {
445 92         228 my $col_nums = $self->column_nums($table);
446 92         144 %cols = reverse %{$col_nums};
  92         482  
447             }
448              
449 196         325 my $rowhash;
450 196         629 for ( sort keys %cols )
451             {
452 368         888 $rowhash->{ $cols{$_} } = $array->[$_];
453             }
454 196         260 my @newarray;
455 196         283 for ( $i = 0; $i < @{ $self->{column_names} }; $i++ )
  564         1114  
456             {
457 368         422 $col = $self->{column_names}->[$i];
458 368         603 push @newarray, $rowhash->{$col};
459             }
460 196         276 push( @rows, \@newarray );
461 196 50       943 return ( scalar(@rows), scalar @{ $self->{column_names} }, \@rows )
  0         0  
462             if ( $self->{fetched_from_key} );
463             }
464             }
465 92 100       366 if ( $self->{order_clause} )
466             {
467 32         53 my ( $sort_col, $desc ) = each %{ $self->{order_clause} };
  32         121  
468 32         109 my @sortCols = ( $self->column_nums( $table, $sort_col, 1 ) );
469 32 100       118 $sortCols[1] = uc $desc eq 'DESC' ? 1 : 0;
470              
471 64         82 @rows = sort {
472 32         142 my ( $result, $colNum, $desc );
473 64         73 my $i = 0;
474             do
475 64   33     74 {
476 64         99 $colNum = $sortCols[ $i++ ];
477 64         74 $desc = $sortCols[ $i++ ];
478 64         176 $result = _anycmp( $a->[$colNum], $b->[$colNum] );
479 64 100       325 $result = -$result if ($desc);
480             } while ( !$result && $i < @sortCols );
481 64         116 $result;
482             } @rows;
483             }
484 92         162 ( scalar(@rows), scalar @{ $self->{column_names} }, \@rows );
  92         573  
485             }
486              
487             sub UPDATE ($$$)
488             {
489 32     32   129 my ( $self, $data, $params ) = @_;
490 32         115 my $table = $self->open_tables( $data, 0, 1 );
491 32         129 $self->verify_columns($table);
492 32 50       102 return undef unless $table;
493 32         69 my $affected = 0;
494 32         149 my $can_usr = $table->can('update_specific_row');
495 32         121 my $can_uor = $table->can('update_one_row');
496 32   33     114 my $can_rwu = $can_usr || $can_uor;
497 32         47 my ( @rows, $array, $f_array, $val, $col, $i );
498              
499 32         143 while ( $array = $table->fetch_row($data) )
500             {
501 56 50       149 if ( $self->eval_where( $table, $array ) )
502             {
503 56 100 66     208 $array = $self->{fetched_value} if ( $self->{fetched_from_key} and $can_rwu );
504 56 50       1467 my $orig_ary = clone($array) if ($can_usr);
505 56         110 for ( $i = 0; $i < @{ $self->{column_names} }; $i++ )
  112         313  
506             {
507 56         111 $col = $self->{column_names}->[$i];
508 56         152 $array->[ $self->column_nums( $table, $col ) ] = $self->row_values($i);
509             }
510 56         70 $affected++;
511 56 100       130 if ( $self->{fetched_value} )
512             {
513 8 50       36 if ($can_usr)
    0          
514             {
515 8         40 $table->update_specific_row( $data, $array, $orig_ary );
516             }
517             elsif ($can_uor)
518             {
519 0         0 $table->update_one_row( $data, $array );
520             }
521 8         62 return ( $affected, 0 );
522             }
523 48 50       234 push( @rows, $can_usr ? [ $array, $orig_ary ] : $array );
524             }
525             else
526             {
527 0 0       0 push( @rows, $array ) unless ($can_rwu);
528             }
529             }
530 24 50       61 if ($can_rwu)
531             {
532 24         54 foreach my $array (@rows)
533             {
534 48 50       95 if ($can_usr)
    0          
535             {
536 48         139 $table->update_specific_row( $data, @$array );
537             }
538             elsif ($can_uor)
539             {
540 0         0 $table->update_one_row( $data, $array );
541             }
542             }
543             }
544             else
545             {
546 0         0 $table->seek( $data, 0, 0 );
547 0         0 foreach my $array (@rows)
548             {
549 0         0 $table->push_row( $data, $array );
550             }
551 0         0 $table->truncate($data);
552             }
553              
554 24         139 return ( $affected, 0 );
555             }
556              
557             sub verify_columns
558             {
559 272     272   470 my ( $self, $table ) = @_;
560 272         359 my @cols = @{ $self->{column_names} };
  272         827  
561 272 100       770 if ( $self->{where_clause} )
562             {
563 48 50       203 if ( my $col = $self->{where_clause}->{arg1} )
564             {
565 48 50       205 push @cols, $col->{value} if $col->{type} eq 'column';
566             }
567 48 50       155 if ( my $col = $self->{where_clause}->{arg2} )
568             {
569 48 50       170 push @cols, $col->{value} if $col->{type} eq 'column';
570             }
571             }
572 272         579 for (@cols)
573             {
574 548         1288 $self->column_nums( $table, $_ );
575             }
576             }
577              
578             sub column_nums
579             {
580 976     976   1211 my ( $self, $table, $stmt_col_name, $find_in_stmt ) = @_;
581 976         805 my %dbd_nums = %{ $table->col_nums() };
  976         1694  
582 976         1166 my @dbd_cols = @{ $table->col_names() };
  976         1507  
583 976         933 my %stmt_nums;
584 976 100 100     3390 if ( $stmt_col_name and !$find_in_stmt )
585             {
586 852         2010 while ( my ( $k, $v ) = each %dbd_nums )
587             {
588 1252 100       5020 return $v if uc $k eq uc $stmt_col_name;
589             }
590 0         0 croak "No such column '$stmt_col_name'";
591             }
592 124 100 66     436 if ( $stmt_col_name and $find_in_stmt )
593             {
594 32         58 for my $i ( 0 .. @{ $self->{column_names} } )
  32         115  
595             {
596 32 50       206 return $i if uc $stmt_col_name eq uc $self->{column_names}->[$i];
597             }
598 0         0 croak "No such column '$stmt_col_name'";
599             }
600 92         281 for my $i ( 0 .. $#dbd_cols )
601             {
602 172         177 for my $stmt_col ( @{ $self->{column_names} } )
  172         331  
603             {
604 332 100       1006 $stmt_nums{$stmt_col} = $i if uc $dbd_cols[$i] eq uc $stmt_col;
605             }
606             }
607 92         415 return \%stmt_nums;
608             }
609              
610             sub eval_where
611             {
612 348     348   536 my ( $self, $table, $rowary ) = @_;
613 348   100     1093 my $where = $self->{"where_clause"} || return 1;
614 120         211 my $col_nums = $table->col_nums();
615 120         142 my %cols = reverse %{$col_nums};
  120         412  
616 120         154 my $rowhash;
617 120         426 for ( sort keys %cols )
618             {
619 240         704 $rowhash->{ uc $cols{$_} } = $rowary->[$_];
620             }
621 120         447 return $self->process_predicate( $where, $table, $rowhash );
622             }
623              
624             sub process_predicate
625             {
626 120     120   166 my ( $self, $pred, $table, $rowhash ) = @_;
627 120         166 my $val1 = $pred->{arg1};
628 120 50       251 if ( $val1->{type} eq 'column' )
629             {
630 120         225 $val1 = $rowhash->{ uc $val1->{value} };
631             }
632             else
633             {
634 0         0 $val1 = $val1->{value};
635             }
636 120         148 my $val2 = $pred->{arg2};
637 120 50       229 if ( $val2->{type} eq 'column' )
638             {
639 0         0 $val2 = $rowhash->{ uc $val2->{value} };
640             }
641             else
642             {
643 120         153 $val2 = $val2->{value};
644             }
645 120         158 my $op = $pred->{op};
646 120         156 my $neg = $pred->{neg};
647 120 50 33     1004 if ( $op eq '=' and !$neg and $table->can('fetch_one_row') )
      33        
648             {
649 120         336 my $key_col = $table->fetch_one_row( 1, 1 );
650 120 100       915 if ( $pred->{arg1}->{value} =~ /^$key_col$/i )
651             {
652 16         67 $self->{fetched_from_key} = 1;
653 16         62 $self->{fetched_value} = $table->fetch_one_row( 0, $pred->{arg2}->{value} );
654 16         89 return 1;
655             }
656             }
657 104   100     323 my $match = $self->is_matched( $val1, $op, $val2 ) || 0;
658 104 0       191 if ($neg) { $match = $match ? 0 : 1; }
  0 50       0  
659 104         468 return $match;
660             }
661              
662             sub is_matched
663             {
664 104     104   154 my ( $self, $val1, $op, $val2 ) = @_;
665 104 50       216 if ( $op eq 'IS' )
666             {
667 0 0 0     0 return 1 if ( !defined $val1 or $val1 eq '' );
668 0         0 return 0;
669             }
670 104 50       186 $val1 = '' unless ( defined $val1 );
671 104 50       174 $val2 = '' unless ( defined $val2 );
672 104 50       193 if ( $op =~ /LIKE|CLIKE/i )
673             {
674 0         0 $val2 = quotemeta($val2);
675 0         0 $val2 =~ s/\\%/.*/g;
676 0         0 $val2 =~ s/_/./g;
677             }
678 104 50       199 if ( $op eq 'LIKE' ) { return $val1 =~ /^$val2$/s; }
  0         0  
679 104 50       200 if ( $op eq 'CLIKE' ) { return $val1 =~ /^$val2$/si; }
  0         0  
680 104 50 33     1382 if ( DBI::looks_like_number($val1) && DBI::looks_like_number($val2) )
681             {
682 0 0       0 if ( $op eq '<' ) { return $val1 < $val2; }
  0         0  
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             }
689             else
690             {
691 104 50       249 if ( $op eq '<' ) { return $val1 lt $val2; }
  0         0  
692 104 50       190 if ( $op eq '>' ) { return $val1 gt $val2; }
  0         0  
693 104 50       193 if ( $op eq '=' ) { return $val1 eq $val2; }
  104         377  
694 0 0       0 if ( $op eq '<>' ) { return $val1 ne $val2; }
  0         0  
695 0 0       0 if ( $op eq '<=' ) { return $val1 ge $val2; }
  0         0  
696 0 0       0 if ( $op eq '>=' ) { return $val1 le $val2; }
  0         0  
697             }
698             }
699              
700             sub params
701             {
702 1628     1628   1831 my ( $self, $val_num ) = @_;
703 1628 100       3357 if ( !$self->{"params"} ) { return 0; }
  1412         3830  
704 216 50       410 if ( defined $val_num )
705             {
706 0         0 return $self->{"params"}->[$val_num];
707             }
708              
709 216 50       365 return wantarray ? @{ $self->{"params"} } : scalar @{ $self->{"params"} };
  0         0  
  216         679  
710             }
711              
712             sub open_tables
713             {
714 476     476   762 my ( $self, $data, $createMode, $lockMode ) = @_;
715 476         931 my $table_name = $self->{table_name};
716 476         512 my $table;
717 476         532 eval { $table = $self->open_table( $data, $table_name, $createMode, $lockMode ) };
  476         1668  
718 476 100       6715 if ($@)
719             {
720 72         197 chomp $@;
721 72         9073 croak $@;
722             }
723 404 50       1371 croak "Couldn't open table '$table_name'" unless $table;
724 404 100 100     2847 if ( !$self->{column_names} or $self->{column_names}->[0] eq '*' )
725             {
726 248         975 $self->{column_names} = $table->col_names();
727             }
728 404         1185 return $table;
729             }
730              
731             sub row_values
732             {
733 304     304   395 my ( $self, $val_num ) = @_;
734 304 50       637 if ( !$self->{"values"} ) { return 0; }
  0         0  
735 304 50       534 if ( defined $val_num )
736             {
737 304         919 return $self->{"values"}->[$val_num]->{value};
738             }
739 0 0       0 if (wantarray)
740             {
741 0         0 return map { $_->{"value"} } @{ $self->{"values"} };
  0         0  
  0         0  
742             }
743             else
744             {
745 0         0 return scalar @{ $self->{"values"} };
  0         0  
746             }
747             }
748              
749             sub column_names
750             {
751 1396     1396   1629 my ($self) = @_;
752 1396         1237 my @col_names;
753 1396 100 100     4898 if ( $self->{column_names} and $self->{column_names}->[0] ne '*' )
754             {
755 456         463 @col_names = @{ $self->{column_names} };
  456         1189  
756             }
757 1396         3311 return @col_names;
758             }
759              
760             ###############################
761             package DBI::SQL::Nano::Table_;
762             ###############################
763              
764 48     48   411 use Carp qw(croak);
  48         88  
  48         23117  
765              
766             sub new ($$)
767             {
768 404     404   702 my ( $proto, $attr ) = @_;
769 404         1487 my ($self) = {%$attr};
770              
771 404 50 33     2732 defined( $self->{col_names} ) and "ARRAY" eq ref( $self->{col_names} )
772             or croak("attribute 'col_names' must be defined as an array");
773 404 50       1881 exists( $self->{col_nums} ) or $self->{col_nums} = _map_colnums( $self->{col_names} );
774 404 50 33     2268 defined( $self->{col_nums} ) and "HASH" eq ref( $self->{col_nums} )
775             or croak("attribute 'col_nums' must be defined as a hash");
776              
777 404   33     1818 bless( $self, ( ref($proto) || $proto ) );
778 404         2100 return $self;
779             }
780              
781             sub _map_colnums
782             {
783 404     404   558 my $col_names = $_[0];
784 404         493 my %col_nums;
785 404         1212 for my $i ( 0 .. $#$col_names )
786             {
787 628 50       1232 next unless $col_names->[$i];
788 628         1506 $col_nums{ $col_names->[$i] } = $i;
789             }
790 404         1273 return \%col_nums;
791             }
792              
793 0     0   0 sub row() { return $_[0]->{row}; }
794 0     0   0 sub column($) { return $_[0]->{row}->[ $_[0]->column_num( $_[1] ) ]; }
795 0     0   0 sub column_num($) { $_[0]->{col_nums}->{ $_[1] }; }
796 1096     1096   3186 sub col_nums() { $_[0]->{col_nums} }
797 1224     1224   2878 sub col_names() { $_[0]->{col_names}; }
798              
799 0     0     sub drop ($$) { croak "Abstract method " . ref( $_[0] ) . "::drop called" }
800 0     0     sub fetch_row ($$$) { croak "Abstract method " . ref( $_[0] ) . "::fetch_row called" }
801 0     0     sub push_row ($$$) { croak "Abstract method " . ref( $_[0] ) . "::push_row called" }
802 0     0     sub push_names ($$$) { croak "Abstract method " . ref( $_[0] ) . "::push_names called" }
803 0     0     sub truncate ($$) { croak "Abstract method " . ref( $_[0] ) . "::truncate called" }
804 0     0     sub seek ($$$$) { croak "Abstract method " . ref( $_[0] ) . "::seek called" }
805              
806             1;
807             __END__