From: Peter Rabbitson Date: Thu, 21 Oct 2010 13:36:51 +0000 (+0000) Subject: Proper placeholder support in the AST X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=4e914a7c1dd88467a0d287073c9a9db477725394;p=scpubgit%2FQ-Branch.git Proper placeholder support in the AST --- diff --git a/lib/SQL/Abstract/Test.pm b/lib/SQL/Abstract/Test.pm index 42491f9..4c28b5f 100644 --- a/lib/SQL/Abstract/Test.pm +++ b/lib/SQL/Abstract/Test.pm @@ -235,9 +235,13 @@ sub _parenthesis_unroll { $changes++; } - # only *ONE* LITERAL element + # only *ONE* LITERAL or placeholder element elsif ( - @{$child->[1]} == 1 && $child->[1][0][0] eq 'LITERAL' + @{$child->[1]} == 1 && ( + $child->[1][0][0] eq 'LITERAL' + or + $child->[1][0][0] eq 'PLACEHOLDER' + ) ) { push @children, $child->[1][0]; $changes++; @@ -272,7 +276,8 @@ sub _parenthesis_unroll { # mathop, and our content is: # a single non-mathop child with a single PAREN grandchild which # would indicate mathop ( nonmathop ( ... ) ) - # or a single non-mathop with a single LITERAL ( nonmathop ? ) + # or a single non-mathop with a single LITERAL ( nonmathop foo ) + # or a single non-mathop with a single PLACEHOLDER ( nonmathop ? ) elsif ( @{$child->[1]} == 1 and @@ -284,8 +289,10 @@ sub _parenthesis_unroll { and ( $child->[1][0][1][0][0] eq 'PAREN' - or + or $child->[1][0][1][0][0] eq 'LITERAL' + or + $child->[1][0][1][0][0] eq 'PLACEHOLDER' ) ) { push @children, $child->[1][0]; diff --git a/lib/SQL/Abstract/Tree.pm b/lib/SQL/Abstract/Tree.pm index 8d8449f..fd9f665 100644 --- a/lib/SQL/Abstract/Tree.pm +++ b/lib/SQL/Abstract/Tree.pm @@ -40,6 +40,8 @@ my $op_look_behind = '(?: (?<= [\,\s\)\(] ) | \A )'; my $quote_left = qr/[\`\'\"\[]/; my $quote_right = qr/[\`\'\"\]]/; +my $placeholder_re = qr/(?: \? | \$\d+ )/x; + # These SQL keywords always signal end of the current expression (except inside # of a parenthesized subexpression). # Format: A list of strings that will be compiled to extended syntax ie. @@ -114,6 +116,7 @@ my $all_known_re = join("\n\t|\n", $binary_op_re, "$op_look_behind (?i: AND|OR|NOT ) $op_look_ahead", (map { quotemeta $_ } qw/, ( ) */), + $placeholder_re, ); $all_known_re = qr/$all_known_re/x; @@ -131,7 +134,7 @@ use constant PARSE_RHS => 4; my $expr_term_re = qr/ ^ (?: $expr_start_re | \) ) $/x; my $rhs_term_re = qr/ ^ (?: $expr_term_re | $binary_op_re | (?i: AND | OR | NOT | \, ) ) $/x; -my $func_start_re = qr/^ (?: \? | \$\d+ | \( ) $/x; +my $func_start_re = qr/^ (?: \* | $placeholder_re | \( ) $/x; my %indents = ( select => 0, @@ -326,6 +329,10 @@ sub _recurse_parse { : [ $op => [$right] ]; } + elsif ( $token =~ $placeholder_re) { + $left = $left ? [ $left, [ PLACEHOLDER => [ $token ] ] ] + : [ PLACEHOLDER => [ $token ] ]; + } # we're now in "unknown token" land - start eating tokens until # we see something familiar else { @@ -421,11 +428,11 @@ sub _unparse { return join (' ', map $self->_unparse($_, $bindargs, $depth), @$tree); } elsif ($car eq 'LITERAL') { - if ($cdr->[0] eq '?') { - return $self->fill_in_placeholder($bindargs) - } return $cdr->[0]; } + elsif ($car eq 'PLACEHOLDER') { + return $self->fill_in_placeholder($bindargs); + } elsif ($car eq 'PAREN') { return '(' . join(' ',