- [#7297] Support deriving a WindowDefinition from another WindowDefinition - [#7663] Referenced WindowDefinitions should not be inlined in MySQL, Sybase SQL Anywhere
This commit is contained in:
parent
e203490c3b
commit
53bd929f5e
@ -60,6 +60,6 @@ package org.jooq;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface WindowDefinition extends QueryPart {
|
||||
public interface WindowDefinition extends WindowSpecificationOrderByStep {
|
||||
|
||||
}
|
||||
|
||||
@ -72,6 +72,7 @@ import static org.jooq.impl.Keywords.K_RESPECT_NULLS;
|
||||
import static org.jooq.impl.Keywords.K_SEPARATOR;
|
||||
import static org.jooq.impl.Keywords.K_WHERE;
|
||||
import static org.jooq.impl.Keywords.K_WITHIN_GROUP;
|
||||
import static org.jooq.impl.SelectQueryImpl.SUPPORT_WINDOW_CLAUSE;
|
||||
import static org.jooq.impl.Term.ARRAY_AGG;
|
||||
import static org.jooq.impl.Term.LIST_AGG;
|
||||
import static org.jooq.impl.Term.MEDIAN;
|
||||
@ -131,13 +132,13 @@ class Function<T> extends AbstractField<T> implements
|
||||
{
|
||||
|
||||
|
||||
private static final long serialVersionUID = 347252741712134044L;
|
||||
private static final EnumSet<SQLDialect> SUPPORT_ARRAY_AGG = EnumSet.of(HSQLDB, POSTGRES);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_GROUP_CONCAT = EnumSet.of(CUBRID, H2, HSQLDB, MARIADB, MYSQL, SQLITE);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_STRING_AGG = EnumSet.of(POSTGRES);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_WINDOW_CLAUSE = EnumSet.of(MYSQL, POSTGRES);
|
||||
private static final long serialVersionUID = 347252741712134044L;
|
||||
private static final EnumSet<SQLDialect> SUPPORT_ARRAY_AGG = EnumSet.of(HSQLDB, POSTGRES);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_GROUP_CONCAT = EnumSet.of(CUBRID, H2, HSQLDB, MARIADB, MYSQL, SQLITE);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_STRING_AGG = EnumSet.of(POSTGRES);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_NO_PARENS_WINDOW_REFERENCE = EnumSet.of(MYSQL, POSTGRES);
|
||||
|
||||
static final Field<Integer> ASTERISK = DSL.field("*", Integer.class);
|
||||
static final Field<Integer> ASTERISK = DSL.field("*", Integer.class);
|
||||
|
||||
// Mutually exclusive attributes: super.getName(), this.name, this.term
|
||||
private final Name name;
|
||||
@ -372,9 +373,9 @@ class Function<T> extends AbstractField<T> implements
|
||||
return DSL.sql("({0})", windowSpecification);
|
||||
|
||||
// [#3727] Referenced WindowDefinitions that contain a frame clause
|
||||
// shouldn't be referenced from within parentheses (in PostgreSQL)
|
||||
// shouldn't be referenced from within parentheses (in MySQL and PostgreSQL)
|
||||
if (windowDefinition != null)
|
||||
if ( POSTGRES == ctx.family())
|
||||
if (SUPPORT_NO_PARENS_WINDOW_REFERENCE.contains(ctx.family()))
|
||||
return windowDefinition;
|
||||
else
|
||||
return DSL.sql("({0})", windowDefinition);
|
||||
@ -644,7 +645,10 @@ class Function<T> extends AbstractField<T> implements
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> over(WindowSpecification specification) {
|
||||
this.windowSpecification = (WindowSpecificationImpl) specification;
|
||||
this.windowSpecification = specification instanceof WindowSpecificationImpl
|
||||
? (WindowSpecificationImpl) specification
|
||||
: new WindowSpecificationImpl((WindowDefinitionImpl) specification);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@ -1254,7 +1254,7 @@ final class ParserImpl implements Parser {
|
||||
Name name = parseIdentifier(ctx);
|
||||
parseKeyword(ctx, "AS");
|
||||
parse(ctx, '(');
|
||||
result.add(name.as(parseWindowSpecificationIf(ctx, true)));
|
||||
result.add(name.as(parseWindowSpecificationIf(ctx, null, true)));
|
||||
parse(ctx, ')');
|
||||
}
|
||||
while (parseIf(ctx, ','));
|
||||
@ -1262,13 +1262,16 @@ final class ParserImpl implements Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final WindowSpecification parseWindowSpecificationIf(ParserContext ctx, boolean orderByAllowed) {
|
||||
private static final WindowSpecification parseWindowSpecificationIf(ParserContext ctx, Name windowName, boolean orderByAllowed) {
|
||||
final WindowSpecificationOrderByStep s1;
|
||||
final WindowSpecificationRowsStep s2;
|
||||
final WindowSpecificationRowsAndStep s3;
|
||||
final WindowSpecificationExcludeStep s4;
|
||||
final WindowSpecification result;
|
||||
|
||||
s1 = parseKeywordIf(ctx, "PARTITION BY")
|
||||
s1 = windowName != null
|
||||
? windowName.as()
|
||||
: parseKeywordIf(ctx, "PARTITION BY")
|
||||
? partitionBy(parseFields(ctx))
|
||||
: null;
|
||||
|
||||
@ -1454,20 +1457,29 @@ final class ParserImpl implements Parser {
|
||||
|
||||
if (parseKeywordIf(ctx, "EXCLUDE"))
|
||||
if (parseKeywordIf(ctx, "CURRENT ROW"))
|
||||
return s4.excludeCurrentRow();
|
||||
result = s4.excludeCurrentRow();
|
||||
else if (parseKeywordIf(ctx, "TIES"))
|
||||
return s4.excludeTies();
|
||||
result = s4.excludeTies();
|
||||
else if (parseKeywordIf(ctx, "GROUP"))
|
||||
return s4.excludeGroup();
|
||||
result = s4.excludeGroup();
|
||||
else if (parseKeywordIf(ctx, "NO OTHERS"))
|
||||
return s4.excludeNoOthers();
|
||||
result = s4.excludeNoOthers();
|
||||
else
|
||||
throw ctx.expected("CURRENT ROW", "TIES", "GROUP", "NO OTHERS");
|
||||
else
|
||||
return s4;
|
||||
result = s4;
|
||||
}
|
||||
else
|
||||
return s2;
|
||||
result = s2;
|
||||
|
||||
if (result != null)
|
||||
return result;
|
||||
else if (windowName != null)
|
||||
return null;
|
||||
else if ((windowName = parseIdentifierIf(ctx)) != null)
|
||||
return parseWindowSpecificationIf(ctx, windowName, orderByAllowed);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final Delete<?> parseDelete(ParserContext ctx, WithImpl with) {
|
||||
@ -6336,11 +6348,7 @@ final class ParserImpl implements Parser {
|
||||
Object result;
|
||||
|
||||
if (parseIf(ctx, '(')) {
|
||||
result = parseWindowSpecificationIf(ctx, orderByAllowed);
|
||||
|
||||
if (result == null)
|
||||
result = parseIdentifierIf(ctx);
|
||||
|
||||
result = parseWindowSpecificationIf(ctx, null, orderByAllowed);
|
||||
parse(ctx, ')');
|
||||
}
|
||||
else {
|
||||
|
||||
@ -202,7 +202,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
private static final EnumSet<SQLDialect> NO_SUPPORT_FOR_UPDATE = EnumSet.of(CUBRID);
|
||||
private static final EnumSet<SQLDialect> NO_SUPPORT_FOR_UPDATE_QUALIFIED = EnumSet.of(DERBY, FIREBIRD, H2, HSQLDB);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_SELECT_INTO = EnumSet.of(HSQLDB, POSTGRES);
|
||||
private static final EnumSet<SQLDialect> SUPPORT_WINDOW_CLAUSE = EnumSet.of(MYSQL, POSTGRES);
|
||||
static final EnumSet<SQLDialect> SUPPORT_WINDOW_CLAUSE = EnumSet.of(MYSQL, POSTGRES);
|
||||
private static final EnumSet<SQLDialect> REQUIRES_FROM_CLAUSE = EnumSet.of(CUBRID, DERBY, FIREBIRD, HSQLDB, MARIADB, MYSQL);
|
||||
private static final EnumSet<SQLDialect> EMULATE_EMPTY_GROUP_BY_OTHER = EnumSet.of(FIREBIRD, HSQLDB, MARIADB, MYSQL, POSTGRES, SQLITE);
|
||||
|
||||
|
||||
@ -37,15 +37,21 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
import static org.jooq.impl.Keywords.K_AS;
|
||||
import static org.jooq.impl.SelectQueryImpl.SUPPORT_WINDOW_CLAUSE;
|
||||
import static org.jooq.impl.Tools.DataKey.DATA_WINDOW_DEFINITIONS;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.Clause;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.OrderField;
|
||||
import org.jooq.WindowDefinition;
|
||||
import org.jooq.WindowSpecification;
|
||||
import org.jooq.WindowSpecificationExcludeStep;
|
||||
import org.jooq.WindowSpecificationRowsAndStep;
|
||||
import org.jooq.WindowSpecificationRowsStep;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
@ -87,12 +93,34 @@ final class WindowDefinitionImpl extends AbstractQueryPart implements WindowDefi
|
||||
|
||||
// Outside the WINDOW clause, only few dialects actually support
|
||||
// referencing WINDOW definitions
|
||||
else if ( ctx.family() == POSTGRES)
|
||||
else if (SUPPORT_WINDOW_CLAUSE.contains(ctx.family())) {
|
||||
ctx.visit(name);
|
||||
}
|
||||
|
||||
// When emulating, just repeat the window specification
|
||||
else if (window != null)
|
||||
else if (window != null) {
|
||||
ctx.visit(window);
|
||||
}
|
||||
|
||||
// Try looking up the window specification from the context
|
||||
else {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
QueryPartList<WindowDefinition> windows = (QueryPartList<WindowDefinition>) ctx.data(DATA_WINDOW_DEFINITIONS);
|
||||
|
||||
renderContextDefinitionOrName:
|
||||
if (windows != null) {
|
||||
for (WindowDefinition w : windows) {
|
||||
if (((WindowDefinitionImpl) w).getName().equals(name)) {
|
||||
ctx.visit(w);
|
||||
break renderContextDefinitionOrName;
|
||||
}
|
||||
}
|
||||
|
||||
// Default to printing the name
|
||||
ctx.visit(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,4 +132,168 @@ final class WindowDefinitionImpl extends AbstractQueryPart implements WindowDefi
|
||||
public final Clause[] clauses(Context<?> ctx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: WindowSpecification API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsStep orderBy(OrderField<?>... fields) {
|
||||
return new WindowSpecificationImpl(this).orderBy(fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsStep orderBy(Collection<? extends OrderField<?>> fields) {
|
||||
return new WindowSpecificationImpl(this).orderBy(fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rowsUnboundedPreceding() {
|
||||
return new WindowSpecificationImpl(this).rowsUnboundedPreceding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rowsPreceding(int number) {
|
||||
return new WindowSpecificationImpl(this).rowsPreceding(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rowsCurrentRow() {
|
||||
return new WindowSpecificationImpl(this).rowsCurrentRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rowsUnboundedFollowing() {
|
||||
return new WindowSpecificationImpl(this).rowsUnboundedFollowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rowsFollowing(int number) {
|
||||
return new WindowSpecificationImpl(this).rowsFollowing(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rowsBetweenUnboundedPreceding() {
|
||||
return new WindowSpecificationImpl(this).rowsBetweenUnboundedPreceding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rowsBetweenPreceding(int number) {
|
||||
return new WindowSpecificationImpl(this).rowsBetweenPreceding(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rowsBetweenCurrentRow() {
|
||||
return new WindowSpecificationImpl(this).rowsBetweenCurrentRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rowsBetweenUnboundedFollowing() {
|
||||
return new WindowSpecificationImpl(this).rowsBetweenUnboundedFollowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rowsBetweenFollowing(int number) {
|
||||
return new WindowSpecificationImpl(this).rowsBetweenFollowing(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rangeUnboundedPreceding() {
|
||||
return new WindowSpecificationImpl(this).rangeUnboundedPreceding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rangePreceding(int number) {
|
||||
return new WindowSpecificationImpl(this).rangePreceding(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rangeCurrentRow() {
|
||||
return new WindowSpecificationImpl(this).rangeCurrentRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rangeUnboundedFollowing() {
|
||||
return new WindowSpecificationImpl(this).rangeUnboundedFollowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep rangeFollowing(int number) {
|
||||
return new WindowSpecificationImpl(this).rangeFollowing(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rangeBetweenUnboundedPreceding() {
|
||||
return new WindowSpecificationImpl(this).rangeBetweenUnboundedPreceding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rangeBetweenPreceding(int number) {
|
||||
return new WindowSpecificationImpl(this).rangeBetweenPreceding(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rangeBetweenCurrentRow() {
|
||||
return new WindowSpecificationImpl(this).rangeBetweenCurrentRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rangeBetweenUnboundedFollowing() {
|
||||
return new WindowSpecificationImpl(this).rangeBetweenUnboundedFollowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep rangeBetweenFollowing(int number) {
|
||||
return new WindowSpecificationImpl(this).rangeBetweenFollowing(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep groupsUnboundedPreceding() {
|
||||
return new WindowSpecificationImpl(this).groupsUnboundedPreceding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep groupsPreceding(int number) {
|
||||
return new WindowSpecificationImpl(this).groupsPreceding(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep groupsCurrentRow() {
|
||||
return new WindowSpecificationImpl(this).groupsCurrentRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep groupsUnboundedFollowing() {
|
||||
return new WindowSpecificationImpl(this).groupsUnboundedFollowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationExcludeStep groupsFollowing(int number) {
|
||||
return new WindowSpecificationImpl(this).groupsFollowing(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep groupsBetweenUnboundedPreceding() {
|
||||
return new WindowSpecificationImpl(this).groupsBetweenUnboundedPreceding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep groupsBetweenPreceding(int number) {
|
||||
return new WindowSpecificationImpl(this).groupsBetweenPreceding(number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep groupsBetweenCurrentRow() {
|
||||
return new WindowSpecificationImpl(this).groupsBetweenCurrentRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep groupsBetweenUnboundedFollowing() {
|
||||
return new WindowSpecificationImpl(this).groupsBetweenUnboundedFollowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowSpecificationRowsAndStep groupsBetweenFollowing(int number) {
|
||||
return new WindowSpecificationImpl(this).groupsBetweenFollowing(number);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,6 +95,7 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements
|
||||
private static final long serialVersionUID = 2996016924769376361L;
|
||||
private static final EnumSet<SQLDialect> OMIT_PARTITION_BY_ONE = EnumSet.of(CUBRID, MYSQL);
|
||||
|
||||
private final WindowDefinitionImpl windowDefinition;
|
||||
private final QueryPartList<Field<?>> partitionBy;
|
||||
private final SortFieldList orderBy;
|
||||
private Integer frameStart;
|
||||
@ -104,6 +105,11 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements
|
||||
private boolean partitionByOne;
|
||||
|
||||
WindowSpecificationImpl() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
WindowSpecificationImpl(WindowDefinitionImpl windowDefinition) {
|
||||
this.windowDefinition = windowDefinition;
|
||||
this.partitionBy = new QueryPartList<Field<?>>();
|
||||
this.orderBy = new SortFieldList();
|
||||
}
|
||||
@ -112,6 +118,18 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements
|
||||
public final void accept(Context<?> ctx) {
|
||||
String glue = "";
|
||||
|
||||
if (windowDefinition != null) {
|
||||
boolean declareWindows = ctx.declareWindows();
|
||||
|
||||
ctx.sql(glue)
|
||||
.declareWindows(false)
|
||||
.visit(windowDefinition)
|
||||
.declareWindows(declareWindows);
|
||||
|
||||
glue = " ";
|
||||
}
|
||||
|
||||
|
||||
if (!partitionBy.isEmpty()) {
|
||||
|
||||
// Ignore PARTITION BY 1 clause. These databases erroneously map the
|
||||
@ -432,25 +450,25 @@ final class WindowSpecificationImpl extends AbstractQueryPart implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowSpecificationFinalStep excludeCurrentRow() {
|
||||
public final WindowSpecificationFinalStep excludeCurrentRow() {
|
||||
exclude = CURRENT_ROW;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowSpecificationFinalStep excludeGroup() {
|
||||
public final WindowSpecificationFinalStep excludeGroup() {
|
||||
exclude = GROUP;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowSpecificationFinalStep excludeTies() {
|
||||
public final WindowSpecificationFinalStep excludeTies() {
|
||||
exclude = TIES;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WindowSpecificationFinalStep excludeNoOthers() {
|
||||
public final WindowSpecificationFinalStep excludeNoOthers() {
|
||||
exclude = NO_OTHERS;
|
||||
return this;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user