diff --git a/jOOQ/src/main/java/org/jooq/GroupField.java b/jOOQ/src/main/java/org/jooq/GroupField.java index f34ea44467..f14374c0bc 100644 --- a/jOOQ/src/main/java/org/jooq/GroupField.java +++ b/jOOQ/src/main/java/org/jooq/GroupField.java @@ -65,6 +65,14 @@ import org.jooq.impl.QOM; * * @author Lukas Eder */ -public /* sealed */ interface GroupField extends QueryPart /* permits Table, Field, QOM.Rollup, QOM.Cube, QOM.GroupingSets */ { - -} +public /* sealed */ interface GroupField +extends + QueryPart +/* permits + Table, + Field, + QOM.EmptyGroupingSet, + QOM.Rollup, + QOM.Cube, + QOM.GroupingSets */ +{} diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index c8aaf7964b..dd97aac36e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -24265,6 +24265,26 @@ public class DSL { // XXX Construction of GROUPING SET functions // ------------------------------------------------------------------------ + /** + * Create a GROUPING SETS(field1, field2, .., fieldn) grouping field where + * each grouping set only consists of a single field. + *

+ * Please check the SQL Server documentation for a very nice explanation of + * CUBE, ROLLUP, and GROUPING SETS + * clauses in grouping contexts: http://msdn.microsoft.com/en-US/library/bb522495.aspx + * + * @param fields The fields that are part of the GROUPING SETS + * function + * @return A field to be used in a GROUP BY clause + */ + @NotNull + @Support({ POSTGRES }) + public static GroupField emptyGroupingSet() { + return EmptyGroupingSet.INSTANCE; + } + /** * Create a ROLLUP(field1, field2, .., fieldn) grouping field. * @@ -24279,16 +24299,6 @@ public class DSL { /** * Create a ROLLUP(field1, field2, .., fieldn) grouping field. *

- * This has been observed to work with the following databases: - *

- *

* Please check the SQL Server documentation for a very nice explanation of * CUBE, ROLLUP, and GROUPING SETS * clauses in grouping contexts: - * This has been observed to work with the following databases: - *

- *

* Please check the SQL Server documentation for a very nice explanation of * CUBE, ROLLUP, and GROUPING SETS * clauses in grouping contexts: - * This has been observed to work with the following databases: - *

- *

* Please check the SQL Server documentation for a very nice explanation of * CUBE, ROLLUP, and GROUPING SETS * clauses in grouping contexts: - * This has been observed to work with the following databases: - *

- *

* Please check the SQL Server documentation for a very nice explanation of * CUBE, ROLLUP, and GROUPING SETS * clauses in grouping contexts: - * This has been observed to work with the following databases: - *

- *

* Please check the SQL Server documentation for a very nice explanation of * CUBE, ROLLUP, and GROUPING SETS * clauses in grouping contexts: { // Few dialects support the SQL standard "grand total" (i.e. empty grouping set) else - ctx.sql("()"); + ctx.visit(emptyGroupingSet()); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/QOM.java b/jOOQ/src/main/java/org/jooq/impl/QOM.java index e46572c75a..ed4e5382c5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QOM.java +++ b/jOOQ/src/main/java/org/jooq/impl/QOM.java @@ -526,6 +526,14 @@ public final class QOM { // XXX: SelectFields, GroupFields and SortFields // ------------------------------------------------------------------------- + public /* sealed */ interface EmptyGroupingSet + extends + GroupField, + UEmpty + /* permits + org.jooq.impl.EmptyGroupingSet */ + {} + // Can't seal these types yet because of https://bugs.eclipse.org/bugs/show_bug.cgi?id=577872 public /* non-sealed */ interface Rollup diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 934a355876..c410c5af2e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -121,6 +121,7 @@ import static org.jooq.impl.CombineOperator.UNION_ALL; import static org.jooq.impl.CommonTableExpressionList.markTopLevelCteAndAccept; import static org.jooq.impl.DSL.asterisk; import static org.jooq.impl.DSL.createTable; +import static org.jooq.impl.DSL.emptyGroupingSet; import static org.jooq.impl.DSL.falseCondition; import static org.jooq.impl.DSL.generateSeries; import static org.jooq.impl.DSL.inline; @@ -366,8 +367,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp private final TableList from; private final ConditionProviderImpl condition; - private boolean grouping; - private GroupFieldList groupBy; + private final GroupFieldList groupBy; private boolean groupByDistinct; private final ConditionProviderImpl having; private WindowList window; @@ -416,6 +416,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp + this.groupBy = new GroupFieldList(); this.having = new ConditionProviderImpl(); this.qualify = new ConditionProviderImpl(); this.orderBy = new SortFieldList(); @@ -504,7 +505,6 @@ final class SelectQueryImpl extends AbstractResultQuery imp - private final SelectQueryImpl copyTo(CopyClause clause, boolean scalarSelect, SelectQueryImpl result) { @@ -531,8 +531,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp - result.grouping = grouping; - result.groupBy = groupBy; + result.groupBy.addAll(groupBy); result.groupByDistinct = groupByDistinct; result.having.setWhere(having.getWhere()); if (window != null) @@ -2380,7 +2379,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp // -------------------------- context.start(SELECT_GROUP_BY); - if (grouping) { + if (!getGroupBy().isEmpty()) { context.formatSeparator() .visit(K_GROUP_BY); @@ -3800,13 +3799,6 @@ final class SelectQueryImpl extends AbstractResultQuery imp return from; } - final void setGrouping() { - grouping = true; - - if (groupBy == null) - groupBy = new GroupFieldList(); - } - final ConditionProviderImpl getWhere(Context ctx) { ConditionProviderImpl result = new ConditionProviderImpl(); @@ -3890,6 +3882,10 @@ final class SelectQueryImpl extends AbstractResultQuery imp + final GroupFieldList getGroupBy() { + return groupBy; + } + final ConditionProviderImpl getHaving() { return having; } @@ -4099,13 +4095,18 @@ final class SelectQueryImpl extends AbstractResultQuery imp @Override public final void addGroupBy(Collection fields) { - setGrouping(); + + // [#12910] For backwards compatibility, adding empty GROUP BY lists to + // a blank GROUP BY clause must maintain empty grouping set + // semantics + if (fields.isEmpty()) + groupBy.add(emptyGroupingSet()); + groupBy.addAll(fields); } @Override public final void setGroupByDistinct(boolean groupByDistinct) { - setGrouping(); this.groupByDistinct = groupByDistinct; }