| 2 |
package SQL::Parser; |
package SQL::Parser; |
| 3 |
###################################################################### |
###################################################################### |
| 4 |
# |
# |
| 5 |
# This module is copyright (c), 2001 by Jeff Zucker. |
# This module is copyright (c), 2001,2002 by Jeff Zucker. |
| 6 |
# All rights resered. |
# All rights resered. |
| 7 |
|
# |
| 8 |
# It may be freely distributed under the same terms as Perl itself. |
# It may be freely distributed under the same terms as Perl itself. |
| 9 |
# See below for help and copyright information (search for SYNOPSIS). |
# See below for help and copyright information (search for SYNOPSIS). |
| 10 |
# |
# |
| 12 |
|
|
| 13 |
use strict; |
use strict; |
| 14 |
use vars qw($VERSION); |
use vars qw($VERSION); |
| 15 |
|
use constant FUNCTION_NAMES => join '|', qw( |
| 16 |
|
TRIM SUBSTRING UPPER LOWER TO_CHAR |
| 17 |
|
); |
| 18 |
|
|
| 19 |
|
$VERSION = '1.005'; |
| 20 |
|
|
| 21 |
$VERSION = '1.004'; |
BEGIN { if( $ENV{SQL_USER_DEFS} ) { require SQL::UserDefs; } } |
| 22 |
|
|
| 23 |
|
|
| 24 |
############################# |
############################# |
| 96 |
delete $self->{"struct"}->{"join"}; |
delete $self->{"struct"}->{"join"}; |
| 97 |
} |
} |
| 98 |
$self->replace_quoted_ids(); |
$self->replace_quoted_ids(); |
| 99 |
|
$self->{struct}->{org_table_names} = $self->{struct}->{table_names}; |
| 100 |
|
my @uTables = map {uc $_ } @{$self->{struct}->{table_names}}; |
| 101 |
|
$self->{struct}->{table_names} = \@uTables; |
| 102 |
|
$self->{struct}->{org_col_names} = $self->{struct}->{column_names}; |
| 103 |
|
my @uCols = map {uc $_ } @{$self->{struct}->{column_names}}; |
| 104 |
|
$self->{struct}->{column_names} = \@uCols; |
| 105 |
|
if ($self->{original_string} =~ /Y\.\*/) { |
| 106 |
|
#use mylibs; zwarn $self; exit; |
| 107 |
|
} |
| 108 |
return $rv; |
return $rv; |
| 109 |
} |
} |
| 110 |
else { |
else { |
| 111 |
|
$self->{struct}={}; |
| 112 |
|
if ($ENV{SQL_USER_DEFS}) { |
| 113 |
|
return SQL::UserDefs::user_parse($self,$sql); |
| 114 |
|
} |
| 115 |
return $self->do_err("Command '$com' not recognized or not supported!"); |
return $self->do_err("Command '$com' not recognized or not supported!"); |
| 116 |
} |
} |
| 117 |
} |
} |
| 233 |
my $stmt = shift; |
my $stmt = shift; |
| 234 |
my $table_name; |
my $table_name; |
| 235 |
$self->{"struct"}->{"command"} = 'DROP'; |
$self->{"struct"}->{"command"} = 'DROP'; |
| 236 |
|
if ($stmt =~ /^\s*DROP\s+TABLE\s+IF\s+EXISTS\s+(.*)$/si ) { |
| 237 |
|
$stmt = "DROP TABLE $1"; |
| 238 |
|
$self->{"struct"}->{ignore_missing_table}=1; |
| 239 |
|
} |
| 240 |
if ($stmt =~ /^\s*DROP\s+(\S+)\s+(.+)$/si ) { |
if ($stmt =~ /^\s*DROP\s+(\S+)\s+(.+)$/si ) { |
| 241 |
my $com2 = $1 || ''; |
my $com2 = $1 || ''; |
| 242 |
$table_name = $2; |
$table_name = $2; |
| 473 |
my $col_str; |
my $col_str; |
| 474 |
my($table_name,$val_str) = $str =~ |
my($table_name,$val_str) = $str =~ |
| 475 |
/^INSERT\s+INTO\s+(.+?)\s+VALUES\s+\((.+?)\)$/i; |
/^INSERT\s+INTO\s+(.+?)\s+VALUES\s+\((.+?)\)$/i; |
| 476 |
if ($table_name =~ /[()]/ ) { |
if ($table_name and $table_name =~ /[()]/ ) { |
| 477 |
($table_name,$col_str,$val_str) = $str =~ |
($table_name,$col_str,$val_str) = $str =~ |
| 478 |
/^INSERT\s+INTO\s+(.+?)\s+\((.+?)\)\s+VALUES\s+\((.+?)\)$/i; |
/^INSERT\s+INTO\s+(.+?)\s+\((.+?)\)\s+VALUES\s+\((.+?)\)$/i; |
| 479 |
} |
} |
| 480 |
return $self->do_err('No table name specified!') unless $table_name; |
return $self->do_err('No table name specified!') unless $table_name; |
| 481 |
return $self->do_err('Missing values list!') unless $val_str; |
return $self->do_err('Missing values list!') unless defined $val_str; |
| 482 |
return undef unless $self->TABLE_NAME($table_name); |
return undef unless $self->TABLE_NAME($table_name); |
| 483 |
$self->{"struct"}->{"command"} = 'INSERT'; |
$self->{"struct"}->{"command"} = 'INSERT'; |
| 484 |
$self->{"struct"}->{"table_names"} = [$table_name]; |
$self->{"struct"}->{"table_names"} = [$table_name]; |
| 533 |
my $self = shift; |
my $self = shift; |
| 534 |
my $stmt = shift; |
my $stmt = shift; |
| 535 |
$self->{"struct"}->{"command"} = 'CREATE'; |
$self->{"struct"}->{"command"} = 'CREATE'; |
| 536 |
my($table_name,$table_element_def); |
my($table_name,$table_element_def,%is_col_name); |
| 537 |
if ($stmt =~ /^CREATE (LOCAL|GLOBAL) TEMPORARY TABLE(.*)$/si ) { |
if ($stmt =~ /^CREATE (LOCAL|GLOBAL) TEMPORARY TABLE(.*)$/si ) { |
| 538 |
$self->{"struct"}->{"table_type"} = "$1 TEMPORARY"; |
$self->{"struct"}->{"table_type"} = "$1 TEMPORARY"; |
| 539 |
$stmt = "CREATE TABLE$2"; |
$stmt = "CREATE TABLE$2"; |
| 554 |
else { |
else { |
| 555 |
return $self->do_err( "Can't find column definitions!" ); |
return $self->do_err( "Can't find column definitions!" ); |
| 556 |
} |
} |
| 557 |
|
return undef unless $self->TABLE_NAME($table_name); |
| 558 |
$table_element_def =~ s/\s+\(/(/g; |
$table_element_def =~ s/\s+\(/(/g; |
| 559 |
my $primary_defined; |
my $primary_defined; |
| 560 |
for my $col(split ',',$table_element_def) { |
for my $col(split ',',$table_element_def) { |
| 576 |
for my $constr(@c) { |
for my $constr(@c) { |
| 577 |
if ( $constr =~ /^\s*(UNIQUE|NOT_NULL|PRIMARY_KEY)\s*$/i ) { |
if ( $constr =~ /^\s*(UNIQUE|NOT_NULL|PRIMARY_KEY)\s*$/i ) { |
| 578 |
my $cur_c = uc $1; |
my $cur_c = uc $1; |
| 579 |
if ($has_c{$cur_c}) { |
if ($has_c{$cur_c}++) { |
| 580 |
return $self->do_err( |
return $self->do_err( |
| 581 |
qq~Duplicate constraint: '$constr'!~ |
qq~Duplicate column constraint: '$constr'!~ |
| 582 |
); |
); |
| 583 |
} |
} |
| 584 |
if ($cur_c eq 'PRIMARY_KEY' and $primary_defined++ ) { |
if ($cur_c eq 'PRIMARY_KEY' and $primary_defined++ ) { |
| 585 |
return $self->do_err( |
return $self->do_err( |
| 586 |
qq~There can be only one PRIMARY KEY in a table!~ |
qq~Can't have two PRIMARY KEYs in a table!~ |
| 587 |
); |
); |
| 588 |
} |
} |
| 589 |
$constr =~ s/_/ /g; |
$constr =~ s/_/ /g; |
| 591 |
|
|
| 592 |
} |
} |
| 593 |
else { |
else { |
| 594 |
return $self->do_err("Bad column constraint: '$constr'!"); |
return $self->do_err("Unknown column constraint: '$constr'!"); |
| 595 |
} |
} |
| 596 |
} |
} |
| 597 |
} |
} |
| 607 |
$self->{"struct"}->{"column_defs"}->{"$name"}->{"data_type"} = $type; |
$self->{"struct"}->{"column_defs"}->{"$name"}->{"data_type"} = $type; |
| 608 |
$self->{"struct"}->{"column_defs"}->{"$name"}->{"data_length"} = $length; |
$self->{"struct"}->{"column_defs"}->{"$name"}->{"data_length"} = $length; |
| 609 |
push @{$self->{"struct"}->{"column_names"}},$name; |
push @{$self->{"struct"}->{"column_names"}},$name; |
| 610 |
|
my $tmpname = $name; |
| 611 |
|
$tmpname = uc $tmpname unless $tmpname =~ /^"/; |
| 612 |
|
return $self->do_err("Duplicate column names!") |
| 613 |
|
if $is_col_name{$tmpname}++; |
| 614 |
|
|
| 615 |
} |
} |
| 616 |
$self->{"struct"}->{"table_names"} = [$table_name]; |
$self->{"struct"}->{"table_names"} = [$table_name]; |
| 629 |
my(@cols,@vals); |
my(@cols,@vals); |
| 630 |
for(@sets) { |
for(@sets) { |
| 631 |
my($col,$val) = split / = /,$_; |
my($col,$val) = split / = /,$_; |
| 632 |
return $self->do_err('Incomplete SET clause!') if !$col or !$val; |
return $self->do_err('Incomplete SET clause!') if !defined $col or !defined $val; |
| 633 |
push @cols, $col; |
push @cols, $col; |
| 634 |
push @vals, $val; |
push @vals, $val; |
| 635 |
} |
} |
| 664 |
$col =~ s/^\s+//; |
$col =~ s/^\s+//; |
| 665 |
$col =~ s/\s+$//; |
$col =~ s/\s+$//; |
| 666 |
if ($col =~ /^(\S+)\.\*$/) { |
if ($col =~ /^(\S+)\.\*$/) { |
| 667 |
my $table = $1; |
my $table = $1; |
| 668 |
|
my %is_table_alias = %{$self->{"tmp"}->{"is_table_alias"}}; |
| 669 |
|
$table = $is_table_alias{$table} if $is_table_alias{$table}; |
| 670 |
|
$table = $is_table_alias{"\L$table"} if $is_table_alias{"\L$table"}; |
| 671 |
|
# $table = uc $table unless $table =~ /^"/; |
| 672 |
|
#use mylibs; zwarn \%is_table_alias; |
| 673 |
|
#print "\n<<$table>>\n"; |
| 674 |
return undef unless $self->TABLE_NAME($table); |
return undef unless $self->TABLE_NAME($table); |
| 675 |
$table = $self->replace_quoted_ids($table); |
$table = $self->replace_quoted_ids($table); |
| 676 |
push @newcols, "$table.*"; |
push @newcols, "$table.*"; |
| 695 |
my $distinct; |
my $distinct; |
| 696 |
if ( $set_function_arg =~ s/(DISTINCT|ALL) (.+)$/$2/i ) { |
if ( $set_function_arg =~ s/(DISTINCT|ALL) (.+)$/$2/i ) { |
| 697 |
$distinct = uc $1; |
$distinct = uc $1; |
| 698 |
|
$self->{"struct"}->{"set_quantifier"} = $distinct; |
| 699 |
} |
} |
| 700 |
my $count_star = 1 if $set_function_name eq 'COUNT' |
my $count_star = 1 if $set_function_name eq 'COUNT' |
| 701 |
and $set_function_arg eq '*'; |
and $set_function_arg eq '*'; |
| 1021 |
# replaces string function parens with square brackets |
# replaces string function parens with square brackets |
| 1022 |
# e.g TRIM (foo) -> TRIM[foo] |
# e.g TRIM (foo) -> TRIM[foo] |
| 1023 |
# |
# |
| 1024 |
|
|
| 1025 |
sub nongroup_string { |
sub nongroup_string { |
| 1026 |
|
my $f= FUNCTION_NAMES; |
| 1027 |
my $str = shift; |
my $str = shift; |
| 1028 |
$str =~ s/(TRIM|SUBSTRING|UPPER|LOWER) \(([^()]+)\)/$1\[$2\]/gi; |
# $str =~ s/(TRIM|SUBSTRING|UPPER|LOWER) \(([^()]+)\)/$1\[$2\]/gi; |
| 1029 |
if ( $str =~ /(TRIM|SUBSTRING|UPPER|LOWER) \(/i ) { |
$str =~ s/($f) \(([^()]+)\)/$1\[$2\]/gi; |
| 1030 |
|
# if ( $str =~ /(TRIM|SUBSTRING|UPPER|LOWER) \(/i ) { |
| 1031 |
|
if ( $str =~ /($f) \(/i ) { |
| 1032 |
return nongroup_string($str); |
return nongroup_string($str); |
| 1033 |
} |
} |
| 1034 |
else { |
else { |
| 1165 |
|
|
| 1166 |
sub undo_string_funcs { |
sub undo_string_funcs { |
| 1167 |
my $str = shift; |
my $str = shift; |
| 1168 |
$str =~ s/(TRIM|UPPER|LOWER|SUBSTRING)\[([^\]\[]+?)\]/$1 ($2)/; |
my $f= FUNCTION_NAMES; |
| 1169 |
if ($str =~ /(TRIM|UPPER|LOWER|SUBSTRING)\[/) { |
# $str =~ s/(TRIM|UPPER|LOWER|SUBSTRING)\[([^\]\[]+?)\]/$1 ($2)/; |
| 1170 |
|
# if ($str =~ /(TRIM|UPPER|LOWER|SUBSTRING)\[/) { |
| 1171 |
|
$str =~ s/($f)\[([^\]\[]+?)\]/$1 ($2)/; |
| 1172 |
|
if ($str =~ /($f)\[/) { |
| 1173 |
return undo_string_funcs($str); |
return undo_string_funcs($str); |
| 1174 |
} |
} |
| 1175 |
return $str; |
return $str; |
| 1250 |
}; |
}; |
| 1251 |
} |
} |
| 1252 |
|
|
| 1253 |
|
# TO_CHAR (value) |
| 1254 |
|
# |
| 1255 |
|
if ($str =~ /^TO_CHAR \((.+)\)\s*$/i ) { |
| 1256 |
|
my $name = 'TO_CHAR'; |
| 1257 |
|
my $value = $self->ROW_VALUE($1); |
| 1258 |
|
return undef unless $value; |
| 1259 |
|
return { |
| 1260 |
|
type => 'function', |
| 1261 |
|
name => $name, |
| 1262 |
|
value => $value, |
| 1263 |
|
}; |
| 1264 |
|
} |
| 1265 |
|
|
| 1266 |
# UPPER (value) and LOWER (value) |
# UPPER (value) and LOWER (value) |
| 1267 |
# |
# |
| 1419 |
$col_name =~ s/\s+$//; |
$col_name =~ s/\s+$//; |
| 1420 |
return undef unless $col_name eq '*' or $self->IDENTIFIER($col_name); |
return undef unless $col_name eq '*' or $self->IDENTIFIER($col_name); |
| 1421 |
# |
# |
| 1422 |
# MAKE COL NAMES ALL LOWER CASE |
# MAKE COL NAMES ALL UPPER CASE |
| 1423 |
my $orgcol = $col_name; |
my $orgcol = $col_name; |
| 1424 |
if ($col_name =~ /^\?QI(\d+)\?$/) { |
if ($col_name =~ /^\?QI(\d+)\?$/) { |
| 1425 |
$col_name = $self->replace_quoted_ids($col_name); |
$col_name = $self->replace_quoted_ids($col_name); |
| 1433 |
# |
# |
| 1434 |
if ($table_name) { |
if ($table_name) { |
| 1435 |
my $alias = $self->{tmp}->{is_table_alias}->{"\L$table_name"}; |
my $alias = $self->{tmp}->{is_table_alias}->{"\L$table_name"}; |
| 1436 |
#use mylibs; print "$table_name"; zwarn $self->{tmp}; exit; |
#use mylibs; print "$table_name"; zwarn $self->{tmp}; |
| 1437 |
$table_name = $alias if defined $alias; |
$table_name = $alias if defined $alias; |
| 1438 |
$table_name = uc $table_name; |
$table_name = uc $table_name; |
| 1439 |
$col_name = "$table_name.$col_name"; |
$col_name = "$table_name.$col_name"; |
| 1440 |
|
#print "<<$col_name>>"; |
| 1441 |
} |
} |
| 1442 |
return $col_name; |
return $col_name; |
| 1443 |
} |
} |
| 1539 |
if (!$table_name) { |
if (!$table_name) { |
| 1540 |
return $self->do_err('No table name specified!'); |
return $self->do_err('No table name specified!'); |
| 1541 |
} |
} |
| 1542 |
return undef if !($self->IDENTIFIER($table_name)); |
return $self->IDENTIFIER($table_name); |
| 1543 |
return 1; |
# return undef if !($self->IDENTIFIER($table_name)); |
| 1544 |
|
# return 1; |
| 1545 |
} |
} |
| 1546 |
|
|
| 1547 |
|
|
| 1558 |
} |
} |
| 1559 |
return 1 if $id =~ /^".+?"$/s; # QUOTED IDENTIFIER |
return 1 if $id =~ /^".+?"$/s; # QUOTED IDENTIFIER |
| 1560 |
my $err = "Bad table or column name '$id' "; # BAD CHARS |
my $err = "Bad table or column name '$id' "; # BAD CHARS |
| 1561 |
if ($id !~ /\w|\./) { |
if ($id =~ /\W/) { |
| 1562 |
$err .= "has chars not alphanumeric or underscore!"; |
$err .= "has chars not alphanumeric or underscore!"; |
| 1563 |
return $self->do_err( $err ); |
return $self->do_err( $err ); |
| 1564 |
} |
} |
| 1570 |
$err .= "contains more than 128 characters!"; |
$err .= "contains more than 128 characters!"; |
| 1571 |
return $self->do_err( $err ); |
return $self->do_err( $err ); |
| 1572 |
} |
} |
| 1573 |
if ( $self->{"opts"}->{"reserved_words"}->{"$id"} ) { # BAD RESERVED WORDS |
$id = uc $id; |
| 1574 |
|
#print "<$id>"; |
| 1575 |
|
#use mylibs; zwarn $self->{opts}->{reserved_words}; |
| 1576 |
|
#exit; |
| 1577 |
|
if ( $self->{"opts"}->{"reserved_words"}->{$id} ) { # BAD RESERVED WORDS |
| 1578 |
$err .= "is a SQL reserved word!"; |
$err .= "is a SQL reserved word!"; |
| 1579 |
return $self->do_err( $err ); |
return $self->do_err( $err ); |
| 1580 |
} |
} |
| 1765 |
$self->{"struct"}->{"errstr"} = $err; |
$self->{"struct"}->{"errstr"} = $err; |
| 1766 |
#$self->{"errstr"} = $err; |
#$self->{"errstr"} = $err; |
| 1767 |
warn $err if $self->{"PrintError"}; |
warn $err if $self->{"PrintError"}; |
| 1768 |
die if $self->{"RaiseError"}; |
die $err if $self->{"RaiseError"}; |
| 1769 |
return undef; |
return undef; |
| 1770 |
} |
} |
| 1771 |
|
|
| 1773 |
|
|
| 1774 |
__END__ |
__END__ |
| 1775 |
|
|
| 1776 |
|
=pod |
| 1777 |
|
|
| 1778 |
=head1 NAME |
=head1 NAME |
| 1779 |
|
|
| 1836 |
|
|
| 1837 |
CREATE [ {LOCAL|GLOBAL} TEMPORARY ] TABLE $table |
CREATE [ {LOCAL|GLOBAL} TEMPORARY ] TABLE $table |
| 1838 |
( |
( |
| 1839 |
$col_1 $col_type1 $col_constraints1, |
$col_1 $col_type1 $col_constraints1, |
| 1840 |
..., |
..., |
| 1841 |
$col_N $col_typeN $col_constraintsN, |
$col_N $col_typeN $col_constraintsN, |
| 1842 |
) |
) |
| 1843 |
[ ON COMMIT {DELETE|PRESERVE} ROWS ] |
[ ON COMMIT {DELETE|PRESERVE} ROWS ] |
| 1844 |
|
|
| 1893 |
|
|
| 1894 |
SELECT select_clause |
SELECT select_clause |
| 1895 |
FROM from_clause |
FROM from_clause |
| 1896 |
[ WHERE search_condition ] |
[ WHERE search_condition ] |
| 1897 |
[ ORDER BY $ocol1 [ASC|DESC], ... $ocolN [ASC|DESC] ] |
[ ORDER BY $ocol1 [ASC|DESC], ... $ocolN [ASC|DESC] ] |
| 1898 |
[ LIMIT [start,] length ] |
[ LIMIT [start,] length ] |
| 1899 |
|
|
| 1910 |
table1 [, table2, ... tableN] |
table1 [, table2, ... tableN] |
| 1911 |
| table1 NATURAL [join_type] JOIN table2 |
| table1 NATURAL [join_type] JOIN table2 |
| 1912 |
| table1 [join_type] table2 USING (col1,col2, ... colN) |
| table1 [join_type] table2 USING (col1,col2, ... colN) |
| 1913 |
| table1 [join_type] JOIN table2 ON (table1.colA = table2.colB) |
| table1 [join_type] JOIN table2 ON table1.colA = table2.colB |
| 1914 |
|
|
| 1915 |
* join type ::= |
* join type ::= |
| 1916 |
INNER |
INNER |
| 1924 |
* self-joins are not currently supported |
* self-joins are not currently supported |
| 1925 |
* if implicit joins are used, the WHERE clause must contain |
* if implicit joins are used, the WHERE clause must contain |
| 1926 |
and equijoin condition for each table |
and equijoin condition for each table |
| 1927 |
|
|
| 1928 |
|
|
| 1929 |
=head2 SEARCH CONDITION |
=head2 SEARCH CONDITION |
| 1930 |
|
|
| 1933 |
|
|
| 1934 |
=head2 OPERATORS |
=head2 OPERATORS |
| 1935 |
|
|
| 1936 |
$op = | <> | < | > | <= | >= |
$op = | <> | < | > | <= | >= |
| 1937 |
| IS NULL | IS NOT NULL | LIKE | CLIKE | BETWEEN | IN |
| IS NULL | IS NOT NULL | LIKE | CLIKE | BETWEEN | IN |
| 1938 |
|
|
| 1939 |
The "CLIKE" operator works exactly the same as the "LIKE" |
The "CLIKE" operator works exactly the same as the "LIKE" |
| 1940 |
operator, but is case insensitive. For example: |
operator, but is case insensitive. For example: |
| 1941 |
|
|
| 1942 |
WHERE foo LIKE 'bar%' # succeeds if foo is "barbaz" |
WHERE foo LIKE 'bar%' # succeeds if foo is "barbaz" |
| 1969 |
|
|
| 1970 |
Examples: |
Examples: |
| 1971 |
|
|
| 1972 |
TRIM( string ) |
TRIM( string ) |
| 1973 |
trims leading and trailing spaces from string |
trims leading and trailing spaces from string |
| 1974 |
|
|
| 1975 |
TRIM( LEADING FROM str ) |
TRIM( LEADING FROM str ) |