diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractWindowFunction.java b/jOOQ/src/main/java/org/jooq/impl/AbstractWindowFunction.java index 36eb24a02e..e3a1e6c460 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractWindowFunction.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractWindowFunction.java @@ -90,6 +90,7 @@ import org.jooq.WindowRowsAndStep; import org.jooq.WindowRowsStep; import org.jooq.WindowSpecification; import org.jooq.impl.Tools.BooleanDataKey; +import org.jooq.impl.Tools.DataExtendedKey; /** * @author Lukas Eder @@ -105,18 +106,6 @@ implements { private static final Set SUPPORT_NO_PARENS_WINDOW_REFERENCE = SQLDialect.supportedBy(MYSQL, POSTGRES, SQLITE); - private static final Set REQUIRES_ORDER_BY_IN_LEAD_LAG = SQLDialect.supportedBy(H2, MARIADB); - private static final Set REQUIRES_ORDER_BY_IN_NTILE = SQLDialect.supportedBy(H2); - private static final Set REQUIRES_ORDER_BY_IN_RANK_DENSE_RANK = SQLDialect.supportedBy(H2, MARIADB); - private static final Set REQUIRES_ORDER_BY_IN_PERCENT_RANK_CUME_DIST = SQLDialect.supportedBy(MARIADB); - - - - - - - - // Other attributes WindowSpecificationImpl windowSpecification; WindowDefinitionImpl windowDefinition; @@ -179,22 +168,11 @@ implements if (window == null) return; - Boolean ordered = - this instanceof Ntile && REQUIRES_ORDER_BY_IN_NTILE.contains(ctx.dialect()) - || this instanceof PositionalWindowFunction && ((PositionalWindowFunction) this).isLeadOrLag() && REQUIRES_ORDER_BY_IN_LEAD_LAG.contains(ctx.dialect()) - || this instanceof RankingFunction && ((RankingFunction) this).isRankOrDenseRank() && REQUIRES_ORDER_BY_IN_RANK_DENSE_RANK.contains(ctx.dialect()) - || this instanceof RankingFunction && !((RankingFunction) this).isRankOrDenseRank() && REQUIRES_ORDER_BY_IN_PERCENT_RANK_CUME_DIST.contains(ctx.dialect()) - - - - - ; - ctx.sql(' ') .visit(K_OVER) .sql(' '); - ctx.data(BooleanDataKey.DATA_WINDOW_FUNCTION_REQUIRES_ORDER_BY, ordered, c -> c.visit(window)); + ctx.data(DataExtendedKey.DATA_WINDOW_FUNCTION, this, c -> c.visit(window)); } diff --git a/jOOQ/src/main/java/org/jooq/impl/ConditionAsField.java b/jOOQ/src/main/java/org/jooq/impl/ConditionAsField.java index c6d41b7310..840d8a0992 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ConditionAsField.java +++ b/jOOQ/src/main/java/org/jooq/impl/ConditionAsField.java @@ -59,8 +59,6 @@ final class ConditionAsField extends AbstractField { public final void accept(Context ctx) { switch (ctx.family()) { - // Some databases don't accept predicates where column expressions - // are expected. diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index cbf27a91e9..879854bdc3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -280,6 +280,7 @@ import org.jooq.TableField; import org.jooq.TableRecord; import org.jooq.UDT; import org.jooq.UpdatableRecord; +import org.jooq.WindowSpecification; import org.jooq.XML; import org.jooq.conf.BackslashEscaping; import org.jooq.conf.ParseNameCase; @@ -504,12 +505,6 @@ final class Tools { */ DATA_EMULATE_BULK_INSERT_RETURNING, - /** - * [#1535] We're currently generating the window specification of a - * window function that requires an ORDER BY clause. - */ - DATA_WINDOW_FUNCTION_REQUIRES_ORDER_BY, - /** * [#9925] In some cases the AS keyword is required for aliasing, e.g. XML. */ @@ -699,7 +694,14 @@ final class Tools { /** * [#9017] We've already transformed ROWNUM expressions to LIMIT. */ - DATA_TRANSFORM_ROWNUM_TO_LIMIT + DATA_TRANSFORM_ROWNUM_TO_LIMIT, + + /** + * [#1535] [#11851] The window function object that uses a + * {@link WindowSpecification}. + */ + DATA_WINDOW_FUNCTION, + } // ------------------------------------------------------------------------ diff --git a/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java b/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java index f1ed7579af..18355266b3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/WindowSpecificationImpl.java @@ -39,13 +39,23 @@ package org.jooq.impl; import static java.lang.Boolean.TRUE; // ... +// ... import static org.jooq.SQLDialect.CUBRID; // ... // ... +import static org.jooq.SQLDialect.H2; +// ... +// ... +import static org.jooq.SQLDialect.MARIADB; +// ... import static org.jooq.SQLDialect.MYSQL; +// ... +// ... +// ... import static org.jooq.SQLDialect.SQLITE; // ... // ... +// ... import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.one; import static org.jooq.impl.DSL.select; @@ -59,6 +69,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.Tools.DataExtendedKey.DATA_WINDOW_FUNCTION; import static org.jooq.impl.WindowSpecificationImpl.Exclude.CURRENT_ROW; import static org.jooq.impl.WindowSpecificationImpl.Exclude.GROUP; import static org.jooq.impl.WindowSpecificationImpl.Exclude.NO_OTHERS; @@ -76,6 +87,7 @@ import org.jooq.Context; import org.jooq.Field; import org.jooq.Keyword; import org.jooq.OrderField; +// ... import org.jooq.SQLDialect; import org.jooq.WindowSpecificationExcludeStep; import org.jooq.WindowSpecificationFinalStep; @@ -84,6 +96,7 @@ import org.jooq.WindowSpecificationPartitionByStep; import org.jooq.WindowSpecificationRowsAndStep; import org.jooq.conf.RenderImplicitWindowRange; import org.jooq.impl.Tools.BooleanDataKey; +import org.jooq.impl.Tools.DataExtendedKey; /** * @author Lukas Eder @@ -96,7 +109,19 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements WindowSpecificationExcludeStep { - private static final Set OMIT_PARTITION_BY_ONE = SQLDialect.supportedBy(CUBRID, MYSQL, SQLITE); + private static final Set OMIT_PARTITION_BY_ONE = SQLDialect.supportedBy(CUBRID, MYSQL, SQLITE); + + private static final Set REQUIRES_ORDER_BY_IN_LEAD_LAG = SQLDialect.supportedBy(H2, MARIADB); + private static final Set REQUIRES_ORDER_BY_IN_NTILE = SQLDialect.supportedBy(H2); + private static final Set REQUIRES_ORDER_BY_IN_RANK_DENSE_RANK = SQLDialect.supportedBy(H2, MARIADB); + private static final Set REQUIRES_ORDER_BY_IN_PERCENT_RANK_CUME_DIST = SQLDialect.supportedBy(MARIADB); + + + + + + + private final WindowDefinitionImpl windowDefinition; private final QueryPartList> partitionBy; @@ -133,19 +158,34 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements public final void accept(Context ctx) { SortFieldList o = orderBy; - // [#8414] [#8593] [#11021] Some RDBMS require ORDER BY in some window functions - if (o.isEmpty() && TRUE.equals(ctx.data(BooleanDataKey.DATA_WINDOW_FUNCTION_REQUIRES_ORDER_BY))) { - Field constant; + // [#8414] [#8593] [#11021] [#11851] Some RDBMS require ORDER BY in some window functions + AbstractWindowFunction w = (AbstractWindowFunction) ctx.data(DATA_WINDOW_FUNCTION); + + if (o.isEmpty()) { + boolean ordered = + w instanceof Ntile && REQUIRES_ORDER_BY_IN_NTILE.contains(ctx.dialect()) + || w instanceof PositionalWindowFunction && ((PositionalWindowFunction) w).isLeadOrLag() && REQUIRES_ORDER_BY_IN_LEAD_LAG.contains(ctx.dialect()) + || w instanceof RankingFunction && ((RankingFunction) w).isRankOrDenseRank() && REQUIRES_ORDER_BY_IN_RANK_DENSE_RANK.contains(ctx.dialect()) + || w instanceof RankingFunction && !((RankingFunction) w).isRankOrDenseRank() && REQUIRES_ORDER_BY_IN_PERCENT_RANK_CUME_DIST.contains(ctx.dialect()) + + + + + ; + + if (ordered) { + Field constant; - constant = field(select(one())); + constant = field(select(one())); - o = new SortFieldList(); - o.add(constant.sortDefault()); + o = new SortFieldList(); + o.add(constant.sortDefault()); + } } boolean hasWindowDefinitions = windowDefinition != null; @@ -155,6 +195,8 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements + + ; int clauses = 0;