diff --git a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java index 4cc9c25c9..15c4f17c5 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java @@ -95,7 +95,14 @@ public String toString() { if (groupByExpressions.isUsingBrackets()) { b.append(" )"); } - } else if (groupingSets.size() > 0) { + } else if (groupByExpressions.isUsingBrackets()) { + b.append("()"); + } + + if (groupingSets.size() > 0) { + if (b.charAt(b.length() - 1) != ' ') { + b.append(' '); + } b.append("GROUPING SETS ("); boolean first = true; for (Object o : groupingSets) { @@ -112,10 +119,6 @@ public String toString() { } } b.append(")"); - } else { - if (groupByExpressions.isUsingBrackets()) { - b.append("()"); - } } return b.toString(); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java index d39a1d934..839ae1adb 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java @@ -51,6 +51,9 @@ public void deParse(GroupByElement groupBy) { buffer.append(" )"); } if (!groupBy.getGroupingSets().isEmpty()) { + if (buffer.charAt(buffer.length() - 1) != ' ') { + buffer.append(' '); + } buffer.append("GROUPING SETS ("); boolean first = true; for (Object o : groupBy.getGroupingSets()) { diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index c2da5b3ab..fa74535e6 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2734,6 +2734,19 @@ GroupByElement GroupByColumnReferences(): ( LOOKAHEAD(2) ( "(" ")" { groupBy.withUsingBrackets(true); } + ( + LOOKAHEAD(2) ( + "(" + ( LOOKAHEAD(2) "(" ")" { groupBy.addGroupingSet(new ExpressionList()); } + | LOOKAHEAD(3) "(" list = SimpleExpressionList(true) ")" { groupBy.addGroupingSet(list); } + | expr = SimpleExpression() { groupBy.addGroupingSet(expr); } ) + + ( "," ( LOOKAHEAD(2) "(" ")" { groupBy.addGroupingSet(new ExpressionList()); } + | LOOKAHEAD(3) "(" list = SimpleExpressionList(true) ")" { groupBy.addGroupingSet(list); } + | expr = SimpleExpression() { groupBy.addGroupingSet(expr); } ) )* + ")" + ) + )? ) | LOOKAHEAD(2) ( @@ -2750,6 +2763,19 @@ GroupByElement GroupByColumnReferences(): | LOOKAHEAD(2) ( list = ComplexExpressionList() { groupBy.setGroupByExpressionList(list.withUsingBrackets(false)); } + ( + LOOKAHEAD(2) ( + "(" + ( LOOKAHEAD(2) "(" ")" { groupBy.addGroupingSet(new ExpressionList()); } + | LOOKAHEAD(3) "(" list = SimpleExpressionList(true) ")" { groupBy.addGroupingSet(list); } + | expr = SimpleExpression() { groupBy.addGroupingSet(expr); } ) + + ( "," ( LOOKAHEAD(2) "(" ")" { groupBy.addGroupingSet(new ExpressionList()); } + | LOOKAHEAD(3) "(" list = SimpleExpressionList(true) ")" { groupBy.addGroupingSet(list); } + | expr = SimpleExpression() { groupBy.addGroupingSet(expr); } ) )* + ")" + ) + )? ) ) { diff --git a/src/test/java/net/sf/jsqlparser/statement/select/HiveTest.java b/src/test/java/net/sf/jsqlparser/statement/select/HiveTest.java index 742d7c87f..8abc10494 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/HiveTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/HiveTest.java @@ -46,4 +46,14 @@ public void testLeftSemiJoin() throws Exception { assertSqlCanBeParsedAndDeparsed(sql, true); } + + @Test + public void testGroupByGroupingSets() throws Exception { + String sql = "SELECT\n" + + " C1, C2, C3, MAX(Value)\n" + + "FROM\n" + + " Sometable\n" + + "GROUP BY C1, C2, C3 GROUPING SETS ((C1, C2), (C1, C2, C3), ())"; + assertSqlCanBeParsedAndDeparsed(sql, true); + } }