diff --git a/CHANGELOG.md b/CHANGELOG.md index 3221774..04994cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # apex-parser - Changelog +## Unreleased + +- Restrict SOQL `FORMULA()` expressions to `WHERE` clauses; `HAVING FORMULA(...)` now reports a syntax error. + ## 5.1.0-beta.1 - Allow functions in `GROUP BY` clause of SOQL queries diff --git a/antlr/BaseApexParser.g4 b/antlr/BaseApexParser.g4 index 6c6c205..03bc5d2 100644 --- a/antlr/BaseApexParser.g4 +++ b/antlr/BaseApexParser.g4 @@ -693,7 +693,20 @@ usingScope : USING SCOPE soqlId; whereClause - : WHERE logicalExpression; + : WHERE whereLogicalExpression; + +whereLogicalExpression + : whereConditionalExpression (SOQLAND whereConditionalExpression)* + | whereConditionalExpression (SOQLOR whereConditionalExpression)* + | NOT whereConditionalExpression; + +whereConditionalExpression + : LPAREN whereLogicalExpression RPAREN + | whereFieldExpression; + +whereFieldExpression + : fieldExpression + | FORMULA LPAREN StringLiteral RPAREN comparisonOperator value; logicalExpression : conditionalExpression (SOQLAND conditionalExpression)* @@ -706,8 +719,7 @@ conditionalExpression fieldExpression : fieldName comparisonOperator value - | soqlFunction comparisonOperator value - | FORMULA LPAREN StringLiteral RPAREN comparisonOperator value; + | soqlFunction comparisonOperator value; comparisonOperator : ASSIGN | NOTEQUAL | LT | GT | LT ASSIGN | GT ASSIGN | LESSANDGREATER | LIKE | IN | NOT IN | INCLUDES | EXCLUDES; diff --git a/jvm/src/test/java/io/github/apexdevtools/apexparser/SOQLParserTest.java b/jvm/src/test/java/io/github/apexdevtools/apexparser/SOQLParserTest.java index b2cb3da..efbcb8e 100644 --- a/jvm/src/test/java/io/github/apexdevtools/apexparser/SOQLParserTest.java +++ b/jvm/src/test/java/io/github/apexdevtools/apexparser/SOQLParserTest.java @@ -250,4 +250,14 @@ void testFormulaFunctionWithEscapedQuotes() { assertNotNull(context); assertEquals(0, parserAndCounter.getValue().getNumErrors()); } + + @Test + void testFormulaFunctionNotAllowedInHaving() { + Map.Entry parserAndCounter = createParser( + "SELECT Name FROM Account GROUP BY Name HAVING FORMULA('1+1') = 2" + ); + ApexParser.QueryContext context = parserAndCounter.getKey().query(); + assertNotNull(context); + assertTrue(parserAndCounter.getValue().getNumErrors() > 0); + } } diff --git a/npm/test/SOQLParserTest.ts b/npm/test/SOQLParserTest.ts index fa28ea8..3b89fbb 100644 --- a/npm/test/SOQLParserTest.ts +++ b/npm/test/SOQLParserTest.ts @@ -244,3 +244,14 @@ test("testFormulaFunctionWithEscapedQuotes", () => { expect(context).toBeInstanceOf(QueryContext); expect(errorCounter.getNumErrors()).toEqual(0); }); + +test("testFormulaFunctionNotAllowedInHaving", () => { + const [parser, errorCounter] = createParser( + "SELECT Name FROM Account GROUP BY Name HAVING FORMULA('1+1') = 2" + ); + + const context = parser.query(); + + expect(context).toBeInstanceOf(QueryContext); + expect(errorCounter.getNumErrors()).toBeGreaterThan(0); +});