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   603740 use strict;
  16         90  
  16         506  
15 16     16   131 use warnings FATAL => "all";
  16         25  
  16         590  
16              
17 16     16   302 use 5.008;
  16         47  
18 16     16   78 use vars qw($VERSION $DEBUG);
  16         26  
  16         880  
19              
20 16     16   11807 use SQL::Parser ();
  16         90  
  16         739  
21 16     16   9038 use SQL::Eval ();
  16         50  
  16         327  
22 16     16   7076 use SQL::Statement::RAM ();
  16         47  
  16         372  
23 16     16   6924 use SQL::Statement::TermFactory ();
  16         60  
  16         415  
24 16     16   8270 use SQL::Statement::Util ();
  16         48  
  16         414  
25              
26 16     16   97 use Carp qw(carp croak);
  16         33  
  16         808  
27 16     16   5959 use Clone qw(clone);
  16         34033  
  16         873  
28 16     16   2872 use Errno;
  16         8579  
  16         711  
29 16     16   93 use Scalar::Util qw(blessed looks_like_number);
  16         31  
  16         720  
30 16     16   89 use List::Util qw(first);
  16         31  
  16         875  
31 16     16   88 use Params::Util qw(_INSTANCE _STRING _ARRAY _ARRAY0 _HASH0 _HASH);
  16         32  
  16         95946  
32              
33             #use locale;
34              
35             $VERSION = '1.414';
36              
37             sub new
38             {
39 872     872 1 365777 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     3834 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         1272 my $parser = $flags;
51 872         1747 my $self = bless( {}, $class );
52 872 50       2062 $flags->{PrintError} = 1 unless defined $flags->{PrintError};
53 872 100       1739 $flags->{text_numbers} = 1 unless defined $flags->{text_numbers};
54 872 100       1712 $flags->{alpha_compare} = 1 unless defined $flags->{alpha_compare};
55              
56 872 50       3323 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         4011 $self->{$_} = $flags->{$_} for qw(RaiseError PrintError opts);
63             }
64              
65 872         1734 $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       5543 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         3266 $self->{termFactory} = SQL::Statement::TermFactory->new($self);
77 872         1652 $self->{capabilities} = {};
78 872         2281 $self->prepare( $sql, $parser );
79 865         2442 return $self;
80             }
81              
82             sub prepare
83             {
84 872     872 1 1510 my ( $self, $sql, $parser ) = @_;
85              
86 872 50       2185 $self->{already_prepared}->{$sql} and return;
87              
88             # delete earlier preparations, they're overwritten after this prepare run
89 872         1570 $self->{already_prepared} = {};
90 872         2704 my $rv = $parser->parse($sql);
91 865 100       1769 if ($rv)
92             {
93 855         2562 undef $self->{errstr};
94 855         40394 my $parser_struct = clone( $parser->{struct} );
95 855         2700 while ( my ( $k, $v ) = each( %{$parser_struct} ) )
  9564         19763  
96             {
97 8709         15035 $self->{$k} = $v;
98             }
99 855         1447 undef $self->{where_terms}; # force rebuild when needed
100 855         1356 undef $self->{columns};
101 855         1187 undef $self->{splitted_all_cols};
102 855         1319 $self->{argnum} = 0;
103              
104 855         1343 my $values = $self->{values};
105 855         1209 my $param_num = -1;
106 855 100       1671 if ( $self->{limit_clause} )
107             {
108 9         67 $self->{limit_clause} = SQL::Statement::Limit->new( $self->{limit_clause} );
109             }
110              
111 855 100       1611 if ( defined( $self->{num_placeholders} ) )
112             {
113 17         60 for my $i ( 0 .. $self->{num_placeholders} - 1 )
114             {
115 36         99 $self->{params}->[$i] = SQL::Statement::Param->new($i);
116             }
117             }
118              
119 855         1183 $self->{tables} = [ map { SQL::Statement::Table->new($_) } @{ $self->{table_names} } ];
  704         1834  
  855         1952  
120              
121 855 100 66     2691 if ( $self->{where_clause} && !defined( $self->{where_terms} ) )
122             {
123 229         828 $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         2675 ++$self->{already_prepared}->{$sql};
132 855         3032 return $self;
133             }
134             else
135             {
136 10         42 $self->{errstr} = $parser->errstr;
137 10         41 ++$self->{already_prepared}->{$sql};
138 10         23 return;
139             }
140             }
141              
142             sub execute
143             {
144 4654     4654 1 197999 my ( $self, $data, $params ) = @_;
145             ( $self->{NUM_OF_ROWS}, $self->{NUM_OF_FIELDS}, $self->{data} ) = ( 0, 0, [] ) and return 'OEO'
146 4654 100 50     10027 if ( $self->{no_execute} );
147 4649 100       9235 $self->{procedure}->{data} = $data if ( $self->{procedure} );
148 4649         8442 $self->{params} = $params;
149              
150 4649         9622 my ($command) = $self->command();
151 4649 50       9157 return $self->do_err('No command found!') unless ($command);
152              
153             $self->{where_clause}
154             and !defined( $self->{where_terms} )
155 4649 100 100     10577 and $self->{where_terms} = $self->{termFactory}->buildCondition( $self->{where_clause} );
156              
157 4649         13420 ( $self->{NUM_OF_ROWS}, $self->{NUM_OF_FIELDS}, $self->{data} ) = $self->$command( $data, $params );
158              
159             $self->{NAME} =
160 4648 100       13123 _ARRAY0( $self->{columns} ) ? [ map { delete $_->{term}->{fastpath}; $_->display_name() } @{ $self->{columns} } ] : [];
  13395         21247  
  13395         25119  
  4642         10363  
161              
162             # Force closing the tables
163 4648         8406 $self->{tables} = [ map { SQL::Statement::Table->new($_->{name}) } @{ delete $self->{tables} } ]; # create keen defs
  4518         11150  
  4648         8945  
164              
165 4648         11384 undef $self->{where_terms}; # force rebuild when needed
166              
167 4648 100       9777 return unless ( defined( $self->{NUM_OF_ROWS} ) );
168 4644   100     17708 return $self->{NUM_OF_ROWS} || '0E0';
169             }
170              
171             sub CREATE ($$$)
172             {
173 35     35 0 91 my ( $self, $data, $params ) = @_;
174 35         56 my $names;
175              
176             # CREATE TABLE AS ...
177 35         73 my $subquery = $self->{subquery};
178 35 50       101 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         115 my ( $eval, $foo ) = $self->open_tables( $data, 1, 1 );
221 35 50       142 return unless ($eval);
222 35         134 $eval->params($params);
223 35         154 my ( $row, $table, $col ) = ( [], $eval->table( $self->tables(0)->name() ) );
224 35 50       113 if ( _ARRAY( $table->col_names() ) )
225             {
226 0         0 return $self->do_err( "Table '" . $self->tables(0)->name() . "' already exists." );
227             }
228 35         103 foreach $col ( $self->columns() )
229             {
230 97         136 push( @{$row}, $col->name() );
  97         218  
231             }
232 35         171 $table->push_names( $data, $row );
233              
234 35         220 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 30 my ( $self, $data, $params ) = @_;
256 12         23 my $eval;
257             my @err;
258 12         26 eval {
259 12     0   98 local $SIG{__WARN__} = sub { push @err, @_ };
  0         0  
260 12         47 ($eval) = $self->open_tables( $data, 0, 1 );
261             };
262 12 100 66     119 if ( $self->{ignore_missing_table}
      100        
      66        
263             and ( $@ or @err or $self->{errstr} )
264 10         98 and grep { $_ =~ $notblrx } ( @err, $@, $self->{errstr} ) )
265             {
266 5         38 return ( -1, 0 );
267             }
268              
269 7 50       25 return if $self->{errstr};
270 7 50 0     37 return $self->do_err( $@ || $err[0] ) if ( $@ || @err );
      33        
271              
272             # return undef unless $eval;
273 7 50       22 return ( -1, 0 ) unless $eval;
274              
275             # $eval->params($params);
276 7         34 my ($table) = $eval->table( $self->tables(0)->name() );
277 7         36 $table->drop($data);
278              
279             #use mylibs; zwarn $self->{sql_stmt};
280 7         104 return ( -1, 0 );
281             }
282              
283             sub INSERT ($$$)
284             {
285 4275     4275 0 7544 my ( $self, $data, $params ) = @_;
286              
287 4275         9929 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
288 4275 50       11858 return unless ($eval);
289              
290 4275 100       14506 $params and $eval->params($params);
291 4275 50       8265 $self->verify_columns( $data, $eval, $all_cols ) if ( scalar( $self->columns() ) );
292 4275 50       8503 return if ( $self->{errstr} );
293              
294 4275         9247 my ($table) = $eval->table( $self->tables(0)->name() );
295 4275 50       11626 $table->seek( $data, 0, 2 ) unless ( $table->capability('insert_new_row') );
296              
297 4275         7274 my ( $val, $col, $i, $k );
298 4275         7813 my ($cNum) = scalar( $self->columns() );
299 4275         6296 my $param_num = 0;
300              
301 4275 50       8854 $cNum
302             or return $self->do_err("Bad col names in INSERT");
303              
304 4275         6648 my $maxCol = $#$all_cols;
305              
306             # INSERT INTO $table (row, ...) VALUES (value, ...), (...)
307 4275         7740 for ( $k = 0; $k < scalar( @{ $self->{values} } ); ++$k )
  8555         18926  
308             {
309 4280         7157 my ($array) = [];
310 4280         8473 for ( $i = 0; $i < $cNum; $i++ )
311             {
312 12791         23026 $col = $self->columns($i);
313 12791         24835 $val = $self->row_values( $k, $i );
314 12791 50 66     58285 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         29928 $val = $eval->param( $param_num++ );
325             }
326             elsif ( defined( _HASH($val) ) )
327             {
328 549         1567 $val = $self->{termFactory}->buildCondition($val);
329 549         1230 $val = $val->value($eval);
330             }
331             else
332             {
333 0         0 return $self->do_err('Internal error: Unexpected column type');
334             }
335 12791         31275 $array->[ $table->column_num( $col->name() ) ] = $val;
336             }
337              
338             # Extend row to put values in ALL fields
339 4280 50       8499 $#$array < $maxCol and $array->[$maxCol] = undef;
340              
341 4280 50       9381 $table->capability('insert_new_row')
342             ? $table->insert_new_row( $data, $array )
343             : $table->push_row( $data, $array );
344             }
345              
346 4275         18424 return ( $k, 0 );
347             }
348              
349             sub DELETE ($$$)
350             {
351 6     6   16 my ( $self, $data, $params ) = @_;
352 6         18 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
353 6 50       23 return unless $eval;
354 6         22 $eval->params($params);
355 6         22 $self->verify_columns( $data, $eval, $all_cols );
356 6 50       19 return if ( $self->{errstr} );
357 6         15 my $tname = $self->tables(0)->name();
358 6         24 my ($table) = $eval->table($tname);
359 6         12 my $affected = 0;
360 6         8 my ( @rows, $array );
361              
362 6         23 while ( $array = $table->fetch_row($data) )
363             {
364 29 100       69 if ( $self->eval_where( $eval, $tname, $array ) )
365             {
366 10         19 ++$affected;
367 10 50 33     36 if ( $table->capability('rowwise_delete') and $table->capability('inplace_delete') )
    0          
368             {
369 10 50       23 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         32 $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         28 next;
384             }
385              
386 19 50       48 push( @rows, $array ) unless ( $table->capability('rowwise_delete') );
387             }
388              
389 6 50       29 if ($affected)
390             {
391 6 50       19 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         47 return ( $affected, 0 );
411             }
412              
413             sub UPDATE ($$$)
414             {
415 5     5 0 12 my ( $self, $data, $params ) = @_;
416              
417 5         17 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
418 5 50       21 return unless $eval;
419              
420 5         13 my $valnum = $self->{num_val_placeholders};
421 5 100       13 my @val_params = splice( @{$params}, 0, $valnum ) if ($valnum);
  3         7  
422 5   33     15 $self->{params} ||= $params;
423 5         19 $eval->params($params);
424 5         17 $self->verify_columns( $data, $eval, $all_cols );
425 5 50       14 return if ( $self->{errstr} );
426              
427 5         15 my $tname = $self->tables(0)->name();
428 5         19 my ($table) = $eval->table($tname);
429 5         11 my $affected = 0;
430 5         6 my @rows;
431              
432 5         32 while ( my $array = $table->fetch_row($data) )
433             {
434 21         26 my $originalValues;
435 21 100       54 if ( $self->eval_where( $eval, $tname, $array ) )
436             {
437 7         11 my $valpos = 0;
438 7 50       17 if ( $table->capability('update_specific_row') )
439             {
440 0         0 $originalValues = clone($array);
441             }
442              
443 7         30 for ( my $i = 0; $i < $self->columns(); $i++ )
444             {
445 9         23 my $val = $self->row_values( 0, $i );
446 9 50 66     78 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         26 $val = $val_params[ $valpos++ ];
457             }
458             elsif ( defined( _HASH($val) ) )
459             {
460 3         12 $val = $self->{termFactory}->buildCondition($val);
461 3         20 $val = $val->value($eval);
462             }
463             else
464             {
465 0         0 return $self->do_err('Internal error: Unexpected column type');
466             }
467              
468 9         20 my $col = $self->columns($i);
469 9         32 $array->[ $table->column_num( $col->name() ) ] = $val;
470             }
471              
472 7         11 ++$affected;
473 7 50 33     17 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       16 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         23 $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       51 push( @rows, $array ) unless ( $table->capability('rowwise_update') );
500             }
501              
502 5 50       17 if ($affected)
503             {
504 5 50       11 if ( $table->capability('rowwise_update') )
505             { # @rows is empty in case of inplace_update capability
506 5         12 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         28 return ( $affected, 0 );
531             }
532              
533             sub find_join_columns
534             {
535 32     32 1 95 my ( $self, @all_cols ) = @_;
536 32         65 my $display_combine = 'NAMED';
537 32 100       129 $display_combine = 'NATURAL' if ( -1 != index( $self->{join}->{type}, 'NATURAL' ) );
538 32 100       93 $display_combine = 'USING' if ( -1 != index( $self->{join}->{clause}, 'USING' ) );
539 32         47 my @display_cols;
540 32         52 my @keycols = ();
541 25         68 @keycols = @{ $self->{join}->{keycols} }
542 32 100       89 if $self->{join}->{keycols};
543 32         80 foreach (@keycols) { $_ =~ s/\./$self->{dlm}/ }
  57         224  
544 32         58 my %is_key_col;
545 32         64 %is_key_col = map { $_ => 1 } @keycols;
  57         326  
546              
547             # IF NAMED COLUMNS, USE NAMED COLUMNS
548             #
549 32 100       114 if ( $display_combine eq 'NAMED' )
    50          
550             {
551 16         44 @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         32 my %tables = ();
562              
563 16         58 $tables{ $_->name() } = $_ foreach (@tbls);
564              
565 16         175 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       176 . $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         27 my %is_natural;
591 16         33 for my $full_col (@all_cols)
592             {
593 64         397 my ( $table, $col ) = $full_col =~ m/^([^$self->{dlm}]+)$self->{dlm}(.+)$/;
594 64 100 100     193 next if ( ( $display_combine eq 'NATURAL' ) and $is_natural{$col} );
595 58 50 100     202 next if ( ( $display_combine eq 'USING' ) && $is_natural{$col} && $is_key_col{$col} );
      66        
596 48         79 push( @display_cols, $full_col );
597 48         111 $is_natural{$col}++;
598             }
599             }
600 32         74 my @shared = ();
601 32         43 my %is_shared;
602 32 100       107 if ( $self->{join}->{type} =~ m/NATURAL/ )
603             {
604 6         12 for my $full_col (@all_cols)
605             {
606 24         124 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         75 @shared = @keycols;
613             }
614 32         81 $self->{join}->{shared_cols} = \@shared;
615 32         116 $self->{join}->{display_cols} = \@display_cols;
616             }
617              
618             sub JOIN
619             {
620 34     34 0 68 my ( $self, $data, $params ) = @_;
621              
622 34         117 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
623 34 50       137 return undef unless $eval;
624 34         152 $eval->params($params);
625 34         128 $self->verify_columns( $data, $eval, $all_cols );
626 34 100       102 return if ( $self->{errstr} );
627 32 100 100     162 if ( $self->{join}->{keycols}
      100        
628             and $self->{join}->{table_order}
629 15         63 and ( scalar( @{ $self->{join}->{table_order} } ) == 0 ) )
630             {
631 7         25 $self->{join}->{table_order} = $self->order_joins( $self->{join}->{keycols} );
632             $self->{join}->{table_order} = $self->{table_names}
633 7 50       24 unless ( defined( $self->{join}->{table_order} ) );
634             }
635 32         97 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         54 my @all_cols;
641 32         74 for my $table (@tables)
642             {
643 76         106 my @cols = @{ $eval->table( $table->{name} )->col_names };
  76         211  
644 76         150 for my $col (@cols)
645             {
646 204         469 push( @all_cols, $table->{name} . $self->{dlm} . $col );
647             }
648             }
649 32         125 $self->find_join_columns(@all_cols);
650              
651             # JOIN THE TABLES
652             # *IN ORDER *BY JOINS*
653             #
654 32 100       97 @tables = @{ $self->{join}->{table_order} } if ( $self->{join}->{table_order} );
  15         53  
655 32         103 my ( $tableA, $tableB ) = splice( @tables, 0, 2 );
656 32 100       114 $tableA = $tableA->{name} if ( ref($tableA) );
657 32 100       85 $tableB = $tableB->{name} if ( ref($tableB) );
658 32         104 my ( $tableAobj, $tableBobj ) = ( $eval->table($tableA), $eval->table($tableB) );
659 32   33     91 $tableAobj->{NAME} ||= $tableA;
660 32   33     74 $tableBobj->{NAME} ||= $tableB;
661 32         133 $self->join_2_tables( $data, $params, $tableAobj, $tableBobj );
662              
663 32         77 for my $next_table (@tables)
664             {
665 12         120 $tableAobj = $self->{join}->{table};
666 12         45 $tableBobj = $eval->table($next_table);
667 12   33     42 $tableBobj->{NAME} ||= $next_table;
668 12         40 $self->join_2_tables( $data, $params, $tableAobj, $tableBobj );
669 12         42 $self->{cur_table} = $next_table;
670             }
671 32         152 return $self->SELECT( $data, $params );
672             }
673              
674             sub join_2_tables
675             {
676 44     44 1 93 my ( $self, $data, $params, $tableAobj, $tableBobj ) = @_;
677 44         82 my $share_type = 'IMPLICIT';
678 44 100       132 $share_type = 'NATURAL' if ( -1 != index( $self->{join}->{type}, 'NATURAL' ) );
679 44 100       112 $share_type = 'USING' if ( -1 != index( $self->{join}->{clause}, 'USING' ) );
680 44 100       117 $share_type = 'ON' if ( -1 != index( $self->{join}->{clause}, 'ON' ) );
681             $share_type = 'USING'
682 44 100 66     111 if ( ( $share_type eq 'ON' ) && ( scalar( @{ $self->{join}->{keycols} } ) == 1 ) );
  7         27  
683 44         86 my $join_type = 'INNER';
684 44 100       104 $join_type = 'LEFT' if ( -1 != index( $self->{join}->{type}, 'LEFT' ) );
685 44 100       106 $join_type = 'RIGHT' if ( -1 != index( $self->{join}->{type}, 'RIGHT' ) );
686 44 100       120 $join_type = 'FULL' if ( -1 != index( $self->{join}->{type}, 'FULL' ) );
687              
688 44         77 my $right_join = $join_type eq 'RIGHT';
689 44 100       87 if ($right_join)
690             {
691 3         6 my $tmpTbl = $tableAobj;
692 3         5 $tableAobj = $tableBobj;
693 3         6 $tableBobj = $tmpTbl;
694             }
695              
696 44         86 my $tableA = $tableAobj->{NAME};
697 44 50       114 ( 0 != index( $tableA, '"' ) ) and $tableA = lc $tableA;
698 44         78 my $tableB = $tableBobj->{NAME};
699 44 50       122 ( 0 != index( $tableB, '"' ) ) and $tableB = lc $tableB;
700 44         65 my @colsA = @{ $tableAobj->col_names() };
  44         114  
701 44         79 my @colsB = @{ $tableBobj->col_names() };
  44         87  
702 44         79 my ( %isunqualA, %isunqualB, @shared_cols );
703 44         207 $isunqualB{ $colsB[$_] } = 1 for ( 0 .. $#colsB );
704 44         68 my @tmpshared = @{ $self->{join}->{shared_cols} };
  44         127  
705              
706 44 50       164 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         36 foreach my $c (@tmpshared)
713             {
714 17         53 substr( $c, 0, index( $c, $self->{dlm} ) + 1 ) = '';
715 17         48 push( @shared_cols, $tableA . $self->{dlm} . $c );
716 17         41 push( @shared_cols, $tableB . $self->{dlm} . $c );
717             }
718             }
719             elsif ( $share_type eq 'NATURAL' )
720             {
721 6         12 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       32 if ( $isunqualB{$c} )
728             {
729 6         17 push( @shared_cols, $tableA . $self->{dlm} . $c );
730 6         18 push( @shared_cols, $tableB . $self->{dlm} . $c );
731             }
732             }
733             }
734              
735 44         79 my %whichqual;
736 44 100 66     176 if ( $share_type eq 'ON' || $share_type eq 'IMPLICIT' )
737             {
738 21         41 foreach my $colb (@colsB)
739             {
740 77         196 $colb = $whichqual{$colb} = $tableB . $self->{dlm} . $colb;
741             }
742             }
743             else
744             {
745 23         44 @colsB = map { $tableB . $self->{dlm} . $_ } @colsB;
  46         139  
746             }
747              
748 44         87 my @all_cols = map { $tableA . $self->{dlm} . $_ } @colsA;
  220         452  
749 44 100       177 @all_cols = $right_join ? ( @colsB, @all_cols ) : ( @all_cols, @colsB );
750             {
751 44         69 my $str = $self->{dlm} . "tmp" . $self->{dlm};
  44         101  
752 44         81 foreach (@all_cols)
753             {
754 343         486 my $pos = index( $_, $str );
755 343 100       646 $pos >= 0 and substr( $_, $pos, length($str) ) = '';
756             }
757             }
758 44 100       114 if ( $tableA eq $self->{dlm} . 'tmp' )
759             {
760 12         22 foreach my $colA (@colsA)
761             {
762 139         217 my $c = substr( $colA, index( $colA, $self->{dlm} ) + 1 );
763 139         231 $isunqualA{$c} = $colA;
764             }
765             #%isunqualA =
766             # map { my ($c) = $_ =~ m/^(?:[^$self->{dlm}]+)$self->{dlm}(.+)$/; $c => $_ } @colsA;
767             }
768             else
769             {
770 32         62 foreach my $cola (@colsA)
771             {
772 81         198 $cola = $isunqualA{$cola} = $tableA . $self->{dlm} . $cola;
773             }
774             }
775              
776 44         78 my ( %col_numsA, %col_numsB );
777 44         238 $col_numsA{ $colsA[$_] } = $_ for ( 0 .. $#colsA );
778 44         182 $col_numsB{ $colsB[$_] } = $_ for ( 0 .. $#colsB );
779              
780 44 100 66     171 if ( $share_type eq 'ON' || $share_type eq 'IMPLICIT' )
781             {
782 21         163 %whichqual = ( %whichqual, %isunqualA );
783              
784 21         110 while (@tmpshared)
785             {
786 62         130 my ( $k1, $k2 ) = splice( @tmpshared, 0, 2 );
787              
788             # if both keys are in one table, bail out - FIXME: errmsg?
789 62 0 33     128 next if ( $isunqualA{$k1} && $isunqualA{$k2} );
790 62 0 33     113 next if ( $isunqualB{$k1} && $isunqualB{$k2} );
791              
792 62 50       123 defined( $whichqual{$k1} ) and $k1 = $whichqual{$k1};
793 62 50       113 defined( $whichqual{$k2} ) and $k2 = $whichqual{$k2};
794              
795 62 100 100     297 if ( defined( $col_numsA{$k1} ) && defined( $col_numsB{$k2} ) )
    100 100        
796             {
797 17         70 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         103 my %is_shared;
807 44         83 for my $c (@shared_cols)
808             {
809 86         146 $is_shared{$c} = 1;
810             defined( $col_numsA{$c} )
811 86 50 66     281 or defined( $col_numsB{$c} )
812             or return $self->do_err("Can't find shared columns!");
813             }
814 44         125 my ( $posA, $posB ) = ( [], [] );
815 44         86 for my $f (@shared_cols)
816             {
817 86 100       174 defined( $col_numsA{$f} ) and push( @{$posA}, $col_numsA{$f} );
  43         91  
818 86 100       183 defined( $col_numsB{$f} ) and push( @{$posB}, $col_numsB{$f} );
  43         96  
819             }
820              
821 44         78 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         77 my $hashB = {};
826 44         165 TBLBFETCH: while ( my $array = $tableBobj->fetch_row($data) )
827             {
828 294         607 my @key_vals = @$array[@$posB];
829 294 100       506 if ($is_inner_join)
830             {
831 247   50     554 defined($_) or next TBLBFETCH for (@key_vals);
832             }
833 294         488 my $hashkey = join( ' ', @key_vals );
834 294         388 push( @{ $hashB->{$hashkey} }, $array );
  294         1030  
835             }
836              
837             # CYCLE THROUGH TABLE A
838             #
839 44         71 my $blankRow;
840 44         75 my $joined_table = [];
841 44         70 my %visited;
842 44         118 TBLAFETCH: while ( my $arrayA = $tableAobj->fetch_row($data) ) # use tbl1st & tbl2nd
843             {
844 355         709 my @key_vals = @$arrayA[@$posA];
845 355 100       603 if ($is_inner_join)
846             {
847 311   50     669 defined($_) or next TBLAFETCH for (@key_vals);
848             }
849 355         620 my $hashkey = join( ' ', @key_vals );
850 355         517 my $rowsB = $hashB->{$hashkey};
851 355 100 100     747 if ( !defined($rowsB) && ( $join_type ne 'INNER' ) )
852             {
853 14 50       56 defined($blankRow) or $blankRow = [ (undef) x scalar(@colsB) ];
854 14         30 $rowsB = [$blankRow];
855             }
856              
857 355 50       591 if ( $join_type ne 'UNION' )
858             {
859 355         443 for my $arrayB ( @{$rowsB} )
  355         527  
860             {
861 404 100       664 my $newRow = $right_join ? [ @{$arrayB}, @{$arrayA} ] : [ @{$arrayA}, @{$arrayB} ];
  11         16  
  11         35  
  393         518  
  393         1530  
862              
863 404         843 push( @$joined_table, $newRow );
864             }
865             }
866              
867 355         1080 ++$visited{$hashkey};
868             }
869              
870             # ADD THE LEFTOVER B ROWS IF NEEDED
871             #
872 44 100 66     175 if ( $join_type eq 'FULL' || $join_type eq 'UNION' )
873             {
874             my $st_is_NaturalOrUsing = ( -1 != index( $self->{join}->{type}, 'NATURAL' ) )
875 2   66     17 || ( -1 != index( $self->{join}->{clause}, 'USING' ) );
876 2         6 while ( my ( $k, $v ) = each %{$hashB} )
  8         27  
877             {
878 6 100       18 next if ( $visited{$k} );
879 2         5 for my $rowB (@$v)
880             {
881 2         5 my ( @arrayA, @tmpB, $rowhash );
882 2         4 @{$rowhash}{@colsB} = @{$rowB};
  2         7  
  2         5  
883 2         6 for my $c (@all_cols)
884             {
885 8         72 my ( $table, $col ) = split( $self->{dlm}, $c, 2 );
886 8 100       41 push( @arrayA, undef ) if ( $table eq $tableA );
887 8 100       23 push( @tmpB, $rowhash->{$c} ) if ( $table eq $tableB );
888             }
889 2 100       9 @arrayA[@$posA] = @tmpB[@$posB] if ($st_is_NaturalOrUsing);
890 2         5 my $newRow = [ @arrayA, @tmpB ];
891 2         4 push( @{$joined_table}, $newRow );
  2         8  
892             }
893             }
894             }
895              
896 44         210 undef $hashB;
897 44         75 undef $tableAobj;
898 44         73 undef $tableBobj;
899              
900             $self->{join}->{table} =
901 44         229 SQL::Statement::TempTable->new( $self->{dlm} . 'tmp', \@all_cols, $self->{join}->{display_cols}, $joined_table );
902              
903 44         348 return;
904             }
905              
906             sub run_functions
907             {
908 176     176 1 357 my ( $self, $data, $params ) = @_;
909 176         443 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
910 176         457 my @row = ();
911 176         469 for my $col ( $self->columns() )
912             {
913 176         467 my $val = $col->value($eval); # FIXME approve
914 176         8945 push( @row, $val );
915             }
916 176         1189 return ( 1, scalar @row, [ \@row ] );
917             }
918              
919             sub SELECT($$)
920             {
921 348     348 0 793 my ( $self, $data, $params ) = @_;
922              
923 348   66     915 $self->{params} ||= $params;
924 348 100       1321 defined( _ARRAY( $self->{table_names} ) ) or return $self->run_functions( $data, $params );
925              
926 172         318 my ( $eval, $all_cols, $tableName, $table );
927 172 100       414 if ( defined( $self->{join} ) )
928             {
929 66 100       243 defined $self->{join}->{table} or return $self->JOIN( $data, $params );
930 32         54 $tableName = $self->{dlm} . 'tmp';
931 32         57 $table = $self->{join}->{table};
932             }
933             else
934             {
935 106         307 ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
936 105 100       366 return unless $eval;
937 104         379 $eval->params($params);
938 104         345 $self->verify_columns( $data, $eval, $all_cols );
939 104 100       271 return if ( $self->{errstr} );
940 103         264 $tableName = $self->tables(0)->name();
941 103         377 $table = $eval->table($tableName);
942             }
943              
944 135         266 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         256 my ( $cList, $col, $tbl, $ar, $i, $c );
949 135         206 my $numFields = 0;
950 135         198 my %columns;
951             my @names;
952 135         243 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         307 foreach my $column ( $self->columns() )
968             {
969 313 50       1754 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         843 ( $col, $tbl ) = ( $column->name(), $column->table() );
988 313   100     779 $tbl ||= '';
989 313         1073 $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     1492 ? $table->column_num( $tbl . $self->{dlm} . $col )
1003             : $table->column_num($col);
1004              
1005 313 100 66     1057 if ( !defined $cnum || $column->{function} )
1006             {
1007 33         71 $funcs{$col} = $column->{function};
1008 33         60 $cnum = $col;
1009             }
1010 313         689 push( @$cList, $cnum );
1011              
1012             # push(@$cList, $table->column_num($col));
1013 313         713 push( @names, $col );
1014             }
1015              
1016             # }
1017 135 50       320 $cList = [] unless ( defined($cList) );
1018 135 100       320 if ( $self->{join} )
1019             {
1020 32         57 foreach (@names) { $_ =~ s/^[^$self->{dlm}]+$self->{dlm}//; }
  122         474  
1021             }
1022 135         331 $self->{NAME} = \@names;
1023             # $self->verify_order_cols($table);
1024 135         374 my @order_by = $self->order();
1025 135         251 my @extraSortCols = ();
1026              
1027 135 100       296 if (@order_by)
1028             {
1029 17         60 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         28 my $i = -1;
1036 17         33 foreach my $column (@order_by)
1037             {
1038 20         33 ++$i;
1039 20         64 ( $col, $tbl ) = ( $column->column(), $column->table() );
1040 20         44 my $pos;
1041 20   66     55 $tbl ||= $self->colname2table($col);
1042 20   100     45 $tbl ||= '';
1043 20 100       58 if ( $self->{join} )
1044             {
1045 6         24 $pos = $table->column_num( $tbl . $self->{dlm} . $col );
1046 6 100       19 defined($pos)
1047             or $pos = $table->column_num( $tbl . '_' . $col );
1048             }
1049 20 100       73 next if ( exists( $columns{$tbl}->{$col} ) );
1050 1 50       3 $pos = $table->column_num($col) unless ( defined($pos) );
1051 1         2 push( @extraSortCols, $pos );
1052 1         3 $columns{$tbl}->{$col} = $nFields++;
1053             }
1054             }
1055              
1056 135 100       320 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     333 my $limit_count = 0 if ( $self->limit() and !$self->order() );
1061 135         272 my $limit = $self->limit();
1062 135         207 my $row_count = 0;
1063 135   100     310 my $offset = $self->offset() || 0;
1064 135         434 while ( my $array = $table->fetch_row($data) )
1065             {
1066 8673 100       19965 if ( $self->eval_where( $e, $tableName, $array, \%funcs ) )
1067             {
1068 8432 100 100     15517 next if ( defined($limit_count) and ( $row_count++ < $offset ) );
1069              
1070 8427         13634 my @row = map { $_->value($e) } $self->columns();
  21086         40456  
1071 8427         12669 push( @{$rows}, \@row );
  8427         14180  
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     25370 defined($limit_count)
1076             and ( ++$limit_count >= $limit )
1077             and return ( $limit, $numFields, $rows );
1078             }
1079             }
1080              
1081 134 100       435 if ( $self->distinct() )
1082             {
1083 5         11 my %seen;
1084 5         22 @{$rows} = map {
1085 33 50       53 $seen{ join( "\0", ( map { defined($_) ? $_ : '' } @{$_} ) ) }++
  89 100       221  
  33         51  
1086             ? ()
1087             : $_
1088 5         11 } @{$rows};
  5         13  
1089             }
1090              
1091 134 100       397 if ( $self->{has_set_functions} )
1092             {
1093 19         29 my $aggreg;
1094 19 100       51 if ( $self->{group_by} )
1095             {
1096 7         15 my @keycols = @{ $self->{colpos} }{ @{ $self->{group_by} } };
  7         23  
  7         17  
1097 7         41 $aggreg = SQL::Statement::Group->new( $self, $rows, \@keycols );
1098             }
1099             else
1100             {
1101 12         109 $aggreg = SQL::Statement::Aggregate->new( $self, $rows );
1102             }
1103 19         60 $rows = $aggreg->calc();
1104             # FIXME re-order if order_by
1105             }
1106              
1107 134 100       338 if (@order_by)
1108 0         0 {
1109 16     16   8277 use sort 'stable';
  16         8901  
  16         97  
1110             my @sortCols = map {
1111 17         43 my ( $col, $tbl ) = ( $_->column(), $_->table() );
  20         66  
1112 20 50 66     108 $self->{join} and $table->is_shared($col) and $tbl = 'shared';
1113 20   50     56 $tbl ||= $self->colname2table($col) || '';
      66        
1114 20         66 ( $columns{$tbl}->{$col}, $_->desc() )
1115             } @order_by;
1116              
1117 17         41 $i = scalar(@sortCols);
1118             do
1119 17         33 {
1120 20         76 my $desc = $sortCols[ --$i ];
1121 20         37 my $colNum = $sortCols[ --$i ];
1122 20         111 @{$rows} = sort {
1123 132         242 my $result;
1124 132         240 $result = _anycmp( $a->[$colNum], $b->[$colNum] );
1125 132 100       238 $desc and $result = -$result;
1126             $result;
1127 20         34 } @{$rows};
  20         115  
1128             } while ( $i > 0 );
1129 16     16   3190 use sort 'defaults'; # for perl < 5.10.0
  16         37  
  16         66  
1130             }
1131              
1132 134 100       344 if ( defined( $self->limit() ) )
1133             {
1134 1   50     3 my $offset = $self->offset() || 0;
1135 1   50     4 my $limit = $self->limit() || 0;
1136 1         2 @{$rows} = splice( @{$rows}, $offset, $limit );
  1         4  
  1         15  
1137             }
1138              
1139             # Rip off columns that have been added for @extraSortCols only
1140 134 100       312 if (@extraSortCols)
1141             {
1142 1         2 foreach my $row ( @{$rows} )
  1         3  
1143             {
1144 4         4 splice( @{$row}, $numFields, scalar(@extraSortCols) );
  4         7  
1145             }
1146             }
1147              
1148 134         204 ( scalar( @{$rows} ), $numFields, $rows );
  134         1879  
1149             }
1150              
1151             sub _anycmp($$;$)
1152             {
1153 32226     32226   50612 my ( $a, $b, $case_fold ) = @_;
1154              
1155 32226 100 66     126400 if ( !defined($a) || !defined($b) )
    100 66        
1156             {
1157 4         8 return defined($a) - defined($b);
1158             }
1159             elsif ( looks_like_number($a) && looks_like_number($b) )
1160             {
1161 24164         61250 return $a <=> $b;
1162             }
1163             else
1164             {
1165 8058 50 0     24383 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 15372 my ( $self, $eval, $tname, $rowary ) = @_;
1172 8723 100       21665 return 1 unless ( defined( $self->{where_terms} ) );
1173 458         648 $self->{argnum} = 0;
1174              
1175 458         1180 return $self->{where_terms}->value($eval);
1176             }
1177              
1178             sub fetch_row
1179             {
1180 123     123 1 7886 my ($self) = @_;
1181 123   50     243 $self->{data} ||= [];
1182 123         141 my $row = shift @{ $self->{data} };
  123         184  
1183 123 100 100     369 return unless $row and scalar @$row;
1184 93         171 return $row;
1185             }
1186              
1187 16     16   7446 no warnings 'once';
  16         46  
  16         1025  
1188             *fetch = \&fetch_row;
1189              
1190 16     16   101 use warnings;
  16         33  
  16         77452  
1191              
1192             sub fetch_rows
1193             {
1194 250     250 1 19534 my $self = $_[0];
1195 250   50     780 my $rows = $self->{data} || [];
1196 250         558 $self->{data} = [];
1197 250         568 return $rows;
1198             }
1199              
1200 7     7 1 1175 sub open_table ($$$$$) { croak "Abstract method " . ref( $_[0] ) . "::open_table called" }
1201              
1202             sub open_tables
1203             {
1204 4649     4649 1 7886 my ( $self, $data, $createMode, $lockMode ) = @_;
1205 4649         6127 my @c;
1206 4649         7516 my $t = {};
1207 4649         10514 my @tables = $self->tables();
1208 4649         6773 my $count = -1;
1209 4649         7781 for my $tbl (@tables)
1210             {
1211 4519         5842 ++$count;
1212 4519         8219 my $name = $tbl->name();
1213 4519 50       10760 if ( $name =~ m/^(.+)\.([^\.]+)$/ )
1214             {
1215 0         0 my $schema = $1; # ignored
1216 0         0 $name = $tbl->{name} = $2;
1217             }
1218              
1219 4519 100 66     28214 if ( defined( $self->{table_func} ) && defined( $self->{table_func}->{ uc $name } ) )
    100 100        
    100 66        
1220             {
1221 2         3 my $u_func = $self->{table_func}->{ uc $name };
1222 2         6 $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         9571 $t->{$name} = $data->{Database}->{sql_ram_tables}->{$name};
1229 4475         15618 $t->{$name}->seek( $data, 0, 0 );
1230             $t->{$name}->init_table( $data, $name, $createMode, $lockMode )
1231 4475 50       13954 if ( $t->{$name}->can('init_table') );
1232             }
1233             elsif ( $self->{is_ram_table} )
1234             {
1235 35         235 $t->{$name} = $data->{Database}->{sql_ram_tables}->{$name} =
1236             SQL::Statement::RAM::Table->new( $name, [], [] );
1237             }
1238             else
1239             {
1240 7         17 undef $@;
1241 7         14 eval {
1242 7         20 my $open_name = $self->{org_table_names}->[$count];
1243 7         26 $t->{$name} = $self->open_table( $data, $open_name, $createMode, $lockMode );
1244             };
1245 7         530 my $err = $t->{$name}->{errstr};
1246 7 50       23 return $self->do_err($err) if ($err);
1247 7 50       49 return $self->do_err($@) if ($@);
1248             }
1249              
1250 4512         6649 my @cnames;
1251 4512         7196 my $table_cols = $t->{$name}->{org_col_names};
1252 4512 100       8214 $table_cols = $t->{$name}->{col_names} unless $table_cols;
1253 4512         8195 for my $c (@$table_cols)
1254             {
1255 13311 100       25494 my $newc = $c =~ m/^"/ ? $c : lc($c);
1256 13311         21942 push( @cnames, $newc );
1257 13311         25019 $self->{ORG_NAME}->{$newc} = $c;
1258             }
1259              
1260             #
1261             # set the col_num => col_obj hash for the table
1262             #
1263 4512         6182 my $col_nums;
1264 4512         6164 my $i = 0;
1265 4512         7163 for (@cnames)
1266             {
1267 13311         22595 $col_nums->{$_} = $i++;
1268             }
1269 4512         10431 $t->{$name}->{col_nums} = $col_nums;
1270 4512         9666 $t->{$name}->{col_names} = \@cnames;
1271              
1272 4512         12589 my $tcols = $t->{$name}->col_names();
1273 4512         6017 my @newcols;
1274 4512         7414 for (@$tcols)
1275             {
1276 13311 50       22964 next unless ( defined($_) );
1277 13311         19029 my $ncol = $_;
1278 13311 50       32586 $ncol = $name . '.' . $ncol unless ( $ncol =~ m/\./ );
1279 13311         23447 push( @newcols, $ncol );
1280             }
1281 4512         12687 @c = ( @c, @newcols );
1282             }
1283              
1284 4642         13501 $self->buildColumnObjects( $t, \@tables );
1285 4642 50       10226 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       9243 if ( !$self->{all_cols} )
1296             {
1297 502         837 my $all_cols = [];
1298 502         767 $all_cols = [ map { $_->{name} } @{ $self->{columns} } ];
  1113         2551  
  502         944  
1299 502   50     1214 $all_cols ||= []; # ?
1300 502         1538 @$all_cols = ( @$all_cols, @c );
1301 502         1002 $self->{all_cols} = $all_cols;
1302             }
1303             ##################################################
1304              
1305 4642         16508 return SQL::Eval->new( { 'tables' => $t } ), \@c;
1306             }
1307              
1308             sub getColumnObject($)
1309             {
1310 686     686 1 1316 my ( $self, $newcol, $t, $tables ) = @_;
1311 686         1249 my @columns;
1312              
1313 686 100 100     2968 if ( ( $newcol->{type} eq 'column' ) && ( -1 != index( $newcol->{value}, '*' ) ) )
    100 66        
1314             {
1315 199         338 my $tbl;
1316             my @tables;
1317 199 50       472 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         295 @tables = map { $_->name() } @{$tables};
  212         392  
  199         394  
1327             }
1328              
1329             my $join = defined( _HASH( $self->{join} ) )
1330             && ( ( -1 != index( $self->{join}->{type}, 'NATURAL' ) )
1331 199   100     768 || ( -1 != index( $self->{join}->{clause}, 'USING' ) ) );
1332 199         328 my %shared_cols;
1333              
1334 199         358 foreach my $table (@tables)
1335             {
1336 212 50       515 return $self->do_err("Can't find table '$table'") unless ( defined( $t->{$table} ) );
1337 212         374 my $tcols = $t->{$table}->{col_names};
1338 212 50       512 return $self->do_err("Couldn't find column names for table '$table'!")
1339             unless ( _ARRAY($tcols) );
1340 212         286 foreach my $colName ( @{$tcols} )
  212         361  
1341             {
1342 652 100 100     1380 next if ( $join && $shared_cols{$colName}++ );
1343 644         2082 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         1467 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       418 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         288 $newcol, # coldef
1366             ];
1367 97         178 push( @columns, $expcol );
1368             }
1369             else
1370             {
1371 390         572 my $col;
1372 390 100       816 if ( $newcol->{type} eq 'setfunc' )
1373             {
1374 24         88 my @cols = $self->getColumnObject( $newcol->{arg}, $t );
1375 24 100       62 if ( 1 == scalar(@cols) )
1376             {
1377 18         53 $col = $cols[0]->[2];
1378             }
1379             else
1380             {
1381             # FIXME add '\0' constants between items?
1382             my $colSep = $self->{termFactory}->buildCondition(
1383             {
1384 6         41 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         31 type => 'function',
1393             name => 'str_concat',
1394             value => \@cols,
1395             }
1396             );
1397             }
1398             }
1399             else
1400             {
1401 366         1149 $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     2103 $newcol, # coldef
      66        
1411             ];
1412 390         785 push( @columns, $expcol );
1413             }
1414              
1415 686         1645 return @columns;
1416             }
1417              
1418             sub buildColumnObjects($)
1419             {
1420 4642     4642 1 8147 my ( $self, $t, $tables ) = @_;
1421              
1422 4642 100       12360 defined( _ARRAY0( $self->{column_defs} ) ) or return;
1423 4635 100       10931 defined( _ARRAY0( $self->{columns} ) ) and return;
1424              
1425 495         858 $self->{columns} = [];
1426              
1427 495         877 my $coldefs = $self->{column_defs};
1428              
1429 495         827 for ( my $i = 0; $i < scalar( @{$coldefs} ); ++$i )
  1157         2695  
1430             {
1431 662         996 my $colentry = $coldefs->[$i];
1432              
1433 662         1582 my @columns = $self->getColumnObject( $colentry, $t, $tables );
1434 662 50       1463 return if ( $self->{errstr} );
1435              
1436 662         1107 foreach my $col (@columns)
1437             {
1438 1113         1566 my $expcol = SQL::Statement::Util::Column->new( @{$col} );
  1113         3117  
1439 1113         1593 push( @{ $self->{columns} }, $expcol );
  1113         2025  
1440 1113   66     4501 $self->{column_aliases}->{ $col->[4] } ||= $col->[3];
1441 1113         1397 $self->{colpos}->{ $col->[3] } = scalar( @{ $self->{columns} } ) - 1;
  1113         4050  
1442             }
1443             }
1444              
1445 495         913 return;
1446             }
1447              
1448             sub verify_expand_column
1449             {
1450 13143     13143 1 24579 my ( $self, $c, $i, $usr_cols, $is_duplicate, $col_exists ) = @_;
1451              
1452             # XXX
1453 13143 100       25287 defined $self->{ALIASES}->{$c} and $c = $self->{ALIASES}->{$c};
1454              
1455 13143         18370 my ( $table, $col, $col_obj );
1456 13143 100       25891 if ( $c =~ m/(\S+)\.(\S+)/ )
    100          
1457             {
1458 1         3 $table = $1;
1459 1         3 $col = $2;
1460             }
1461 13142         24786 elsif ( ++${$i} >= 0 )
1462             {
1463 13122         16898 $col_obj = $usr_cols->[ ${$i} ];
  13122         19916  
1464 13122         27193 ( $table, $col ) = ( $col_obj->{table}, $col_obj->{name} );
1465             }
1466             else
1467             {
1468 20         52 ( $table, $col ) = $self->full_qualified_column_name($c);
1469             }
1470 13143 50       23747 return unless ($col);
1471              
1472             my $is_column =
1473 13143 100 100     86310 ( defined( _INSTANCE( $col_obj, 'SQL::Statement::Util::Column' ) ) and ( $col_obj->{coldef}->{type} eq 'column' ) )
1474             ? 1
1475             : 0;
1476              
1477 13143 100 100     38590 unless ( $is_column and defined($table) )
1478             {
1479 210         483 ( $table, undef ) = $self->full_qualified_column_name($col);
1480             }
1481              
1482 13143 50       26855 if ( defined( _INSTANCE( $table, 'SQL::Statement::Table' ) ) )
1483             {
1484 0         0 $table = $table->name();
1485             }
1486              
1487 13143 100 100     37581 if ( $is_column and !$table )
    100          
1488             {
1489 2 50       6 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       25824 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     32440 or $col_exists->{ "\L$table." . $col }
      33        
1499             or $is_user_def );
1500             }
1501              
1502 13141 100 100     48148 return ( $table, $col ) if ( $is_column or ${$i} < 0 );
  55         200  
1503 34         83 return;
1504             }
1505              
1506             sub verify_columns
1507             {
1508 4424     4424 1 8209 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     8059 $all_cols ||= [];
1515 4424         6599 my @tmp_cols = @{$all_cols};
  4424         9082  
1516 4424         7723 my @usr_cols = $self->columns();
1517 4424 50       8834 return $self->do_err('No fetchable columns') if ( 0 == scalar(@usr_cols) );
1518              
1519 4424         9010 my ( $cnum, $fully_qualified_cols ) = ( 0, [] );
1520 4424         7769 my @tmpcols = map { $_->{name} } @usr_cols;
  13122         26597  
1521 4424         6809 my %col_exists = map { $_ => 1 } @tmp_cols;
  13296         28371  
1522              
1523 4424         7925 my ( %is_member, @duplicates, %is_duplicate );
1524             # $_ =~ s/[^.]*\.(.*)/$1/;
1525 4424         8001 foreach (@$all_cols)
1526             {
1527 13296         29819 substr( $_, 0, index( $_, '.' ) + 1 ) = '';
1528             } # XXX we're modifying $all_cols from caller!
1529 4424         15107 @duplicates = grep( $is_member{$_}++, @$all_cols );
1530 4424         7504 %is_duplicate = map { $_ => 1 } @duplicates;
  54         136  
1531 4424 100 100     19208 if ( exists( $self->{join} ) && defined( _HASH( $self->{join} ) ) )
1532             {
1533 34         75 my $join = $self->{join};
1534 34 100       166 if ( -1 != index( uc $join->{type}, 'NATURAL' ) )
    100          
1535             {
1536 6         16 %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         16 my @keys = @{ $join->{keycols} };
  10         29  
1544 10         31 delete @is_duplicate{@keys};
1545             }
1546             }
1547              
1548 4424         6397 my %set_func_nofunc;
1549 4424 100       8518 if ( defined( $self->{has_set_functions} ) )
1550             {
1551 20         40 my @set_func_nofunc = grep { ( $_->{type} ne 'setfunc' ) } @{ $self->{column_defs} };
  34         103  
  20         51  
1552 20   66     46 %set_func_nofunc = map { ( $_->{alias} || $_->{fullorg} ) => 1 } @set_func_nofunc;
  9         49  
1553             }
1554 4424         9760 my ( $is_fully, $set_fully ) = ( {}, {} );
1555 4424         7309 my $i = -1;
1556 4424         8961 my $num_tables = $self->tables();
1557 4424         7545 for my $c (@tmpcols)
1558             {
1559 13122         32834 my ( $table, $col ) = $self->verify_expand_column( $c, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1560 13122 100       28338 return if ( $self->{errstr} );
1561 13120 100 66     34414 next unless ( $table && $col );
1562              
1563 13086         24375 my $ftc = "$table.$col";
1564 13086 50 33     47969 next if ( $table and $col and $is_fully->{$ftc} );
      33        
1565              
1566 13086         22697 $self->{columns}->[$i]->{name} = $col;
1567 13086         19416 $self->{columns}->[$i]->{table} = $table;
1568              
1569 13086 50 33     33154 if ( $table and $col )
1570             {
1571 13086         21386 push( @$fully_qualified_cols, $ftc );
1572 13086         22554 ++$is_fully->{$ftc};
1573 13086 100       29265 ++$set_fully->{$ftc} if ( $set_func_nofunc{$c} );
1574             }
1575             }
1576              
1577 4422 100       8507 if ( defined( $self->{has_set_functions} ) )
1578             {
1579 20 100       94 if ( defined( _ARRAY( $self->{group_by} ) ) )
1580             {
1581 7         14 foreach my $grpby ( @{ $self->{group_by} } )
  7         18  
1582             {
1583 8         14 $i = -2;
1584 8         22 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     30 $col ||= $grpby;
1587 8 50 33     36 ( $table, $col ) = $self->full_qualified_column_name($col)
1588             if ( defined($col) && !defined($table) );
1589 8 50 33     29 next unless ( defined($table) && defined($col) );
1590 8         33 delete $set_fully->{"$table.$col"};
1591             }
1592             }
1593              
1594 20 100       76 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         11  
1601             )
1602             );
1603             }
1604             }
1605              
1606 4421 100       8232 if ( $self->{sort_spec_list} )
1607             {
1608 17         34 for my $n ( 0 .. scalar @{ $self->{sort_spec_list} } - 1 )
  17         97  
1609             {
1610 20 100       138 defined( _INSTANCE( $self->{sort_spec_list}->[$n], 'SQL::Statement::Order' ) ) and next;
1611 13         22 my ( $newcol, $direction ) = each %{ $self->{sort_spec_list}->[$n] };
  13         59  
1612 13   66     62 my $desc = $direction && ( $direction eq "DESC" ); # ($direction || "ASC") eq "DESC";
1613              
1614             # XXX parse order by like group by and select list
1615 13         25 $i = -2;
1616 13         58 my ( $table, $col ) = $self->verify_expand_column( $newcol, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1617 13 50       50 $self->{errstr} and return;
1618 13 100 66     76 ( $table, $col ) = $self->full_qualified_column_name($newcol)
1619             if ( defined($col) && !defined($table) );
1620 13 100       73 defined($table) and $col = $table . "." . $col;
1621 13         76 $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         19464 return $fully_qualified_cols;
1635             }
1636              
1637             sub distinct()
1638             {
1639 134     134 1 660 my $q = _STRING( $_[0]->{set_quantifier} );
1640 134   66     569 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 127060 sub command() { return $_[0]->{command} }
1650              
1651             sub params(;$)
1652             {
1653 2 50   2 1 15 if ( !$_[0]->{params} )
1654             {
1655 0 0       0 return wantarray ? () : 0;
1656             }
1657 2 50       7 return $_[0]->{params}->[ $_[1] ] if ( defined $_[1] );
1658              
1659 2 50       5 return wantarray ? @{ $_[0]->{params} } : scalar @{ $_[0]->{params} };
  0         0  
  2         10  
1660             }
1661              
1662             sub row_values(;$$)
1663             {
1664 12803 50   12803 1 30095 unless ( defined( _ARRAY( $_[0]->{values} ) ) )
1665             {
1666 0 0       0 return wantarray ? () : 0;
1667             }
1668 12803 100       20685 if ( defined( $_[1] ) )
1669             {
1670 12802 50       24692 return 0 unless ( defined( $_[0]->{values}->[ $_[1] ] ) );
1671 12802 100       29830 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         5  
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       3 : 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 53488 my ( $self, $col ) = @_;
1696 34581 100       60096 if ( !$self->{columns} )
1697             {
1698 1 50       8 return wantarray ? () : 0;
1699             }
1700              
1701 34580 100 66     112872 if ( defined $col and $col =~ m/^\d+$/ )
    50          
1702             { # arg1 = a number
1703 12801         27628 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       35021 return wantarray ? @{ $self->{columns} } : scalar @{ $self->{columns} };
  13213         26196  
  8566         24583  
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 6 my ( $self, $col_name ) = @_;
1729 2 50       8 return undef unless defined $col_name;
1730              
1731 2         5 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         3 for my $full_col ( @{ $self->{all_cols} } )
  2         7  
1743             {
1744 10         34 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         10 return $found_table;
1751             }
1752              
1753             sub full_qualified_column_name($)
1754             {
1755 574     574 1 1035 my ( $self, $col_name ) = @_;
1756 574 50       1073 return unless ( defined($col_name) );
1757              
1758             # XXX
1759 574 100       1168 defined $self->{ALIASES}->{$col_name} and $col_name = $self->{ALIASES}->{$col_name};
1760              
1761 574         842 my ( $tbl, $col );
1762 574 100       1976 unless ( ( $tbl, $col ) = $col_name =~ m/^((?:"[^"]+")|(?:[^.]+))\.(.*)$/ )
1763             {
1764 449         698 $col = $col_name;
1765             }
1766              
1767 574 100       1329 unless ( defined( $self->{splitted_all_cols} ) )
1768             {
1769 118         189 my @rc;
1770 118         177 for my $full_col ( @{ $self->{all_cols} } )
  118         315  
1771             {
1772 722 100       2853 if ( my ( $stbl, $scol ) = $full_col =~ m/^((?:"[^"]+")|(?:[^.]+))\.(.*)$/ )
1773             {
1774 440         624 push( @{ $self->{splitted_all_cols} }, [ $stbl, $scol ] );
  440         1142  
1775 440 100 100     1009 defined($tbl) and ( $tbl ne $stbl ) and next;
1776 416 100       1073 ( $scol eq $col ) and @rc = ( $stbl, $scol );
1777             }
1778             }
1779 118 100       507 @rc and return @rc;
1780             }
1781             else
1782             {
1783 456         655 for my $splitted_col ( @{ $self->{splitted_all_cols} } )
  456         916  
1784             {
1785 1576 100 100     3435 defined($tbl) and ( $tbl ne $splitted_col->[0] ) and next;
1786 1228 100       3270 ( $splitted_col->[1] eq $col ) and return @$splitted_col;
1787             }
1788             }
1789              
1790 39         113 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 1126 sub limit ($) { $_[0]->{limit_clause}->{limit}; }
1819 138     138 1 475 sub offset ($) { $_[0]->{limit_clause}->{offset}; }
1820              
1821             sub order
1822             {
1823 139 100   139 1 825 return unless ( defined $_[0]->{sort_spec_list} );
1824              
1825             return
1826             defined( $_[1] ) && looks_like_number( $_[1] ) ? $_[0]->{sort_spec_list}->[ $_[1] ]
1827 18         63 : wantarray ? @{ $_[0]->{sort_spec_list} }
1828 20 100 66     117 : scalar @{ $_[0]->{sort_spec_list} };
  1 100       3  
1829             }
1830              
1831             sub tables
1832             {
1833             return
1834             defined( $_[1] ) && looks_like_number( $_[1] ) ? $_[0]->{tables}->[ $_[1] ]
1835 4701         9542 : wantarray ? @{ $_[0]->{tables} }
1836 13557 100 66 13557 1 49904 : scalar @{ $_[0]->{tables} };
  4424 100       9007  
1837             }
1838              
1839             sub order_joins
1840             {
1841 7     7 1 17 my ( $self, $links ) = @_;
1842 7         15 my ( @new_keycols, @new_links );
1843 7         19 for (@$links)
1844             {
1845 7         22 my ( $tbl, $col ) = $self->full_qualified_column_name($_);
1846 7         23 push( @new_keycols, $tbl . $self->{dlm} . $col );
1847 7         19 push( @new_links, $tbl );
1848             }
1849 7         20 $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         34 my @all_tables;
1855             my %relations;
1856 7         0 my %is_table;
1857              
1858 7         22 while (@new_links)
1859             {
1860 7         14 my $t1 = shift(@new_links);
1861 7         15 my $t2 = shift(@new_links);
1862 7 50 33     45 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 150 my $self = shift;
1906 12         23 my $err = shift;
1907 12         29 my $errtype = shift;
1908 12         72 my @c = caller 6;
1909              
1910             #$err = "[" . $self->{original_string} . "]\n$err\n\n";
1911             # $err = "$err\n\n";
1912 12         28 my $prog = $c[1];
1913 12         23 my $line = $c[2];
1914 12 100       47 $prog = defined($prog) ? " called from $prog" : '';
1915 12 100       44 $prog .= defined($line) ? " at $line" : '';
1916 12         52 $err = "\nExecution ERROR: $err$prog.\n\n";
1917              
1918 12         27 $self->{errstr} = $err;
1919 12 50       36 carp $err if $self->{PrintError};
1920 12 100       95 croak "$err" if $self->{RaiseError};
1921 11         75 return;
1922             }
1923              
1924 14     14 1 12571 sub errstr() { return $_[0]->{errstr}; }
1925              
1926 1     1 1 14 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 31 return undef unless $_[0]->{where_terms};
1933 5         60 return $_[0]->{where_terms};
1934             }
1935              
1936             sub get_user_func_table
1937             {
1938 2     2 1 4 my ( $self, $name, $u_func ) = @_;
1939 2         7 my $term = $self->{termFactory}->buildCondition($u_func);
1940              
1941 2         4 my @data_aryref = @{ $term->value(undef) };
  2         5  
1942 2         4 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         12 my $tempTable = SQL::Statement::RAM::Table->new( $name, $col_names, \@data_aryref );
1948 2   33     15 $tempTable->{all_cols} ||= $col_names;
1949 2         7 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   81966 my $self = $_[0];
1963              
1964 870         1781 undef $self->{NAME};
1965 870         1792 undef $self->{ORG_NAME};
1966 870         1625 undef $self->{all_cols};
1967 870         1606 undef $self->{already_prepared};
1968 870         1206 undef $self->{argnum};
1969 870         1959 undef $self->{col_obj};
1970 870         1315 undef $self->{column_names};
1971 870         2861 undef $self->{columns};
1972 870         1422 undef $self->{cur_table};
1973 870         1432 undef $self->{data};
1974 870         2046 undef $self->{group_by};
1975             #undef $self->{has_OR};
1976 870         1768 undef $self->{join};
1977 870         1377 undef $self->{limit_clause};
1978 870         1344 undef $self->{num_placeholders};
1979 870         1286 undef $self->{num_val_placeholders};
1980 870         1396 undef $self->{org_table_names};
1981 870         1303 undef $self->{params};
1982 870         1839 undef $self->{opts};
1983 870         1368 undef $self->{procedure};
1984 870         1263 undef $self->{set_function};
1985 870         1354 undef $self->{sort_spec_list};
1986 870         1330 undef $self->{subquery};
1987 870         1658 undef $self->{tables};
1988 870         1326 undef $self->{table_names};
1989 870         1312 undef $self->{table_func};
1990 870         1748 undef $self->{where_clause};
1991 870         1416 undef $self->{where_terms};
1992 870         5558 undef $self->{values};
1993             }
1994              
1995             package SQL::Statement::Aggregate;
1996              
1997 16     16   165 use Scalar::Util qw(looks_like_number);
  16         48  
  16         1115  
1998 16     16   118 use Params::Util qw(_HASH);
  16         34  
  16         761  
1999 16     16   101 use Clone qw(clone);
  16         33  
  16         12296  
2000              
2001             sub new
2002             {
2003 19     19   49 my ( $class, $owner, $rows ) = @_;
2004 19         66 my $self = {
2005             owner => $owner,
2006             records => $rows,
2007             };
2008 19         53 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   34 my $self = $_[0];
2022              
2023 19         30 foreach my $line ( 0 .. ( scalar( @{ $self->{records} } ) - 1 ) )
  19         69  
2024             {
2025 8073         12576 my $row = $self->{records}->[$line];
2026 8073         13528 my $result = $self->getAffectedResult($row);
2027              
2028 8073         10645 foreach my $colidx ( 0 .. ( scalar( @{ $self->{owner}->{columns} } ) - 1 ) )
  8073         15579  
2029             {
2030 20115         29837 my $coldef = $self->{owner}->{columns}->[$colidx]->{coldef};
2031 20115         26835 my $colval = $row->[$colidx];
2032              
2033 20115 100       32978 if ( $coldef->{type} eq 'setfunc' )
2034             {
2035 16086 100       27219 if ( $coldef->{distinct} eq 'DISTINCT' )
2036             {
2037 9 100       27 next if defined( $result->{uniq}->[$colidx]->{$colval} );
2038 6         12 $result->{uniq}->[$colidx]->{$colval} = 1;
2039             }
2040              
2041             $result->{agg}->[$colidx] = clone($empty_agg)
2042 16083 100       31729 unless ( defined( _HASH( $result->{agg}->[$colidx] ) ) );
2043 16083         20982 my $agg = $result->{agg}->[$colidx];
2044              
2045 16083         19826 ++$agg->{count};
2046 16083 100 100     32574 unless ( defined( $agg->{max} )
2047             && ( SQL::Statement::_anycmp( $colval, $agg->{max} ) < 0 ) )
2048             {
2049 16038         23321 $agg->{max} = $colval;
2050             }
2051 16083 100 100     33694 unless ( defined( $agg->{min} )
2052             && ( SQL::Statement::_anycmp( $colval, $agg->{min} ) > 0 ) )
2053             {
2054 4069         5735 $agg->{min} = $colval;
2055             }
2056 16083 100       40359 $agg->{sum} += $colval if ( looks_like_number($colval) );
2057             }
2058             else
2059             {
2060             $result->{pure}->[$colidx] = $colval
2061 4029 100       7950 unless ( defined( $result->{pure}->[$colidx] ) );
2062             }
2063             }
2064             }
2065             }
2066              
2067             sub build_row # (\%)
2068             {
2069 32     32   60 my ( $self, $result ) = @_;
2070 32         50 my @row;
2071              
2072 32         58 foreach my $colidx ( 0 .. ( scalar( @{ $self->{owner}->{columns} } ) - 1 ) )
  32         81  
2073             {
2074 65         283 my $coldef = $self->{owner}->{columns}->[$colidx]->{coldef};
2075              
2076 65 100       137 if ( $coldef->{type} eq 'setfunc' )
2077             {
2078 41 100       114 if ( $coldef->{name} eq 'COUNT' )
    100          
    100          
    100          
    50          
2079             {
2080 20   100     77 push( @row, $result->{agg}->[$colidx]->{count} || 0 );
2081             }
2082             elsif ( $coldef->{name} eq 'MAX' )
2083             {
2084 11         37 push( @row, $result->{agg}->[$colidx]->{max} );
2085             }
2086             elsif ( $coldef->{name} eq 'MIN' )
2087             {
2088 1         8 push( @row, $result->{agg}->[$colidx]->{min} );
2089             }
2090             elsif ( $coldef->{name} eq 'SUM' )
2091             {
2092 8         22 push( @row, $result->{agg}->[$colidx]->{sum} );
2093             }
2094             elsif ( $coldef->{name} eq 'AVG' )
2095             {
2096 1         4 my $count = $result->{agg}->[$colidx]->{count};
2097 1         4 my $sum = $result->{agg}->[$colidx]->{sum};
2098 1 50 33     10 my $avg = $sum / $count if ( $count && $sum );
2099 1         3 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         57 push( @row, $result->{pure}->[$colidx] );
2109             }
2110             }
2111              
2112 32         65 return \@row;
2113             }
2114              
2115             sub calc()
2116             {
2117 12     12   24 my $self = $_[0];
2118              
2119 12         40 $self->{final_row} = {};
2120              
2121 12         46 $self->do_calc();
2122              
2123 12         43 my $final_row = $self->build_row( $self->{final_row} );
2124              
2125 12         836 return [$final_row];
2126             }
2127              
2128             sub getAffectedResult # (\@)
2129             {
2130 4049     4049   5837 return $_[0]->{final_row};
2131             }
2132              
2133             package SQL::Statement::Group;
2134              
2135 16     16   140 use vars qw(@ISA);
  16         52  
  16         886  
2136              
2137 16     16   106 use Params::Util qw(_HASH);
  16         43  
  16         5354  
2138              
2139             @ISA = qw(SQL::Statement::Aggregate);
2140              
2141             sub new
2142             {
2143 7     7   22 my ( $class, $owner, $rows, $keycols ) = @_;
2144              
2145 7         37 my $self = $class->SUPER::new( $owner, $rows );
2146 7         22 $self->{keycols} = $keycols;
2147              
2148 7         18 return $self;
2149             }
2150              
2151             sub calc()
2152             {
2153 7     7   16 my $self = $_[0];
2154 7         9 my @final_table;
2155              
2156 7         30 $self->do_calc();
2157              
2158 7 100       14 if ( scalar( keys( %{ $self->{final_rows} } ) ) )
  7         32  
2159             {
2160 6         12 foreach my $key ( keys( %{ $self->{final_rows} } ) )
  6         19  
2161             {
2162 19         58 my $final_row = $self->build_row( $self->{final_rows}->{$key} );
2163 19         42 push( @final_table, $final_row );
2164             }
2165             }
2166             else
2167             {
2168 1         5 my $final_row = $self->build_row( {} );
2169 1         4 push( @final_table, $final_row );
2170             }
2171              
2172 7         770 return \@final_table;
2173             }
2174              
2175             sub getAffectedResult # (\@)
2176             {
2177 4024     4024   6179 my ( $self, $row ) = @_;
2178              
2179 4024         4954 my $rowkey = join( "\0", @$row[ @{ $self->{keycols} } ] );
  4024         8787  
2180              
2181             $self->{final_rows}->{$rowkey} = {}
2182 4024 100       9696 unless ( defined( _HASH( $self->{final_rows}->{$rowkey} ) ) );
2183              
2184 4024         6509 return $self->{final_rows}->{$rowkey};
2185             }
2186              
2187             package SQL::Statement::TempTable;
2188              
2189 16     16   115 use vars qw(@ISA);
  16         43  
  16         954  
2190              
2191             BEGIN
2192             {
2193 16     16   124 require SQL::Eval;
2194              
2195 16         12786 @SQL::Statement::TempTable::ISA = qw(SQL::Eval::Table);
2196             }
2197              
2198             sub new
2199             {
2200 44     44   110 my ( $class, $name, $col_names, $table_cols, $table ) = @_;
2201 44         63 my %col_nums;
2202 44         337 $col_nums{ $col_names->[$_] } = $_ for ( 0 .. scalar @$col_names - 1 );
2203 44         160 my @display_order = @col_nums{@$table_cols};
2204 44         227 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         184 return $class->SUPER::new($self);
2214             }
2215              
2216 6     6   29 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   234 my ( $s, $col ) = @_;
2222 129         224 my $new_col = $s->{col_nums}->{$col};
2223 129 100       296 unless ( defined($new_col) )
2224             {
2225 6         21 my @tmp = split( '~', $col );
2226 6 100       26 return unless ( 2 == scalar(@tmp) );
2227 1         12 $new_col = lc( $tmp[0] ) . '~' . $tmp[1];
2228 1         5 $new_col = $s->{col_nums}->{$new_col};
2229             }
2230 124         214 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   1469 : $_[0]->{table}->[ $_[0]->{rowpos}++ ];
2239             }
2240              
2241 1189     1189   3812 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         53 my $self = {@_};
2249 13   33     106 bless( $self, ( ref($proto) || $proto ) );
2250             }
2251 40     40   110 sub table ($) { $_[0]->{col}->table(); }
2252 40     40   140 sub column ($) { $_[0]->{col}->display_name(); }
2253 20     20   91 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     52 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   62 my ( $class, $idx ) = @_;
2272 36         70 my $self = { 'idx' => $idx };
2273 36         104 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   10710 my ( $class, $table_name ) = @_;
2283              
2284 5222 100       15269 if ( $table_name !~ m/"/ )
2285             {
2286 5194         10267 $table_name = lc $table_name;
2287             }
2288              
2289 5222         12104 my $self = {
2290             name => $table_name,
2291             };
2292              
2293 5222         16716 return bless( $self, $class );
2294             }
2295              
2296 9281     9281   23238 sub name { $_[0]->{name} }
2297              
2298             1;
2299             __END__