[#11851] Do this only for aggregate window functions

This commit is contained in:
Lukas Eder 2021-05-06 14:04:15 +02:00
parent fbda63cae6
commit 153de56fa7
4 changed files with 60 additions and 40 deletions

View File

@ -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<SQLDialect> SUPPORT_NO_PARENS_WINDOW_REFERENCE = SQLDialect.supportedBy(MYSQL, POSTGRES, SQLITE);
private static final Set<SQLDialect> REQUIRES_ORDER_BY_IN_LEAD_LAG = SQLDialect.supportedBy(H2, MARIADB);
private static final Set<SQLDialect> REQUIRES_ORDER_BY_IN_NTILE = SQLDialect.supportedBy(H2);
private static final Set<SQLDialect> REQUIRES_ORDER_BY_IN_RANK_DENSE_RANK = SQLDialect.supportedBy(H2, MARIADB);
private static final Set<SQLDialect> 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));
}

View File

@ -59,8 +59,6 @@ final class ConditionAsField extends AbstractField<Boolean> {
public final void accept(Context<?> ctx) {
switch (ctx.family()) {
// Some databases don't accept predicates where column expressions
// are expected.

View File

@ -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 <code>AS</code> 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,
}
// ------------------------------------------------------------------------

View File

@ -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<SQLDialect> OMIT_PARTITION_BY_ONE = SQLDialect.supportedBy(CUBRID, MYSQL, SQLITE);
private static final Set<SQLDialect> OMIT_PARTITION_BY_ONE = SQLDialect.supportedBy(CUBRID, MYSQL, SQLITE);
private static final Set<SQLDialect> REQUIRES_ORDER_BY_IN_LEAD_LAG = SQLDialect.supportedBy(H2, MARIADB);
private static final Set<SQLDialect> REQUIRES_ORDER_BY_IN_NTILE = SQLDialect.supportedBy(H2);
private static final Set<SQLDialect> REQUIRES_ORDER_BY_IN_RANK_DENSE_RANK = SQLDialect.supportedBy(H2, MARIADB);
private static final Set<SQLDialect> REQUIRES_ORDER_BY_IN_PERCENT_RANK_CUME_DIST = SQLDialect.supportedBy(MARIADB);
private final WindowDefinitionImpl windowDefinition;
private final QueryPartList<Field<?>> 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<Integer> 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<Integer> 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;