From 1cf1dfc96bf281e16f564a976078ed23f9bac862 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 1 Dec 2018 21:35:27 +0100 Subject: [PATCH] [plsql] ParseException for IF/CASE statement with >=, <=, != Fixes #1454 --- docs/pages/release_notes.md | 2 + pmd-plsql/etc/grammar/PldocAST.jjt | 97 +++++++++++-------- .../pmd/lang/plsql/PLSQLParserTest.java | 5 + .../pmd/lang/plsql/ast/CaseIssue1454.pls | 31 ++++++ 4 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CaseIssue1454.pls diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 689b1e48d4..20493f93d9 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -48,6 +48,8 @@ This means, you can use CPD to find duplicated code in your Kotlin projects. * [#1440](https://github.com/pmd/pmd/issues/1440): \[java] CommentDefaultAccessModifierRule shows incorrect message * java-design * [#1483](https://github.com/pmd/pmd/issues/1483): \[java] Cyclo metric should count conditions of for statements correctly +* plsql + * [#1454](https://github.com/pmd/pmd/issues/1454): \[plsql] ParseException for IF/CASE statement with >=, <=, != ### API Changes diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index cac0995006..d6d82ae949 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -2494,57 +2494,68 @@ ASTEqualityExpression EqualityExpression() #EqualityExpression(>1) : } } +/** + * Relational operators: https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-language-fundamentals.html#GUID-2EB964C8-9B36-4009-A45F-B340F44EE2A2 + */ ASTRelationalExpression RelationalExpression() #RelationalExpression(>1) : { PLSQLNode simpleNode = null; StringBuilder sb = new StringBuilder() ; } { ( //AdditiveExpression() ( ( "<" | ">" | "<=" | ">=" | [] ( | | ) ) AdditiveExpression() )* - (simpleNode = AdditiveExpression() ) { sb.append(simpleNode.getImage()); } - ( - ( + ( simpleNode = AdditiveExpression() ) { sb.append(simpleNode.getImage()); } + ( + ( + ( - ( - (("<" ) { sb.append("<"); } - [">" { sb.append(">"); } ] // <> - ) - | (">" ) { sb.append(">"); } - ) - [ ("=" ) { sb.append("="); } ] - + ("<>" { sb.append(" <> "); } ) + | ("<=" { sb.append(" <= "); } ) + | (">=" { sb.append(" >= "); } ) + | ("!=" { sb.append(" != "); } ) + | ("~=" { sb.append(" ~= "); } ) + | ("^=" { sb.append(" ^= "); } ) + | ("<" { sb.append(" < "); } ) + | (">" { sb.append(" > "); } ) ) + { sb.append(" "); } - | [() { sb.append(" NOT "); }] - (() { sb.append(" IN "); } - | ( ) { sb.append(" BETWEEN "); } - | ( ) { sb.append(" LIKE "); } - | ( - ( - () { sb.append(" MEMBER "); } - | - () { sb.append(" SUBMULTISET "); } - ) - [ { sb.append(" OF "); } ] - ) - ) - // MULTISET Operators - | ( - { sb.append (" MULTISET " );} - ( { sb.append (" EXCEPT " );} - | { sb.append (" INTERSECT " );} - | { sb.append (" UNION " ); } - ) - [ { sb.append (" DISTINCT " );} - | { sb.append (" ALL " );} - ] - ) - ) - (AdditiveExpression() ) { sb.append(simpleNode.getImage()); } - [ - { sb.append(" ESCAPE ");} - ( { sb.append(" "); sb.append(token.toString()); } - | simpleNode = StringLiteral() { sb.append(" "); sb.append(simpleNode.getImage()); } - ) - ] + | [() { sb.append(" NOT "); }] + ( + () { sb.append(" IN "); } + | ( ) { sb.append(" BETWEEN "); } + | ( ) { sb.append(" LIKE "); } + | + ( + ( + () { sb.append(" MEMBER "); } + | + () { sb.append(" SUBMULTISET "); } + ) + [ { sb.append(" OF "); } ] + ) + ) + // MULTISET Operators + | + ( + { sb.append (" MULTISET " );} + ( + { sb.append (" EXCEPT " );} + | { sb.append (" INTERSECT " );} + | { sb.append (" UNION " ); } + ) + [ + { sb.append (" DISTINCT " );} + | { sb.append (" ALL " );} + ] + ) + ) + ( AdditiveExpression() ) { sb.append(simpleNode.getImage()); } + [ + { sb.append(" ESCAPE ");} + ( + { sb.append(" "); sb.append(token.toString()); } + | simpleNode = StringLiteral() { sb.append(" "); sb.append(simpleNode.getImage()); } + ) + ] )* ) { diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java index f1568e199b..afa641c06c 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/PLSQLParserTest.java @@ -69,4 +69,9 @@ public class PLSQLParserTest extends AbstractPLSQLParserTst { public void testCodingStyleExample() throws Exception { parsePLSQL(IOUtils.toString(PLSQLParserTest.class.getResourceAsStream("ast/CodingStyleExample.pls"), StandardCharsets.UTF_8)); } + + @Test + public void testCaseIssue1454() throws Exception { + parsePLSQL(IOUtils.toString(PLSQLParserTest.class.getResourceAsStream("ast/CaseIssue1454.pls"), StandardCharsets.UTF_8)); + } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CaseIssue1454.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CaseIssue1454.pls new file mode 100644 index 0000000000..e4e7a4bd11 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CaseIssue1454.pls @@ -0,0 +1,31 @@ +create or replace procedure PMD_TEST_CASE( a IN NUMBER) AS + +begin + + CASE WHEN a >= 100 THEN -- Test the same with <=,!=,<> all cases fail both with IF and CASE statements + dbms_output.put_line('Number is greater than equal to 100'); + WHEN a <= 100 THEN + dbms_output.put_line('Number is less than equal to 100'); + WHEN a < 100 THEN + dbms_output.put_line('Number is less than 100'); + WHEN a > 100 THEN + dbms_output.put_line('Number is greater than 100'); + WHEN a = 42 THEN + dbms_output.put_line('Number is equal to 42'); + WHEN a != 42 THEN + dbms_output.put_line('Number is not 42'); + WHEN a ~= 42 THEN + dbms_output.put_line('Number is not 42'); + WHEN a ^= 42 THEN + dbms_output.put_line('Number is not 42'); + WHEN a <> 42 THEN + dbms_output.put_line('Number is not 42'); + ELSE + dbms_output.put_line('Number is less than 100'); + END CASE; + +exception + when others then + dbms_output.put_line('ERROR: ' || sqlerrm); + +end PMD_TEST_CASE;