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 b0ba784b7a..f7be412e6d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java @@ -33,6 +33,8 @@ public enum SortDirection { private List> groupingSets = new ArrayList<>(); // postgres rollup is an ExpressionList private boolean mysqlWithRollup = false; + private boolean all = false; + private boolean distinct = false; public boolean isUsingBrackets() { return groupByExpressions.isUsingBrackets(); @@ -115,6 +117,12 @@ public String toString() { public void appendTo(StringBuilder builder, Consumer> listRenderer, Consumer expressionRenderer) { builder.append("GROUP BY "); + if (all) { + builder.append("ALL "); + } + if (distinct) { + builder.append("DISTINCT "); + } if (groupByExpressions != null) { if (hasGroupBySortDirections()) { appendOrderedExpressions(builder, expressionRenderer); @@ -200,4 +208,22 @@ public GroupByElement setMysqlWithRollup(boolean mysqlWithRollup) { this.mysqlWithRollup = mysqlWithRollup; return this; } + + public boolean isAll() { + return all; + } + + public GroupByElement setAll(boolean all) { + this.all = all; + return this; + } + + public boolean isDistinct() { + return distinct; + } + + public GroupByElement setDistinct(boolean distinct) { + this.distinct = distinct; + return this; + } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index bece55b798..c4938d1a7f 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -11316,6 +11316,11 @@ GroupByElement GroupByColumnReferences(): } { + // PostgreSQL: GROUP BY [ ALL | DISTINCT ] grouping_element [, ...] + [ LOOKAHEAD({ Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect)) + && (getToken(1).kind == K_ALL || getToken(1).kind == K_DISTINCT) }) + ( { groupBy.setAll(true); } | { groupBy.setDistinct(true); } ) + ] ( LOOKAHEAD(2) ( 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 31f510c160..122b13ba45 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -2413,6 +2413,20 @@ public void testSelectWithoutTargetListPostgreSql() throws JSQLParserException { false, parser -> parser.withDialect(Dialect.POSTGRESQL)); } + @Test + public void testGroupByAllDistinctPostgreSql() throws JSQLParserException { + // PostgreSQL: GROUP BY [ ALL | DISTINCT ] grouping_element [, ...] + assertSqlCanBeParsedAndDeparsed( + "SELECT 1 GROUP BY DISTINCT GROUPING SETS ((1), (1))", + false, parser -> parser.withDialect(Dialect.POSTGRESQL)); + assertSqlCanBeParsedAndDeparsed( + "SELECT 1 GROUP BY ALL GROUPING SETS ((1), (2))", + false, parser -> parser.withDialect(Dialect.POSTGRESQL)); + assertSqlCanBeParsedAndDeparsed( + "SELECT a FROM t GROUP BY DISTINCT a", + false, parser -> parser.withDialect(Dialect.POSTGRESQL)); + } + @Test public void testIsUnknown() throws JSQLParserException { String statement = "SELECT col FROM tbl WHERE col IS UNKNOWN";