From 7553a694358ff9a5bc24b1239be864897be6956a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 13 Feb 2022 00:57:17 +0100 Subject: [PATCH 1/2] Fix #3746 - Parsing exception "Less than or equal to/Greater than or equal to" operators in DML statements --- pmd-plsql/etc/grammar/PldocAST.jjt | 91 +++++++++++++------ .../pmd/lang/plsql/PLSQLParser.java | 1 + .../pmd/lang/plsql/ast/PLSQLParserTest.java | 6 ++ .../lang/plsql/ast/RelationalOperators.pls | 18 ++++ 4 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RelationalOperators.pls diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 3c5656c028..14e42bacdd 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -257,6 +257,34 @@ TOKEN_MGR_DECLS : { List exclusions = new ArrayList(); } +// add names to SINGLE CHARACTER tokens +// multiple character operators are sequences of tokens. +TOKEN: { + < LPAREN: "(" > +| < RPAREN: ")" > +| < LBRACE: "{" > +| < RBRACE: "}" > +| < LBRACKET: "[" > +| < RBRACKET: "]" > +| < SEMICOLON: ";" > +| < COMMA: "," > +| < DOT: "." > +| < AROBASE: "@" > +| < ASSIGN: "=" > +| < LT: "<" > +| < BANG: "!" > +| < TILDE: "~" > +| < HOOK: "?" > +| < COLON: ":" > +| < PLUSSIGN: "+" > +| < MINUSSIGN: "-" > +| < STAR: "*" > +| < SLASH: "/" > +| < BIT_AND: "&" > +| < BIT_OR: "|" > +| < XOR: "^" > +| < REM: "%" > +} /** * 2006-05-22 - Matthias Hendler - Added parsing of triggers and global functions/procedures @@ -1603,18 +1631,26 @@ ASTInCondition InCondition() : { return jjtThis; } } -ASTComparisonCondition ComparisonCondition() : +private String ComparisonOp() #void : {} { - ( - // SimpleComparisonCondition - LOOKAHEAD(3) (SqlExpression() ( "=" | "!=" | "^=" | "<>" | ">" | "<" | ">=" | "<=" ) { jjtThis.setOperator(token.getImage()); } SqlExpression() ) - | LOOKAHEAD(3) ( "(" SqlExpression() ("," SqlExpression())* ")" ( "=" | "!=" | "^=" | "<>" ) { jjtThis.setOperator(token.getImage()); } "(" ( LOOKAHEAD(3) ExpressionList() | LOOKAHEAD(3) Subquery() ) ")" ) + "=" {return "=";} + | "!" "=" {return "!=";} + | "^" "=" {return "^=";} + | "<" ( "=" {return "<=";} | ">" {return "<>";} )? {return "<";} + | ">" ( "=" {return ">=";} )? {return ">";} +} - // GroupComparisonCondition - | LOOKAHEAD(3) (SqlExpression() ( "=" | "!=" | "^=" | "<>" | ">" | "<" | ">=" | "<=" ) { jjtThis.setOperator(token.getImage()); } ( | | ) "(" ( LOOKAHEAD(3) ExpressionListSingle() | LOOKAHEAD(3) Subquery() ) ")" ) - | LOOKAHEAD(3) ( "(" SqlExpression() ("," SqlExpression())* ")" ( "=" | "!=" | "^=" | "<>" ) { jjtThis.setOperator(token.getImage()); } ( | | ) "(" ( LOOKAHEAD(3) ExpressionListMultiple() ("," ExpressionListMultiple())* | LOOKAHEAD(3) Subquery() ) ")" ) - ) +ASTComparisonCondition ComparisonCondition() : +{String op;} +{ + (LOOKAHEAD(3) SqlExpression() | ExpressionListMultiple() ) + op=ComparisonOp() { jjtThis.setOperator(op); } + ( | | )? + (LOOKAHEAD(3) "(" Subquery() ")" + |LOOKAHEAD(3) "(" ExpressionListSingle() ")" + |LOOKAHEAD(3) "(" ExpressionListMultiple() ("," ExpressionListMultiple())* ")" + |LOOKAHEAD(3) SqlExpression()) { return jjtThis; } } @@ -3179,17 +3215,17 @@ ASTEqualityExpression EqualityExpression() #EqualityExpression(>1) : { //RelationalExpression() ( ( "=" | "!=" | "<>" | ) RelationalExpression() )* ( + + simpleNode=RelationalExpression() + {sb.append(simpleNode.getImage());} ( - simpleNode = RelationalExpression() - ) {sb.append(simpleNode.getImage());} - ( - ( ("=" ) {sb.append(" = ");} - | ("!" "=" ) {sb.append(" != ");} + ( "=" {sb.append(" = ");} + | "!" "=" {sb.append(" != ");} // Now unde RelationalExpression | ("<" ">" ) {sb.append(" <> ");} - | () {sb.append(" IS ");}) - ( - simpleNode = RelationalExpression() - ) {sb.append(simpleNode.getImage());} + | {sb.append(" IS ");} + ) + simpleNode=RelationalExpression() + {sb.append(simpleNode.getImage());} )* ) { @@ -3209,17 +3245,16 @@ ASTRelationalExpression RelationalExpression() #RelationalExpression(>1) : ( ( - ( - ("<>" { sb.append(" <> "); } ) - | ("<=" { sb.append(" <= "); } ) - | (">=" { sb.append(" >= "); } ) - | ("!=" { sb.append(" != "); } ) - | ("~=" { sb.append(" ~= "); } ) - | ("^=" { sb.append(" ^= "); } ) - | ("<" { sb.append(" < "); } ) - | (">" { sb.append(" > "); } ) + ( LOOKAHEAD(2) "<" ">" { sb.append(" <> "); } + |LOOKAHEAD(2) "<" "=" { sb.append(" <= "); } + |LOOKAHEAD(2) ">" "=" { sb.append(" >= "); } + // then lookahead(1) is enough + | "<" { sb.append(" < "); } + | ">" { sb.append(" > "); } + | "!" "=" { sb.append(" != "); } + | "~" "=" { sb.append(" ~= "); } + | "^" "=" { sb.append(" ^= "); } ) - { sb.append(" "); } | [() { sb.append(" NOT "); }] ( diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLParser.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLParser.java index 4dac5fa4ea..4466d61480 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLParser.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/PLSQLParser.java @@ -69,3 +69,4 @@ public class PLSQLParser extends AbstractParser { return new HashMap<>(); // FIXME } } + diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserTest.java index 52d71e2bcc..25d7bfca55 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserTest.java @@ -74,6 +74,12 @@ public class PLSQLParserTest extends AbstractPLSQLParserTst { plsql.parseResource("CaseIssue1454.pls"); } + @Test + public void testRelationalOperators() { + // https://github.com/pmd/pmd/issues/3746 + plsql.parseResource("RelationalOperators.pls"); + } + @Test public void testExecuteImmediateIssue3106() { plsql.parseResource("ExecuteImmediateIssue3106.pls"); diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RelationalOperators.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RelationalOperators.pls new file mode 100644 index 0000000000..804d513111 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RelationalOperators.pls @@ -0,0 +1,18 @@ +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + l_total_objects NUMBER(10); + -- +BEGIN + -- + SELECT COUNT(1) + INTO l_total_objects + FROM USER_OBJECTS + WHERE namespace < = 1 + OR namespace > = 0 + OR namespace > + = 0 + ; + -- + DBMS_OUTPUT.Put_Line('Total number of objects: ' || l_total_objects); + -- +END EXAMPLE_PROCEDURE; From 9d349dbcc7b2623e38e8f3fcf68095846186cc41 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 19 Feb 2022 09:58:47 +0100 Subject: [PATCH 2/2] [doc] Update release notes (#3746 #3783) --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index dab590463f..e7a9637636 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -18,6 +18,8 @@ This is a {{ site.pmd.release_type }} release. * misc * [#3759](https://github.com/pmd/pmd/issues/3759): \[lang-test] Upgrade dokka maven plugin to 1.4.32 +* plsql + * [#3746](https://github.com/pmd/pmd/issues/3746): \[plsql] Parsing exception "Less than or equal to/Greater than or equal to" operators in DML statements ### API Changes