X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FSQL%2FAbstract%2FTest.pm;h=cfedf160812f260d1e399e23a0e3d5dd678ceead;hb=9e8dab3fcb42dd5eeaab3b630bd71018ebc141d3;hp=8f41167503f3fb326e8b5a309f32545b26bece09;hpb=e96c510a9e5b209f8211c3af2f9418d4a0fd0fd3;p=scpubgit%2FQ-Branch.git diff --git a/lib/SQL/Abstract/Test.pm b/lib/SQL/Abstract/Test.pm index 8f41167..cfedf16 100644 --- a/lib/SQL/Abstract/Test.pm +++ b/lib/SQL/Abstract/Test.pm @@ -53,6 +53,7 @@ my @expression_terminator_sql_keywords = ( # These are binary operator keywords always a single LHS and RHS # * AND/OR are handled separately as they are N-ary +# * so is NOT as being unary # * BETWEEN without paranthesis around the ANDed arguments (which # makes it a non-binary op) is detected and accomodated in # _recurse_parse() @@ -63,7 +64,7 @@ my @binary_op_keywords = ( ); my $tokenizer_re_str = join("\n\t|\n", - ( map { '\b' . $_ . '\b' } @expression_terminator_sql_keywords, 'AND', 'OR' ), + ( map { '\b' . $_ . '\b' } @expression_terminator_sql_keywords, 'AND', 'OR', 'NOT'), ( map { q! (?<= [\w\s\`\'\)] ) ! . $_ . q! (?= [\w\s\`\'\(] ) ! } @binary_op_keywords ), ); @@ -261,7 +262,7 @@ sub _recurse_parse { or ($state == PARSE_IN_EXPR && grep { $lookahead =~ /^ $_ $/xi } ('\)', @expression_terminator_sql_keywords ) ) or - ($state == PARSE_RHS && grep { $lookahead =~ /^ $_ $/xi } ('\)', @expression_terminator_sql_keywords, @binary_op_keywords, 'AND', 'OR' ) ) + ($state == PARSE_RHS && grep { $lookahead =~ /^ $_ $/xi } ('\)', @expression_terminator_sql_keywords, @binary_op_keywords, 'AND', 'OR', 'NOT' ) ) ) { return $left; } @@ -310,6 +311,14 @@ sub _recurse_parse { $left = $left ? [@$left, [$op => [$right] ]] : [[ $op => [$right] ]]; } + # NOT (last as to allow all other NOT X pieces first) + elsif ( $token =~ /^ not $/ix ) { + my $op = uc $token; + my $right = _recurse_parse ($tokens, PARSE_RHS); + $left = $left ? [ @$left, [$op => [$right] ]] + : [[ $op => [$right] ]]; + + } # leaf expression else { $left = $left ? [@$left, [EXPR => [$token] ] ] @@ -357,6 +366,14 @@ sub _parenthesis_unroll { $changes++; } + # only one EXPR element in the parenthesis + elsif ( + @{$child->[1]} == 1 && $child->[1][0][0] eq 'EXPR' + ) { + push @children, $child->[1][0]; + $changes++; + } + # only one element in the parenthesis which is a binary op with two EXPR sub-children elsif ( @{$child->[1]} == 1 @@ -424,7 +441,7 @@ SQL::Abstract::Test - Helper function for testing SQL::Abstract is_same_sql_bind is_same_sql is_same_bind eq_sql_bind eq_sql eq_bind /]; - + my ($sql, @bind) = SQL::Abstract->new->select(%args); is_same_sql_bind($given_sql, \@given_bind, @@ -451,10 +468,14 @@ ignoring differences in spaces or in levels of parentheses. Therefore the tests will pass as long as the semantics is preserved, even if the surface syntax has changed. -B : this is only a half-cooked semantic equivalence; -parsing is simple-minded, and comparison of SQL abstract syntax trees -ignores commutativity or associativity of AND/OR operators, Morgan -laws, etc. +B : the semantic equivalence handling is pretty limited. +A lot of effort goes into distinguishing significant from +non-significant parenthesis, including AND/OR operator associativity. +Currently this module does not support commutativity and more +intelligent transformations like Morgan laws, etc. + +For a good overview of what this test framework is capable of refer +to C =head1 FUNCTIONS