File Coverage

blib/lib/SQL/Statement.pm
Criterion Covered Total %
statement 1041 1184 87.9
branch 433 610 70.9
condition 193 302 63.9
subroutine 88 97 90.7
pod 36 43 83.7
total 1791 2236 80.1


line stmt bran cond sub pod time code
1             package SQL::Statement;
2              
3             #########################################################################
4             #
5             # This module is copyright (c), 2001,2005 by Jeff Zucker.
6             # This module is copyright (c), 2007-2020 by Jens Rehsack.
7             # All rights reserved.
8             #
9             # It may be freely distributed under the same terms as Perl itself.
10             #
11             # See below for help (search for SYNOPSIS)
12             #########################################################################
13              
14 16     16   555119 use strict;
  16         102  
  16         537  
15 16     16   88 use warnings FATAL => "all";
  16         40  
  16         582  
16              
17 16     16   355 use 5.008;
  16         56  
18 16     16   89 use vars qw($VERSION $DEBUG);
  16         30  
  16         1051  
19              
20 16     16   12997 use SQL::Parser ();
  16         88  
  16         807  
21 16     16   9211 use SQL::Eval ();
  16         48  
  16         366  
22 16     16   7649 use SQL::Statement::RAM ();
  16         44  
  16         418  
23 16     16   7604 use SQL::Statement::TermFactory ();
  16         64  
  16         521  
24 16     16   8662 use SQL::Statement::Util ();
  16         45  
  16         463  
25              
26 16     16   105 use Carp qw(carp croak);
  16         36  
  16         1249  
27 16     16   6609 use Clone qw(clone);
  16         37815  
  16         978  
28 16     16   3283 use Errno;
  16         9615  
  16         829  
29 16     16   109 use Scalar::Util qw(blessed looks_like_number);
  16         34  
  16         825  
30 16     16   101 use List::Util qw(first);
  16         36  
  16         975  
31 16     16   93 use Params::Util qw(_INSTANCE _STRING _ARRAY _ARRAY0 _HASH0 _HASH);
  16         30  
  16         107788  
32              
33             #use locale;
34              
35             $VERSION = '1.413_001';
36              
37             sub new
38             {
39 872     872 1 368937 my ( $class, $sql, $flags ) = @_;
40              
41             # IF USER DEFINED extend_csv IN SCRIPT
42             # USE THE ANYDATA DIALECT RATHER THAN THE CSV DIALECT
43             # WITH DBD::CSV
44              
45 872 0 33     4110 if ( ( defined($main::extend_csv) && $main::extend_csv )
      33        
      33        
46             || ( defined($main::extend_sql) && $main::extend_sql ) )
47             {
48 0         0 $flags = SQL::Parser->new('AnyData');
49             }
50 872         1480 my $parser = $flags;
51 872         1838 my $self = bless( {}, $class );
52 872 50       2194 $flags->{PrintError} = 1 unless defined $flags->{PrintError};
53 872 100       1976 $flags->{text_numbers} = 1 unless defined $flags->{text_numbers};
54 872 100       1875 $flags->{alpha_compare} = 1 unless defined $flags->{alpha_compare};
55              
56 872 50       3455 unless ( blessed($flags) ) # avoid copying stale data from earlier parsing sessions
57             {
58 0         0 %$self = ( %$self, %{ clone($flags) } );
  0         0  
59             }
60             else
61             {
62 872         4703 $self->{$_} = $flags->{$_} for qw(RaiseError PrintError opts);
63             }
64              
65 872         2002 $self->{dlm} = '~';
66              
67             # Dean Arnold improvement to allow better subclassing
68             # if (!ref($parser) or (ref($parser) and ref($parser) !~ /^SQL::Parser/)) {
69 872 50       5859 unless ( _INSTANCE( $parser, 'SQL::Parser' ) )
70             {
71 0   0     0 my $parser_dialect = $flags->{dialect} || 'AnyData';
72 0 0       0 $parser_dialect = 'AnyData' if ( $parser_dialect =~ m/^(?:CSV|Excel)$/ );
73              
74 0         0 $parser = SQL::Parser->new( $parser_dialect, $flags );
75             }
76 872         3479 $self->{termFactory} = SQL::Statement::TermFactory->new($self);
77 872         1849 $self->{capabilities} = {};
78 872         2366 $self->prepare( $sql, $parser );
79 865         2658 return $self;
80             }
81              
82             sub prepare
83             {
84 872     872 1 1718 my ( $self, $sql, $parser ) = @_;
85              
86 872 50       2347 $self->{already_prepared}->{$sql} and return;
87              
88             # delete earlier preparations, they're overwritten after this prepare run
89 872         1762 $self->{already_prepared} = {};
90 872         2891 my $rv = $parser->parse($sql);
91 865 100       1885 if ($rv)
92             {
93 855         2912 undef $self->{errstr};
94 855         43836 my $parser_struct = clone( $parser->{struct} );
95 855         2925 while ( my ( $k, $v ) = each( %{$parser_struct} ) )
  9564         22052  
96             {
97 8709         16945 $self->{$k} = $v;
98             }
99 855         1659 undef $self->{where_terms}; # force rebuild when needed
100 855         1499 undef $self->{columns};
101 855         1370 undef $self->{splitted_all_cols};
102 855         1459 $self->{argnum} = 0;
103              
104 855         1426 my $values = $self->{values};
105 855         1268 my $param_num = -1;
106 855 100       2087 if ( $self->{limit_clause} )
107             {
108 9         58 $self->{limit_clause} = SQL::Statement::Limit->new( $self->{limit_clause} );
109             }
110              
111 855 100       1860 if ( defined( $self->{num_placeholders} ) )
112             {
113 17         69 for my $i ( 0 .. $self->{num_placeholders} - 1 )
114             {
115 36         111 $self->{params}->[$i] = SQL::Statement::Param->new($i);
116             }
117             }
118              
119 855         1274 $self->{tables} = [ map { SQL::Statement::Table->new($_) } @{ $self->{table_names} } ];
  704         1929  
  855         2050  
120              
121 855 100 66     2889 if ( $self->{where_clause} && !defined( $self->{where_terms} ) )
122             {
123 229         948 $self->{where_terms} = $self->{termFactory}->buildCondition( $self->{where_clause} );
124             #if ( $self->{where_clause}->{combiners} )
125             #{
126             # $self->{has_OR} = 1
127             # if ( first { -1 != index( $_, 'OR' ) } @{ $self->{where_clause}->{combiners} } );
128             #}
129             }
130              
131 855         2672 ++$self->{already_prepared}->{$sql};
132 855         3377 return $self;
133             }
134             else
135             {
136 10         49 $self->{errstr} = $parser->errstr;
137 10         31 ++$self->{already_prepared}->{$sql};
138 10         22 return;
139             }
140             }
141              
142             sub execute
143             {
144 4654     4654 1 194375 my ( $self, $data, $params ) = @_;
145             ( $self->{NUM_OF_ROWS}, $self->{NUM_OF_FIELDS}, $self->{data} ) = ( 0, 0, [] ) and return 'OEO'
146 4654 100 50     10915 if ( $self->{no_execute} );
147 4649 100       9794 $self->{procedure}->{data} = $data if ( $self->{procedure} );
148 4649         9029 $self->{params} = $params;
149              
150 4649         11821 my ($command) = $self->command();
151 4649 50       9200 return $self->do_err('No command found!') unless ($command);
152              
153             $self->{where_clause}
154             and !defined( $self->{where_terms} )
155 4649 100 100     10796 and $self->{where_terms} = $self->{termFactory}->buildCondition( $self->{where_clause} );
156              
157 4649         12393 ( $self->{NUM_OF_ROWS}, $self->{NUM_OF_FIELDS}, $self->{data} ) = $self->$command( $data, $params );
158              
159             $self->{NAME} =
160 4648 100       12836 _ARRAY0( $self->{columns} ) ? [ map { delete $_->{term}->{fastpath}; $_->display_name() } @{ $self->{columns} } ] : [];
  13395         21228  
  13395         25387  
  4642         8943  
161              
162             # Force closing the tables
163 4648         8780 $self->{tables} = [ map { SQL::Statement::Table->new($_->{name}) } @{ delete $self->{tables} } ]; # create keen defs
  4518         11796  
  4648         9126  
164              
165 4648         11217 undef $self->{where_terms}; # force rebuild when needed
166              
167 4648 100       10145 return unless ( defined( $self->{NUM_OF_ROWS} ) );
168 4644   100     17236 return $self->{NUM_OF_ROWS} || '0E0';
169             }
170              
171             sub CREATE ($$$)
172             {
173 35     35 0 94 my ( $self, $data, $params ) = @_;
174 35         53 my $names;
175              
176             # CREATE TABLE AS ...
177 35         71 my $subquery = $self->{subquery};
178 35 50       85 if ($subquery)
179             {
180 0         0 my $sth;
181              
182             # AS IMPORT
183 0 0       0 if ( $subquery =~ m/^IMPORT/i )
184             {
185             $sth = $data->{Database}->prepare("SELECT * FROM $subquery")
186 0 0       0 or return $self->do_err( $data->{Database}->errstr() );
187 0 0       0 $sth->execute(@$params) or return $self->do_err( $sth->errstr() );
188 0         0 $names = $sth->{NAME};
189             }
190              
191             # AS SELECT
192             else
193             {
194             $sth = $data->{Database}->prepare($subquery)
195 0 0       0 or return $self->do_err( $data->{Database}->errstr() );
196 0 0       0 $sth->execute() or return $self->do_err( $sth->errstr() );
197 0         0 $names = $sth->{NAME};
198             }
199 0 0       0 $names = $sth->{NAME} unless defined $names;
200 0         0 my $tbl_data = $sth->{sql_stmt}->{data};
201 0   0     0 my $tbl_name = $self->{org_table_names}->[0] || $self->tables(0)->name;
202              
203             # my @tbl_cols = map {$_->name} $sth->{sql_stmt}->columns;
204             #my @tbl_cols=map{$_->name} $sth->{sql_stmt}->columns if $sth->{sql_stmt};
205 0         0 my @tbl_cols;
206              
207             # @tbl_cols=@{ $sth->{NAME} } unless @tbl_cols;
208 0 0       0 @tbl_cols = @{$names} unless (@tbl_cols);
  0         0  
209 0         0 my $create_sql = "CREATE TABLE $tbl_name";
210 0 0       0 $create_sql = "CREATE TEMP TABLE $tbl_name" if ( $self->{is_ram_table} );
211 0         0 my @coldefs = map { "'$_' TEXT" } @tbl_cols;
  0         0  
212 0         0 $create_sql .= '(' . join( ',', @coldefs ) . ')';
213 0 0       0 $data->{Database}->do($create_sql) or die "Can't do <$create_sql>: " . $data->{Database}->errstr;
214 0         0 my $colstr = ('?,') x @tbl_cols;
215 0         0 my $insert_sql = "INSERT INTO $tbl_name VALUES($colstr)";
216 0         0 my $local_sth = $data->{Database}->prepare($insert_sql);
217 0         0 $local_sth->execute(@$_) for @$tbl_data;
218 0         0 return ( 0, 0 );
219             }
220 35         128 my ( $eval, $foo ) = $self->open_tables( $data, 1, 1 );
221 35 50       187 return unless ($eval);
222 35         156 $eval->params($params);
223 35         118 my ( $row, $table, $col ) = ( [], $eval->table( $self->tables(0)->name() ) );
224 35 50       119 if ( _ARRAY( $table->col_names() ) )
225             {
226 0         0 return $self->do_err( "Table '" . $self->tables(0)->name() . "' already exists." );
227             }
228 35         109 foreach $col ( $self->columns() )
229             {
230 97         146 push( @{$row}, $col->name() );
  97         225  
231             }
232 35         182 $table->push_names( $data, $row );
233              
234 35         214 return ( 0, 0 );
235             }
236              
237             sub CALL
238             {
239 0     0 0 0 my ( $self, $data, $params ) = @_;
240              
241             # my $dbh = $data->{Database};
242             # $self->{procedure}->{data} = $data;
243              
244 0         0 my $procTerm = $self->{termFactory}->buildCondition( $self->{procedure} );
245              
246 0         0 ( $self->{NUM_OF_ROWS}, $self->{NUM_OF_FIELDS}, $self->{data} ) = $procTerm->value($data);
247             }
248              
249             my $enoentstr = "Cannot open .*\(" . Errno::ENOENT . "\)";
250             my $eabstrstr = "Abstract method .*::open_table called";
251             my $notblrx = qr/(?:$enoentstr|$eabstrstr)/;
252              
253             sub DROP ($$$)
254             {
255 12     12 0 31 my ( $self, $data, $params ) = @_;
256 12         25 my $eval;
257             my @err;
258 12         26 eval {
259 12     0   102 local $SIG{__WARN__} = sub { push @err, @_ };
  0         0  
260 12         50 ($eval) = $self->open_tables( $data, 0, 1 );
261             };
262 12 100 66     115 if ( $self->{ignore_missing_table}
      100        
      66        
263             and ( $@ or @err or $self->{errstr} )
264 10         95 and grep { $_ =~ $notblrx } ( @err, $@, $self->{errstr} ) )
265             {
266 5         28 return ( -1, 0 );
267             }
268              
269 7 50       27 return if $self->{errstr};
270 7 50 0     39 return $self->do_err( $@ || $err[0] ) if ( $@ || @err );
      33        
271              
272             # return undef unless $eval;
273 7 50       21 return ( -1, 0 ) unless $eval;
274              
275             # $eval->params($params);
276 7         22 my ($table) = $eval->table( $self->tables(0)->name() );
277 7         39 $table->drop($data);
278              
279             #use mylibs; zwarn $self->{sql_stmt};
280 7         77 return ( -1, 0 );
281             }
282              
283             sub INSERT ($$$)
284             {
285 4275     4275 0 7511 my ( $self, $data, $params ) = @_;
286              
287 4275         11049 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
288 4275 50       12587 return unless ($eval);
289              
290 4275 100       14622 $params and $eval->params($params);
291 4275 50       8937 $self->verify_columns( $data, $eval, $all_cols ) if ( scalar( $self->columns() ) );
292 4275 50       9113 return if ( $self->{errstr} );
293              
294 4275         9246 my ($table) = $eval->table( $self->tables(0)->name() );
295 4275 50       11953 $table->seek( $data, 0, 2 ) unless ( $table->capability('insert_new_row') );
296              
297 4275         7110 my ( $val, $col, $i, $k );
298 4275         8831 my ($cNum) = scalar( $self->columns() );
299 4275         6282 my $param_num = 0;
300              
301 4275 50       8201 $cNum
302             or return $self->do_err("Bad col names in INSERT");
303              
304 4275         6682 my $maxCol = $#$all_cols;
305              
306             # INSERT INTO $table (row, ...) VALUES (value, ...), (...)
307 4275         7237 for ( $k = 0; $k < scalar( @{ $self->{values} } ); ++$k )
  8555         19708  
308             {
309 4280         7526 my ($array) = [];
310 4280         9114 for ( $i = 0; $i < $cNum; $i++ )
311             {
312 12791         23064 $col = $self->columns($i);
313 12791         25348 $val = $self->row_values( $k, $i );
314 12791 50 66     60067 if ( defined( _INSTANCE( $val, 'SQL::Statement::Param' ) ) )
    50          
    100          
    50          
315             {
316 0         0 $val = $eval->param( $val->idx() );
317             }
318             elsif ( defined( _INSTANCE( $val, 'SQL::Statement::Term' ) ) )
319             {
320 0         0 $val = $val->value($eval);
321             }
322             elsif ( $val and $val->{type} eq 'placeholder' )
323             {
324 12242         31132 $val = $eval->param( $param_num++ );
325             }
326             elsif ( defined( _HASH($val) ) )
327             {
328 549         1577 $val = $self->{termFactory}->buildCondition($val);
329 549         1215 $val = $val->value($eval);
330             }
331             else
332             {
333 0         0 return $self->do_err('Internal error: Unexpected column type');
334             }
335 12791         30947 $array->[ $table->column_num( $col->name() ) ] = $val;
336             }
337              
338             # Extend row to put values in ALL fields
339 4280 50       9132 $#$array < $maxCol and $array->[$maxCol] = undef;
340              
341 4280 50       9369 $table->capability('insert_new_row')
342             ? $table->insert_new_row( $data, $array )
343             : $table->push_row( $data, $array );
344             }
345              
346 4275         18108 return ( $k, 0 );
347             }
348              
349             sub DELETE ($$$)
350             {
351 6     6   17 my ( $self, $data, $params ) = @_;
352 6         19 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
353 6 50       36 return unless $eval;
354 6         35 $eval->params($params);
355 6         26 $self->verify_columns( $data, $eval, $all_cols );
356 6 50       25 return if ( $self->{errstr} );
357 6         17 my $tname = $self->tables(0)->name();
358 6         24 my ($table) = $eval->table($tname);
359 6         9 my $affected = 0;
360 6         12 my ( @rows, $array );
361              
362 6         26 while ( $array = $table->fetch_row($data) )
363             {
364 29 100       72 if ( $self->eval_where( $eval, $tname, $array ) )
365             {
366 10         16 ++$affected;
367 10 50 33     48 if ( $table->capability('rowwise_delete') and $table->capability('inplace_delete') )
    0          
368             {
369 10 50       26 if ( $table->capability('delete_one_row') )
    50          
370             {
371 0         0 $table->delete_one_row( $data, $array );
372             }
373             elsif ( $table->capability('delete_current_row') )
374             {
375 10         29 $table->delete_current_row( $data, $array );
376             }
377             }
378             elsif ( $table->capability('rowwise_delete') )
379             {
380 0         0 push( @rows, $array );
381             }
382              
383 10         32 next;
384             }
385              
386 19 50       49 push( @rows, $array ) unless ( $table->capability('rowwise_delete') );
387             }
388              
389 6 50       19 if ($affected)
390             {
391 6 50       16 if ( $table->capability('rowwise_delete') )
392             { # @rows is empty in case of inplace_delete capability
393 6         18 foreach my $array (@rows)
394             {
395 0         0 $table->delete_one_row( $data, $array );
396             }
397             }
398             else
399             {
400             # rewrite table without deleted elements
401 0         0 $table->seek( $data, 0, 0 );
402 0         0 foreach my $array (@rows)
403             {
404 0         0 $table->push_row( $data, $array );
405             }
406 0         0 $table->truncate($data);
407             }
408             }
409              
410 6         44 return ( $affected, 0 );
411             }
412              
413             sub UPDATE ($$$)
414             {
415 5     5 0 15 my ( $self, $data, $params ) = @_;
416              
417 5         19 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
418 5 50       23 return unless $eval;
419              
420 5         15 my $valnum = $self->{num_val_placeholders};
421 5 100       17 my @val_params = splice( @{$params}, 0, $valnum ) if ($valnum);
  3         8  
422 5   33     27 $self->{params} ||= $params;
423 5         25 $eval->params($params);
424 5         19 $self->verify_columns( $data, $eval, $all_cols );
425 5 50       19 return if ( $self->{errstr} );
426              
427 5         18 my $tname = $self->tables(0)->name();
428 5         20 my ($table) = $eval->table($tname);
429 5         8 my $affected = 0;
430 5         12 my @rows;
431              
432 5         23 while ( my $array = $table->fetch_row($data) )
433             {
434 21         38 my $originalValues;
435 21 100       54 if ( $self->eval_where( $eval, $tname, $array ) )
436             {
437 7         15 my $valpos = 0;
438 7 50       22 if ( $table->capability('update_specific_row') )
439             {
440 0         0 $originalValues = clone($array);
441             }
442              
443 7         27 for ( my $i = 0; $i < $self->columns(); $i++ )
444             {
445 9         27 my $val = $self->row_values( 0, $i );
446 9 50 66     101 if ( defined( _INSTANCE( $val, 'SQL::Statement::Param' ) ) )
    50          
    100          
    50          
447             {
448 0         0 $val = $val_params[ $valpos++ ];
449             }
450             elsif ( defined( _INSTANCE( $val, 'SQL::Statement::Term' ) ) )
451             {
452 0         0 $val = $val->value($eval);
453             }
454             elsif ( $val and $val->{type} eq 'placeholder' )
455             {
456 6         18 $val = $val_params[ $valpos++ ];
457             }
458             elsif ( defined( _HASH($val) ) )
459             {
460 3         14 $val = $self->{termFactory}->buildCondition($val);
461 3         24 $val = $val->value($eval);
462             }
463             else
464             {
465 0         0 return $self->do_err('Internal error: Unexpected column type');
466             }
467              
468 9         21 my $col = $self->columns($i);
469 9         36 $array->[ $table->column_num( $col->name() ) ] = $val;
470             }
471              
472 7         14 ++$affected;
473 7 50 33     23 if ( $table->capability('rowwise_update') and $table->capability('inplace_update') )
    0          
474             {
475             # Martin Fabiani :
476             # the following block is the most important enhancement to SQL::Statement::UPDATE
477 7 50       34 if ( $table->capability('update_specific_row') )
    50          
    50          
478             {
479 0         0 $table->update_specific_row( $data, $array, $originalValues );
480             }
481             elsif ( $table->capability('update_one_row') )
482             {
483             # NOTE: this prevents from updating index keys
484 0         0 $table->update_one_row( $data, $array );
485             }
486             elsif ( $table->capability('update_current_row') )
487             {
488 7         27 $table->update_current_row( $data, $array );
489             }
490             }
491             elsif ( $table->capability('rowwise_update') )
492             {
493 0 0       0 push( @rows, $array ) unless ( $table->capability('update_specific_row') );
494 0 0       0 push( @rows, [ $array, $originalValues ] )
495             if ( $table->capability('update_specific_row') );
496             }
497             }
498              
499 21 50       56 push( @rows, $array ) unless ( $table->capability('rowwise_update') );
500             }
501              
502 5 50       22 if ($affected)
503             {
504 5 50       15 if ( $table->capability('rowwise_update') )
505             { # @rows is empty in case of inplace_update capability
506 5         17 foreach my $array (@rows)
507             {
508 0 0       0 if ( $table->capability('update_specific_row') )
    0          
509             {
510 0         0 $table->update_specific_row( $data, $array->[0], $array->[1] );
511             }
512             elsif ( $table->capability('update_one_row') )
513             {
514 0         0 $table->update_one_row( $data, $array );
515             }
516             }
517             }
518             else
519             {
520             # rewrite table with updated elements
521 0         0 $table->seek( $data, 0, 0 );
522 0         0 foreach my $array (@rows)
523             {
524 0         0 $table->push_row( $data, $array );
525             }
526 0         0 $table->truncate($data);
527             }
528             }
529              
530 5         34 return ( $affected, 0 );
531             }
532              
533             sub find_join_columns
534             {
535 32     32 1 93 my ( $self, @all_cols ) = @_;
536 32         60 my $display_combine = 'NAMED';
537 32 100       99 $display_combine = 'NATURAL' if ( -1 != index( $self->{join}->{type}, 'NATURAL' ) );
538 32 100       88 $display_combine = 'USING' if ( -1 != index( $self->{join}->{clause}, 'USING' ) );
539 32         46 my @display_cols;
540 32         58 my @keycols = ();
541 25         64 @keycols = @{ $self->{join}->{keycols} }
542 32 100       82 if $self->{join}->{keycols};
543 32         68 foreach (@keycols) { $_ =~ s/\./$self->{dlm}/ }
  57         205  
544 32         51 my %is_key_col;
545 32         66 %is_key_col = map { $_ => 1 } @keycols;
  57         308  
546              
547             # IF NAMED COLUMNS, USE NAMED COLUMNS
548             #
549 32 100       103 if ( $display_combine eq 'NAMED' )
    50          
550             {
551 16         45 @display_cols = $self->columns();
552              
553             #
554             # DAA
555             # need to get to $self's table objects to get the name
556             #
557             # @display_cols = map {$_->table . $self->{dlm} . $_->name} @display_cols;
558             # @display_cols = map {$_->table->{NAME} . $self->{dlm} . $_->name} @display_cols;
559              
560 16         42 my @tbls = $self->tables();
561 16         38 my %tables = ();
562              
563 16         53 $tables{ $_->name() } = $_ foreach (@tbls);
564              
565 16         178 foreach ( 0 .. $#display_cols )
566             {
567             $display_cols[$_] = (
568             $display_cols[$_]->table()
569             ? $tables{ $display_cols[$_]->table() }->name()
570             : ''
571             )
572             . $self->{dlm}
573 72 100       167 . $display_cols[$_]->name();
574             }
575             }
576              
577             # IF ASTERISKED COLUMNS AND NOT NATURAL OR USING
578             # USE ALL COLUMNS, IN ORDER OF NAMING OF TABLES
579             #
580             elsif ( $display_combine eq 'NONE' )
581             {
582 0         0 @display_cols = @all_cols;
583             }
584              
585             # IF NATURAL, COMBINE ALL SHARED COLUMNS
586             # IF USING, COMBINE ALL KEY COLUMNS
587             #
588             else
589             {
590 16         24 my %is_natural;
591 16         26 for my $full_col (@all_cols)
592             {
593 64         422 my ( $table, $col ) = $full_col =~ m/^([^$self->{dlm}]+)$self->{dlm}(.+)$/;
594 64 100 100     196 next if ( ( $display_combine eq 'NATURAL' ) and $is_natural{$col} );
595 58 50 100     195 next if ( ( $display_combine eq 'USING' ) && $is_natural{$col} && $is_key_col{$col} );
      66        
596 48         74 push( @display_cols, $full_col );
597 48         97 $is_natural{$col}++;
598             }
599             }
600 32         67 my @shared = ();
601 32         50 my %is_shared;
602 32 100       115 if ( $self->{join}->{type} =~ m/NATURAL/ )
603             {
604 6         14 for my $full_col (@all_cols)
605             {
606 24         123 my ( $table, $col ) = $full_col =~ m/^([^$self->{dlm}]+)$self->{dlm}(.+)$/;
607 24 100       78 push( @shared, $col ) if ( $is_shared{$col}++ ); # using side-effect of post-inc
608             }
609             }
610             else
611             {
612 26         68 @shared = @keycols;
613             }
614 32         79 $self->{join}->{shared_cols} = \@shared;
615 32         114 $self->{join}->{display_cols} = \@display_cols;
616             }
617              
618             sub JOIN
619             {
620 34     34 0 63 my ( $self, $data, $params ) = @_;
621              
622 34         97 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
623 34 50       122 return undef unless $eval;
624 34         135 $eval->params($params);
625 34         123 $self->verify_columns( $data, $eval, $all_cols );
626 34 100       108 return if ( $self->{errstr} );
627 32 100 100     149 if ( $self->{join}->{keycols}
      100        
628             and $self->{join}->{table_order}
629 15         59 and ( scalar( @{ $self->{join}->{table_order} } ) == 0 ) )
630             {
631 7         24 $self->{join}->{table_order} = $self->order_joins( $self->{join}->{keycols} );
632             $self->{join}->{table_order} = $self->{table_names}
633 7 50       26 unless ( defined( $self->{join}->{table_order} ) );
634             }
635 32         80 my @tables = $self->tables;
636              
637             # GET THE LIST OF QUALIFIED COLUMN NAMES FOR DISPLAY
638             # *IN ORDER BY NAMING OF TABLES*
639             #
640 32         51 my @all_cols;
641 32         61 for my $table (@tables)
642             {
643 76         104 my @cols = @{ $eval->table( $table->{name} )->col_names };
  76         203  
644 76         129 for my $col (@cols)
645             {
646 204         487 push( @all_cols, $table->{name} . $self->{dlm} . $col );
647             }
648             }
649 32         121 $self->find_join_columns(@all_cols);
650              
651             # JOIN THE TABLES
652             # *IN ORDER *BY JOINS*
653             #
654 32 100       86 @tables = @{ $self->{join}->{table_order} } if ( $self->{join}->{table_order} );
  15         51  
655 32         90 my ( $tableA, $tableB ) = splice( @tables, 0, 2 );
656 32 100       93 $tableA = $tableA->{name} if ( ref($tableA) );
657 32 100       76 $tableB = $tableB->{name} if ( ref($tableB) );
658 32         91 my ( $tableAobj, $tableBobj ) = ( $eval->table($tableA), $eval->table($tableB) );
659 32   33     84 $tableAobj->{NAME} ||= $tableA;
660 32   33     86 $tableBobj->{NAME} ||= $tableB;
661 32         100 $self->join_2_tables( $data, $params, $tableAobj, $tableBobj );
662              
663 32         81 for my $next_table (@tables)
664             {
665 12         118 $tableAobj = $self->{join}->{table};
666 12         39 $tableBobj = $eval->table($next_table);
667 12   33     40 $tableBobj->{NAME} ||= $next_table;
668 12         37 $self->join_2_tables( $data, $params, $tableAobj, $tableBobj );
669 12         41 $self->{cur_table} = $next_table;
670             }
671 32         154 return $self->SELECT( $data, $params );
672             }
673              
674             sub join_2_tables
675             {
676 44     44 1 97 my ( $self, $data, $params, $tableAobj, $tableBobj ) = @_;
677 44         72 my $share_type = 'IMPLICIT';
678 44 100       123 $share_type = 'NATURAL' if ( -1 != index( $self->{join}->{type}, 'NATURAL' ) );
679 44 100       107 $share_type = 'USING' if ( -1 != index( $self->{join}->{clause}, 'USING' ) );
680 44 100       111 $share_type = 'ON' if ( -1 != index( $self->{join}->{clause}, 'ON' ) );
681             $share_type = 'USING'
682 44 100 66     112 if ( ( $share_type eq 'ON' ) && ( scalar( @{ $self->{join}->{keycols} } ) == 1 ) );
  7         26  
683 44         63 my $join_type = 'INNER';
684 44 100       105 $join_type = 'LEFT' if ( -1 != index( $self->{join}->{type}, 'LEFT' ) );
685 44 100       100 $join_type = 'RIGHT' if ( -1 != index( $self->{join}->{type}, 'RIGHT' ) );
686 44 100       95 $join_type = 'FULL' if ( -1 != index( $self->{join}->{type}, 'FULL' ) );
687              
688 44         71 my $right_join = $join_type eq 'RIGHT';
689 44 100       82 if ($right_join)
690             {
691 3         7 my $tmpTbl = $tableAobj;
692 3         7 $tableAobj = $tableBobj;
693 3         5 $tableBobj = $tmpTbl;
694             }
695              
696 44         99 my $tableA = $tableAobj->{NAME};
697 44 50       115 ( 0 != index( $tableA, '"' ) ) and $tableA = lc $tableA;
698 44         65 my $tableB = $tableBobj->{NAME};
699 44 50       101 ( 0 != index( $tableB, '"' ) ) and $tableB = lc $tableB;
700 44         68 my @colsA = @{ $tableAobj->col_names() };
  44         132  
701 44         71 my @colsB = @{ $tableBobj->col_names() };
  44         87  
702 44         86 my ( %isunqualA, %isunqualB, @shared_cols );
703 44         197 $isunqualB{ $colsB[$_] } = 1 for ( 0 .. $#colsB );
704 44         77 my @tmpshared = @{ $self->{join}->{shared_cols} };
  44         115  
705              
706 44 50       147 if ( $share_type eq 'ON' )
    100          
    100          
707             {
708 0 0       0 $right_join and @tmpshared = reverse @tmpshared;
709             }
710             elsif ( $share_type eq 'USING' )
711             {
712 17         34 foreach my $c (@tmpshared)
713             {
714 17         49 substr( $c, 0, index( $c, $self->{dlm} ) + 1 ) = '';
715 17         43 push( @shared_cols, $tableA . $self->{dlm} . $c );
716 17         38 push( @shared_cols, $tableB . $self->{dlm} . $c );
717             }
718             }
719             elsif ( $share_type eq 'NATURAL' )
720             {
721 6         13 for my $c (@colsA)
722             {
723 12 50       33 if ( $tableA eq $self->{dlm} . 'tmp' )
724             {
725 0         0 substr( $c, 0, index( $c, $self->{dlm} ) + 1 ) = '';
726             }
727 12 100       25 if ( $isunqualB{$c} )
728             {
729 6         16 push( @shared_cols, $tableA . $self->{dlm} . $c );
730 6         19 push( @shared_cols, $tableB . $self->{dlm} . $c );
731             }
732             }
733             }
734              
735 44         72 my %whichqual;
736 44 100 66     183 if ( $share_type eq 'ON' || $share_type eq 'IMPLICIT' )
737             {
738 21         40 foreach my $colb (@colsB)
739             {
740 77         198 $colb = $whichqual{$colb} = $tableB . $self->{dlm} . $colb;
741             }
742             }
743             else
744             {
745 23         50 @colsB = map { $tableB . $self->{dlm} . $_ } @colsB;
  46         132  
746             }
747              
748 44         88 my @all_cols = map { $tableA . $self->{dlm} . $_ } @colsA;
  220         433  
749 44 100       165 @all_cols = $right_join ? ( @colsB, @all_cols ) : ( @all_cols, @colsB );
750             {
751 44         62 my $str = $self->{dlm} . "tmp" . $self->{dlm};
  44         96  
752 44         78 foreach (@all_cols)
753             {
754 343         505 my $pos = index( $_, $str );
755 343 100       656 $pos >= 0 and substr( $_, $pos, length($str) ) = '';
756             }
757             }
758 44 100       109 if ( $tableA eq $self->{dlm} . 'tmp' )
759             {
760 12         23 foreach my $colA (@colsA)
761             {
762 139         250 my $c = substr( $colA, index( $colA, $self->{dlm} ) + 1 );
763 139         222 $isunqualA{$c} = $colA;
764             }
765             #%isunqualA =
766             # map { my ($c) = $_ =~ m/^(?:[^$self->{dlm}]+)$self->{dlm}(.+)$/; $c => $_ } @colsA;
767             }
768             else
769             {
770 32         60 foreach my $cola (@colsA)
771             {
772 81         194 $cola = $isunqualA{$cola} = $tableA . $self->{dlm} . $cola;
773             }
774             }
775              
776 44         73 my ( %col_numsA, %col_numsB );
777 44         233 $col_numsA{ $colsA[$_] } = $_ for ( 0 .. $#colsA );
778 44         174 $col_numsB{ $colsB[$_] } = $_ for ( 0 .. $#colsB );
779              
780 44 100 66     170 if ( $share_type eq 'ON' || $share_type eq 'IMPLICIT' )
781             {
782 21         148 %whichqual = ( %whichqual, %isunqualA );
783              
784 21         112 while (@tmpshared)
785             {
786 62         139 my ( $k1, $k2 ) = splice( @tmpshared, 0, 2 );
787              
788             # if both keys are in one table, bail out - FIXME: errmsg?
789 62 0 33     131 next if ( $isunqualA{$k1} && $isunqualA{$k2} );
790 62 0 33     131 next if ( $isunqualB{$k1} && $isunqualB{$k2} );
791              
792 62 50       114 defined( $whichqual{$k1} ) and $k1 = $whichqual{$k1};
793 62 50       119 defined( $whichqual{$k2} ) and $k2 = $whichqual{$k2};
794              
795 62 100 100     304 if ( defined( $col_numsA{$k1} ) && defined( $col_numsB{$k2} ) )
    100 100        
796             {
797 17         47 push( @shared_cols, $k1, $k2 );
798             }
799             elsif ( defined( $col_numsA{$k2} ) && defined( $col_numsB{$k1} ) )
800             {
801 3         10 push( @shared_cols, $k2, $k1 );
802             }
803             }
804             }
805              
806 44         67 my %is_shared;
807 44         73 for my $c (@shared_cols)
808             {
809 86         147 $is_shared{$c} = 1;
810             defined( $col_numsA{$c} )
811 86 50 66     328 or defined( $col_numsB{$c} )
812             or return $self->do_err("Can't find shared columns!");
813             }
814 44         101 my ( $posA, $posB ) = ( [], [] );
815 44         85 for my $f (@shared_cols)
816             {
817 86 100       172 defined( $col_numsA{$f} ) and push( @{$posA}, $col_numsA{$f} );
  43         93  
818 86 100       178 defined( $col_numsB{$f} ) and push( @{$posB}, $col_numsB{$f} );
  43         94  
819             }
820              
821 44         79 my $is_inner_join = $join_type eq "INNER";
822             #use mylibs; zwarn $self->{join};
823             # CYCLE THROUGH TABLE B, CREATING A HASH OF ITS VALUES
824             #
825 44         76 my $hashB = {};
826 44         152 TBLBFETCH: while ( my $array = $tableBobj->fetch_row($data) )
827             {
828 294         610 my @key_vals = @$array[@$posB];
829 294 100       472 if ($is_inner_join)
830             {
831 247   50     550 defined($_) or next TBLBFETCH for (@key_vals);
832             }
833 294         508 my $hashkey = join( ' ', @key_vals );
834 294         372 push( @{ $hashB->{$hashkey} }, $array );
  294         971  
835             }
836              
837             # CYCLE THROUGH TABLE A
838             #
839 44         81 my $blankRow;
840 44         74 my $joined_table = [];
841 44         63 my %visited;
842 44         108 TBLAFETCH: while ( my $arrayA = $tableAobj->fetch_row($data) ) # use tbl1st & tbl2nd
843             {
844 355         710 my @key_vals = @$arrayA[@$posA];
845 355 100       593 if ($is_inner_join)
846             {
847 311   50     656 defined($_) or next TBLAFETCH for (@key_vals);
848             }
849 355         536 my $hashkey = join( ' ', @key_vals );
850 355         539 my $rowsB = $hashB->{$hashkey};
851 355 100 100     740 if ( !defined($rowsB) && ( $join_type ne 'INNER' ) )
852             {
853 14 50       53 defined($blankRow) or $blankRow = [ (undef) x scalar(@colsB) ];
854 14         31 $rowsB = [$blankRow];
855             }
856              
857 355 50       640 if ( $join_type ne 'UNION' )
858             {
859 355         472 for my $arrayB ( @{$rowsB} )
  355         557  
860             {
861 404 100       607 my $newRow = $right_join ? [ @{$arrayB}, @{$arrayA} ] : [ @{$arrayA}, @{$arrayB} ];
  11         13  
  11         25  
  393         540  
  393         1476  
862              
863 404         848 push( @$joined_table, $newRow );
864             }
865             }
866              
867 355         996 ++$visited{$hashkey};
868             }
869              
870             # ADD THE LEFTOVER B ROWS IF NEEDED
871             #
872 44 100 66     185 if ( $join_type eq 'FULL' || $join_type eq 'UNION' )
873             {
874             my $st_is_NaturalOrUsing = ( -1 != index( $self->{join}->{type}, 'NATURAL' ) )
875 2   66     15 || ( -1 != index( $self->{join}->{clause}, 'USING' ) );
876 2         7 while ( my ( $k, $v ) = each %{$hashB} )
  8         26  
877             {
878 6 100       19 next if ( $visited{$k} );
879 2         6 for my $rowB (@$v)
880             {
881 2         6 my ( @arrayA, @tmpB, $rowhash );
882 2         3 @{$rowhash}{@colsB} = @{$rowB};
  2         8  
  2         6  
883 2         8 for my $c (@all_cols)
884             {
885 8         71 my ( $table, $col ) = split( $self->{dlm}, $c, 2 );
886 8 100       23 push( @arrayA, undef ) if ( $table eq $tableA );
887 8 100       24 push( @tmpB, $rowhash->{$c} ) if ( $table eq $tableB );
888             }
889 2 100       8 @arrayA[@$posA] = @tmpB[@$posB] if ($st_is_NaturalOrUsing);
890 2         4 my $newRow = [ @arrayA, @tmpB ];
891 2         4 push( @{$joined_table}, $newRow );
  2         11  
892             }
893             }
894             }
895              
896 44         209 undef $hashB;
897 44         126 undef $tableAobj;
898 44         63 undef $tableBobj;
899              
900             $self->{join}->{table} =
901 44         215 SQL::Statement::TempTable->new( $self->{dlm} . 'tmp', \@all_cols, $self->{join}->{display_cols}, $joined_table );
902              
903 44         351 return;
904             }
905              
906             sub run_functions
907             {
908 176     176 1 347 my ( $self, $data, $params ) = @_;
909 176         426 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
910 176         467 my @row = ();
911 176         434 for my $col ( $self->columns() )
912             {
913 176         504 my $val = $col->value($eval); # FIXME approve
914 176         9418 push( @row, $val );
915             }
916 176         1140 return ( 1, scalar @row, [ \@row ] );
917             }
918              
919             sub SELECT($$)
920             {
921 348     348 0 736 my ( $self, $data, $params ) = @_;
922              
923 348   66     943 $self->{params} ||= $params;
924 348 100       1326 defined( _ARRAY( $self->{table_names} ) ) or return $self->run_functions( $data, $params );
925              
926 172         343 my ( $eval, $all_cols, $tableName, $table );
927 172 100       456 if ( defined( $self->{join} ) )
928             {
929 66 100       216 defined $self->{join}->{table} or return $self->JOIN( $data, $params );
930 32         63 $tableName = $self->{dlm} . 'tmp';
931 32         74 $table = $self->{join}->{table};
932             }
933             else
934             {
935 106         313 ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
936 105 100       375 return unless $eval;
937 104         429 $eval->params($params);
938 104         380 $self->verify_columns( $data, $eval, $all_cols );
939 104 100       300 return if ( $self->{errstr} );
940 103         260 $tableName = $self->tables(0)->name();
941 103         411 $table = $eval->table($tableName);
942             }
943              
944 135         261 my $rows = [];
945              
946             # In a loop, build the list of columns to retrieve; this will be
947             # used both for fetching data and ordering.
948 135         273 my ( $cList, $col, $tbl, $ar, $i, $c );
949 135         216 my $numFields = 0;
950 135         223 my %columns;
951             my @names;
952 135         233 my %funcs = ();
953              
954             #
955             # DAA
956             #
957             # lets just disable this and see where it leads...
958             #
959             # if ($self->{join}) {
960             # @names = @{ $table->col_names };
961             # for my $col(@names) {
962             # $columns{$tableName}->{"$col"} = $numFields++;
963             # push(@$cList, $table->column_num($col));
964             # }
965             # }
966             # else {
967 135         299 foreach my $column ( $self->columns() )
968             {
969 313 50       1792 if ( _INSTANCE( $column, 'SQL::Statement::Param' ) )
970             {
971 0         0 my $val = $eval->param( $column->idx() );
972 0 0       0 if ( -1 != ( my $idx = index( $val, '.' ) ) )
973             {
974 0         0 $col = substr( $val, 0, $idx );
975 0         0 $tbl = substr( $val, $idx + 1 );
976             }
977             else
978             {
979 0         0 $col = $val;
980 0         0 $tbl = $tableName;
981             }
982 0   0     0 $tbl ||= '';
983 0         0 $columns{$tbl}->{$col} = $numFields++;
984             }
985             else
986             {
987 313         871 ( $col, $tbl ) = ( $column->name(), $column->table() );
988 313   100     754 $tbl ||= '';
989 313         1046 $columns{$tbl}->{ $column->display_name() } = $columns{$tbl}->{$col} = $numFields++;
990             }
991              
992             #
993             # handle functions in select list
994             #
995             # DAA
996             #
997             # check for a join temp table; if so, check if we can locate
998             # the column in its delimited set
999             #
1000             my $cnum =
1001             ( ( $tableName eq ( $self->{dlm} . 'tmp' ) ) && ( $tbl ne '' ) )
1002 313 100 100     1465 ? $table->column_num( $tbl . $self->{dlm} . $col )
1003             : $table->column_num($col);
1004              
1005 313 100 66     1121 if ( !defined $cnum || $column->{function} )
1006             {
1007 33         74 $funcs{$col} = $column->{function};
1008 33         62 $cnum = $col;
1009             }
1010 313         616 push( @$cList, $cnum );
1011              
1012             # push(@$cList, $table->column_num($col));
1013 313         687 push( @names, $col );
1014             }
1015              
1016             # }
1017 135 50       342 $cList = [] unless ( defined($cList) );
1018 135 100       342 if ( $self->{join} )
1019             {
1020 32         70 foreach (@names) { $_ =~ s/^[^$self->{dlm}]+$self->{dlm}//; }
  122         395  
1021             }
1022 135         363 $self->{NAME} = \@names;
1023             # $self->verify_order_cols($table);
1024 135         418 my @order_by = $self->order();
1025 135         229 my @extraSortCols = ();
1026              
1027 135 100       302 if (@order_by)
1028             {
1029 17         33 my $nFields = $numFields;
1030              
1031             # It is possible that the user gave an ORDER BY clause with columns
1032             # that are not part of $cList yet. These columns will need to be
1033             # present in the array of arrays for sorting, but will be stripped
1034             # off later.
1035 17         37 my $i = -1;
1036 17         38 foreach my $column (@order_by)
1037             {
1038 20         31 ++$i;
1039 20         63 ( $col, $tbl ) = ( $column->column(), $column->table() );
1040 20         42 my $pos;
1041 20   66     67 $tbl ||= $self->colname2table($col);
1042 20   100     55 $tbl ||= '';
1043 20 100       57 if ( $self->{join} )
1044             {
1045 6         19 $pos = $table->column_num( $tbl . $self->{dlm} . $col );
1046 6 100       18 defined($pos)
1047             or $pos = $table->column_num( $tbl . '_' . $col );
1048             }
1049 20 100       75 next if ( exists( $columns{$tbl}->{$col} ) );
1050 1 50       6 $pos = $table->column_num($col) unless ( defined($pos) );
1051 1         3 push( @extraSortCols, $pos );
1052 1         3 $columns{$tbl}->{$col} = $nFields++;
1053             }
1054             }
1055              
1056 135 100       410 my $e = $self->{join} ? $table : $eval;
1057              
1058             # begin count for limiting if there's a limit clause and no order clause
1059             #
1060 135 100 100     332 my $limit_count = 0 if ( $self->limit() and !$self->order() );
1061 135         295 my $limit = $self->limit();
1062 135         213 my $row_count = 0;
1063 135   100     283 my $offset = $self->offset() || 0;
1064 135         450 while ( my $array = $table->fetch_row($data) )
1065             {
1066 8673 100       18821 if ( $self->eval_where( $e, $tableName, $array, \%funcs ) )
1067             {
1068 8432 100 100     16668 next if ( defined($limit_count) and ( $row_count++ < $offset ) );
1069              
1070 8427         14763 my @row = map { $_->value($e) } $self->columns();
  21086         41805  
1071 8427         13247 push( @{$rows}, \@row );
  8427         14882  
1072              
1073             # We quit here if there's a limit clause without order clause
1074             # and the limit has been reached
1075 8427 100 100     27148 defined($limit_count)
1076             and ( ++$limit_count >= $limit )
1077             and return ( $limit, $numFields, $rows );
1078             }
1079             }
1080              
1081 134 100       424 if ( $self->distinct() )
1082             {
1083 5         9 my %seen;
1084 5         24 @{$rows} = map {
1085 33 50       50 $seen{ join( "\0", ( map { defined($_) ? $_ : '' } @{$_} ) ) }++
  89 100       218  
  33         48  
1086             ? ()
1087             : $_
1088 5         9 } @{$rows};
  5         13  
1089             }
1090              
1091 134 100       393 if ( $self->{has_set_functions} )
1092             {
1093 19         44 my $aggreg;
1094 19 100       65 if ( $self->{group_by} )
1095             {
1096 7         13 my @keycols = @{ $self->{colpos} }{ @{ $self->{group_by} } };
  7         27  
  7         15  
1097 7         41 $aggreg = SQL::Statement::Group->new( $self, $rows, \@keycols );
1098             }
1099             else
1100             {
1101 12         114 $aggreg = SQL::Statement::Aggregate->new( $self, $rows );
1102             }
1103 19         71 $rows = $aggreg->calc();
1104             # FIXME re-order if order_by
1105             }
1106              
1107 134 100       349 if (@order_by)
1108 0         0 {
1109 16     16   8739 use sort 'stable';
  16         9566  
  16         104  
1110             my @sortCols = map {
1111 17         61 my ( $col, $tbl ) = ( $_->column(), $_->table() );
  20         60  
1112 20 50 66     100 $self->{join} and $table->is_shared($col) and $tbl = 'shared';
1113 20   50     73 $tbl ||= $self->colname2table($col) || '';
      66        
1114 20         83 ( $columns{$tbl}->{$col}, $_->desc() )
1115             } @order_by;
1116              
1117 17         49 $i = scalar(@sortCols);
1118             do
1119 17         31 {
1120 20         58 my $desc = $sortCols[ --$i ];
1121 20         34 my $colNum = $sortCols[ --$i ];
1122 20         101 @{$rows} = sort {
1123 132         166 my $result;
1124 132         246 $result = _anycmp( $a->[$colNum], $b->[$colNum] );
1125 132 100       255 $desc and $result = -$result;
1126             $result;
1127 20         40 } @{$rows};
  20         99  
1128             } while ( $i > 0 );
1129 16     16   3296 use sort 'defaults'; # for perl < 5.10.0
  16         42  
  16         69  
1130             }
1131              
1132 134 100       363 if ( defined( $self->limit() ) )
1133             {
1134 1   50     4 my $offset = $self->offset() || 0;
1135 1   50     8 my $limit = $self->limit() || 0;
1136 1         3 @{$rows} = splice( @{$rows}, $offset, $limit );
  1         3  
  1         4  
1137             }
1138              
1139             # Rip off columns that have been added for @extraSortCols only
1140 134 100       305 if (@extraSortCols)
1141             {
1142 1         3 foreach my $row ( @{$rows} )
  1         3  
1143             {
1144 4         6 splice( @{$row}, $numFields, scalar(@extraSortCols) );
  4         8  
1145             }
1146             }
1147              
1148 134         226 ( scalar( @{$rows} ), $numFields, $rows );
  134         1505  
1149             }
1150              
1151             sub _anycmp($$;$)
1152             {
1153 32226     32226   51521 my ( $a, $b, $case_fold ) = @_;
1154              
1155 32226 100 66     134747 if ( !defined($a) || !defined($b) )
    100 66        
1156             {
1157 4         9 return defined($a) - defined($b);
1158             }
1159             elsif ( looks_like_number($a) && looks_like_number($b) )
1160             {
1161 24164         64540 return $a <=> $b;
1162             }
1163             else
1164             {
1165 8058 50 0     24074 return $case_fold ? lc($a) cmp lc($b) || $a cmp $b : $a cmp $b;
1166             }
1167             }
1168              
1169             sub eval_where
1170             {
1171 8723     8723 1 14853 my ( $self, $eval, $tname, $rowary ) = @_;
1172 8723 100       21879 return 1 unless ( defined( $self->{where_terms} ) );
1173 458         686 $self->{argnum} = 0;
1174              
1175 458         1195 return $self->{where_terms}->value($eval);
1176             }
1177              
1178             sub fetch_row
1179             {
1180 123     123 1 10623 my ($self) = @_;
1181 123   50     282 $self->{data} ||= [];
1182 123         162 my $row = shift @{ $self->{data} };
  123         219  
1183 123 100 100     427 return unless $row and scalar @$row;
1184 93         188 return $row;
1185             }
1186              
1187 16     16   8429 no warnings 'once';
  16         44  
  16         1134  
1188             *fetch = \&fetch_row;
1189              
1190 16     16   121 use warnings;
  16         67  
  16         87119  
1191              
1192             sub fetch_rows
1193             {
1194 250     250 1 22330 my $self = $_[0];
1195 250   50     753 my $rows = $self->{data} || [];
1196 250         522 $self->{data} = [];
1197 250         606 return $rows;
1198             }
1199              
1200 7     7 1 1138 sub open_table ($$$$$) { croak "Abstract method " . ref( $_[0] ) . "::open_table called" }
1201              
1202             sub open_tables
1203             {
1204 4649     4649 1 9079 my ( $self, $data, $createMode, $lockMode ) = @_;
1205 4649         6287 my @c;
1206 4649         7360 my $t = {};
1207 4649         9834 my @tables = $self->tables();
1208 4649         7458 my $count = -1;
1209 4649         8199 for my $tbl (@tables)
1210             {
1211 4519         6116 ++$count;
1212 4519         8480 my $name = $tbl->name();
1213 4519 50       11984 if ( $name =~ m/^(.+)\.([^\.]+)$/ )
1214             {
1215 0         0 my $schema = $1; # ignored
1216 0         0 $name = $tbl->{name} = $2;
1217             }
1218              
1219 4519 100 66     28644 if ( defined( $self->{table_func} ) && defined( $self->{table_func}->{ uc $name } ) )
    100 100        
    100 66        
1220             {
1221 2         4 my $u_func = $self->{table_func}->{ uc $name };
1222 2         7 $t->{$name} = $self->get_user_func_table( $name, $u_func );
1223             }
1224             elsif (defined( $data->{Database}->{sql_ram_tables} )
1225             && defined( $data->{Database}->{sql_ram_tables}->{$name} )
1226             && $data->{Database}->{sql_ram_tables}->{$name} )
1227             {
1228 4475         9830 $t->{$name} = $data->{Database}->{sql_ram_tables}->{$name};
1229 4475         16514 $t->{$name}->seek( $data, 0, 0 );
1230             $t->{$name}->init_table( $data, $name, $createMode, $lockMode )
1231 4475 50       13859 if ( $t->{$name}->can('init_table') );
1232             }
1233             elsif ( $self->{is_ram_table} )
1234             {
1235 35         230 $t->{$name} = $data->{Database}->{sql_ram_tables}->{$name} =
1236             SQL::Statement::RAM::Table->new( $name, [], [] );
1237             }
1238             else
1239             {
1240 7         16 undef $@;
1241 7         15 eval {
1242 7         16 my $open_name = $self->{org_table_names}->[$count];
1243 7         27 $t->{$name} = $self->open_table( $data, $open_name, $createMode, $lockMode );
1244             };
1245 7         562 my $err = $t->{$name}->{errstr};
1246 7 50       26 return $self->do_err($err) if ($err);
1247 7 50       45 return $self->do_err($@) if ($@);
1248             }
1249              
1250 4512         7201 my @cnames;
1251 4512         7736 my $table_cols = $t->{$name}->{org_col_names};
1252 4512 100       8335 $table_cols = $t->{$name}->{col_names} unless $table_cols;
1253 4512         8107 for my $c (@$table_cols)
1254             {
1255 13311 100       26040 my $newc = $c =~ m/^"/ ? $c : lc($c);
1256 13311         22270 push( @cnames, $newc );
1257 13311         24043 $self->{ORG_NAME}->{$newc} = $c;
1258             }
1259              
1260             #
1261             # set the col_num => col_obj hash for the table
1262             #
1263 4512         6500 my $col_nums;
1264 4512         6254 my $i = 0;
1265 4512         7818 for (@cnames)
1266             {
1267 13311         23006 $col_nums->{$_} = $i++;
1268             }
1269 4512         10547 $t->{$name}->{col_nums} = $col_nums;
1270 4512         10246 $t->{$name}->{col_names} = \@cnames;
1271              
1272 4512         13549 my $tcols = $t->{$name}->col_names();
1273 4512         6816 my @newcols;
1274 4512         7831 for (@$tcols)
1275             {
1276 13311 50       23003 next unless ( defined($_) );
1277 13311         19777 my $ncol = $_;
1278 13311 50       32982 $ncol = $name . '.' . $ncol unless ( $ncol =~ m/\./ );
1279 13311         23843 push( @newcols, $ncol );
1280             }
1281 4512         12833 @c = ( @c, @newcols );
1282             }
1283              
1284 4642         14481 $self->buildColumnObjects( $t, \@tables );
1285 4642 50       10631 return $self->do_err( $self->{errstr} ) if ( $self->{errstr} );
1286              
1287             ##################################################
1288             # Patch from Cosimo Streppone
1289              
1290             # my $all_cols = $self->{all_cols}
1291             # || [ map {$_->{name} }@{$self->{columns}} ]
1292             # || [];
1293             # @$all_cols = (@$all_cols,@c);
1294             # $self->{all_cols} = $all_cols;
1295 4642 100       9109 if ( !$self->{all_cols} )
1296             {
1297 502         872 my $all_cols = [];
1298 502         770 $all_cols = [ map { $_->{name} } @{ $self->{columns} } ];
  1113         2616  
  502         1000  
1299 502   50     1268 $all_cols ||= []; # ?
1300 502         1551 @$all_cols = ( @$all_cols, @c );
1301 502         1081 $self->{all_cols} = $all_cols;
1302             }
1303             ##################################################
1304              
1305 4642         15772 return SQL::Eval->new( { 'tables' => $t } ), \@c;
1306             }
1307              
1308             sub getColumnObject($)
1309             {
1310 686     686 1 1289 my ( $self, $newcol, $t, $tables ) = @_;
1311 686         1324 my @columns;
1312              
1313 686 100 100     3107 if ( ( $newcol->{type} eq 'column' ) && ( -1 != index( $newcol->{value}, '*' ) ) )
    100 66        
1314             {
1315 199         374 my $tbl;
1316             my @tables;
1317 199 50       436 if ( $newcol->{value} =~ m/^(.+)\.\*$/ )
1318             {
1319 0         0 $tbl = $1;
1320 0 0       0 return $self->do_err("No table name given in '$newcol->{value}'")
1321             unless ( defined( _STRING($tbl) ) );
1322 0         0 @tables = ($tbl);
1323             }
1324             else
1325             {
1326 199         305 @tables = map { $_->name() } @{$tables};
  212         408  
  199         401  
1327             }
1328              
1329             my $join = defined( _HASH( $self->{join} ) )
1330             && ( ( -1 != index( $self->{join}->{type}, 'NATURAL' ) )
1331 199   100     834 || ( -1 != index( $self->{join}->{clause}, 'USING' ) ) );
1332 199         353 my %shared_cols;
1333              
1334 199         371 foreach my $table (@tables)
1335             {
1336 212 50       489 return $self->do_err("Can't find table '$table'") unless ( defined( $t->{$table} ) );
1337 212         358 my $tcols = $t->{$table}->{col_names};
1338 212 50       529 return $self->do_err("Couldn't find column names for table '$table'!")
1339             unless ( _ARRAY($tcols) );
1340 212         337 foreach my $colName ( @{$tcols} )
  212         366  
1341             {
1342 652 100 100     1378 next if ( $join && $shared_cols{$colName}++ );
1343 644         2087 my $expcol = [
1344             $colName, # column name
1345             $table, # table name
1346             SQL::Statement::ColumnValue->new( $self, $table . '.' . $colName ), # term
1347             $colName, # display name
1348             $colName,
1349             $newcol,
1350             ];
1351 644         1564 push( @columns, $expcol );
1352             }
1353             }
1354             }
1355             elsif ( ( 'CREATE' eq $self->command() ) || ( 'DROP' eq $self->command() ) )
1356             {
1357             return $self->do_err("Invalid column type '$newcol->{type}'")
1358 97 50       421 unless ( 'column' eq $newcol->{type} );
1359             my $expcol = [
1360             $newcol->{value}, # column name
1361             undef, # table name
1362             undef, # term
1363             $newcol->{value}, # display name
1364             $newcol->{value}, # original name
1365 97         274 $newcol, # coldef
1366             ];
1367 97         184 push( @columns, $expcol );
1368             }
1369             else
1370             {
1371 390         597 my $col;
1372 390 100       848 if ( $newcol->{type} eq 'setfunc' )
1373             {
1374 24         106 my @cols = $self->getColumnObject( $newcol->{arg}, $t );
1375 24 100       68 if ( 1 == scalar(@cols) )
1376             {
1377 18         48 $col = $cols[0]->[2];
1378             }
1379             else
1380             {
1381             # FIXME add '\0' constants between items?
1382             my $colSep = $self->{termFactory}->buildCondition(
1383             {
1384 6         43 type => 'string',
1385             value => "\0",
1386             }
1387             );
1388 6         23 @cols = map { $_->[2], $colSep } @cols;
  0         0  
1389 6         15 pop(@cols);
1390             $col = $self->{termFactory}->buildCondition(
1391             {
1392 6         44 type => 'function',
1393             name => 'str_concat',
1394             value => \@cols,
1395             }
1396             );
1397             }
1398             }
1399             else
1400             {
1401 366         1263 $col = $self->{termFactory}->buildCondition($newcol);
1402             }
1403              
1404             my $expcol = [
1405             $newcol->{name} || $newcol->{value}, # column name
1406             undef, # table name
1407             $col, # term
1408             $newcol->{alias} || $newcol->{fullorg}, # display name
1409             $newcol->{fullorg}, # original name
1410 390   66     2181 $newcol, # coldef
      66        
1411             ];
1412 390         843 push( @columns, $expcol );
1413             }
1414              
1415 686         1706 return @columns;
1416             }
1417              
1418             sub buildColumnObjects($)
1419             {
1420 4642     4642 1 8072 my ( $self, $t, $tables ) = @_;
1421              
1422 4642 100       14299 defined( _ARRAY0( $self->{column_defs} ) ) or return;
1423 4635 100       12375 defined( _ARRAY0( $self->{columns} ) ) and return;
1424              
1425 495         924 $self->{columns} = [];
1426              
1427 495         867 my $coldefs = $self->{column_defs};
1428              
1429 495         871 for ( my $i = 0; $i < scalar( @{$coldefs} ); ++$i )
  1157         2814  
1430             {
1431 662         1046 my $colentry = $coldefs->[$i];
1432              
1433 662         1626 my @columns = $self->getColumnObject( $colentry, $t, $tables );
1434 662 50       1566 return if ( $self->{errstr} );
1435              
1436 662         1143 foreach my $col (@columns)
1437             {
1438 1113         1542 my $expcol = SQL::Statement::Util::Column->new( @{$col} );
  1113         3315  
1439 1113         1649 push( @{ $self->{columns} }, $expcol );
  1113         2138  
1440 1113   66     4925 $self->{column_aliases}->{ $col->[4] } ||= $col->[3];
1441 1113         1443 $self->{colpos}->{ $col->[3] } = scalar( @{ $self->{columns} } ) - 1;
  1113         4103  
1442             }
1443             }
1444              
1445 495         1374 return;
1446             }
1447              
1448             sub verify_expand_column
1449             {
1450 13143     13143 1 26761 my ( $self, $c, $i, $usr_cols, $is_duplicate, $col_exists ) = @_;
1451              
1452             # XXX
1453 13143 100       25848 defined $self->{ALIASES}->{$c} and $c = $self->{ALIASES}->{$c};
1454              
1455 13143         19145 my ( $table, $col, $col_obj );
1456 13143 100       27971 if ( $c =~ m/(\S+)\.(\S+)/ )
    100          
1457             {
1458 1         3 $table = $1;
1459 1         2 $col = $2;
1460             }
1461 13142         25434 elsif ( ++${$i} >= 0 )
1462             {
1463 13122         17844 $col_obj = $usr_cols->[ ${$i} ];
  13122         19689  
1464 13122         27752 ( $table, $col ) = ( $col_obj->{table}, $col_obj->{name} );
1465             }
1466             else
1467             {
1468 20         57 ( $table, $col ) = $self->full_qualified_column_name($c);
1469             }
1470 13143 50       24290 return unless ($col);
1471              
1472             my $is_column =
1473 13143 100 100     83918 ( defined( _INSTANCE( $col_obj, 'SQL::Statement::Util::Column' ) ) and ( $col_obj->{coldef}->{type} eq 'column' ) )
1474             ? 1
1475             : 0;
1476              
1477 13143 100 100     39429 unless ( $is_column and defined($table) )
1478             {
1479 210         550 ( $table, undef ) = $self->full_qualified_column_name($col);
1480             }
1481              
1482 13143 50       27387 if ( defined( _INSTANCE( $table, 'SQL::Statement::Table' ) ) )
1483             {
1484 0         0 $table = $table->name();
1485             }
1486              
1487 13143 100 100     39534 if ( $is_column and !$table )
    100          
1488             {
1489 2 50       8 return $self->do_err("Ambiguous column name '$c'") if ( $is_duplicate->{$c} );
1490 2         10 return $self->do_err("No such column '$col'");
1491 0         0 $col = $c;
1492             }
1493             elsif ($is_column)
1494             {
1495 13086 50       26440 my $is_user_def = 1 if ( $self->{opts}->{function_defs}->{$col} );
1496             return $self->do_err("No such column '$table.$col'")
1497             unless ( $col_exists->{"$table.$col"}
1498 13086 0 33     34295 or $col_exists->{ "\L$table." . $col }
      33        
1499             or $is_user_def );
1500             }
1501              
1502 13141 100 100     47917 return ( $table, $col ) if ( $is_column or ${$i} < 0 );
  55         205  
1503 34         90 return;
1504             }
1505              
1506             sub verify_columns
1507             {
1508 4424     4424 1 8155 my ( $self, $data, $eval, $all_cols ) = @_;
1509              
1510             #
1511             # NOTE FOR LATER:
1512             # perhaps cache column names and skip this after first table open
1513             #
1514 4424   50     8290 $all_cols ||= [];
1515 4424         5866 my @tmp_cols = @{$all_cols};
  4424         9209  
1516 4424         9014 my @usr_cols = $self->columns();
1517 4424 50       9348 return $self->do_err('No fetchable columns') if ( 0 == scalar(@usr_cols) );
1518              
1519 4424         8314 my ( $cnum, $fully_qualified_cols ) = ( 0, [] );
1520 4424         7827 my @tmpcols = map { $_->{name} } @usr_cols;
  13122         28082  
1521 4424         7866 my %col_exists = map { $_ => 1 } @tmp_cols;
  13296         29576  
1522              
1523 4424         8338 my ( %is_member, @duplicates, %is_duplicate );
1524             # $_ =~ s/[^.]*\.(.*)/$1/;
1525 4424         8471 foreach (@$all_cols)
1526             {
1527 13296         29295 substr( $_, 0, index( $_, '.' ) + 1 ) = '';
1528             } # XXX we're modifying $all_cols from caller!
1529 4424         14723 @duplicates = grep( $is_member{$_}++, @$all_cols );
1530 4424         7290 %is_duplicate = map { $_ => 1 } @duplicates;
  54         126  
1531 4424 100 100     19555 if ( exists( $self->{join} ) && defined( _HASH( $self->{join} ) ) )
1532             {
1533 34         71 my $join = $self->{join};
1534 34 100       169 if ( -1 != index( uc $join->{type}, 'NATURAL' ) )
    100          
1535             {
1536 6         14 %is_duplicate = ();
1537             }
1538              
1539             # the following should be probably conditioned on an option,
1540             # but I do not know which --BW
1541             elsif ( 'USING' eq $join->{clause} )
1542             {
1543 10         21 my @keys = @{ $join->{keycols} };
  10         27  
1544 10         31 delete @is_duplicate{@keys};
1545             }
1546             }
1547              
1548 4424         6329 my %set_func_nofunc;
1549 4424 100       8335 if ( defined( $self->{has_set_functions} ) )
1550             {
1551 20         40 my @set_func_nofunc = grep { ( $_->{type} ne 'setfunc' ) } @{ $self->{column_defs} };
  34         96  
  20         55  
1552 20   66     50 %set_func_nofunc = map { ( $_->{alias} || $_->{fullorg} ) => 1 } @set_func_nofunc;
  9         64  
1553             }
1554 4424         10344 my ( $is_fully, $set_fully ) = ( {}, {} );
1555 4424         7019 my $i = -1;
1556 4424         9630 my $num_tables = $self->tables();
1557 4424         7520 for my $c (@tmpcols)
1558             {
1559 13122         33691 my ( $table, $col ) = $self->verify_expand_column( $c, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1560 13122 100       29311 return if ( $self->{errstr} );
1561 13120 100 66     36249 next unless ( $table && $col );
1562              
1563 13086         24401 my $ftc = "$table.$col";
1564 13086 50 33     49982 next if ( $table and $col and $is_fully->{$ftc} );
      33        
1565              
1566 13086         23282 $self->{columns}->[$i]->{name} = $col;
1567 13086         20299 $self->{columns}->[$i]->{table} = $table;
1568              
1569 13086 50 33     34537 if ( $table and $col )
1570             {
1571 13086         21324 push( @$fully_qualified_cols, $ftc );
1572 13086         23418 ++$is_fully->{$ftc};
1573 13086 100       30683 ++$set_fully->{$ftc} if ( $set_func_nofunc{$c} );
1574             }
1575             }
1576              
1577 4422 100       8717 if ( defined( $self->{has_set_functions} ) )
1578             {
1579 20 100       93 if ( defined( _ARRAY( $self->{group_by} ) ) )
1580             {
1581 7         10 foreach my $grpby ( @{ $self->{group_by} } )
  7         18  
1582             {
1583 8         15 $i = -2;
1584 8         23 my ( $table, $col ) = $self->verify_expand_column( $grpby, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1585 8 50       24 return if ( $self->{errstr} );
1586 8   33     18 $col ||= $grpby;
1587 8 50 33     32 ( $table, $col ) = $self->full_qualified_column_name($col)
1588             if ( defined($col) && !defined($table) );
1589 8 50 33     36 next unless ( defined($table) && defined($col) );
1590 8         31 delete $set_fully->{"$table.$col"};
1591             }
1592             }
1593              
1594 20 100       75 if ( defined( _HASH($set_fully) ) )
1595             {
1596             return $self->do_err(
1597             sprintf(
1598             "Column%s '%s' must appear in the GROUP BY clause or be used in an aggregate function",
1599 1         7 scalar( keys( %{$set_fully} ) ) > 1 ? 's' : '',
1600 1 50       3 join( "', '", keys( %{$set_fully} ) )
  1         10  
1601             )
1602             );
1603             }
1604             }
1605              
1606 4421 100       9170 if ( $self->{sort_spec_list} )
1607             {
1608 17         70 for my $n ( 0 .. scalar @{ $self->{sort_spec_list} } - 1 )
  17         67  
1609             {
1610 20 100       124 defined( _INSTANCE( $self->{sort_spec_list}->[$n], 'SQL::Statement::Order' ) ) and next;
1611 13         25 my ( $newcol, $direction ) = each %{ $self->{sort_spec_list}->[$n] };
  13         63  
1612 13   66     68 my $desc = $direction && ( $direction eq "DESC" ); # ($direction || "ASC") eq "DESC";
1613              
1614             # XXX parse order by like group by and select list
1615 13         26 $i = -2;
1616 13         61 my ( $table, $col ) = $self->verify_expand_column( $newcol, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1617 13 50       53 $self->{errstr} and return;
1618 13 100 66     80 ( $table, $col ) = $self->full_qualified_column_name($newcol)
1619             if ( defined($col) && !defined($table) );
1620 13 100       68 defined($table) and $col = $table . "." . $col;
1621 13         68 $self->{sort_spec_list}->[$n] = SQL::Statement::Order->new(
1622             col => SQL::Statement::Util::Column->new(
1623             $col, # column name
1624             $table, # table name
1625             SQL::Statement::ColumnValue->new( $self, $col ), # term
1626             $newcol # display name
1627             ),
1628             direction => $direction,
1629             desc => $desc,
1630             );
1631             }
1632             }
1633              
1634 4421         19751 return $fully_qualified_cols;
1635             }
1636              
1637             sub distinct()
1638             {
1639 134     134 1 695 my $q = _STRING( $_[0]->{set_quantifier} );
1640 134   66     597 return defined($q) && ( 'DISTINCT' eq $q );
1641             }
1642              
1643             sub column_names()
1644             {
1645 0     0 1 0 my @cols = map { $_->name() } $_[0]->columns();
  0         0  
1646 0         0 return @cols;
1647             }
1648              
1649 5823     5823 1 107712 sub command() { return $_[0]->{command} }
1650              
1651             sub params(;$)
1652             {
1653 2 50   2 1 20 if ( !$_[0]->{params} )
1654             {
1655 0 0       0 return wantarray ? () : 0;
1656             }
1657 2 50       8 return $_[0]->{params}->[ $_[1] ] if ( defined $_[1] );
1658              
1659 2 50       15 return wantarray ? @{ $_[0]->{params} } : scalar @{ $_[0]->{params} };
  0         0  
  2         14  
1660             }
1661              
1662             sub row_values(;$$)
1663             {
1664 12803 50   12803 1 30688 unless ( defined( _ARRAY( $_[0]->{values} ) ) )
1665             {
1666 0 0       0 return wantarray ? () : 0;
1667             }
1668 12803 100       20699 if ( defined( $_[1] ) )
1669             {
1670 12802 50       24441 return 0 unless ( defined( $_[0]->{values}->[ $_[1] ] ) );
1671 12802 100       31127 return $_[0]->{values}->[ $_[1] ]->[ $_[2] ] if ( defined $_[2] );
1672              
1673             return wantarray
1674 0         0 ? map { $_->{value} } @{ $_[0]->{values}->[ $_[1] ] }
  0         0  
1675 1 50       3 : scalar @{ $_[0]->{values}->[ $_[1] ] };
  1         7  
1676             }
1677             else
1678             {
1679             return wantarray
1680             ? map {
1681 0         0 [ map { $_->{value} } @{$_} ]
  0         0  
  0         0  
1682 0         0 } @{ $_[0]->{values} }
1683 1 50       4 : scalar( @{ $_[0]->{values} } );
  1         7  
1684             }
1685             }
1686              
1687             #
1688             # $num_of_cols = $stmt->columns() # number of columns
1689             # @cols = $stmt->columns() # array of S::S::Column objects
1690             # $col = $stmt->columns($cnum) # S::S::Column obj for col number $cnum
1691             # $col = $stmt->columns($cname) # S::S::Column obj for col named $cname
1692             #
1693             sub columns
1694             {
1695 34581     34581 1 55086 my ( $self, $col ) = @_;
1696 34581 100       62236 if ( !$self->{columns} )
1697             {
1698 1 50       9 return wantarray ? () : 0;
1699             }
1700              
1701 34580 100 66     116641 if ( defined $col and $col =~ m/^\d+$/ )
    50          
1702             { # arg1 = a number
1703 12801         28420 return $self->{columns}->[$col];
1704             }
1705             elsif ( defined $col )
1706             { # arg1 = string
1707 0         0 for my $c ( @{ $self->{columns} } )
  0         0  
1708             {
1709 0 0       0 return $c if ( $c->name() eq $col );
1710             }
1711             }
1712              
1713 21779 100       33172 return wantarray ? @{ $self->{columns} } : scalar @{ $self->{columns} };
  13213         26188  
  8566         24958  
1714             }
1715              
1716             sub colname2colnum
1717             {
1718 0 0   0 1 0 if ( !$_[0]->{columns} ) { return undef; }
  0         0  
1719 0         0 for my $i ( 0 .. $#{ $_[0]->{columns} } )
  0         0  
1720             {
1721 0 0       0 return $i if ( $_[0]->{columns}->[$i]->name() eq $_[1] );
1722             }
1723 0         0 return undef;
1724             }
1725              
1726             sub colname2table($)
1727             {
1728 2     2 1 5 my ( $self, $col_name ) = @_;
1729 2 50       7 return undef unless defined $col_name;
1730              
1731 2         4 my ( $tbl, $col );
1732 2 50       7 if ( $col_name =~ /^(.+)\.(.+)$/ )
1733             {
1734 0         0 ( $tbl, $col ) = ( $1, $2 );
1735             }
1736             else
1737             {
1738 2         5 $col = $col_name;
1739             }
1740              
1741 2         3 my $found_table;
1742 2         4 for my $full_col ( @{ $self->{all_cols} } )
  2         5  
1743             {
1744 10         32 my ( $stbl, $scol ) = $full_col =~ /^(.+)\.(.+)$/;
1745 10 50 100     36 next unless ( $scol || '' ) eq $col;
1746 0 0 0     0 next if ( defined($tbl) && ( $tbl ne $stbl ) );
1747 0         0 $found_table = $stbl;
1748 0         0 last;
1749             }
1750 2         11 return $found_table;
1751             }
1752              
1753             sub full_qualified_column_name($)
1754             {
1755 574     574 1 1091 my ( $self, $col_name ) = @_;
1756 574 50       1110 return unless ( defined($col_name) );
1757              
1758             # XXX
1759 574 100       1237 defined $self->{ALIASES}->{$col_name} and $col_name = $self->{ALIASES}->{$col_name};
1760              
1761 574         837 my ( $tbl, $col );
1762 574 100       1987 unless ( ( $tbl, $col ) = $col_name =~ m/^((?:"[^"]+")|(?:[^.]+))\.(.*)$/ )
1763             {
1764 449         743 $col = $col_name;
1765             }
1766              
1767 574 100       1199 unless ( defined( $self->{splitted_all_cols} ) )
1768             {
1769 118         187 my @rc;
1770 118         188 for my $full_col ( @{ $self->{all_cols} } )
  118         277  
1771             {
1772 722 100       2849 if ( my ( $stbl, $scol ) = $full_col =~ m/^((?:"[^"]+")|(?:[^.]+))\.(.*)$/ )
1773             {
1774 440         646 push( @{ $self->{splitted_all_cols} }, [ $stbl, $scol ] );
  440         1144  
1775 440 100 100     1076 defined($tbl) and ( $tbl ne $stbl ) and next;
1776 416 100       1088 ( $scol eq $col ) and @rc = ( $stbl, $scol );
1777             }
1778             }
1779 118 100       569 @rc and return @rc;
1780             }
1781             else
1782             {
1783 456         636 for my $splitted_col ( @{ $self->{splitted_all_cols} } )
  456         944  
1784             {
1785 1576 100 100     3503 defined($tbl) and ( $tbl ne $splitted_col->[0] ) and next;
1786 1228 100       3411 ( $splitted_col->[1] eq $col ) and return @$splitted_col;
1787             }
1788             }
1789              
1790 39         117 return ( $tbl, $col );
1791             }
1792              
1793             #sub verify_order_cols
1794             #{
1795             # my ( $self, $table ) = @_;
1796             # return unless $self->{sort_spec_list};
1797             # my @ocols = $self->order();
1798             # my @tcols = @{ $table->col_names() };
1799             # my @n_ocols;
1800             #
1801             # for my $colnum ( 0 .. $#ocols )
1802             # {
1803             # my $col = $self->order($colnum);
1804             #
1805             # if ( !defined( $col->table() ) )
1806             # {
1807             # my $cname = $ocols[$colnum]->{col}->name();
1808             # my $tname = $self->colname2table($cname);
1809             # return $self->do_err("No such column '$cname'.") unless ($tname);
1810             # $self->{sort_spec_list}->[$colnum]->{col}->{table} = $tname;
1811             # push( @n_ocols, $tname );
1812             # }
1813             # }
1814             #
1815             # return 1;
1816             #}
1817              
1818 407     407 1 1186 sub limit ($) { $_[0]->{limit_clause}->{limit}; }
1819 138     138 1 479 sub offset ($) { $_[0]->{limit_clause}->{offset}; }
1820              
1821             sub order
1822             {
1823 139 100   139 1 952 return unless ( defined $_[0]->{sort_spec_list} );
1824              
1825             return
1826             defined( $_[1] ) && looks_like_number( $_[1] ) ? $_[0]->{sort_spec_list}->[ $_[1] ]
1827 18         62 : wantarray ? @{ $_[0]->{sort_spec_list} }
1828 20 100 66     109 : scalar @{ $_[0]->{sort_spec_list} };
  1 100       5  
1829             }
1830              
1831             sub tables
1832             {
1833             return
1834             defined( $_[1] ) && looks_like_number( $_[1] ) ? $_[0]->{tables}->[ $_[1] ]
1835 4701         10684 : wantarray ? @{ $_[0]->{tables} }
1836 13557 100 66 13557 1 54229 : scalar @{ $_[0]->{tables} };
  4424 100       9169  
1837             }
1838              
1839             sub order_joins
1840             {
1841 7     7 1 18 my ( $self, $links ) = @_;
1842 7         12 my ( @new_keycols, @new_links );
1843 7         16 for (@$links)
1844             {
1845 7         17 my ( $tbl, $col ) = $self->full_qualified_column_name($_);
1846 7         26 push( @new_keycols, $tbl . $self->{dlm} . $col );
1847 7         18 push( @new_links, $tbl );
1848             }
1849 7         19 $self->{join}->{keycols} = $links = \@new_keycols;
1850             # my @tmp = @new_keycols;
1851             # foreach (@tmp) { $_ =~ s/\./$self->{dlm}/g; }
1852             # $self->{join}->{keycols} = \@tmp;
1853             # @$links = \@new_keycols;
1854 7         19 my @all_tables;
1855             my %relations;
1856 7         0 my %is_table;
1857              
1858 7         20 while (@new_links)
1859             {
1860 7         15 my $t1 = shift(@new_links);
1861 7         11 my $t2 = shift(@new_links);
1862 7 50 33     40 return undef unless ( defined($t1) and defined($t2) );
1863 0 0       0 push @all_tables, $t1 unless ( $is_table{$t1}++ );
1864 0 0       0 push @all_tables, $t2 unless ( $is_table{$t2}++ );
1865 0         0 $relations{$t1}{$t2}++;
1866 0         0 $relations{$t2}{$t1}++;
1867             }
1868 0         0 my @tables = @all_tables;
1869 0         0 my @order = shift @tables;
1870 0         0 my %is_ordered = ( $order[0] => 1 );
1871 0         0 my %visited;
1872 0         0 while (@tables)
1873             {
1874 0         0 my $t = shift @tables;
1875 0         0 my @rels = keys %{ $relations{$t} };
  0         0  
1876 0         0 for my $t2 (@rels)
1877             {
1878 0 0       0 next unless $is_ordered{$t2};
1879 0         0 push @order, $t;
1880 0         0 $is_ordered{$t}++;
1881 0         0 last;
1882             }
1883 0 0       0 if ( !$is_ordered{$t} )
1884             {
1885 0 0       0 push( @tables, $t ) if ( $visited{$t}++ < @all_tables );
1886             }
1887             }
1888 0 0       0 if ( @order < @all_tables )
1889             {
1890 0         0 my @missing;
1891 0         0 my %in_order = map { $_ => 1 } @order;
  0         0  
1892 0         0 foreach my $tbl (@all_tables)
1893             {
1894 0 0       0 next if ( $in_order{$tbl} );
1895 0         0 push( @missing, $tbl );
1896             }
1897 0         0 return $self->do_err( sprintf( 'Unconnected tables (%s) in equijoin statement!', join( ', ', @missing ) ) );
1898             }
1899 0         0 $self->{join}->{table_order} = \@order;
1900 0         0 return \@order;
1901             }
1902              
1903             sub do_err
1904             {
1905 12     12 1 168 my $self = shift;
1906 12         27 my $err = shift;
1907 12         23 my $errtype = shift;
1908 12         90 my @c = caller 6;
1909              
1910             #$err = "[" . $self->{original_string} . "]\n$err\n\n";
1911             # $err = "$err\n\n";
1912 12         31 my $prog = $c[1];
1913 12         23 my $line = $c[2];
1914 12 100       47 $prog = defined($prog) ? " called from $prog" : '';
1915 12 100       42 $prog .= defined($line) ? " at $line" : '';
1916 12         41 $err = "\nExecution ERROR: $err$prog.\n\n";
1917              
1918 12         24 $self->{errstr} = $err;
1919 12 50       47 carp $err if $self->{PrintError};
1920 12 100       173 croak "$err" if $self->{RaiseError};
1921 11         79 return;
1922             }
1923              
1924 14     14 1 11756 sub errstr() { return $_[0]->{errstr}; }
1925              
1926 1     1 1 18 sub where_hash() { return $_[0]->{where_clause}; }
1927              
1928 0     0 1 0 sub column_defs() { return $_[0]->{column_defs}; }
1929              
1930             sub where()
1931             {
1932 5 50   5 1 39 return undef unless $_[0]->{where_terms};
1933 5         87 return $_[0]->{where_terms};
1934             }
1935              
1936             sub get_user_func_table
1937             {
1938 2     2 1 5 my ( $self, $name, $u_func ) = @_;
1939 2         24 my $term = $self->{termFactory}->buildCondition($u_func);
1940              
1941 2         6 my @data_aryref = @{ $term->value(undef) };
  2         16  
1942 2         5 my $col_names = shift @data_aryref;
1943              
1944             # my $tempTable = SQL::Statement::TempTable->new(
1945             # $name, $col_names, $col_names, $data_aryref
1946             # );
1947 2         16 my $tempTable = SQL::Statement::RAM::Table->new( $name, $col_names, \@data_aryref );
1948 2   33     25 $tempTable->{all_cols} ||= $col_names;
1949 2         10 return $tempTable;
1950             }
1951              
1952             sub capability($)
1953             {
1954 0     0 1 0 my ( $self, $capname ) = @_;
1955 0 0       0 return $self->{capabilities}->{$capname} if ( defined( $self->{capabilities}->{$capname} ) );
1956              
1957 0         0 return;
1958             }
1959              
1960             sub DESTROY
1961             {
1962 870     870   95286 my $self = $_[0];
1963              
1964 870         1987 undef $self->{NAME};
1965 870         1881 undef $self->{ORG_NAME};
1966 870         1698 undef $self->{all_cols};
1967 870         1812 undef $self->{already_prepared};
1968 870         1375 undef $self->{argnum};
1969 870         2014 undef $self->{col_obj};
1970 870         1486 undef $self->{column_names};
1971 870         3237 undef $self->{columns};
1972 870         1452 undef $self->{cur_table};
1973 870         1744 undef $self->{data};
1974 870         1535 undef $self->{group_by};
1975             #undef $self->{has_OR};
1976 870         1936 undef $self->{join};
1977 870         1465 undef $self->{limit_clause};
1978 870         1495 undef $self->{num_placeholders};
1979 870         1349 undef $self->{num_val_placeholders};
1980 870         1513 undef $self->{org_table_names};
1981 870         1367 undef $self->{params};
1982 870         2255 undef $self->{opts};
1983 870         1484 undef $self->{procedure};
1984 870         1282 undef $self->{set_function};
1985 870         1488 undef $self->{sort_spec_list};
1986 870         1341 undef $self->{subquery};
1987 870         1879 undef $self->{tables};
1988 870         1451 undef $self->{table_names};
1989 870         1321 undef $self->{table_func};
1990 870         1999 undef $self->{where_clause};
1991 870         1663 undef $self->{where_terms};
1992 870         7738 undef $self->{values};
1993             }
1994              
1995             package SQL::Statement::Aggregate;
1996              
1997 16     16   165 use Scalar::Util qw(looks_like_number);
  16         46  
  16         1080  
1998 16     16   128 use Params::Util qw(_HASH);
  16         52  
  16         841  
1999 16     16   119 use Clone qw(clone);
  16         35  
  16         13906  
2000              
2001             sub new
2002             {
2003 19     19   53 my ( $class, $owner, $rows ) = @_;
2004 19         68 my $self = {
2005             owner => $owner,
2006             records => $rows,
2007             };
2008 19         61 return bless( $self, $class );
2009             }
2010              
2011             my $empty_agg = {
2012             uniq => [],
2013             count => 0,
2014             sum => undef,
2015             min => undef,
2016             max => undef,
2017             };
2018              
2019             sub do_calc()
2020             {
2021 19     19   39 my $self = $_[0];
2022              
2023 19         30 foreach my $line ( 0 .. ( scalar( @{ $self->{records} } ) - 1 ) )
  19         88  
2024             {
2025 8073         13989 my $row = $self->{records}->[$line];
2026 8073         12925 my $result = $self->getAffectedResult($row);
2027              
2028 8073         10505 foreach my $colidx ( 0 .. ( scalar( @{ $self->{owner}->{columns} } ) - 1 ) )
  8073         15539  
2029             {
2030 20115         31525 my $coldef = $self->{owner}->{columns}->[$colidx]->{coldef};
2031 20115         29214 my $colval = $row->[$colidx];
2032              
2033 20115 100       31470 if ( $coldef->{type} eq 'setfunc' )
2034             {
2035 16086 100       27428 if ( $coldef->{distinct} eq 'DISTINCT' )
2036             {
2037 9 100       30 next if defined( $result->{uniq}->[$colidx]->{$colval} );
2038 6         14 $result->{uniq}->[$colidx]->{$colval} = 1;
2039             }
2040              
2041             $result->{agg}->[$colidx] = clone($empty_agg)
2042 16083 100       32523 unless ( defined( _HASH( $result->{agg}->[$colidx] ) ) );
2043 16083         21525 my $agg = $result->{agg}->[$colidx];
2044              
2045 16083         20645 ++$agg->{count};
2046 16083 100 100     33699 unless ( defined( $agg->{max} )
2047             && ( SQL::Statement::_anycmp( $colval, $agg->{max} ) < 0 ) )
2048             {
2049 16038         22977 $agg->{max} = $colval;
2050             }
2051 16083 100 100     36358 unless ( defined( $agg->{min} )
2052             && ( SQL::Statement::_anycmp( $colval, $agg->{min} ) > 0 ) )
2053             {
2054 4069         6073 $agg->{min} = $colval;
2055             }
2056 16083 100       41601 $agg->{sum} += $colval if ( looks_like_number($colval) );
2057             }
2058             else
2059             {
2060             $result->{pure}->[$colidx] = $colval
2061 4029 100       8130 unless ( defined( $result->{pure}->[$colidx] ) );
2062             }
2063             }
2064             }
2065             }
2066              
2067             sub build_row # (\%)
2068             {
2069 32     32   58 my ( $self, $result ) = @_;
2070 32         60 my @row;
2071              
2072 32         55 foreach my $colidx ( 0 .. ( scalar( @{ $self->{owner}->{columns} } ) - 1 ) )
  32         83  
2073             {
2074 65         308 my $coldef = $self->{owner}->{columns}->[$colidx]->{coldef};
2075              
2076 65 100       127 if ( $coldef->{type} eq 'setfunc' )
2077             {
2078 41 100       130 if ( $coldef->{name} eq 'COUNT' )
    100          
    100          
    100          
    50          
2079             {
2080 20   100     96 push( @row, $result->{agg}->[$colidx]->{count} || 0 );
2081             }
2082             elsif ( $coldef->{name} eq 'MAX' )
2083             {
2084 11         39 push( @row, $result->{agg}->[$colidx]->{max} );
2085             }
2086             elsif ( $coldef->{name} eq 'MIN' )
2087             {
2088 1         9 push( @row, $result->{agg}->[$colidx]->{min} );
2089             }
2090             elsif ( $coldef->{name} eq 'SUM' )
2091             {
2092 8         26 push( @row, $result->{agg}->[$colidx]->{sum} );
2093             }
2094             elsif ( $coldef->{name} eq 'AVG' )
2095             {
2096 1         3 my $count = $result->{agg}->[$colidx]->{count};
2097 1         4 my $sum = $result->{agg}->[$colidx]->{sum};
2098 1 50 33     9 my $avg = $sum / $count if ( $count && $sum );
2099 1         5 push( @row, $avg );
2100             }
2101             else
2102             {
2103 0         0 return $self->{owner}->do_err("Invalid SET FUNCTION '$coldef->{name}'");
2104             }
2105             }
2106             else
2107             {
2108 24         59 push( @row, $result->{pure}->[$colidx] );
2109             }
2110             }
2111              
2112 32         67 return \@row;
2113             }
2114              
2115             sub calc()
2116             {
2117 12     12   27 my $self = $_[0];
2118              
2119 12         39 $self->{final_row} = {};
2120              
2121 12         41 $self->do_calc();
2122              
2123 12         50 my $final_row = $self->build_row( $self->{final_row} );
2124              
2125 12         769 return [$final_row];
2126             }
2127              
2128             sub getAffectedResult # (\@)
2129             {
2130 4049     4049   6098 return $_[0]->{final_row};
2131             }
2132              
2133             package SQL::Statement::Group;
2134              
2135 16     16   158 use vars qw(@ISA);
  16         59  
  16         1002  
2136              
2137 16     16   135 use Params::Util qw(_HASH);
  16         45  
  16         5854  
2138              
2139             @ISA = qw(SQL::Statement::Aggregate);
2140              
2141             sub new
2142             {
2143 7     7   17 my ( $class, $owner, $rows, $keycols ) = @_;
2144              
2145 7         46 my $self = $class->SUPER::new( $owner, $rows );
2146 7         26 $self->{keycols} = $keycols;
2147              
2148 7         17 return $self;
2149             }
2150              
2151             sub calc()
2152             {
2153 7     7   12 my $self = $_[0];
2154 7         10 my @final_table;
2155              
2156 7         32 $self->do_calc();
2157              
2158 7 100       16 if ( scalar( keys( %{ $self->{final_rows} } ) ) )
  7         29  
2159             {
2160 6         12 foreach my $key ( keys( %{ $self->{final_rows} } ) )
  6         18  
2161             {
2162 19         67 my $final_row = $self->build_row( $self->{final_rows}->{$key} );
2163 19         38 push( @final_table, $final_row );
2164             }
2165             }
2166             else
2167             {
2168 1         7 my $final_row = $self->build_row( {} );
2169 1         5 push( @final_table, $final_row );
2170             }
2171              
2172 7         744 return \@final_table;
2173             }
2174              
2175             sub getAffectedResult # (\@)
2176             {
2177 4024     4024   5857 my ( $self, $row ) = @_;
2178              
2179 4024         5472 my $rowkey = join( "\0", @$row[ @{ $self->{keycols} } ] );
  4024         10249  
2180              
2181             $self->{final_rows}->{$rowkey} = {}
2182 4024 100       9353 unless ( defined( _HASH( $self->{final_rows}->{$rowkey} ) ) );
2183              
2184 4024         6745 return $self->{final_rows}->{$rowkey};
2185             }
2186              
2187             package SQL::Statement::TempTable;
2188              
2189 16     16   140 use vars qw(@ISA);
  16         56  
  16         1043  
2190              
2191             BEGIN
2192             {
2193 16     16   122 require SQL::Eval;
2194              
2195 16         14283 @SQL::Statement::TempTable::ISA = qw(SQL::Eval::Table);
2196             }
2197              
2198             sub new
2199             {
2200 44     44   123 my ( $class, $name, $col_names, $table_cols, $table ) = @_;
2201 44         68 my %col_nums;
2202 44         315 $col_nums{ $col_names->[$_] } = $_ for ( 0 .. scalar @$col_names - 1 );
2203 44         158 my @display_order = @col_nums{@$table_cols};
2204 44         239 my $self = {
2205             col_names => $col_names,
2206             table_cols => \@display_order,
2207             col_nums => \%col_nums,
2208             table => $table,
2209             NAME => $name,
2210             rowpos => 0,
2211             maxrow => scalar @$table
2212             };
2213 44         174 return $class->SUPER::new($self);
2214             }
2215              
2216 6     6   26 sub is_shared($) { $_[0]->{is_shared}->{ $_[1] }; }
2217 0     0   0 sub get_pos() { $_[0]->{rowpos} }
2218              
2219             sub column_num($)
2220             {
2221 129     129   239 my ( $s, $col ) = @_;
2222 129         230 my $new_col = $s->{col_nums}->{$col};
2223 129 100       290 unless ( defined($new_col) )
2224             {
2225 6         22 my @tmp = split( '~', $col );
2226 6 100       22 return unless ( 2 == scalar(@tmp) );
2227 1         4 $new_col = lc( $tmp[0] ) . '~' . $tmp[1];
2228 1         3 $new_col = $s->{col_nums}->{$new_col};
2229             }
2230 124         207 return $new_col;
2231             }
2232              
2233             sub fetch_row()
2234             {
2235             return $_[0]->{row} =
2236             ( $_[0]->{rowpos} >= $_[0]->{maxrow} )
2237             ? undef
2238 450 100   450   1412 : $_[0]->{table}->[ $_[0]->{rowpos}++ ];
2239             }
2240              
2241 1189     1189   3671 sub column($) { return $_[0]->{row}->[ $_[0]->{col_nums}->{ $_[1] } ]; }
2242              
2243             package SQL::Statement::Order;
2244              
2245             sub new ($$)
2246             {
2247 13     13   31 my $proto = shift;
2248 13         62 my $self = {@_};
2249 13   33     109 bless( $self, ( ref($proto) || $proto ) );
2250             }
2251 40     40   94 sub table ($) { $_[0]->{col}->table(); }
2252 40     40   149 sub column ($) { $_[0]->{col}->display_name(); }
2253 20     20   80 sub desc ($) { $_[0]->{desc}; }
2254 0     0   0 sub direction ($) { $_[0]->{direction}; }
2255              
2256             package SQL::Statement::Limit;
2257              
2258             sub new ($$)
2259             {
2260 9     9   23 my ( $proto, $self ) = @_;
2261 9   33     60 bless( $self, ( ref($proto) || $proto ) );
2262             }
2263              
2264             #sub limit ($) { shift->{limit}; }
2265             #sub offset ($) { shift->{offset}; }
2266              
2267             package SQL::Statement::Param;
2268              
2269             sub new
2270             {
2271 36     36   69 my ( $class, $idx ) = @_;
2272 36         82 my $self = { 'idx' => $idx };
2273 36         115 return bless( $self, $class );
2274             }
2275              
2276 0     0   0 sub idx ($) { $_[0]->{idx}; }
2277              
2278             package SQL::Statement::Table;
2279              
2280             sub new
2281             {
2282 5222     5222   10073 my ( $class, $table_name ) = @_;
2283              
2284 5222 100       14302 if ( $table_name !~ m/"/ )
2285             {
2286 5194         10941 $table_name = lc $table_name;
2287             }
2288              
2289 5222         12357 my $self = {
2290             name => $table_name,
2291             };
2292              
2293 5222         16432 return bless( $self, $class );
2294             }
2295              
2296 9281     9281   24272 sub name { $_[0]->{name} }
2297              
2298             1;
2299             __END__