File Coverage

blib/lib/SQL/Statement.pm
Criterion Covered Total %
statement 1040 1184 87.8
branch 433 610 70.9
condition 187 302 61.9
subroutine 88 97 90.7
pod 36 43 83.7
total 1784 2236 79.7


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-2017 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   160232 use strict;
  16         25  
  16         524  
15 16     16   54 use warnings FATAL => "all";
  16         16  
  16         616  
16              
17 16     16   321 use 5.008;
  16         40  
18 16     16   54 use vars qw($VERSION $DEBUG);
  16         17  
  16         806  
19              
20 16     16   9407 use SQL::Parser ();
  16         41  
  16         691  
21 16     16   8050 use SQL::Eval ();
  16         33  
  16         269  
22 16     16   6077 use SQL::Statement::RAM ();
  16         36  
  16         287  
23 16     16   5972 use SQL::Statement::TermFactory ();
  16         50  
  16         335  
24 16     16   7317 use SQL::Statement::Util ();
  16         28  
  16         326  
25              
26 16     16   62 use Carp qw(carp croak);
  16         17  
  16         746  
27 16     16   5734 use Clone qw(clone);
  16         28598  
  16         912  
28 16     16   3071 use Errno;
  16         7252  
  16         613  
29 16     16   88 use Scalar::Util qw(blessed looks_like_number);
  16         16  
  16         643  
30 16     16   56 use List::Util qw(first);
  16         20  
  16         777  
31 16     16   56 use Params::Util qw(_INSTANCE _STRING _ARRAY _ARRAY0 _HASH0 _HASH);
  16         16  
  16         73141  
32              
33             #use locale;
34              
35             $VERSION = '1.412';
36              
37             sub new
38             {
39 868     868 1 272323 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 868 0 33     3531 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 868         786 my $parser = $flags;
51 868         1277 my $self = bless( {}, $class );
52 868 50       1683 $flags->{PrintError} = 1 unless defined $flags->{PrintError};
53 868 100       1422 $flags->{text_numbers} = 1 unless defined $flags->{text_numbers};
54 868 100       1343 $flags->{alpha_compare} = 1 unless defined $flags->{alpha_compare};
55              
56 868 50       2782 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 868         3573 $self->{$_} = $flags->{$_} for qw(RaiseError PrintError opts);
63             }
64              
65 868         1226 $self->{dlm} = '~';
66              
67             # Dean Arnold improvement to allow better subclassing
68             # if (!ref($parser) or (ref($parser) and ref($parser) !~ /^SQL::Parser/)) {
69 868 50       4869 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 868         2548 $self->{termFactory} = SQL::Statement::TermFactory->new($self);
77 868         1043 $self->{capabilities} = {};
78 868         1472 $self->prepare( $sql, $parser );
79 861         1656 return $self;
80             }
81              
82             sub prepare
83             {
84 868     868 1 923 my ( $self, $sql, $parser ) = @_;
85              
86 868 50       1701 $self->{already_prepared}->{$sql} and return;
87              
88             # delete earlier preparations, they're overwritten after this prepare run
89 868         875 $self->{already_prepared} = {};
90 868         2459 my $rv = $parser->parse($sql);
91 861 100       1229 if ($rv)
92             {
93 850         2115 undef $self->{errstr};
94 850         34362 my $parser_struct = clone( $parser->{struct} );
95 850         1605 while ( my ( $k, $v ) = each( %{$parser_struct} ) )
  9498         14329  
96             {
97 8648         9248 $self->{$k} = $v;
98             }
99 850         883 undef $self->{where_terms}; # force rebuild when needed
100 850         852 undef $self->{columns};
101 850         767 undef $self->{splitted_all_cols};
102 850         910 $self->{argnum} = 0;
103              
104 850         857 my $values = $self->{values};
105 850         652 my $param_num = -1;
106 850 100       1365 if ( $self->{limit_clause} )
107             {
108 9         46 $self->{limit_clause} = SQL::Statement::Limit->new( $self->{limit_clause} );
109             }
110              
111 850 100       1259 if ( defined( $self->{num_placeholders} ) )
112             {
113 17         42 for my $i ( 0 .. $self->{num_placeholders} - 1 )
114             {
115 36         85 $self->{params}->[$i] = SQL::Statement::Param->new($i);
116             }
117             }
118              
119 850         662 $self->{tables} = [ map { SQL::Statement::Table->new($_) } @{ $self->{table_names} } ];
  699         1383  
  850         1319  
120              
121 850 100 66     2192 if ( $self->{where_clause} && !defined( $self->{where_terms} ) )
122             {
123 229         689 $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 850         1527 ++$self->{already_prepared}->{$sql};
132 850         2377 return $self;
133             }
134             else
135             {
136 11         38 $self->{errstr} = $parser->errstr;
137 11         24 ++$self->{already_prepared}->{$sql};
138 11         16 return;
139             }
140             }
141              
142             sub execute
143             {
144 4654     4654 1 146989 my ( $self, $data, $params ) = @_;
145             ( $self->{NUM_OF_ROWS}, $self->{NUM_OF_FIELDS}, $self->{data} ) = ( 0, 0, [] ) and return 'OEO'
146 4654 100 50     7585 if ( $self->{no_execute} );
147 4649 100       7061 $self->{procedure}->{data} = $data if ( $self->{procedure} );
148 4649         4072 $self->{params} = $params;
149              
150 4649         7188 my ($command) = $self->command();
151 4649 50       6804 return $self->do_err('No command found!') unless ($command);
152              
153             $self->{where_clause}
154             and !defined( $self->{where_terms} )
155 4649 100 100     9086 and $self->{where_terms} = $self->{termFactory}->buildCondition( $self->{where_clause} );
156              
157 4649         8890 ( $self->{NUM_OF_ROWS}, $self->{NUM_OF_FIELDS}, $self->{data} ) = $self->$command( $data, $params );
158              
159             $self->{NAME} =
160 4648 100       10351 _ARRAY0( $self->{columns} ) ? [ map { delete $_->{term}->{fastpath}; $_->display_name() } @{ $self->{columns} } ] : [];
  13395         12082  
  13395         18105  
  4642         5349  
161              
162             # Force closing the tables
163 4648         5885 $self->{tables} = [ map { SQL::Statement::Table->new($_->{name}) } @{ delete $self->{tables} } ]; # create keen defs
  4518         8113  
  4648         5758  
164              
165 4648         7089 undef $self->{where_terms}; # force rebuild when needed
166              
167 4648 100       6915 return unless ( defined( $self->{NUM_OF_ROWS} ) );
168 4644   100     15053 return $self->{NUM_OF_ROWS} || '0E0';
169             }
170              
171             sub CREATE ($$$)
172             {
173 35     35 0 43 my ( $self, $data, $params ) = @_;
174 35         40 my $names;
175              
176             # CREATE TABLE AS ...
177 35         56 my $subquery = $self->{subquery};
178 35 50       78 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         92 my ( $eval, $foo ) = $self->open_tables( $data, 1, 1 );
221 35 50       116 return unless ($eval);
222 35         114 $eval->params($params);
223 35         132 my ( $row, $table, $col ) = ( [], $eval->table( $self->tables(0)->name() ) );
224 35 50       90 if ( _ARRAY( $table->col_names() ) )
225             {
226 0         0 return $self->do_err( "Table '" . $self->tables(0)->name() . "' already exists." );
227             }
228 35         98 foreach $col ( $self->columns() )
229             {
230 97         71 push( @{$row}, $col->name() );
  97         189  
231             }
232 35         137 $table->push_names( $data, $row );
233              
234 35         165 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 13 my ( $self, $data, $params ) = @_;
256 12         14 my $eval;
257             my @err;
258 12         17 eval {
259 12     0   74 local $SIG{__WARN__} = sub { push @err, @_ };
  0         0  
260 12         34 ($eval) = $self->open_tables( $data, 0, 1 );
261             };
262 12 100 33     100 if ( $self->{ignore_missing_table}
      66        
      66        
263             and ( $@ or @err or $self->{errstr} )
264 10         77 and grep { $_ =~ $notblrx } ( @err, $@, $self->{errstr} ) )
265             {
266 5         17 return ( -1, 0 );
267             }
268              
269 7 50       22 return if $self->{errstr};
270 7 50 0     34 return $self->do_err( $@ || $err[0] ) if ( $@ || @err );
      33        
271              
272             # return undef unless $eval;
273 7 50       18 return ( -1, 0 ) unless $eval;
274              
275             # $eval->params($params);
276 7         20 my ($table) = $eval->table( $self->tables(0)->name() );
277 7         26 $table->drop($data);
278              
279             #use mylibs; zwarn $self->{sql_stmt};
280 7         64 return ( -1, 0 );
281             }
282              
283             sub INSERT ($$$)
284             {
285 4275     4275 0 3544 my ( $self, $data, $params ) = @_;
286              
287 4275         6244 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
288 4275 50       8007 return unless ($eval);
289              
290 4275 100       10247 $params and $eval->params($params);
291 4275 50       5831 $self->verify_columns( $data, $eval, $all_cols ) if ( scalar( $self->columns() ) );
292 4275 50       6192 return if ( $self->{errstr} );
293              
294 4275         5452 my ($table) = $eval->table( $self->tables(0)->name() );
295 4275 50       8677 $table->seek( $data, 0, 2 ) unless ( $table->capability('insert_new_row') );
296              
297 4275         3311 my ( $val, $col, $i, $k );
298 4275         5032 my ($cNum) = scalar( $self->columns() );
299 4275         3452 my $param_num = 0;
300              
301 4275 50       6043 $cNum
302             or return $self->do_err("Bad col names in INSERT");
303              
304 4275         3203 my $maxCol = $#$all_cols;
305              
306             # INSERT INTO $table (row, ...) VALUES (value, ...), (...)
307 4275         3881 for ( $k = 0; $k < scalar( @{ $self->{values} } ); ++$k )
  8555         13477  
308             {
309 4280         4069 my ($array) = [];
310 4280         6532 for ( $i = 0; $i < $cNum; $i++ )
311             {
312 12791         13223 $col = $self->columns($i);
313 12791         15937 $val = $self->row_values( $k, $i );
314 12791 50 66     52474 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         21425 $val = $eval->param( $param_num++ );
325             }
326             elsif ( defined( _HASH($val) ) )
327             {
328 549         1244 $val = $self->{termFactory}->buildCondition($val);
329 549         889 $val = $val->value($eval);
330             }
331             else
332             {
333 0         0 return $self->do_err('Internal error: Unexpected column type');
334             }
335 12791         21207 $array->[ $table->column_num( $col->name() ) ] = $val;
336             }
337              
338             # Extend row to put values in ALL fields
339 4280 50       5875 $#$array < $maxCol and $array->[$maxCol] = undef;
340              
341 4280 50       7612 $table->capability('insert_new_row')
342             ? $table->insert_new_row( $data, $array )
343             : $table->push_row( $data, $array );
344             }
345              
346 4275         11787 return ( $k, 0 );
347             }
348              
349             sub DELETE ($$$)
350             {
351 6     6   8 my ( $self, $data, $params ) = @_;
352 6         18 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
353 6 50       18 return unless $eval;
354 6         16 $eval->params($params);
355 6         15 $self->verify_columns( $data, $eval, $all_cols );
356 6 50       14 return if ( $self->{errstr} );
357 6         10 my $tname = $self->tables(0)->name();
358 6         21 my ($table) = $eval->table($tname);
359 6         12 my $affected = 0;
360 6         7 my ( @rows, $array );
361              
362 6         18 while ( $array = $table->fetch_row($data) )
363             {
364 29 100       53 if ( $self->eval_where( $eval, $tname, $array ) )
365             {
366 10         9 ++$affected;
367 10 50 33     19 if ( $table->capability('rowwise_delete') and $table->capability('inplace_delete') )
    0          
368             {
369 10 50       17 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         27 $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         23 next;
384             }
385              
386 19 50       42 push( @rows, $array ) unless ( $table->capability('rowwise_delete') );
387             }
388              
389 6 50       17 if ($affected)
390             {
391 6 50       17 if ( $table->capability('rowwise_delete') )
392             { # @rows is empty in case of inplace_delete capability
393 6         14 foreach my $array (@rows)
394             {
395 0         0 $table->delete_one_row( $data, $array );
396             }
397             }
398             else
399             {
400             # rewrite table without deleted elements
401 0         0 $table->seek( $data, 0, 0 );
402 0         0 foreach my $array (@rows)
403             {
404 0         0 $table->push_row( $data, $array );
405             }
406 0         0 $table->truncate($data);
407             }
408             }
409              
410 6         44 return ( $affected, 0 );
411             }
412              
413             sub UPDATE ($$$)
414             {
415 5     5 0 8 my ( $self, $data, $params ) = @_;
416              
417 5         15 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 1 );
418 5 50       15 return unless $eval;
419              
420 5         11 my $valnum = $self->{num_val_placeholders};
421 5 100       12 my @val_params = splice( @{$params}, 0, $valnum ) if ($valnum);
  3         8  
422 5   33     13 $self->{params} ||= $params;
423 5         19 $eval->params($params);
424 5         15 $self->verify_columns( $data, $eval, $all_cols );
425 5 50       15 return if ( $self->{errstr} );
426              
427 5         11 my $tname = $self->tables(0)->name();
428 5         19 my ($table) = $eval->table($tname);
429 5         7 my $affected = 0;
430 5         7 my @rows;
431              
432 5         17 while ( my $array = $table->fetch_row($data) )
433             {
434 21         10 my $originalValues;
435 21 100       38 if ( $self->eval_where( $eval, $tname, $array ) )
436             {
437 7         7 my $valpos = 0;
438 7 50       15 if ( $table->capability('update_specific_row') )
439             {
440 0         0 $originalValues = clone($array);
441             }
442              
443 7         22 for ( my $i = 0; $i < $self->columns(); $i++ )
444             {
445 9         19 my $val = $self->row_values( 0, $i );
446 9 50 66     77 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         8 $val = $val_params[ $valpos++ ];
457             }
458             elsif ( defined( _HASH($val) ) )
459             {
460 3         11 $val = $self->{termFactory}->buildCondition($val);
461 3         14 $val = $val->value($eval);
462             }
463             else
464             {
465 0         0 return $self->do_err('Internal error: Unexpected column type');
466             }
467              
468 9         16 my $col = $self->columns($i);
469 9         25 $array->[ $table->column_num( $col->name() ) ] = $val;
470             }
471              
472 7         6 ++$affected;
473 7 50 33     16 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       13 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         16 $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       41 push( @rows, $array ) unless ( $table->capability('rowwise_update') );
500             }
501              
502 5 50       11 if ($affected)
503             {
504 5 50       11 if ( $table->capability('rowwise_update') )
505             { # @rows is empty in case of inplace_update capability
506 5         10 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 77 my ( $self, @all_cols ) = @_;
536 32         46 my $display_combine = 'NAMED';
537 32 100       147 $display_combine = 'NATURAL' if ( -1 != index( $self->{join}->{type}, 'NATURAL' ) );
538 32 100       89 $display_combine = 'USING' if ( -1 != index( $self->{join}->{clause}, 'USING' ) );
539 32         37 my @display_cols;
540 32         40 my @keycols = ();
541 25         61 @keycols = @{ $self->{join}->{keycols} }
542 32 100       75 if $self->{join}->{keycols};
543 32         56 foreach (@keycols) { $_ =~ s/\./$self->{dlm}/ }
  57         150  
544 32         34 my %is_key_col;
545 32         55 %is_key_col = map { $_ => 1 } @keycols;
  57         144  
546              
547             # IF NAMED COLUMNS, USE NAMED COLUMNS
548             #
549 32 100       89 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         51 my @tbls = $self->tables();
561 16         31 my %tables = ();
562              
563 16         73 $tables{ $_->name() } = $_ foreach (@tbls);
564              
565 16         51 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       151 . $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         15 my %is_natural;
591 16         14 for my $full_col (@all_cols)
592             {
593 64         273 my ( $table, $col ) = $full_col =~ m/^([^$self->{dlm}]+)$self->{dlm}(.+)$/;
594 64 100 66     139 next if ( ( $display_combine eq 'NATURAL' ) and $is_natural{$col} );
595 58 50 66     142 next if ( ( $display_combine eq 'USING' ) && $is_natural{$col} && $is_key_col{$col} );
      66        
596 48         41 push( @display_cols, $full_col );
597 48         64 $is_natural{$col}++;
598             }
599             }
600 32         52 my @shared = ();
601 32         29 my %is_shared;
602 32 100       90 if ( $self->{join}->{type} =~ m/NATURAL/ )
603             {
604 6         9 for my $full_col (@all_cols)
605             {
606 24         84 my ( $table, $col ) = $full_col =~ m/^([^$self->{dlm}]+)$self->{dlm}(.+)$/;
607 24 100       53 push( @shared, $col ) if ( $is_shared{$col}++ ); # using side-effect of post-inc
608             }
609             }
610             else
611             {
612 26         53 @shared = @keycols;
613             }
614 32         73 $self->{join}->{shared_cols} = \@shared;
615 32         100 $self->{join}->{display_cols} = \@display_cols;
616             }
617              
618             sub JOIN
619             {
620 34     34 0 51 my ( $self, $data, $params ) = @_;
621              
622 34         99 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
623 34 50       97 return undef unless $eval;
624 34         115 $eval->params($params);
625 34         111 $self->verify_columns( $data, $eval, $all_cols );
626 34 100       92 return if ( $self->{errstr} );
627 32 100 66     154 if ( $self->{join}->{keycols}
      100        
628             and $self->{join}->{table_order}
629 15         64 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       25 unless ( defined( $self->{join}->{table_order} ) );
634             }
635 32         75 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         37 my @all_cols;
641 32         50 for my $table (@tables)
642             {
643 76         63 my @cols = @{ $eval->table( $table->{name} )->col_names };
  76         197  
644 76         87 for my $col (@cols)
645             {
646 204         324 push( @all_cols, $table->{name} . $self->{dlm} . $col );
647             }
648             }
649 32         105 $self->find_join_columns(@all_cols);
650              
651             # JOIN THE TABLES
652             # *IN ORDER *BY JOINS*
653             #
654 32 100       77 @tables = @{ $self->{join}->{table_order} } if ( $self->{join}->{table_order} );
  15         42  
655 32         114 my ( $tableA, $tableB ) = splice( @tables, 0, 2 );
656 32 100       81 $tableA = $tableA->{name} if ( ref($tableA) );
657 32 100       68 $tableB = $tableB->{name} if ( ref($tableB) );
658 32         94 my ( $tableAobj, $tableBobj ) = ( $eval->table($tableA), $eval->table($tableB) );
659 32   33     78 $tableAobj->{NAME} ||= $tableA;
660 32   33     66 $tableBobj->{NAME} ||= $tableB;
661 32         85 $self->join_2_tables( $data, $params, $tableAobj, $tableBobj );
662              
663 32         46 for my $next_table (@tables)
664             {
665 12         22 $tableAobj = $self->{join}->{table};
666 12         165 $tableBobj = $eval->table($next_table);
667 12   33     30 $tableBobj->{NAME} ||= $next_table;
668 12         34 $self->join_2_tables( $data, $params, $tableAobj, $tableBobj );
669 12         40 $self->{cur_table} = $next_table;
670             }
671 32         92 return $self->SELECT( $data, $params );
672             }
673              
674             sub join_2_tables
675             {
676 44     44 1 55 my ( $self, $data, $params, $tableAobj, $tableBobj ) = @_;
677 44         50 my $share_type = 'IMPLICIT';
678 44 100       110 $share_type = 'NATURAL' if ( -1 != index( $self->{join}->{type}, 'NATURAL' ) );
679 44 100       99 $share_type = 'USING' if ( -1 != index( $self->{join}->{clause}, 'USING' ) );
680 44 100       96 $share_type = 'ON' if ( -1 != index( $self->{join}->{clause}, 'ON' ) );
681             $share_type = 'USING'
682 44 100 66     95 if ( ( $share_type eq 'ON' ) && ( scalar( @{ $self->{join}->{keycols} } ) == 1 ) );
  7         26  
683 44         281 my $join_type = 'INNER';
684 44 100       94 $join_type = 'LEFT' if ( -1 != index( $self->{join}->{type}, 'LEFT' ) );
685 44 100       93 $join_type = 'RIGHT' if ( -1 != index( $self->{join}->{type}, 'RIGHT' ) );
686 44 100       85 $join_type = 'FULL' if ( -1 != index( $self->{join}->{type}, 'FULL' ) );
687              
688 44         51 my $right_join = $join_type eq 'RIGHT';
689 44 100       59 if ($right_join)
690             {
691 3         4 my $tmpTbl = $tableAobj;
692 3         3 $tableAobj = $tableBobj;
693 3         5 $tableBobj = $tmpTbl;
694             }
695              
696 44         54 my $tableA = $tableAobj->{NAME};
697 44 50       99 ( 0 != index( $tableA, '"' ) ) and $tableA = lc $tableA;
698 44         59 my $tableB = $tableBobj->{NAME};
699 44 50       92 ( 0 != index( $tableB, '"' ) ) and $tableB = lc $tableB;
700 44         50 my @colsA = @{ $tableAobj->col_names() };
  44         99  
701 44         46 my @colsB = @{ $tableBobj->col_names() };
  44         96  
702 44         42 my ( %isunqualA, %isunqualB, @shared_cols );
703 44         168 $isunqualB{ $colsB[$_] } = 1 for ( 0 .. $#colsB );
704 44         40 my @tmpshared = @{ $self->{join}->{shared_cols} };
  44         108  
705              
706 44 50       153 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         29 foreach my $c (@tmpshared)
713             {
714 17         42 substr( $c, 0, index( $c, $self->{dlm} ) + 1 ) = '';
715 17         32 push( @shared_cols, $tableA . $self->{dlm} . $c );
716 17         35 push( @shared_cols, $tableB . $self->{dlm} . $c );
717             }
718             }
719             elsif ( $share_type eq 'NATURAL' )
720             {
721 6         8 for my $c (@colsA)
722             {
723 12 50       21 if ( $tableA eq $self->{dlm} . 'tmp' )
724             {
725 0         0 substr( $c, 0, index( $c, $self->{dlm} ) + 1 ) = '';
726             }
727 12 100       21 if ( $isunqualB{$c} )
728             {
729 6         12 push( @shared_cols, $tableA . $self->{dlm} . $c );
730 6         11 push( @shared_cols, $tableB . $self->{dlm} . $c );
731             }
732             }
733             }
734              
735 44         43 my %whichqual;
736 44 100 66     173 if ( $share_type eq 'ON' || $share_type eq 'IMPLICIT' )
737             {
738 21         27 foreach my $colb (@colsB)
739             {
740 77         168 $colb = $whichqual{$colb} = $tableB . $self->{dlm} . $colb;
741             }
742             }
743             else
744             {
745 23         28 @colsB = map { $tableB . $self->{dlm} . $_ } @colsB;
  46         113  
746             }
747              
748 44         68 my @all_cols = map { $tableA . $self->{dlm} . $_ } @colsA;
  220         326  
749 44 100       141 @all_cols = $right_join ? ( @colsB, @all_cols ) : ( @all_cols, @colsB );
750             {
751 44         59 my $str = $self->{dlm} . "tmp" . $self->{dlm};
  44         76  
752 44         70 foreach (@all_cols)
753             {
754 343         303 my $pos = index( $_, $str );
755 343 100       495 $pos >= 0 and substr( $_, $pos, length($str) ) = '';
756             }
757             }
758 44 100       95 if ( $tableA eq $self->{dlm} . 'tmp' )
759             {
760 12         14 foreach my $colA (@colsA)
761             {
762 139         147 my $c = substr( $colA, index( $colA, $self->{dlm} ) + 1 );
763 139         146 $isunqualA{$c} = $colA;
764             }
765             #%isunqualA =
766             # map { my ($c) = $_ =~ m/^(?:[^$self->{dlm}]+)$self->{dlm}(.+)$/; $c => $_ } @colsA;
767             }
768             else
769             {
770 32         45 foreach my $cola (@colsA)
771             {
772 81         156 $cola = $isunqualA{$cola} = $tableA . $self->{dlm} . $cola;
773             }
774             }
775              
776 44         50 my ( %col_numsA, %col_numsB );
777 44         258 $col_numsA{ $colsA[$_] } = $_ for ( 0 .. $#colsA );
778 44         174 $col_numsB{ $colsB[$_] } = $_ for ( 0 .. $#colsB );
779              
780 44 100 66     194 if ( $share_type eq 'ON' || $share_type eq 'IMPLICIT' )
781             {
782 21         147 %whichqual = ( %whichqual, %isunqualA );
783              
784 21         67 while (@tmpshared)
785             {
786 62         86 my ( $k1, $k2 ) = splice( @tmpshared, 0, 2 );
787              
788             # if both keys are in one table, bail out - FIXME: errmsg?
789 62 0 33     108 next if ( $isunqualA{$k1} && $isunqualA{$k2} );
790 62 0 33     87 next if ( $isunqualB{$k1} && $isunqualB{$k2} );
791              
792 62 50       90 defined( $whichqual{$k1} ) and $k1 = $whichqual{$k1};
793 62 50       91 defined( $whichqual{$k2} ) and $k2 = $whichqual{$k2};
794              
795 62 100 100     321 if ( defined( $col_numsA{$k1} ) && defined( $col_numsB{$k2} ) )
    100 100        
796             {
797 17         41 push( @shared_cols, $k1, $k2 );
798             }
799             elsif ( defined( $col_numsA{$k2} ) && defined( $col_numsB{$k1} ) )
800             {
801 3         8 push( @shared_cols, $k2, $k1 );
802             }
803             }
804             }
805              
806 44         40 my %is_shared;
807 44         51 for my $c (@shared_cols)
808             {
809 86         84 $is_shared{$c} = 1;
810             defined( $col_numsA{$c} )
811 86 50 66     271 or defined( $col_numsB{$c} )
812             or return $self->do_err("Can't find shared columns!");
813             }
814 44         109 my ( $posA, $posB ) = ( [], [] );
815 44         102 for my $f (@shared_cols)
816             {
817 86 100       139 defined( $col_numsA{$f} ) and push( @{$posA}, $col_numsA{$f} );
  43         80  
818 86 100       152 defined( $col_numsB{$f} ) and push( @{$posB}, $col_numsB{$f} );
  43         64  
819             }
820              
821 44         59 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         57 my $hashB = {};
826 44         164 TBLBFETCH: while ( my $array = $tableBobj->fetch_row($data) )
827             {
828 294         483 my @key_vals = @$array[@$posB];
829 294 100       402 if ($is_inner_join)
830             {
831 247   50     432 defined($_) or next TBLBFETCH for (@key_vals);
832             }
833 294         317 my $hashkey = join( ' ', @key_vals );
834 294         212 push( @{ $hashB->{$hashkey} }, $array );
  294         871  
835             }
836              
837             # CYCLE THROUGH TABLE A
838             #
839 44         46 my $blankRow;
840 44         61 my $joined_table = [];
841 44         45 my %visited;
842 44         87 TBLAFETCH: while ( my $arrayA = $tableAobj->fetch_row($data) ) # use tbl1st & tbl2nd
843             {
844 355         552 my @key_vals = @$arrayA[@$posA];
845 355 100       460 if ($is_inner_join)
846             {
847 311   50     567 defined($_) or next TBLAFETCH for (@key_vals);
848             }
849 355         347 my $hashkey = join( ' ', @key_vals );
850 355         368 my $rowsB = $hashB->{$hashkey};
851 355 100 100     727 if ( !defined($rowsB) && ( $join_type ne 'INNER' ) )
852             {
853 14 50       45 defined($blankRow) or $blankRow = [ (undef) x scalar(@colsB) ];
854 14         20 $rowsB = [$blankRow];
855             }
856              
857 355 50       478 if ( $join_type ne 'UNION' )
858             {
859 355         238 for my $arrayB ( @{$rowsB} )
  355         357  
860             {
861 404 100       417 my $newRow = $right_join ? [ @{$arrayB}, @{$arrayA} ] : [ @{$arrayA}, @{$arrayB} ];
  11         11  
  11         14  
  393         290  
  393         1315  
862              
863 404         570 push( @$joined_table, $newRow );
864             }
865             }
866              
867 355         793 ++$visited{$hashkey};
868             }
869              
870             # ADD THE LEFTOVER B ROWS IF NEEDED
871             #
872 44 100 66     206 if ( $join_type eq 'FULL' || $join_type eq 'UNION' )
873             {
874             my $st_is_NaturalOrUsing = ( -1 != index( $self->{join}->{type}, 'NATURAL' ) )
875 2   66     13 || ( -1 != index( $self->{join}->{clause}, 'USING' ) );
876 2         3 while ( my ( $k, $v ) = each %{$hashB} )
  8         20  
877             {
878 6 100       12 next if ( $visited{$k} );
879 2         4 for my $rowB (@$v)
880             {
881 2         3 my ( @arrayA, @tmpB, $rowhash );
882 2         2 @{$rowhash}{@colsB} = @{$rowB};
  2         6  
  2         3  
883 2         3 for my $c (@all_cols)
884             {
885 8         52 my ( $table, $col ) = split( $self->{dlm}, $c, 2 );
886 8 100       18 push( @arrayA, undef ) if ( $table eq $tableA );
887 8 100       14 push( @tmpB, $rowhash->{$c} ) if ( $table eq $tableB );
888             }
889 2 100       6 @arrayA[@$posA] = @tmpB[@$posB] if ($st_is_NaturalOrUsing);
890 2         4 my $newRow = [ @arrayA, @tmpB ];
891 2         12 push( @{$joined_table}, $newRow );
  2         5  
892             }
893             }
894             }
895              
896 44         180 undef $hashB;
897 44         38 undef $tableAobj;
898 44         38 undef $tableBobj;
899              
900             $self->{join}->{table} =
901 44         210 SQL::Statement::TempTable->new( $self->{dlm} . 'tmp', \@all_cols, $self->{join}->{display_cols}, $joined_table );
902              
903 44         302 return;
904             }
905              
906             sub run_functions
907             {
908 176     176 1 181 my ( $self, $data, $params ) = @_;
909 176         283 my ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
910 176         281 my @row = ();
911 176         332 for my $col ( $self->columns() )
912             {
913 176         418 my $val = $col->value($eval); # FIXME approve
914 176         5811 push( @row, $val );
915             }
916 176         776 return ( 1, scalar @row, [ \@row ] );
917             }
918              
919             sub SELECT($$)
920             {
921 348     348 0 371 my ( $self, $data, $params ) = @_;
922              
923 348   66     678 $self->{params} ||= $params;
924 348 100       1058 defined( _ARRAY( $self->{table_names} ) ) or return $self->run_functions( $data, $params );
925              
926 172         166 my ( $eval, $all_cols, $tableName, $table );
927 172 100       321 if ( defined( $self->{join} ) )
928             {
929 66 100       204 defined $self->{join}->{table} or return $self->JOIN( $data, $params );
930 32         48 $tableName = $self->{dlm} . 'tmp';
931 32         48 $table = $self->{join}->{table};
932             }
933             else
934             {
935 106         215 ( $eval, $all_cols ) = $self->open_tables( $data, 0, 0 );
936 105 100       262 return unless $eval;
937 104         242 $eval->params($params);
938 104         201 $self->verify_columns( $data, $eval, $all_cols );
939 104 100       180 return if ( $self->{errstr} );
940 103         170 $tableName = $self->tables(0)->name();
941 103         271 $table = $eval->table($tableName);
942             }
943              
944 135         163 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         144 my ( $cList, $col, $tbl, $ar, $i, $c );
949 135         117 my $numFields = 0;
950 135         103 my %columns;
951             my @names;
952 135         183 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         214 foreach my $column ( $self->columns() )
968             {
969 313 50       1540 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         576 ( $col, $tbl ) = ( $column->name(), $column->table() );
988 313   100     525 $tbl ||= '';
989 313         853 $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     1292 ? $table->column_num( $tbl . $self->{dlm} . $col )
1003             : $table->column_num($col);
1004              
1005 313 100 66     814 if ( !defined $cnum || $column->{function} )
1006             {
1007 33         48 $funcs{$col} = $column->{function};
1008 33         37 $cnum = $col;
1009             }
1010 313         368 push( @$cList, $cnum );
1011              
1012             # push(@$cList, $table->column_num($col));
1013 313         412 push( @names, $col );
1014             }
1015              
1016             # }
1017 135 50       235 $cList = [] unless ( defined($cList) );
1018 135 100       225 if ( $self->{join} )
1019             {
1020 32         54 foreach (@names) { $_ =~ s/^[^$self->{dlm}]+$self->{dlm}//; }
  122         300  
1021             }
1022 135         206 $self->{NAME} = \@names;
1023             # $self->verify_order_cols($table);
1024 135         282 my @order_by = $self->order();
1025 135         145 my @extraSortCols = ();
1026              
1027 135 100       243 if (@order_by)
1028             {
1029 17         19 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         22 my $i = -1;
1036 17         28 foreach my $column (@order_by)
1037             {
1038 20         21 ++$i;
1039 20         50 ( $col, $tbl ) = ( $column->column(), $column->table() );
1040 20         25 my $pos;
1041 20   66     51 $tbl ||= $self->colname2table($col);
1042 20   100     40 $tbl ||= '';
1043 20 100       60 if ( $self->{join} )
1044             {
1045 6         19 $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       56 next if ( exists( $columns{$tbl}->{$col} ) );
1050 1 50       4 $pos = $table->column_num($col) unless ( defined($pos) );
1051 1         1 push( @extraSortCols, $pos );
1052 1         2 $columns{$tbl}->{$col} = $nFields++;
1053             }
1054             }
1055              
1056 135 100       246 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     232 my $limit_count = 0 if ( $self->limit() and !$self->order() );
1061 135         181 my $limit = $self->limit();
1062 135         136 my $row_count = 0;
1063 135   100     213 my $offset = $self->offset() || 0;
1064 135         326 while ( my $array = $table->fetch_row($data) )
1065             {
1066 8673 100       10460 if ( $self->eval_where( $e, $tableName, $array, \%funcs ) )
1067             {
1068 8432 100 100     11437 next if ( defined($limit_count) and ( $row_count++ < $offset ) );
1069              
1070 8427         8774 my @row = map { $_->value($e) } $self->columns();
  21086         28106  
1071 8427         6560 push( @{$rows}, \@row );
  8427         7307  
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     22591 defined($limit_count)
1076             and ( ++$limit_count >= $limit )
1077             and return ( $limit, $numFields, $rows );
1078             }
1079             }
1080              
1081 134 100       275 if ( $self->distinct() )
1082             {
1083 5         8 my %seen;
1084 5         17 @{$rows} = map {
1085 33 50       28 $seen{ join( "\0", ( map { defined($_) ? $_ : '' } @{$_} ) ) }++
  89 100       174  
  33         29  
1086             ? ()
1087             : $_
1088 5         9 } @{$rows};
  5         7  
1089             }
1090              
1091 134 100       274 if ( $self->{has_set_functions} )
1092             {
1093 19         18 my $aggreg;
1094 19 100       37 if ( $self->{group_by} )
1095             {
1096 7         11 my @keycols = @{ $self->{colpos} }{ @{ $self->{group_by} } };
  7         15  
  7         7  
1097 7         28 $aggreg = SQL::Statement::Group->new( $self, $rows, \@keycols );
1098             }
1099             else
1100             {
1101 12         103 $aggreg = SQL::Statement::Aggregate->new( $self, $rows );
1102             }
1103 19         41 $rows = $aggreg->calc();
1104             # FIXME re-order if order_by
1105             }
1106              
1107 134 100       240 if (@order_by)
1108 0         0 {
1109 16     16   7656 use sort 'stable';
  16         6596  
  16         75  
1110             my @sortCols = map {
1111 17         30 my ( $col, $tbl ) = ( $_->column(), $_->table() );
  20         49  
1112 20 50 66     86 $self->{join} and $table->is_shared($col) and $tbl = 'shared';
1113 20   50     44 $tbl ||= $self->colname2table($col) || '';
      66        
1114 20         50 ( $columns{$tbl}->{$col}, $_->desc() )
1115             } @order_by;
1116              
1117 17         28 $i = scalar(@sortCols);
1118             do
1119 17         21 {
1120 20         33 my $desc = $sortCols[ --$i ];
1121 20         31 my $colNum = $sortCols[ --$i ];
1122 20         80 @{$rows} = sort {
1123 132         83 my $result;
1124 132         166 $result = _anycmp( $a->[$colNum], $b->[$colNum] );
1125 132 100       183 $desc and $result = -$result;
1126             $result;
1127 20         17 } @{$rows};
  20         78  
1128             } while ( $i > 0 );
1129 16     16   2396 use sort 'defaults'; # for perl < 5.10.0
  16         25  
  16         64  
1130             }
1131              
1132 134 100       246 if ( defined( $self->limit() ) )
1133             {
1134 1   50     2 my $offset = $self->offset() || 0;
1135 1   50     2 my $limit = $self->limit() || 0;
1136 1         2 @{$rows} = splice( @{$rows}, $offset, $limit );
  1         3  
  1         3  
1137             }
1138              
1139             # Rip off columns that have been added for @extraSortCols only
1140 134 100       224 if (@extraSortCols)
1141             {
1142 1         1 foreach my $row ( @{$rows} )
  1         3  
1143             {
1144 4         3 splice( @{$row}, $numFields, scalar(@extraSortCols) );
  4         5  
1145             }
1146             }
1147              
1148 134         128 ( scalar( @{$rows} ), $numFields, $rows );
  134         1397  
1149             }
1150              
1151             sub _anycmp($$;$)
1152             {
1153 32226     32226   22510 my ( $a, $b, $case_fold ) = @_;
1154              
1155 32226 100 66     126081 if ( !defined($a) || !defined($b) )
    100 66        
1156             {
1157 4         6 return defined($a) - defined($b);
1158             }
1159             elsif ( looks_like_number($a) && looks_like_number($b) )
1160             {
1161 24164         47971 return $a <=> $b;
1162             }
1163             else
1164             {
1165 8058 50 0     19339 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 7107 my ( $self, $eval, $tname, $rowary ) = @_;
1172 8723 100       16413 return 1 unless ( defined( $self->{where_terms} ) );
1173 458         408 $self->{argnum} = 0;
1174              
1175 458         954 return $self->{where_terms}->value($eval);
1176             }
1177              
1178             sub fetch_row
1179             {
1180 123     123 1 6370 my ($self) = @_;
1181 123   50     198 $self->{data} ||= [];
1182 123         74 my $row = shift @{ $self->{data} };
  123         124  
1183 123 100 100     274 return unless $row and scalar @$row;
1184 93         106 return $row;
1185             }
1186              
1187 16     16   5765 no warnings 'once';
  16         28  
  16         714  
1188             *fetch = \&fetch_row;
1189              
1190 16     16   56 use warnings;
  16         24  
  16         60100  
1191              
1192             sub fetch_rows
1193             {
1194 250     250 1 15841 my $self = $_[0];
1195 250   50     609 my $rows = $self->{data} || [];
1196 250         333 $self->{data} = [];
1197 250         336 return $rows;
1198             }
1199              
1200 7     7 1 972 sub open_table ($$$$$) { croak "Abstract method " . ref( $_[0] ) . "::open_table called" }
1201              
1202             sub open_tables
1203             {
1204 4649     4649 1 3924 my ( $self, $data, $createMode, $lockMode ) = @_;
1205 4649         3021 my @c;
1206 4649         4205 my $t = {};
1207 4649         5993 my @tables = $self->tables();
1208 4649         3379 my $count = -1;
1209 4649         4519 for my $tbl (@tables)
1210             {
1211 4519         3004 ++$count;
1212 4519         4693 my $name = $tbl->name();
1213 4519 50       8536 if ( $name =~ m/^(.+)\.([^\.]+)$/ )
1214             {
1215 0         0 my $schema = $1; # ignored
1216 0         0 $name = $tbl->{name} = $2;
1217             }
1218              
1219 4519 100 66     26280 if ( defined( $self->{table_func} ) && defined( $self->{table_func}->{ uc $name } ) )
    100 100        
    100 66        
1220             {
1221 2         4 my $u_func = $self->{table_func}->{ uc $name };
1222 2         4 $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         5758 $t->{$name} = $data->{Database}->{sql_ram_tables}->{$name};
1229 4475         10571 $t->{$name}->seek( $data, 0, 0 );
1230             $t->{$name}->init_table( $data, $name, $createMode, $lockMode )
1231 4475 50       11597 if ( $t->{$name}->can('init_table') );
1232             }
1233             elsif ( $self->{is_ram_table} )
1234             {
1235 35         201 $t->{$name} = $data->{Database}->{sql_ram_tables}->{$name} =
1236             SQL::Statement::RAM::Table->new( $name, [], [] );
1237             }
1238             else
1239             {
1240 7         10 undef $@;
1241 7         9 eval {
1242 7         13 my $open_name = $self->{org_table_names}->[$count];
1243 7         22 $t->{$name} = $self->open_table( $data, $open_name, $createMode, $lockMode );
1244             };
1245 7         449 my $err = $t->{$name}->{errstr};
1246 7 50       17 return $self->do_err($err) if ($err);
1247 7 50       31 return $self->do_err($@) if ($@);
1248             }
1249              
1250 4512         3137 my @cnames;
1251 4512         4306 my $table_cols = $t->{$name}->{org_col_names};
1252 4512 100       6884 $table_cols = $t->{$name}->{col_names} unless $table_cols;
1253 4512         4321 for my $c (@$table_cols)
1254             {
1255 13311 100       17622 my $newc = $c =~ m/^"/ ? $c : lc($c);
1256 13311         11150 push( @cnames, $newc );
1257 13311         14233 $self->{ORG_NAME}->{$newc} = $c;
1258             }
1259              
1260             #
1261             # set the col_num => col_obj hash for the table
1262             #
1263 4512         2973 my $col_nums;
1264 4512         3002 my $i = 0;
1265 4512         4221 for (@cnames)
1266             {
1267 13311         13651 $col_nums->{$_} = $i++;
1268             }
1269 4512         4498 $t->{$name}->{col_nums} = $col_nums;
1270 4512         6914 $t->{$name}->{col_names} = \@cnames;
1271              
1272 4512         11270 my $tcols = $t->{$name}->col_names();
1273 4512         3111 my @newcols;
1274 4512         4210 for (@$tcols)
1275             {
1276 13311 50       16140 next unless ( defined($_) );
1277 13311         9209 my $ncol = $_;
1278 13311 50       23422 $ncol = $name . '.' . $ncol unless ( $ncol =~ m/\./ );
1279 13311         12609 push( @newcols, $ncol );
1280             }
1281 4512         8534 @c = ( @c, @newcols );
1282             }
1283              
1284 4642         7879 $self->buildColumnObjects( $t, \@tables );
1285 4642 50       7595 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       7895 if ( !$self->{all_cols} )
1296             {
1297 502         490 my $all_cols = [];
1298 502         456 $all_cols = [ map { $_->{name} } @{ $self->{columns} } ];
  1113         1729  
  502         690  
1299 502   50     962 $all_cols ||= []; # ?
1300 502         1106 @$all_cols = ( @$all_cols, @c );
1301 502         666 $self->{all_cols} = $all_cols;
1302             }
1303             ##################################################
1304              
1305 4642         12205 return SQL::Eval->new( { 'tables' => $t } ), \@c;
1306             }
1307              
1308             sub getColumnObject($)
1309             {
1310 686     686 1 696 my ( $self, $newcol, $t, $tables ) = @_;
1311 686         482 my @columns;
1312              
1313 686 100 100     2711 if ( ( $newcol->{type} eq 'column' ) && ( -1 != index( $newcol->{value}, '*' ) ) )
    100 66        
1314             {
1315 199         196 my $tbl;
1316             my @tables;
1317 199 50       362 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         180 @tables = map { $_->name() } @{$tables};
  212         305  
  199         316  
1327             }
1328              
1329             my $join = defined( _HASH( $self->{join} ) )
1330             && ( ( -1 != index( $self->{join}->{type}, 'NATURAL' ) )
1331 199   66     812 || ( -1 != index( $self->{join}->{clause}, 'USING' ) ) );
1332 199         205 my %shared_cols;
1333              
1334 199         304 foreach my $table (@tables)
1335             {
1336 212 50       394 return $self->do_err("Can't find table '$table'") unless ( defined( $t->{$table} ) );
1337 212         298 my $tcols = $t->{$table}->{col_names};
1338 212 50       485 return $self->do_err("Couldn't find column names for table '$table'!")
1339             unless ( _ARRAY($tcols) );
1340 212         164 foreach my $colName ( @{$tcols} )
  212         271  
1341             {
1342 652 100 100     1126 next if ( $join && $shared_cols{$colName}++ );
1343 644         1763 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         1026 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       170 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         199 $newcol, # coldef
1366             ];
1367 97         102 push( @columns, $expcol );
1368             }
1369             else
1370             {
1371 390         312 my $col;
1372 390 100       528 if ( $newcol->{type} eq 'setfunc' )
1373             {
1374 24         67 my @cols = $self->getColumnObject( $newcol->{arg}, $t );
1375 24 100       49 if ( 1 == scalar(@cols) )
1376             {
1377 18         25 $col = $cols[0]->[2];
1378             }
1379             else
1380             {
1381             # FIXME add '\0' constants between items?
1382             my $colSep = $self->{termFactory}->buildCondition(
1383             {
1384 6         34 type => 'string',
1385             value => "\0",
1386             }
1387             );
1388 6         19 @cols = map { $_->[2], $colSep } @cols;
  0         0  
1389 6         7 pop(@cols);
1390             $col = $self->{termFactory}->buildCondition(
1391             {
1392 6         28 type => 'function',
1393             name => 'str_concat',
1394             value => \@cols,
1395             }
1396             );
1397             }
1398             }
1399             else
1400             {
1401 366         980 $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     1660 $newcol, # coldef
      66        
1411             ];
1412 390         466 push( @columns, $expcol );
1413             }
1414              
1415 686         1149 return @columns;
1416             }
1417              
1418             sub buildColumnObjects($)
1419             {
1420 4642     4642 1 4272 my ( $self, $t, $tables ) = @_;
1421              
1422 4642 100       9549 defined( _ARRAY0( $self->{column_defs} ) ) or return;
1423 4635 100       8883 defined( _ARRAY0( $self->{columns} ) ) and return;
1424              
1425 495         576 $self->{columns} = [];
1426              
1427 495         528 my $coldefs = $self->{column_defs};
1428              
1429 495         465 for ( my $i = 0; $i < scalar( @{$coldefs} ); ++$i )
  1157         2019  
1430             {
1431 662         628 my $colentry = $coldefs->[$i];
1432              
1433 662         1027 my @columns = $self->getColumnObject( $colentry, $t, $tables );
1434 662 50       1115 return if ( $self->{errstr} );
1435              
1436 662         705 foreach my $col (@columns)
1437             {
1438 1113         811 my $expcol = SQL::Statement::Util::Column->new( @{$col} );
  1113         2660  
1439 1113         927 push( @{ $self->{columns} }, $expcol );
  1113         1349  
1440 1113   66     3324 $self->{column_aliases}->{ $col->[4] } ||= $col->[3];
1441 1113         702 $self->{colpos}->{ $col->[3] } = scalar( @{ $self->{columns} } ) - 1;
  1113         2974  
1442             }
1443             }
1444              
1445 495         848 return;
1446             }
1447              
1448             sub verify_expand_column
1449             {
1450 13143     13143 1 11598 my ( $self, $c, $i, $usr_cols, $is_duplicate, $col_exists ) = @_;
1451              
1452             # XXX
1453 13143 100       17990 defined $self->{ALIASES}->{$c} and $c = $self->{ALIASES}->{$c};
1454              
1455 13143         8448 my ( $table, $col, $col_obj );
1456 13143 100       17921 if ( $c =~ m/(\S+)\.(\S+)/ )
    100          
1457             {
1458 1         3 $table = $1;
1459 1         5 $col = $2;
1460             }
1461 13142         17231 elsif ( ++${$i} >= 0 )
1462             {
1463 13122         8371 $col_obj = $usr_cols->[ ${$i} ];
  13122         9900  
1464 13122         15013 ( $table, $col ) = ( $col_obj->{table}, $col_obj->{name} );
1465             }
1466             else
1467             {
1468 20         39 ( $table, $col ) = $self->full_qualified_column_name($c);
1469             }
1470 13143 50       16353 return unless ($col);
1471              
1472             my $is_column =
1473 13143 100 100     71511 ( defined( _INSTANCE( $col_obj, 'SQL::Statement::Util::Column' ) ) and ( $col_obj->{coldef}->{type} eq 'column' ) )
1474             ? 1
1475             : 0;
1476              
1477 13143 100 100     32852 unless ( $is_column and defined($table) )
1478             {
1479 210         376 ( $table, undef ) = $self->full_qualified_column_name($col);
1480             }
1481              
1482 13143 50       19977 if ( defined( _INSTANCE( $table, 'SQL::Statement::Table' ) ) )
1483             {
1484 0         0 $table = $table->name();
1485             }
1486              
1487 13143 100 100     36073 if ( $is_column and !$table )
    100          
1488             {
1489 2 50       5 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       18615 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     24889 or $col_exists->{ "\L$table." . $col }
      33        
1499             or $is_user_def );
1500             }
1501              
1502 13141 100 100     33697 return ( $table, $col ) if ( $is_column or ${$i} < 0 );
  55         175  
1503 34         55 return;
1504             }
1505              
1506             sub verify_columns
1507             {
1508 4424     4424 1 3712 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     6633 $all_cols ||= [];
1515 4424         3068 my @tmp_cols = @{$all_cols};
  4424         6581  
1516 4424         5164 my @usr_cols = $self->columns();
1517 4424 50       7320 return $self->do_err('No fetchable columns') if ( 0 == scalar(@usr_cols) );
1518              
1519 4424         4613 my ( $cnum, $fully_qualified_cols ) = ( 0, [] );
1520 4424         4563 my @tmpcols = map { $_->{name} } @usr_cols;
  13122         19444  
1521 4424         4515 my %col_exists = map { $_ => 1 } @tmp_cols;
  13296         18115  
1522              
1523 4424         4333 my ( %is_member, @duplicates, %is_duplicate );
1524             # $_ =~ s/[^.]*\.(.*)/$1/;
1525 4424         4579 foreach (@$all_cols)
1526             {
1527 13296         17868 substr( $_, 0, index( $_, '.' ) + 1 ) = '';
1528             } # XXX we're modifying $all_cols from caller!
1529 4424         10579 @duplicates = grep( $is_member{$_}++, @$all_cols );
1530 4424         4914 %is_duplicate = map { $_ => 1 } @duplicates;
  54         103  
1531 4424 100 100     16847 if ( exists( $self->{join} ) && defined( _HASH( $self->{join} ) ) )
1532             {
1533 34         49 my $join = $self->{join};
1534 34 100       152 if ( -1 != index( uc $join->{type}, 'NATURAL' ) )
    100          
1535             {
1536 6         8 %is_duplicate = ();
1537             }
1538              
1539             # the following should be probably conditioned on an option,
1540             # but I don't know which --BW
1541             elsif ( 'USING' eq $join->{clause} )
1542             {
1543 10         11 my @keys = @{ $join->{keycols} };
  10         18  
1544 10         23 delete @is_duplicate{@keys};
1545             }
1546             }
1547              
1548 4424         3886 my %set_func_nofunc;
1549 4424 100       6529 if ( defined( $self->{has_set_functions} ) )
1550             {
1551 20         20 my @set_func_nofunc = grep { ( $_->{type} ne 'setfunc' ) } @{ $self->{column_defs} };
  34         57  
  20         28  
1552 20   66     28 %set_func_nofunc = map { ( $_->{alias} || $_->{fullorg} ) => 1 } @set_func_nofunc;
  9         33  
1553             }
1554 4424         4989 my ( $is_fully, $set_fully ) = ( {}, {} );
1555 4424         3644 my $i = -1;
1556 4424         4868 my $num_tables = $self->tables();
1557 4424         4166 for my $c (@tmpcols)
1558             {
1559 13122         20317 my ( $table, $col ) = $self->verify_expand_column( $c, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1560 13122 100       20352 return if ( $self->{errstr} );
1561 13120 100 66     32959 next unless ( $table && $col );
1562              
1563 13086         14597 my $ftc = "$table.$col";
1564 13086 50 33     41305 next if ( $table and $col and $is_fully->{$ftc} );
      33        
1565              
1566 13086         11345 $self->{columns}->[$i]->{name} = $col;
1567 13086         10553 $self->{columns}->[$i]->{table} = $table;
1568              
1569 13086 50 33     32242 if ( $table and $col )
1570             {
1571 13086         11862 push( @$fully_qualified_cols, $ftc );
1572 13086         12818 ++$is_fully->{$ftc};
1573 13086 100       20930 ++$set_fully->{$ftc} if ( $set_func_nofunc{$c} );
1574             }
1575             }
1576              
1577 4422 100       6663 if ( defined( $self->{has_set_functions} ) )
1578             {
1579 20 100       73 if ( defined( _ARRAY( $self->{group_by} ) ) )
1580             {
1581 7         8 foreach my $grpby ( @{ $self->{group_by} } )
  7         15  
1582             {
1583 8         8 $i = -2;
1584 8         19 my ( $table, $col ) = $self->verify_expand_column( $grpby, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1585 8 50       19 return if ( $self->{errstr} );
1586 8   33     11 $col ||= $grpby;
1587 8 50 33     40 ( $table, $col ) = $self->full_qualified_column_name($col)
1588             if ( defined($col) && !defined($table) );
1589 8 50 33     31 next unless ( defined($table) && defined($col) );
1590 8         19 delete $set_fully->{"$table.$col"};
1591             }
1592             }
1593              
1594 20 100       56 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         5 scalar( keys( %{$set_fully} ) ) > 1 ? 's' : '',
1600 1 50       2 join( "', '", keys( %{$set_fully} ) )
  1         8  
1601             )
1602             );
1603             }
1604             }
1605              
1606 4421 100       5461 if ( $self->{sort_spec_list} )
1607             {
1608 17         24 for my $n ( 0 .. scalar @{ $self->{sort_spec_list} } - 1 )
  17         53  
1609             {
1610 20 100       97 defined( _INSTANCE( $self->{sort_spec_list}->[$n], 'SQL::Statement::Order' ) ) and next;
1611 13         18 my ( $newcol, $direction ) = each %{ $self->{sort_spec_list}->[$n] };
  13         46  
1612 13   66     55 my $desc = $direction && ( $direction eq "DESC" ); # ($direction || "ASC") eq "DESC";
1613              
1614             # XXX parse order by like group by and select list
1615 13         18 $i = -2;
1616 13         37 my ( $table, $col ) = $self->verify_expand_column( $newcol, \$i, \@usr_cols, \%is_duplicate, \%col_exists );
1617 13 50       36 $self->{errstr} and return;
1618 13 100 66     62 ( $table, $col ) = $self->full_qualified_column_name($newcol)
1619             if ( defined($col) && !defined($table) );
1620 13 100       44 defined($table) and $col = $table . "." . $col;
1621 13         62 $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         13898 return $fully_qualified_cols;
1635             }
1636              
1637             sub distinct()
1638             {
1639 134     134 1 538 my $q = _STRING( $_[0]->{set_quantifier} );
1640 134   66     480 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 85555 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       5 return $_[0]->{params}->[ $_[1] ] if ( defined $_[1] );
1658              
1659 2 50       5 return wantarray ? @{ $_[0]->{params} } : scalar @{ $_[0]->{params} };
  0         0  
  2         8  
1660             }
1661              
1662             sub row_values(;$$)
1663             {
1664 12803 50   12803 1 22631 unless ( defined( _ARRAY( $_[0]->{values} ) ) )
1665             {
1666 0 0       0 return wantarray ? () : 0;
1667             }
1668 12803 100       12620 if ( defined( $_[1] ) )
1669             {
1670 12802 50       16892 return 0 unless ( defined( $_[0]->{values}->[ $_[1] ] ) );
1671 12802 100       20747 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         4  
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       2 : scalar( @{ $_[0]->{values} } );
  1         5  
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 25419 my ( $self, $col ) = @_;
1696 34581 100       41930 if ( !$self->{columns} )
1697             {
1698 1 50       7 return wantarray ? () : 0;
1699             }
1700              
1701 34580 100 66     92152 if ( defined $col and $col =~ m/^\d+$/ )
    50          
1702             { # arg1 = a number
1703 12801         15020 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       21893 return wantarray ? @{ $self->{columns} } : scalar @{ $self->{columns} };
  13213         15505  
  8566         15155  
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 2 my ( $self, $col_name ) = @_;
1729 2 50       6 return undef unless defined $col_name;
1730              
1731 2         2 my ( $tbl, $col );
1732 2 50       6 if ( $col_name =~ /^(.+)\.(.+)$/ )
1733             {
1734 0         0 ( $tbl, $col ) = ( $1, $2 );
1735             }
1736             else
1737             {
1738 2         2 $col = $col_name;
1739             }
1740              
1741 2         2 my $found_table;
1742 2         1 for my $full_col ( @{ $self->{all_cols} } )
  2         4  
1743             {
1744 10         21 my ( $stbl, $scol ) = $full_col =~ /^(.+)\.(.+)$/;
1745 10 50 100     25 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         8 return $found_table;
1751             }
1752              
1753             sub full_qualified_column_name($)
1754             {
1755 574     574 1 563 my ( $self, $col_name ) = @_;
1756 574 50       800 return unless ( defined($col_name) );
1757              
1758             # XXX
1759 574 100       859 defined $self->{ALIASES}->{$col_name} and $col_name = $self->{ALIASES}->{$col_name};
1760              
1761 574         408 my ( $tbl, $col );
1762 574 100       1585 unless ( ( $tbl, $col ) = $col_name =~ m/^((?:"[^"]+")|(?:[^.]+))\.(.*)$/ )
1763             {
1764 449         389 $col = $col_name;
1765             }
1766              
1767 574 100       769 unless ( defined( $self->{splitted_all_cols} ) )
1768             {
1769 118         99 my @rc;
1770 118         109 for my $full_col ( @{ $self->{all_cols} } )
  118         205  
1771             {
1772 722 100       2103 if ( my ( $stbl, $scol ) = $full_col =~ m/^((?:"[^"]+")|(?:[^.]+))\.(.*)$/ )
1773             {
1774 440         305 push( @{ $self->{splitted_all_cols} }, [ $stbl, $scol ] );
  440         756  
1775 440 100 100     813 defined($tbl) and ( $tbl ne $stbl ) and next;
1776 416 100       802 ( $scol eq $col ) and @rc = ( $stbl, $scol );
1777             }
1778             }
1779 118 100       428 @rc and return @rc;
1780             }
1781             else
1782             {
1783 456         326 for my $splitted_col ( @{ $self->{splitted_all_cols} } )
  456         612  
1784             {
1785 1576 100 100     3072 defined($tbl) and ( $tbl ne $splitted_col->[0] ) and next;
1786 1228 100       2624 ( $splitted_col->[1] eq $col ) and return @$splitted_col;
1787             }
1788             }
1789              
1790 39         74 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 879 sub limit ($) { $_[0]->{limit_clause}->{limit}; }
1819 138     138 1 400 sub offset ($) { $_[0]->{limit_clause}->{offset}; }
1820              
1821             sub order
1822             {
1823 139 100   139 1 693 return unless ( defined $_[0]->{sort_spec_list} );
1824              
1825             return
1826             defined( $_[1] ) && looks_like_number( $_[1] ) ? $_[0]->{sort_spec_list}->[ $_[1] ]
1827 18         50 : wantarray ? @{ $_[0]->{sort_spec_list} }
1828 20 100 66     92 : scalar @{ $_[0]->{sort_spec_list} };
  1 100       4  
1829             }
1830              
1831             sub tables
1832             {
1833             return
1834             defined( $_[1] ) && looks_like_number( $_[1] ) ? $_[0]->{tables}->[ $_[1] ]
1835 4701         6802 : wantarray ? @{ $_[0]->{tables} }
1836 13557 100 66 13557 1 41810 : scalar @{ $_[0]->{tables} };
  4424 100       4948  
1837             }
1838              
1839             sub order_joins
1840             {
1841 7     7 1 8 my ( $self, $links ) = @_;
1842 7         14 my ( @new_keycols, @new_links );
1843 7         11 for (@$links)
1844             {
1845 7         22 my ( $tbl, $col ) = $self->full_qualified_column_name($_);
1846 7         21 push( @new_keycols, $tbl . $self->{dlm} . $col );
1847 7         13 push( @new_links, $tbl );
1848             }
1849 7         17 $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         10 my @all_tables;
1855             my %relations;
1856 0         0 my %is_table;
1857              
1858 7         16 while (@new_links)
1859             {
1860 7         10 my $t1 = shift(@new_links);
1861 7         10 my $t2 = shift(@new_links);
1862 7 50 33     48 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 138 my $self = shift;
1906 12         16 my $err = shift;
1907 12         13 my $errtype = shift;
1908 12         63 my @c = caller 6;
1909              
1910             #$err = "[" . $self->{original_string} . "]\n$err\n\n";
1911             # $err = "$err\n\n";
1912 12         19 my $prog = $c[1];
1913 12         16 my $line = $c[2];
1914 12 100       32 $prog = defined($prog) ? " called from $prog" : '';
1915 12 100       33 $prog .= defined($line) ? " at $line" : '';
1916 12         33 $err = "\nExecution ERROR: $err$prog.\n\n";
1917              
1918 12         21 $self->{errstr} = $err;
1919 12 50       30 carp $err if $self->{PrintError};
1920 12 100       89 croak "$err" if $self->{RaiseError};
1921 11         54 return;
1922             }
1923              
1924 15     15 1 6830 sub errstr() { return $_[0]->{errstr}; }
1925              
1926 1     1 1 12 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 29 return undef unless $_[0]->{where_terms};
1933 5         58 return $_[0]->{where_terms};
1934             }
1935              
1936             sub get_user_func_table
1937             {
1938 2     2 1 3 my ( $self, $name, $u_func ) = @_;
1939 2         7 my $term = $self->{termFactory}->buildCondition($u_func);
1940              
1941 2         2 my @data_aryref = @{ $term->value(undef) };
  2         5  
1942 2         3 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         13 my $tempTable = SQL::Statement::RAM::Table->new( $name, $col_names, \@data_aryref );
1948 2   33     11 $tempTable->{all_cols} ||= $col_names;
1949 2         9 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 866     866   56646 my $self = $_[0];
1963              
1964 866         1307 undef $self->{NAME};
1965 866         1184 undef $self->{ORG_NAME};
1966 866         1012 undef $self->{all_cols};
1967 866         1020 undef $self->{already_prepared};
1968 866         776 undef $self->{argnum};
1969 866         1354 undef $self->{col_obj};
1970 866         809 undef $self->{column_names};
1971 866         2451 undef $self->{columns};
1972 866         851 undef $self->{cur_table};
1973 866         948 undef $self->{data};
1974 866         846 undef $self->{group_by};
1975             #undef $self->{has_OR};
1976 866         1288 undef $self->{join};
1977 866         854 undef $self->{limit_clause};
1978 866         865 undef $self->{num_placeholders};
1979 866         791 undef $self->{num_val_placeholders};
1980 866         868 undef $self->{org_table_names};
1981 866         801 undef $self->{params};
1982 866         1300 undef $self->{opts};
1983 866         1023 undef $self->{procedure};
1984 866         668 undef $self->{set_function};
1985 866         828 undef $self->{sort_spec_list};
1986 866         775 undef $self->{subquery};
1987 866         1150 undef $self->{tables};
1988 866         805 undef $self->{table_names};
1989 866         783 undef $self->{table_func};
1990 866         1262 undef $self->{where_clause};
1991 866         1062 undef $self->{where_terms};
1992 866         6178 undef $self->{values};
1993             }
1994              
1995             package SQL::Statement::Aggregate;
1996              
1997 16     16   113 use Scalar::Util qw(looks_like_number);
  16         25  
  16         956  
1998 16     16   66 use Params::Util qw(_HASH);
  16         28  
  16         605  
1999 16     16   62 use Clone qw(clone);
  16         19  
  16         9182  
2000              
2001             sub new
2002             {
2003 19     19   24 my ( $class, $owner, $rows ) = @_;
2004 19         52 my $self = {
2005             owner => $owner,
2006             records => $rows,
2007             };
2008 19         49 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   24 my $self = $_[0];
2022              
2023 19         18 foreach my $line ( 0 .. ( scalar( @{ $self->{records} } ) - 1 ) )
  19         51  
2024             {
2025 8073         5647 my $row = $self->{records}->[$line];
2026 8073         7430 my $result = $self->getAffectedResult($row);
2027              
2028 8073         5261 foreach my $colidx ( 0 .. ( scalar( @{ $self->{owner}->{columns} } ) - 1 ) )
  8073         8053  
2029             {
2030 20115         15198 my $coldef = $self->{owner}->{columns}->[$colidx]->{coldef};
2031 20115         14129 my $colval = $row->[$colidx];
2032              
2033 20115 100       19858 if ( $coldef->{type} eq 'setfunc' )
2034             {
2035 16086 100       18545 if ( $coldef->{distinct} eq 'DISTINCT' )
2036             {
2037 9 100       18 next if defined( $result->{uniq}->[$colidx]->{$colval} );
2038 6         8 $result->{uniq}->[$colidx]->{$colval} = 1;
2039             }
2040              
2041             $result->{agg}->[$colidx] = clone($empty_agg)
2042 16083 100       23575 unless ( defined( _HASH( $result->{agg}->[$colidx] ) ) );
2043 16083         10277 my $agg = $result->{agg}->[$colidx];
2044              
2045 16083         9698 ++$agg->{count};
2046 16083 100 100     25068 unless ( defined( $agg->{max} )
2047             && ( SQL::Statement::_anycmp( $colval, $agg->{max} ) < 0 ) )
2048             {
2049 16038         11201 $agg->{max} = $colval;
2050             }
2051 16083 100 100     24695 unless ( defined( $agg->{min} )
2052             && ( SQL::Statement::_anycmp( $colval, $agg->{min} ) > 0 ) )
2053             {
2054 4069         2891 $agg->{min} = $colval;
2055             }
2056 16083 100       30710 $agg->{sum} += $colval if ( looks_like_number($colval) );
2057             }
2058             else
2059             {
2060             $result->{pure}->[$colidx] = $colval
2061 4029 100       5316 unless ( defined( $result->{pure}->[$colidx] ) );
2062             }
2063             }
2064             }
2065             }
2066              
2067             sub build_row # (\%)
2068             {
2069 32     32   32 my ( $self, $result ) = @_;
2070 32         27 my @row;
2071              
2072 32         31 foreach my $colidx ( 0 .. ( scalar( @{ $self->{owner}->{columns} } ) - 1 ) )
  32         49  
2073             {
2074 65         57 my $coldef = $self->{owner}->{columns}->[$colidx]->{coldef};
2075              
2076 65 100       79 if ( $coldef->{type} eq 'setfunc' )
2077             {
2078 41 100       82 if ( $coldef->{name} eq 'COUNT' )
    100          
    100          
    100          
    50          
2079             {
2080 20   100     64 push( @row, $result->{agg}->[$colidx]->{count} || 0 );
2081             }
2082             elsif ( $coldef->{name} eq 'MAX' )
2083             {
2084 11         60 push( @row, $result->{agg}->[$colidx]->{max} );
2085             }
2086             elsif ( $coldef->{name} eq 'MIN' )
2087             {
2088 1         5 push( @row, $result->{agg}->[$colidx]->{min} );
2089             }
2090             elsif ( $coldef->{name} eq 'SUM' )
2091             {
2092 8         11 push( @row, $result->{agg}->[$colidx]->{sum} );
2093             }
2094             elsif ( $coldef->{name} eq 'AVG' )
2095             {
2096 1         3 my $count = $result->{agg}->[$colidx]->{count};
2097 1         2 my $sum = $result->{agg}->[$colidx]->{sum};
2098 1 50 33     11 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         42 push( @row, $result->{pure}->[$colidx] );
2109             }
2110             }
2111              
2112 32         42 return \@row;
2113             }
2114              
2115             sub calc()
2116             {
2117 12     12   17 my $self = $_[0];
2118              
2119 12         24 $self->{final_row} = {};
2120              
2121 12         30 $self->do_calc();
2122              
2123 12         44 my $final_row = $self->build_row( $self->{final_row} );
2124              
2125 12         746 return [$final_row];
2126             }
2127              
2128             sub getAffectedResult # (\@)
2129             {
2130 4049     4049   3247 return $_[0]->{final_row};
2131             }
2132              
2133             package SQL::Statement::Group;
2134              
2135 16     16   110 use vars qw(@ISA);
  16         30  
  16         731  
2136              
2137 16     16   56 use Params::Util qw(_HASH);
  16         20  
  16         4013  
2138              
2139             @ISA = qw(SQL::Statement::Aggregate);
2140              
2141             sub new
2142             {
2143 7     7   10 my ( $class, $owner, $rows, $keycols ) = @_;
2144              
2145 7         32 my $self = $class->SUPER::new( $owner, $rows );
2146 7         19 $self->{keycols} = $keycols;
2147              
2148 7         11 return $self;
2149             }
2150              
2151             sub calc()
2152             {
2153 7     7   8 my $self = $_[0];
2154 7         7 my @final_table;
2155              
2156 7         17 $self->do_calc();
2157              
2158 7 100       10 if ( scalar( keys( %{ $self->{final_rows} } ) ) )
  7         22  
2159             {
2160 6         5 foreach my $key ( keys( %{ $self->{final_rows} } ) )
  6         17  
2161             {
2162 19         40 my $final_row = $self->build_row( $self->{final_rows}->{$key} );
2163 19         22 push( @final_table, $final_row );
2164             }
2165             }
2166             else
2167             {
2168 1         2 my $final_row = $self->build_row( {} );
2169 1         3 push( @final_table, $final_row );
2170             }
2171              
2172 7         571 return \@final_table;
2173             }
2174              
2175             sub getAffectedResult # (\@)
2176             {
2177 4024     4024   2638 my ( $self, $row ) = @_;
2178              
2179 4024         2402 my $rowkey = join( "\0", @$row[ @{ $self->{keycols} } ] );
  4024         4427  
2180              
2181             $self->{final_rows}->{$rowkey} = {}
2182 4024 100       6722 unless ( defined( _HASH( $self->{final_rows}->{$rowkey} ) ) );
2183              
2184 4024         3371 return $self->{final_rows}->{$rowkey};
2185             }
2186              
2187             package SQL::Statement::TempTable;
2188              
2189 16     16   75 use vars qw(@ISA);
  16         19  
  16         736  
2190              
2191             BEGIN
2192             {
2193 16     16   63 require SQL::Eval;
2194              
2195 16         9068 @SQL::Statement::TempTable::ISA = qw(SQL::Eval::Table);
2196             }
2197              
2198             sub new
2199             {
2200 44     44   58 my ( $class, $name, $col_names, $table_cols, $table ) = @_;
2201 44         42 my %col_nums;
2202 44         292 $col_nums{ $col_names->[$_] } = $_ for ( 0 .. scalar @$col_names - 1 );
2203 44         126 my @display_order = @col_nums{@$table_cols};
2204 44         225 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         167 return $class->SUPER::new($self);
2214             }
2215              
2216 6     6   22 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   120 my ( $s, $col ) = @_;
2222 129         122 my $new_col = $s->{col_nums}->{$col};
2223 129 100       204 unless ( defined($new_col) )
2224             {
2225 6         21 my @tmp = split( '~', $col );
2226 6 100       23 return unless ( 2 == scalar(@tmp) );
2227 1         5 $new_col = lc( $tmp[0] ) . '~' . $tmp[1];
2228 1         9 $new_col = $s->{col_nums}->{$new_col};
2229             }
2230 124         125 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   1411 : $_[0]->{table}->[ $_[0]->{rowpos}++ ];
2239             }
2240              
2241 1189     1189   3257 sub column($) { return $_[0]->{row}->[ $_[0]->{col_nums}->{ $_[1] } ]; }
2242              
2243             package SQL::Statement::Order;
2244              
2245             sub new ($$)
2246             {
2247 13     13   18 my $proto = shift;
2248 13         45 my $self = {@_};
2249 13   33     91 bless( $self, ( ref($proto) || $proto ) );
2250             }
2251 40     40   72 sub table ($) { $_[0]->{col}->table(); }
2252 40     40   124 sub column ($) { $_[0]->{col}->display_name(); }
2253 20     20   67 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   13 my ( $proto, $self ) = @_;
2261 9   33     43 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   39 my ( $class, $idx ) = @_;
2272 36         51 my $self = { 'idx' => $idx };
2273 36         77 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 5217     5217   4970 my ( $class, $table_name ) = @_;
2283              
2284 5217 100       10546 if ( $table_name !~ m/"/ )
2285             {
2286 5189         6383 $table_name = lc $table_name;
2287             }
2288              
2289 5217         8225 my $self = {
2290             name => $table_name,
2291             };
2292              
2293 5217         11879 return bless( $self, $class );
2294             }
2295              
2296 9281     9281   16216 sub name { $_[0]->{name} }
2297              
2298             1;
2299             __END__