diff --git a/settings.gradle b/settings.gradle index 523623eb1..78feb00f5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,4 +2,4 @@ * This file was generated by the Gradle 'init' task. */ -rootProject.name = 'jsqlparser' +rootProject.name = 'JSQLFormatter' diff --git a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java index cae3d07fe..31e7915d6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java @@ -75,6 +75,7 @@ public AnalyticExpression(Function function) { } } this.havingClause = function.getHavingClause(); + this.ignoreNullsOutside = function.isIgnoreNullsOutside(); this.nullHandling = function.getNullHandling(); this.funcOrderBy = function.getOrderByElements(); this.limit = function.getLimit(); diff --git a/src/main/java/net/sf/jsqlparser/expression/Function.java b/src/main/java/net/sf/jsqlparser/expression/Function.java index 6f1f24d21..7510c4e0e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/Function.java +++ b/src/main/java/net/sf/jsqlparser/expression/Function.java @@ -86,6 +86,7 @@ public String toString() { private Column attributeColumn = null; private List orderByElements; private NullHandling nullHandling = null; + private boolean ignoreNullsOutside = false; // IGNORE NULLS outside function parameters private Limit limit = null; private KeepExpression keep = null; @@ -148,6 +149,15 @@ public Function setNullHandling(NullHandling nullHandling) { return this; } + public boolean isIgnoreNullsOutside() { + return ignoreNullsOutside; + } + + public Function setIgnoreNullsOutside(boolean ignoreNullsOutside) { + this.ignoreNullsOutside = ignoreNullsOutside; + return this; + } + public Limit getLimit() { return limit; } @@ -321,7 +331,7 @@ public String toString() { havingClause.appendTo(b); } - if (nullHandling != null) { + if (nullHandling != null && !isIgnoreNullsOutside()) { switch (nullHandling) { case IGNORE_NULLS: b.append(" IGNORE NULLS"); @@ -357,6 +367,17 @@ public String toString() { String ans = getName() + params; + if (nullHandling != null && isIgnoreNullsOutside()) { + switch (nullHandling) { + case IGNORE_NULLS: + ans += " IGNORE NULLS"; + break; + case RESPECT_NULLS: + ans += " RESPECT NULLS"; + break; + } + } + if (attributeExpression != null) { ans += "." + attributeExpression; } else if (attributeColumn != null) { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Values.java b/src/main/java/net/sf/jsqlparser/statement/select/Values.java index dfce8506d..4ab2c95da 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Values.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Values.java @@ -20,15 +20,21 @@ public class Values extends Select implements FromItem { private ExpressionList expressions; + private Alias alias; public Values() { - // empty constructor + this(null, null); } public Values(ExpressionList expressions) { this.expressions = expressions; } + public Values(ExpressionList expressions, Alias alias) { + this.expressions = expressions; + this.alias = alias; + } + public ExpressionList getExpressions() { return expressions; } @@ -42,6 +48,9 @@ public void setExpressions(ExpressionList expressions) { public StringBuilder appendSelectBodyTo(StringBuilder builder) { builder.append("VALUES "); builder.append(expressions.toString()); + if (alias != null) { + builder.append(" ").append(alias); + } return builder; } @@ -74,12 +83,12 @@ public void accept(FromItemVisitor fromItemVisitor) { @Override public Alias getAlias() { - return null; + return alias; } @Override public void setAlias(Alias alias) { - + this.alias = alias; } @Override diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 310e7a56c..a12ddb2ac 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -613,7 +613,7 @@ public void visit(Function function) { havingClause.getExpression().accept(this); } - if (function.getNullHandling() != null) { + if (function.getNullHandling() != null && !function.isIgnoreNullsOutside()) { switch (function.getNullHandling()) { case IGNORE_NULLS: buffer.append(" IGNORE NULLS"); @@ -643,6 +643,17 @@ public void visit(Function function) { buffer.append(")"); } + if (function.getNullHandling() != null && function.isIgnoreNullsOutside()) { + switch (function.getNullHandling()) { + case IGNORE_NULLS: + buffer.append(" IGNORE NULLS"); + break; + case RESPECT_NULLS: + buffer.append(" RESPECT NULLS"); + break; + } + } + if (function.getAttribute() != null) { buffer.append(".").append(function.getAttribute()); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java index 233ec71c3..028c8bea1 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java @@ -25,5 +25,8 @@ public ValuesStatementDeParser(ExpressionVisitor expressionVisitor, StringBuilde public void deParse(Values values) { buffer.append("VALUES "); values.getExpressions().accept(expressionVisitor); + if (values.getAlias() != null) { + buffer.append(" ").append(values.getAlias()); + } } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index b9d2e5c9c..5c7841a21 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5086,16 +5086,6 @@ void windowFun(AnalyticExpression retval):{ WindowDefinition winDef; } { ( - [ - ( - { retval.setNullHandling(Function.NullHandling.IGNORE_NULLS); retval.setIgnoreNullsOutside(true); } - ) - | - ( - { retval.setNullHandling(Function.NullHandling.RESPECT_NULLS); retval.setIgnoreNullsOutside(true); } - ) - ] - {retval.setType(AnalyticType.OVER);} | {retval.setType(AnalyticType.WITHIN_GROUP);} @@ -5146,8 +5136,13 @@ AnalyticExpression AnalyticExpression(Function function) : Expression filter = null; } { - (( "(" {retval.setType(AnalyticType.FILTER_ONLY);} filter = Expression() ")" [ LOOKAHEAD(2) windowFun(retval) ] ) - | windowFun(retval)) + ( + ( + "(" {retval.setType(AnalyticType.FILTER_ONLY);} filter = Expression() ")" + [ LOOKAHEAD(2) windowFun(retval) ] + ) + | windowFun(retval) + ) { retval.setFilterExpression(filter); return retval; @@ -5610,6 +5605,7 @@ Function InternalFunction(boolean escaped): ")" + [ "." ( // tricky lookahead since we do need to support the following constructs // schema.f1().f2() - Function with Function Column @@ -5620,6 +5616,24 @@ Function InternalFunction(boolean escaped): ) ] + [ + ( + + { + retval.setNullHandling(Function.NullHandling.IGNORE_NULLS); + retval.setIgnoreNullsOutside(true); + } + ) + | + ( + + { + retval.setNullHandling(Function.NullHandling.RESPECT_NULLS); + retval.setIgnoreNullsOutside(true); + } + ) + ] + [ LOOKAHEAD(2) keep = KeepExpression() ] { diff --git a/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java index 48e4fe44d..df4ef1eba 100644 --- a/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java @@ -32,4 +32,15 @@ void testRedshiftApproximate() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testDatabricks() throws JSQLParserException { + String sqlStr = "SELECT any_value(col) IGNORE NULLS FROM test;"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + sqlStr = "SELECT any_value(col) IGNORE NULLS FROM VALUES (NULL), (5), (20) AS tab(col);"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query04.sql index f0b32e881..718264dfb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query04.sql @@ -14,4 +14,5 @@ select deptno from emp --@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:23 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:23 AM +--@FAILURE: Encountered unexpected token: "group" "GROUP" recorded first on May 27, 2024, 9:38:25 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query05.sql index 6b4f671ae..cca31f24b 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query05.sql @@ -26,4 +26,5 @@ --@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:22 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:22 AM +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on May 27, 2024, 9:38:28 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query08.sql index cf7820674..8f785038f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query08.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query08.sql @@ -12,4 +12,5 @@ select manager_id, last_name, hire_date, range numtodsinterval(100, 'day') preceding) as t_count from employees ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on May 27, 2024, 9:38:27 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql index b60a7eef1..f4ba295ab 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql @@ -21,4 +21,5 @@ from ) ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "group" "GROUP" recorded first on May 27, 2024, 9:38:28 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query10.sql index 51c48bf92..58792ad38 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query10.sql @@ -20,4 +20,5 @@ SELECT STALENESS, FROM A ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on May 27, 2024, 9:38:27 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when01.sql index 8a8a5bb81..9700f405e 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when01.sql @@ -17,4 +17,5 @@ from T ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "over" "OVER" recorded first on May 27, 2024, 9:38:27 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when04.sql index 677909b77..60562775c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when04.sql @@ -11,4 +11,5 @@ select case when row_number() over (partition by bo# order by staleness, osize, obj#) = 1 then 32 else 0 end + 64 aflags from f ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "over" "OVER" recorded first on May 27, 2024, 9:38:27 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when05.sql index f0dfdfa9b..55937d1cb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/case_when05.sql @@ -20,4 +20,5 @@ select staleness , part#, bo# from st0 ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "over" "OVER" recorded first on May 27, 2024, 9:38:28 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql index e9e35ce56..51162295d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql @@ -31,4 +31,5 @@ level4[any] = case when org_level[cv()] = 4 then ename [cv()] end ))) --@FAILURE: Encountered unexpected token: "return" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:44 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:44 +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on May 27, 2024, 9:38:28 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql index f17f8247c..48a925c34 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql @@ -38,4 +38,5 @@ select spf.*, nvl(a, ddr_a) as a, b, d, ) ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on May 27, 2024, 9:38:28 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql index bd3934e5a..7ed2c571e 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql @@ -87,4 +87,5 @@ select ) --@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:23 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:23 AM +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on May 27, 2024, 9:38:28 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql index 47f09e09c..6f0e277ae 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql @@ -51,4 +51,5 @@ select * from ( ) where rownum_ >= ? ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on May 27, 2024, 9:38:27 AM \ No newline at end of file