diff --git a/src/main/java/net/sf/jsqlparser/expression/Function.java b/src/main/java/net/sf/jsqlparser/expression/Function.java index db921f339..8ea50c19d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/Function.java +++ b/src/main/java/net/sf/jsqlparser/expression/Function.java @@ -52,6 +52,11 @@ public void setName(String string) { nameparts = Arrays.asList(string); } + public Function withName(String name) { + this.setName(name); + return this; + } + public void setName(List string) { nameparts = string; } diff --git a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java index 0e52b8b36..ca0874c19 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java @@ -120,7 +120,7 @@ public static Expression parseExpression(String expression, boolean allowPartial consumer.accept(parser); } try { - Expression expr = parser.SimpleExpression(); + Expression expr = parser.Expression(); if (!allowPartialParse && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { throw new JSQLParserException("could only parse partial expression " + expr.toString()); } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 673b29926..d338c6e31 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -382,6 +382,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -1519,6 +1520,7 @@ String RelObjectNameWithoutValue() : /*| tk= | tk= | tk= | tk= */ | tk= | tk= | tk= | tk= | tk= | tk= + | tk= | tk= /* Keywords for ALTER SESSION */ @@ -1536,7 +1538,7 @@ String RelObjectName() : { (result = RelObjectNameWithoutValue() | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk= | tk= | tk= ) + | tk= | tk= | tk= ) { if (tk!=null) result=tk.image; @@ -1566,7 +1568,7 @@ String RelObjectNameExt(): { ( result=RelObjectName() | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk= | tk= | tk= + | tk= | tk= | tk= | tk= | tk= ) { if (tk!=null) result=tk.image; @@ -4282,6 +4284,7 @@ Function Function() #Function: { ( "{" { retval.setEscaped(true); } InternalFunction(retval) "}" + | LOOKAHEAD(3) retval = SpecialStringFunctionWithNamedParameters() | InternalFunction(retval) ) { @@ -4290,6 +4293,33 @@ Function Function() #Function: } } +Function SpecialStringFunctionWithNamedParameters() : +{ + Token funcName; + NamedExpressionList namedExpressionList = null; + ExpressionList expressionList = null; + List orderByList; +} +{ + funcName = + + "(" + ( + LOOKAHEAD(NamedExpressionList1()) namedExpressionList=NamedExpressionList1() + | + LOOKAHEAD(NamedExpressionListExprFirst(), { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() + | + LOOKAHEAD(3, { getAsBoolean(Feature.allowComplexParsing) }) expressionList=ComplexExpressionList() {expressionList.setUsingBrackets(false);} + | + LOOKAHEAD(3) expressionList=SimpleExpressionList(false) + ) + ")" + + { + return new Function().withName(funcName.image).withNamedParameters(namedExpressionList).withParameters(expressionList); + } +} + Function InternalFunction(Function retval) : { List funcName; @@ -4312,10 +4342,6 @@ Function InternalFunction(Function retval) : ( LOOKAHEAD(4) "*" { retval.setAllColumns(true); } | - LOOKAHEAD(NamedExpressionList1()) namedExpressionList=NamedExpressionList1() - | - LOOKAHEAD(NamedExpressionListExprFirst(), { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() - | LOOKAHEAD(3, { getAsBoolean(Feature.allowComplexParsing) }) (expressionList=ComplexExpressionList() {expressionList.setUsingBrackets(false);} [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ]) | LOOKAHEAD(3) (expressionList=SimpleExpressionList(false) [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ]) @@ -4324,7 +4350,7 @@ Function InternalFunction(Function retval) : )] [ {retval.setIgnoreNulls(true); }] - ")" + ")" [ "." ( LOOKAHEAD(2) expr1=Function() { retval.setAttribute(expr1); } @@ -4336,7 +4362,6 @@ Function InternalFunction(Function retval) : { retval.setParameters(expressionList); - retval.setNamedParameters(namedExpressionList); retval.setName(funcName); retval.setKeep(keep); return retval; diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java index 696e4a162..350404464 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -4664,4 +4664,20 @@ public void testDB2SpecialRegisterDateTimeIssue1249() throws JSQLParserException public void testKeywordFilterIssue1255() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT col1 AS filter FROM table"); } + + @Test + public void testCollisionWithSpecialStringFunctionsIssue1284() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "SELECT test( a in (1) AND 2=2) ", true); + + assertSqlCanBeParsedAndDeparsed( + "select\n" + + "sum(if(column1 in('value1', 'value2'), 1, 0)) as tcp_logs,\n" + + "sum(if(column1 in ('value1', 'value2') and column2 = 'value3', 1, 0)) as base_tcp_logs\n" + + "from\n" + + "table1\n" + + "where\n" + + "recv_time >= toDateTime('2021-07-20 00:00:00')\n" + + "and recv_time < toDateTime('2021-07-21 00:00:00')", true); + } }