diff --git a/jOOQ/src/main/java/org/jooq/WindowRowsStep.java b/jOOQ/src/main/java/org/jooq/WindowRowsStep.java index ed0b387b23..e56f5e1292 100644 --- a/jOOQ/src/main/java/org/jooq/WindowRowsStep.java +++ b/jOOQ/src/main/java/org/jooq/WindowRowsStep.java @@ -44,6 +44,7 @@ import static org.jooq.SQLDialect.MARIADB; import static org.jooq.SQLDialect.MYSQL_8_0; // ... import static org.jooq.SQLDialect.POSTGRES; +import static org.jooq.SQLDialect.POSTGRES_11; // ... // ... // ... @@ -206,4 +207,73 @@ public interface WindowRowsStep extends WindowFinalStep { */ @Support({ MARIADB, MYSQL_8_0, POSTGRES }) WindowRowsAndStep rangeBetweenFollowing(int number); + + /** + * Add a GROUPS UNBOUNDED PRECEDING frame clause to the window + * function. + */ + @Support({ POSTGRES_11 }) + WindowFinalStep groupsUnboundedPreceding(); + + /** + * Add a GROUPS [number] PRECEDING frame clause to the window + * function. + */ + @Support({ POSTGRES_11 }) + WindowFinalStep groupsPreceding(int number); + + /** + * Add a GROUPS CURRENT ROW frame clause to the window function. + */ + @Support({ POSTGRES_11 }) + WindowFinalStep groupsCurrentRow(); + + /** + * Add a GROUPS UNBOUNDED FOLLOWING frame clause to the window + * function. + */ + @Support({ POSTGRES_11 }) + WindowFinalStep groupsUnboundedFollowing(); + + /** + * Add a GROUPS [number] FOLLOWING frame clause to the window + * function. + */ + @Support({ POSTGRES_11 }) + WindowFinalStep groupsFollowing(int number); + + /** + * Add a GROUPS BETWEEN UNBOUNDED PRECEDING ... frame clause to + * the window function. + */ + @Support({ POSTGRES_11 }) + WindowRowsAndStep groupsBetweenUnboundedPreceding(); + + /** + * Add a GROUPS BETWEEN [number] PRECEDING ... frame clause to + * the window function. + */ + @Support({ POSTGRES_11 }) + WindowRowsAndStep groupsBetweenPreceding(int number); + + /** + * Add a GROUPS BETWEEN CURRENT ROW ... frame clause to + * the window function. + */ + @Support({ POSTGRES_11 }) + WindowRowsAndStep groupsBetweenCurrentRow(); + + /** + * Add a GROUPS BETWEEN UNBOUNDED FOLLOWING ... frame clause to + * the window function. + */ + @Support({ POSTGRES_11 }) + WindowRowsAndStep groupsBetweenUnboundedFollowing(); + + /** + * Add a GROUPS BETWEEN [number] FOLLOWING ... frame clause to + * the window function. + */ + @Support({ POSTGRES_11 }) + WindowRowsAndStep groupsBetweenFollowing(int number); } diff --git a/jOOQ/src/main/java/org/jooq/WindowSpecificationRowsStep.java b/jOOQ/src/main/java/org/jooq/WindowSpecificationRowsStep.java index 983c3af25d..975db2e779 100644 --- a/jOOQ/src/main/java/org/jooq/WindowSpecificationRowsStep.java +++ b/jOOQ/src/main/java/org/jooq/WindowSpecificationRowsStep.java @@ -44,6 +44,7 @@ import static org.jooq.SQLDialect.MARIADB; import static org.jooq.SQLDialect.MYSQL_8_0; // ... import static org.jooq.SQLDialect.POSTGRES; +import static org.jooq.SQLDialect.POSTGRES_11; // ... // ... // ... @@ -223,4 +224,74 @@ public interface WindowSpecificationRowsStep extends WindowSpecificationFinalSte */ @Support({ MARIADB, MYSQL_8_0, POSTGRES }) WindowSpecificationRowsAndStep rangeBetweenFollowing(int number); + + /** + * Add a GROUPS UNBOUNDED PRECEDING frame clause to the window + * specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationFinalStep groupsUnboundedPreceding(); + + /** + * Add a GROUPS [number] PRECEDING frame clause to the window + * specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationFinalStep groupsPreceding(int number); + + /** + * Add a GROUPS CURRENT ROW frame clause to the window + * specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationFinalStep groupsCurrentRow(); + + /** + * Add a GROUPS UNBOUNDED FOLLOWING frame clause to the window + * specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationFinalStep groupsUnboundedFollowing(); + + /** + * Add a GROUPS [number] FOLLOWING frame clause to the window + * specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationFinalStep groupsFollowing(int number); + + /** + * Add a GROUPS BETWEEN UNBOUNDED PRECEDING ... frame clause to + * the window specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationRowsAndStep groupsBetweenUnboundedPreceding(); + + /** + * Add a GROUPS BETWEEN [number] PRECEDING ... frame clause to + * the window specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationRowsAndStep groupsBetweenPreceding(int number); + + /** + * Add a GROUPS BETWEEN CURRENT ROW ... frame clause to the + * window specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationRowsAndStep groupsBetweenCurrentRow(); + + /** + * Add a GROUPS BETWEEN UNBOUNDED FOLLOWING ... frame clause to + * the window specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationRowsAndStep groupsBetweenUnboundedFollowing(); + + /** + * Add a GROUPS BETWEEN [number] FOLLOWING ... frame clause to + * the window specification. + */ + @Support({ POSTGRES_11 }) + WindowSpecificationRowsAndStep groupsBetweenFollowing(int number); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 90d9dab472..0768afad0a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -62,6 +62,7 @@ import static org.jooq.SQLDialect.MYSQL_8_0; // ... // ... import static org.jooq.SQLDialect.POSTGRES; +import static org.jooq.SQLDialect.POSTGRES_11; import static org.jooq.SQLDialect.POSTGRES_9_3; import static org.jooq.SQLDialect.POSTGRES_9_4; import static org.jooq.SQLDialect.POSTGRES_9_5; @@ -17715,6 +17716,86 @@ public class DSL { return new WindowSpecificationImpl().rangeBetweenFollowing(number); } + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationFinalStep groupsUnboundedPreceding() { + return new WindowSpecificationImpl().groupsUnboundedPreceding(); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationFinalStep groupsPreceding(int number) { + return new WindowSpecificationImpl().groupsPreceding(number); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationFinalStep groupsCurrentRow() { + return new WindowSpecificationImpl().groupsCurrentRow(); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationFinalStep groupsUnboundedFollowing() { + return new WindowSpecificationImpl().groupsUnboundedFollowing(); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationFinalStep groupsFollowing(int number) { + return new WindowSpecificationImpl().groupsFollowing(number); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationRowsAndStep groupsBetweenUnboundedPreceding() { + return new WindowSpecificationImpl().groupsBetweenUnboundedPreceding(); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationRowsAndStep groupsBetweenPreceding(int number) { + return new WindowSpecificationImpl().groupsBetweenPreceding(number); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationRowsAndStep groupsBetweenCurrentRow() { + return new WindowSpecificationImpl().groupsBetweenCurrentRow(); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationRowsAndStep groupsBetweenUnboundedFollowing() { + return new WindowSpecificationImpl().groupsBetweenUnboundedFollowing(); + } + + /** + * Create a {@link WindowSpecification} with a GROUPS clause. + */ + @Support({ POSTGRES_11 }) + public static WindowSpecificationRowsAndStep groupsBetweenFollowing(int number) { + return new WindowSpecificationImpl().groupsBetweenFollowing(number); + } + // ------------------------------------------------------------------------- // XXX Window functions // ------------------------------------------------------------------------- diff --git a/jOOQ/src/main/java/org/jooq/impl/Function.java b/jOOQ/src/main/java/org/jooq/impl/Function.java index 6ac0f58cc1..11f5634b4b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Function.java +++ b/jOOQ/src/main/java/org/jooq/impl/Function.java @@ -822,6 +822,66 @@ class Function extends AbstractField implements return this; } + @Override + public final WindowFinalStep groupsUnboundedPreceding() { + windowSpecification.groupsUnboundedPreceding(); + return this; + } + + @Override + public final WindowFinalStep groupsPreceding(int number) { + windowSpecification.groupsPreceding(number); + return this; + } + + @Override + public final WindowFinalStep groupsCurrentRow() { + windowSpecification.groupsCurrentRow(); + return this; + } + + @Override + public final WindowFinalStep groupsUnboundedFollowing() { + windowSpecification.groupsUnboundedFollowing(); + return this; + } + + @Override + public final WindowFinalStep groupsFollowing(int number) { + windowSpecification.groupsFollowing(number); + return this; + } + + @Override + public final WindowRowsAndStep groupsBetweenUnboundedPreceding() { + windowSpecification.groupsBetweenUnboundedPreceding(); + return this; + } + + @Override + public final WindowRowsAndStep groupsBetweenPreceding(int number) { + windowSpecification.groupsBetweenPreceding(number); + return this; + } + + @Override + public final WindowRowsAndStep groupsBetweenCurrentRow() { + windowSpecification.groupsBetweenCurrentRow(); + return this; + } + + @Override + public final WindowRowsAndStep groupsBetweenUnboundedFollowing() { + windowSpecification.groupsBetweenUnboundedFollowing(); + return this; + } + + @Override + public final WindowRowsAndStep groupsBetweenFollowing(int number) { + windowSpecification.groupsBetweenFollowing(number); + return this; + } + @Override public final WindowFinalStep andUnboundedPreceding() { windowSpecification.andUnboundedPreceding(); diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index d291b959d4..b1bc2350d5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -104,6 +104,16 @@ import static org.jooq.impl.DSL.greatest; import static org.jooq.impl.DSL.grouping; import static org.jooq.impl.DSL.groupingId; import static org.jooq.impl.DSL.groupingSets; +import static org.jooq.impl.DSL.groupsBetweenCurrentRow; +import static org.jooq.impl.DSL.groupsBetweenFollowing; +import static org.jooq.impl.DSL.groupsBetweenPreceding; +import static org.jooq.impl.DSL.groupsBetweenUnboundedFollowing; +import static org.jooq.impl.DSL.groupsBetweenUnboundedPreceding; +import static org.jooq.impl.DSL.groupsCurrentRow; +import static org.jooq.impl.DSL.groupsFollowing; +import static org.jooq.impl.DSL.groupsPreceding; +import static org.jooq.impl.DSL.groupsUnboundedFollowing; +import static org.jooq.impl.DSL.groupsUnboundedPreceding; import static org.jooq.impl.DSL.hour; import static org.jooq.impl.DSL.ifnull; import static org.jooq.impl.DSL.iif; @@ -1272,58 +1282,79 @@ final class ParserImpl implements Parser { boolean rows = parseKeywordIf(ctx, "ROWS"); boolean range = !rows && parseKeywordIf(ctx, "RANGE"); + boolean groups = !rows && !range && parseKeywordIf(ctx, "GROUPS"); - if ((rows || range) &&!orderByAllowed) + if ((rows || range || groups) && !orderByAllowed) throw ctx.exception("ROWS or RANGE not allowed"); - if (rows || range) { + if (rows || range || groups) { Long n; if (parseKeywordIf(ctx, "BETWEEN")) { if (parseKeywordIf(ctx, "UNBOUNDED")) if (parseKeywordIf(ctx, "PRECEDING")) s3 = s2 == null - ? rows + ? rows ? rowsBetweenUnboundedPreceding() - : rangeBetweenUnboundedPreceding() - : rows + : range + ? rangeBetweenUnboundedPreceding() + : groupsBetweenUnboundedPreceding() + : rows ? s2.rowsBetweenUnboundedPreceding() - : s2.rangeBetweenUnboundedPreceding(); + : range + ? s2.rangeBetweenUnboundedPreceding() + : s2.groupsBetweenUnboundedPreceding(); else if (parseKeywordIf(ctx, "FOLLOWING")) s3 = s2 == null - ? rows + ? rows ? rowsBetweenUnboundedFollowing() - : rangeBetweenUnboundedFollowing() - : rows + : range + ? rangeBetweenUnboundedFollowing() + : groupsBetweenUnboundedFollowing() + : rows ? s2.rowsBetweenUnboundedFollowing() - : s2.rangeBetweenUnboundedFollowing(); + : range + ? s2.rangeBetweenUnboundedFollowing() + : s2.groupsBetweenUnboundedFollowing(); else throw ctx.expected("FOLLOWING", "PRECEDING"); else if (parseKeywordIf(ctx, "CURRENT ROW")) s3 = s2 == null - ? rows + ? rows ? rowsBetweenCurrentRow() - : rangeBetweenCurrentRow() - : rows + : range + ? rangeBetweenCurrentRow() + : groupsBetweenCurrentRow() + : rows ? s2.rowsBetweenCurrentRow() - : s2.rangeBetweenCurrentRow(); + : range + ? s2.rangeBetweenCurrentRow() + : s2.groupsBetweenCurrentRow(); else if ((n = parseUnsignedIntegerIf(ctx)) != null) if (parseKeywordIf(ctx, "PRECEDING")) s3 = s2 == null - ? rows + ? rows ? rowsBetweenPreceding(n.intValue()) - : rangeBetweenPreceding(n.intValue()) - : rows + : range + ? rangeBetweenPreceding(n.intValue()) + : groupsBetweenPreceding(n.intValue()) + : rows ? s2.rowsBetweenPreceding(n.intValue()) - : s2.rangeBetweenPreceding(n.intValue()); + : range + ? s2.rangeBetweenPreceding(n.intValue()) + : s2.groupsBetweenPreceding(n.intValue()); else if (parseKeywordIf(ctx, "FOLLOWING")) s3 = s2 == null - ? rows + ? rows ? rowsBetweenFollowing(n.intValue()) - : rangeBetweenFollowing(n.intValue()) - : rows + : range + ? rangeBetweenFollowing(n.intValue()) + : groupsBetweenFollowing(n.intValue()) + : rows ? s2.rowsBetweenFollowing(n.intValue()) - : s2.rangeBetweenFollowing(n.intValue()); + : range + ? s2.rangeBetweenFollowing(n.intValue()) + : s2.groupsBetweenFollowing(n.intValue()); else throw ctx.expected("FOLLOWING", "PRECEDING"); else @@ -1353,47 +1384,67 @@ final class ParserImpl implements Parser { else if (parseKeywordIf(ctx, "UNBOUNDED")) if (parseKeywordIf(ctx, "PRECEDING")) return s2 == null - ? rows + ? rows ? rowsUnboundedPreceding() - : rangeUnboundedPreceding() - : rows + : range + ? rangeUnboundedPreceding() + : groupsUnboundedPreceding() + : rows ? s2.rowsUnboundedPreceding() - : s2.rangeUnboundedPreceding(); + : range + ? s2.rangeUnboundedPreceding() + : s2.groupsUnboundedPreceding(); else if (parseKeywordIf(ctx, "FOLLOWING")) return s2 == null - ? rows + ? rows ? rowsUnboundedFollowing() - : rangeUnboundedFollowing() - : rows + : range + ? rangeUnboundedFollowing() + : groupsUnboundedFollowing() + : rows ? s2.rowsUnboundedFollowing() - : s2.rangeUnboundedFollowing(); + : range + ? s2.rangeUnboundedFollowing() + : s2.groupsUnboundedFollowing(); else throw ctx.expected("FOLLOWING", "PRECEDING"); else if (parseKeywordIf(ctx, "CURRENT ROW")) return s2 == null - ? rows + ? rows ? rowsCurrentRow() - : rangeCurrentRow() - : rows + : range + ? rangeCurrentRow() + : groupsCurrentRow() + : rows ? s2.rowsCurrentRow() - : s2.rangeCurrentRow(); + : range + ? s2.rangeCurrentRow() + : s2.groupsCurrentRow(); else if ((n = parseUnsignedInteger(ctx)) != null) if (parseKeywordIf(ctx, "PRECEDING")) return s2 == null - ? rows + ? rows ? rowsPreceding(n.intValue()) - : rangePreceding(n.intValue()) - : rows + : range + ? rangePreceding(n.intValue()) + : groupsPreceding(n.intValue()) + : rows ? s2.rowsPreceding(n.intValue()) - : s2.rangePreceding(n.intValue()); + : range + ? s2.rangePreceding(n.intValue()) + : s2.groupsPreceding(n.intValue()); else if (parseKeywordIf(ctx, "FOLLOWING")) return s2 == null - ? rows + ? rows ? rowsFollowing(n.intValue()) - : rangeFollowing(n.intValue()) - : rows + : range + ? rangeFollowing(n.intValue()) + : groupsFollowing(n.intValue()) + : rows ? s2.rowsFollowing(n.intValue()) - : s2.rangeFollowing(n.intValue()); + : range + ? s2.rangeFollowing(n.intValue()) + : s2.groupsFollowing(n.intValue()); else throw ctx.expected("FOLLOWING", "PRECEDING"); else diff --git a/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java b/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java index ad3ceb5048..01dca27fb5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java @@ -52,6 +52,7 @@ import static org.jooq.impl.Keywords.K_PARTITION_BY; import static org.jooq.impl.Keywords.K_PRECEDING; import static org.jooq.impl.Keywords.K_UNBOUNDED_FOLLOWING; import static org.jooq.impl.Keywords.K_UNBOUNDED_PRECEDING; +import static org.jooq.impl.WindowSpecificationImpl.FrameUnits.GROUPS; import static org.jooq.impl.WindowSpecificationImpl.FrameUnits.RANGE; import static org.jooq.impl.WindowSpecificationImpl.FrameUnits.ROWS; @@ -324,6 +325,71 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements return this; } + @Override + public final WindowSpecificationFinalStep groupsUnboundedPreceding() { + frameUnits = GROUPS; + frameStart = Integer.MIN_VALUE; + return this; + } + + @Override + public final WindowSpecificationFinalStep groupsPreceding(int number) { + frameUnits = GROUPS; + frameStart = -number; + return this; + } + + @Override + public final WindowSpecificationFinalStep groupsCurrentRow() { + frameUnits = GROUPS; + frameStart = 0; + return this; + } + + @Override + public final WindowSpecificationFinalStep groupsUnboundedFollowing() { + frameUnits = GROUPS; + frameStart = Integer.MAX_VALUE; + return this; + } + + @Override + public final WindowSpecificationFinalStep groupsFollowing(int number) { + frameUnits = GROUPS; + frameStart = number; + return this; + } + + @Override + public final WindowSpecificationRowsAndStep groupsBetweenUnboundedPreceding() { + groupsUnboundedPreceding(); + return this; + } + + @Override + public final WindowSpecificationRowsAndStep groupsBetweenPreceding(int number) { + groupsPreceding(number); + return this; + } + + @Override + public final WindowSpecificationRowsAndStep groupsBetweenCurrentRow() { + groupsCurrentRow(); + return this; + } + + @Override + public final WindowSpecificationRowsAndStep groupsBetweenUnboundedFollowing() { + groupsUnboundedFollowing(); + return this; + } + + @Override + public final WindowSpecificationRowsAndStep groupsBetweenFollowing(int number) { + groupsFollowing(number); + return this; + } + @Override public final WindowSpecificationFinalStep andUnboundedPreceding() { frameEnd = Integer.MIN_VALUE; @@ -356,7 +422,8 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements enum FrameUnits { ROWS("rows"), - RANGE("range"); + RANGE("range"), + GROUPS("groups"); private final Keyword keyword;