diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 0bdead858..464d7bdda 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -7966,7 +7966,7 @@ ExpressionList SimpleExpressionList(): ( LOOKAHEAD(2, {!interrupted} ) "," ( - LOOKAHEAD( 7 ) expr=LambdaExpression() + LOOKAHEAD( RelObjectName() "->" ) expr=LambdaExpression() | expr=SimpleExpression() ) @@ -8029,7 +8029,7 @@ ExpressionList ComplexExpressionList(): | LOOKAHEAD(2) expr=PostgresNamedFunctionParameter() | - LOOKAHEAD(7) expr=LambdaExpression() + LOOKAHEAD( RelObjectName() "->" ) expr=LambdaExpression() | expr=Expression() ) { expressions.add(expr); } diff --git a/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java index 4dcc4c6e1..bd6a0fcd8 100644 --- a/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; @@ -20,7 +21,10 @@ class LambdaExpressionTest { @Test void testLambdaFunctionSingleParameter() throws JSQLParserException { String sqlStr = "select list_transform( split('test', ''), x -> unicode(x) )"; - TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Select select = assertInstanceOf( + Select.class, TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true)); + Function function = select.getPlainSelect().getSelectItem(0).getExpression(Function.class); + assertInstanceOf(LambdaExpression.class, function.getParameters().get(1)); } @Test @@ -52,4 +56,15 @@ void testLambdaFirstArgumentIssue2195() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void testLambdaFunctionFourParameters() throws JSQLParserException { + String sqlStr = "SELECT list_transform([1], (a, b, c, d) -> a)"; + Select select = assertInstanceOf( + Select.class, TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true)); + Function function = select.getPlainSelect().getSelectItem(0).getExpression(Function.class); + LambdaExpression lambda = + assertInstanceOf(LambdaExpression.class, function.getParameters().get(1)); + assertEquals(4, lambda.getIdentifiers().size()); + } + } 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 a385e17bb..bb3fa0656 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -43,6 +43,7 @@ import net.sf.jsqlparser.expression.IntervalExpression; import net.sf.jsqlparser.expression.JdbcNamedParameter; import net.sf.jsqlparser.expression.JdbcParameter; +import net.sf.jsqlparser.expression.JsonExpression; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.NotExpression; import net.sf.jsqlparser.expression.NullValue; @@ -60,6 +61,7 @@ import net.sf.jsqlparser.expression.operators.relational.GreaterThan; import net.sf.jsqlparser.expression.operators.relational.InExpression; import net.sf.jsqlparser.expression.operators.relational.LikeExpression; +import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.parser.CCJSqlParserUtil; @@ -1375,6 +1377,47 @@ public void testGroupBy() throws JSQLParserException { assertStatementCanBeDeparsedAs(select, statement); } + @Test + public void testIssue2485OracleParenthesizedFullyQualifiedGroupByColumn() + throws JSQLParserException { + String sql = "SELECT sys.dual.dummy, count(*)\n" + + "FROM sys.dual\n" + + "GROUP BY (sys.dual.dummy), (sys.dual.dummy)"; + + Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true); + Select select = assertInstanceOf(Select.class, statement); + PlainSelect plainSelect = select.getPlainSelect(); + assertNotNull(plainSelect.getGroupBy()); + + ExpressionList groupByExpressions = plainSelect.getGroupBy() + .getGroupByExpressionList(); + assertEquals(2, groupByExpressions.size()); + for (Expression groupByExpression : groupByExpressions) { + ParenthesedExpressionList parenthesedExpression = assertInstanceOf( + ParenthesedExpressionList.class, groupByExpression); + Column column = assertInstanceOf(Column.class, parenthesedExpression.get(0)); + assertEquals("sys.dual.dummy", column.getFullyQualifiedName()); + } + } + + @Test + public void testIssue2485OracleParenthesizedFourPartGroupByColumn() + throws JSQLParserException { + String sql = "SELECT 1\n" + + "FROM sys.dual\n" + + "GROUP BY sys.dual.dummy, (catalog.sys.dual.dummy)"; + + Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true); + Select select = assertInstanceOf(Select.class, statement); + ExpressionList groupByExpressions = select.getPlainSelect().getGroupBy() + .getGroupByExpressionList(); + assertEquals(2, groupByExpressions.size()); + ParenthesedExpressionList parenthesedExpression = assertInstanceOf( + ParenthesedExpressionList.class, groupByExpressions.get(1)); + Column column = assertInstanceOf(Column.class, parenthesedExpression.get(0)); + assertEquals("catalog.sys.dual.dummy", column.getFullyQualifiedName()); + } + @Test public void testHaving() throws JSQLParserException { String statement = @@ -3205,6 +3248,13 @@ public void testJsonExpression() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( "SELECT json_typeof(sale->'items'), json_typeof(sale->'items'->'quantity') FROM sales"); + Select jsonSelect = (Select) CCJSqlParserUtil.parse("SELECT data->'images' FROM instagram"); + assertInstanceOf(JsonExpression.class, + jsonSelect.getPlainSelect().getSelectItem(0).getExpression()); + jsonSelect = (Select) CCJSqlParserUtil.parse("SELECT data->>'images' FROM instagram"); + assertInstanceOf(JsonExpression.class, + jsonSelect.getPlainSelect().getSelectItem(0).getExpression()); + // The following staments can be parsed but not deparsed for (String statement : new String[] { "SELECT doc->'site_name' FROM websites WHERE doc @> '{\"tags\":[{\"term\":\"paris\"}, {\"term\":\"food\"}]}'",