[jOOQ/jOOQ#5810] Emulate QUALIFY where not supported
This includes: - [jOOQ/jOOQ#11663] Wrong order of WINDOW / QUALIFY clauses
This commit is contained in:
parent
71f26063df
commit
4febe602d8
@ -38,9 +38,28 @@
|
||||
package org.jooq;
|
||||
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.MARIADB;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.MYSQL;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -115,7 +134,7 @@ public interface SelectQualifyStep<R extends Record> extends SelectOrderByStep<R
|
||||
* other with {@link Operator#AND}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
SelectQualifyConditionStep<R> qualify(Condition condition);
|
||||
|
||||
/**
|
||||
@ -123,7 +142,7 @@ public interface SelectQualifyStep<R extends Record> extends SelectOrderByStep<R
|
||||
* other with {@link Operator#AND}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
SelectQualifyConditionStep<R> qualify(Condition... conditions);
|
||||
|
||||
/**
|
||||
@ -131,14 +150,14 @@ public interface SelectQualifyStep<R extends Record> extends SelectOrderByStep<R
|
||||
* other with {@link Operator#AND}.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
SelectQualifyConditionStep<R> qualify(Collection<? extends Condition> conditions);
|
||||
|
||||
/**
|
||||
* Add a <code>QUALIFY</code> clause to the query.
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
SelectQualifyConditionStep<R> qualify(Field<Boolean> condition);
|
||||
|
||||
/**
|
||||
@ -153,7 +172,7 @@ public interface SelectQualifyStep<R extends Record> extends SelectOrderByStep<R
|
||||
* @see SQL
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
@PlainSQL
|
||||
SelectQualifyConditionStep<R> qualify(SQL sql);
|
||||
|
||||
@ -169,7 +188,7 @@ public interface SelectQualifyStep<R extends Record> extends SelectOrderByStep<R
|
||||
* @see SQL
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
@PlainSQL
|
||||
SelectQualifyConditionStep<R> qualify(String sql);
|
||||
|
||||
@ -186,7 +205,7 @@ public interface SelectQualifyStep<R extends Record> extends SelectOrderByStep<R
|
||||
* @see SQL
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
@PlainSQL
|
||||
SelectQualifyConditionStep<R> qualify(String sql, Object... bindings);
|
||||
|
||||
@ -203,7 +222,7 @@ public interface SelectQualifyStep<R extends Record> extends SelectOrderByStep<R
|
||||
* @see SQL
|
||||
*/
|
||||
@NotNull
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
@PlainSQL
|
||||
SelectQualifyConditionStep<R> qualify(String sql, QueryPart... parts);
|
||||
|
||||
|
||||
@ -423,7 +423,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
*
|
||||
* @param condition The condition
|
||||
*/
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
void addQualify(Condition condition);
|
||||
|
||||
/**
|
||||
@ -432,7 +432,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
*
|
||||
* @param conditions The condition
|
||||
*/
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
void addQualify(Condition... conditions);
|
||||
|
||||
/**
|
||||
@ -441,7 +441,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
*
|
||||
* @param conditions The condition
|
||||
*/
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
void addQualify(Collection<? extends Condition> conditions);
|
||||
|
||||
/**
|
||||
@ -452,7 +452,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
* conditions
|
||||
* @param condition The condition
|
||||
*/
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
void addQualify(Operator operator, Condition condition);
|
||||
|
||||
/**
|
||||
@ -463,7 +463,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
* conditions
|
||||
* @param conditions The condition
|
||||
*/
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
void addQualify(Operator operator, Condition... conditions);
|
||||
|
||||
/**
|
||||
@ -474,7 +474,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
* conditions
|
||||
* @param conditions The condition
|
||||
*/
|
||||
@Support({ H2 })
|
||||
@Support({ CUBRID, FIREBIRD, H2, MARIADB, MYSQL, POSTGRES, SQLITE })
|
||||
void addQualify(Operator operator, Collection<? extends Condition> conditions);
|
||||
|
||||
/**
|
||||
|
||||
@ -226,7 +226,7 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
|
||||
QueryPart replacement = start(part);
|
||||
|
||||
if (replacement != null) {
|
||||
QueryPartInternal internal = (QueryPartInternal) replacement;
|
||||
QueryPartInternal internal = (QueryPartInternal) scopeMapping(replacement);
|
||||
|
||||
// If this is supposed to be a declaration section and the part isn't
|
||||
// able to declare anything, then disable declaration temporarily
|
||||
@ -701,7 +701,7 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
|
||||
|
||||
@Override
|
||||
public /* non-final */ QueryPart scopeMapping(QueryPart part) {
|
||||
return null;
|
||||
return part;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1011,6 +1011,7 @@ abstract class AbstractContext<C extends Context<C>> extends AbstractScope imple
|
||||
|
||||
ScopeStackElement(QueryPart part, int scopeLevel) {
|
||||
this.part = part;
|
||||
this.mapped = part;
|
||||
this.scopeLevel = scopeLevel;
|
||||
}
|
||||
|
||||
|
||||
@ -100,7 +100,8 @@ implements
|
||||
WindowPartitionByStep<T>,
|
||||
WindowRowsStep<T>,
|
||||
WindowRowsAndStep<T>,
|
||||
WindowExcludeStep<T>
|
||||
WindowExcludeStep<T>,
|
||||
ScopeMappable
|
||||
{
|
||||
|
||||
/**
|
||||
|
||||
@ -93,18 +93,18 @@ import org.jooq.SQLDialect;
|
||||
*/
|
||||
final class BetweenCondition<T> extends AbstractCondition implements BetweenAndStep<T> {
|
||||
|
||||
private static final long serialVersionUID = -4666251100802237878L;
|
||||
private static final Clause[] CLAUSES_BETWEEN = { CONDITION, CONDITION_BETWEEN };
|
||||
private static final Clause[] CLAUSES_BETWEEN_SYMMETRIC = { CONDITION, CONDITION_BETWEEN_SYMMETRIC };
|
||||
private static final Clause[] CLAUSES_NOT_BETWEEN = { CONDITION, CONDITION_NOT_BETWEEN };
|
||||
private static final Clause[] CLAUSES_NOT_BETWEEN_SYMMETRIC = { CONDITION, CONDITION_NOT_BETWEEN_SYMMETRIC };
|
||||
private static final Set<SQLDialect> NO_SUPPORT_SYMMETRIC = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, IGNITE, MARIADB, MYSQL, SQLITE);
|
||||
private static final long serialVersionUID = -4666251100802237878L;
|
||||
private static final Clause[] CLAUSES_BETWEEN = { CONDITION, CONDITION_BETWEEN };
|
||||
private static final Clause[] CLAUSES_BETWEEN_SYMMETRIC = { CONDITION, CONDITION_BETWEEN_SYMMETRIC };
|
||||
private static final Clause[] CLAUSES_NOT_BETWEEN = { CONDITION, CONDITION_NOT_BETWEEN };
|
||||
private static final Clause[] CLAUSES_NOT_BETWEEN_SYMMETRIC = { CONDITION, CONDITION_NOT_BETWEEN_SYMMETRIC };
|
||||
private static final Set<SQLDialect> NO_SUPPORT_SYMMETRIC = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, H2, IGNITE, MARIADB, MYSQL, SQLITE);
|
||||
|
||||
private final boolean symmetric;
|
||||
private final boolean not;
|
||||
private final Field<T> field;
|
||||
private final Field<T> minValue;
|
||||
private Field<T> maxValue;
|
||||
private final boolean symmetric;
|
||||
private final boolean not;
|
||||
final Field<T> field;
|
||||
final Field<T> minValue;
|
||||
Field<T> maxValue;
|
||||
|
||||
BetweenCondition(Field<T> field, Field<T> minValue, boolean not, boolean symmetric) {
|
||||
this.field = nullableIf(false, nullSafe(field, minValue.getDataType()));
|
||||
|
||||
@ -195,21 +195,21 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
|
||||
@Override
|
||||
public QueryPart scopeMapping(QueryPart part) {
|
||||
if (scopeStack.inScope()) {
|
||||
if (part instanceof TableImpl) {
|
||||
ScopeStackElement e = scopeStack.get(part);
|
||||
if (scopeStack.inScope() && part instanceof ScopeMappable) {
|
||||
ScopeStackElement e = scopeStack.get(part);
|
||||
|
||||
if (e != null)
|
||||
return e.mapped;
|
||||
}
|
||||
if (e != null && e.mapped != null)
|
||||
return e.mapped;
|
||||
}
|
||||
|
||||
return null;
|
||||
return part;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderContext scopeRegister(QueryPart part, boolean forceNew, QueryPart mapped) {
|
||||
if (scopeStack.inScope()) {
|
||||
ScopeStackElement e;
|
||||
|
||||
if (part instanceof TableImpl) {
|
||||
Table<?> root = (Table<?>) part;
|
||||
Table<?> child = root;
|
||||
@ -220,11 +220,10 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
root = child;
|
||||
}
|
||||
|
||||
ScopeStackElement e = forceNew
|
||||
e = forceNew
|
||||
? scopeStack.create(root)
|
||||
: scopeStack.getOrCreate(root);
|
||||
|
||||
e.mapped = mapped;
|
||||
if (e.joinNode == null)
|
||||
e.joinNode = new JoinNode(configuration(), root);
|
||||
|
||||
@ -243,15 +242,24 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
}
|
||||
}
|
||||
else if (forceNew)
|
||||
scopeStack.create(part);
|
||||
e = scopeStack.create(part);
|
||||
else
|
||||
scopeStack.getOrCreate(part);
|
||||
e = scopeStack.getOrCreate(part);
|
||||
|
||||
e.mapped = mapped;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
void scopeStart0() {
|
||||
for (ScopeStackElement e : scopeStack) {
|
||||
if (e.part != e.mapped && !(e.part instanceof ScopeNestable))
|
||||
scopeStack.set(e.part, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void scopeEnd0() {
|
||||
ScopeMarker[] markers = ScopeMarker.values();
|
||||
|
||||
@ -99,16 +99,16 @@ import org.jooq.SQLDialect;
|
||||
*/
|
||||
final class InCondition<T> extends AbstractCondition {
|
||||
|
||||
private static final long serialVersionUID = -1653924248576930761L;
|
||||
private static final int IN_LIMIT = 1000;
|
||||
private static final Clause[] CLAUSES_IN = { CONDITION, CONDITION_IN };
|
||||
private static final Clause[] CLAUSES_IN_NOT = { CONDITION, CONDITION_NOT_IN };
|
||||
private static final Set<SQLDialect> REQUIRES_IN_LIMIT = SQLDialect.supportedBy(FIREBIRD);
|
||||
private static final Set<SQLDialect> NO_SUPPORT_EMPTY_LISTS = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, HSQLDB, MARIADB, MYSQL, POSTGRES);
|
||||
private static final long serialVersionUID = -1653924248576930761L;
|
||||
private static final int IN_LIMIT = 1000;
|
||||
private static final Clause[] CLAUSES_IN = { CONDITION, CONDITION_IN };
|
||||
private static final Clause[] CLAUSES_IN_NOT = { CONDITION, CONDITION_NOT_IN };
|
||||
private static final Set<SQLDialect> REQUIRES_IN_LIMIT = SQLDialect.supportedBy(FIREBIRD);
|
||||
private static final Set<SQLDialect> NO_SUPPORT_EMPTY_LISTS = SQLDialect.supportedBy(CUBRID, DERBY, FIREBIRD, HSQLDB, MARIADB, MYSQL, POSTGRES);
|
||||
|
||||
private final Field<T> field;
|
||||
private final List<? extends Field<?>> values;
|
||||
private final Comparator comparator;
|
||||
final Field<T> field;
|
||||
final List<? extends Field<?>> values;
|
||||
final Comparator comparator;
|
||||
|
||||
InCondition(Field<T> field, List<? extends Field<?>> values, Comparator comparator) {
|
||||
this.field = field;
|
||||
|
||||
@ -95,9 +95,9 @@ final class IsDistinctFrom<T> extends AbstractCondition {
|
||||
|
||||
|
||||
|
||||
private final Field<T> lhs;
|
||||
private final Field<T> rhs;
|
||||
private final Comparator comparator;
|
||||
final Field<T> lhs;
|
||||
final Field<T> rhs;
|
||||
final Comparator comparator;
|
||||
|
||||
IsDistinctFrom(Field<T> lhs, Field<T> rhs, Comparator comparator) {
|
||||
this.lhs = lhs;
|
||||
|
||||
@ -50,7 +50,7 @@ final class NotCondition extends AbstractCondition {
|
||||
private static final long serialVersionUID = 2921001862882237932L;
|
||||
private static final Clause[] CLAUSES = { CONDITION, CONDITION_NOT };
|
||||
|
||||
private final Condition condition;
|
||||
final Condition condition;
|
||||
|
||||
NotCondition(Condition condition) {
|
||||
this.condition = condition;
|
||||
|
||||
51
jOOQ/src/main/java/org/jooq/impl/ScopeMappable.java
Normal file
51
jOOQ/src/main/java/org/jooq/impl/ScopeMappable.java
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
|
||||
/**
|
||||
* A marker interface for all query parts that can be mapped via
|
||||
* {@link Context#scopeMapping(QueryPart)}
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
interface ScopeMappable extends QueryPartInternal {
|
||||
}
|
||||
50
jOOQ/src/main/java/org/jooq/impl/ScopeNestable.java
Normal file
50
jOOQ/src/main/java/org/jooq/impl/ScopeNestable.java
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
|
||||
/**
|
||||
* A marker interface for all query parts that are visible from nested scopes.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
interface ScopeNestable extends QueryPartInternal {
|
||||
}
|
||||
@ -184,12 +184,18 @@ final class ScopeStack<K, V> implements Iterable<V> {
|
||||
}
|
||||
|
||||
private final V get0(List<V> list) {
|
||||
int i = list.size() - 1;
|
||||
return i == -1 ? null : list.get(i);
|
||||
int i;
|
||||
|
||||
if (list == null)
|
||||
return null;
|
||||
else if ((i = list.size()) == 0)
|
||||
return null;
|
||||
else
|
||||
return list.get(i - 1);
|
||||
}
|
||||
|
||||
final V get(K key) {
|
||||
return get0(list(key));
|
||||
return get0(listOrNull(key));
|
||||
}
|
||||
|
||||
final <T extends Throwable> V getOrThrow(K key, Supplier<T> exception) throws T {
|
||||
@ -223,6 +229,10 @@ final class ScopeStack<K, V> implements Iterable<V> {
|
||||
list.set(scopeLevel, value);
|
||||
}
|
||||
|
||||
private List<V> listOrNull(K key) {
|
||||
return stack().get(key);
|
||||
}
|
||||
|
||||
private List<V> list(K key) {
|
||||
return stack().computeIfAbsent(key, k -> new ArrayList<>());
|
||||
}
|
||||
|
||||
@ -74,6 +74,7 @@ import static org.jooq.SQLDialect.DEFAULT;
|
||||
import static org.jooq.SQLDialect.DERBY;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
@ -170,12 +171,16 @@ import static org.jooq.impl.SQLDataType.XML;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.EMPTY_SORTFIELD;
|
||||
import static org.jooq.impl.Tools.fieldArray;
|
||||
import static org.jooq.impl.Tools.fieldName;
|
||||
import static org.jooq.impl.Tools.hasAmbiguousNames;
|
||||
import static org.jooq.impl.Tools.isNotEmpty;
|
||||
import static org.jooq.impl.Tools.qualify;
|
||||
import static org.jooq.impl.Tools.recordType;
|
||||
import static org.jooq.impl.Tools.selectQueryImpl;
|
||||
import static org.jooq.impl.Tools.traverseConditions;
|
||||
import static org.jooq.impl.Tools.traverseJoins;
|
||||
import static org.jooq.impl.Tools.traverseOrderBy;
|
||||
import static org.jooq.impl.Tools.traverseSelectList;
|
||||
import static org.jooq.impl.Tools.unalias;
|
||||
import static org.jooq.impl.Tools.unqualified;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_COLLECT_SEMI_ANTI_JOIN;
|
||||
@ -203,12 +208,15 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -244,6 +252,7 @@ import org.jooq.SelectOffsetStep;
|
||||
import org.jooq.SelectQuery;
|
||||
import org.jooq.SelectWithTiesStep;
|
||||
import org.jooq.SortField;
|
||||
import org.jooq.Support;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableField;
|
||||
import org.jooq.TableLike;
|
||||
@ -325,6 +334,8 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -379,7 +390,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
private final QueryPartList<Field<?>> unionSeek;
|
||||
private boolean unionSeekBefore; // [#3579] TODO
|
||||
private final Limit unionLimit;
|
||||
private final Map<Table<?>, Table<?>> localTableMapping;
|
||||
private final Map<QueryPart, QueryPart> localQueryPartMapping;
|
||||
|
||||
SelectQueryImpl(Configuration configuration, WithImpl with) {
|
||||
this(configuration, with, null);
|
||||
@ -419,7 +430,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
if (from != null)
|
||||
this.from.add(from.asTable());
|
||||
|
||||
this.localTableMapping = new LinkedHashMap<>();
|
||||
this.localQueryPartMapping = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -596,10 +607,9 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
private final SelectQueryImpl<R> nest(SelectQueryImpl<R> result, SelectQueryImpl<R> nested, Function<? super SelectQueryImpl<R>, ? extends SelectQueryImpl<R>> nestedFinisher) {
|
||||
|
||||
// [#10716] TODO: Qualify all fields with c1, c2, to avoid ambiguous
|
||||
nested.select.add(DSL.asterisk());
|
||||
nested = nestedFinisher.apply(nested);
|
||||
Table<R> t = nested.asTable("t");
|
||||
traverseJoins(from, t0 -> result.localTableMapping.put(t0, t));
|
||||
traverseJoins(from, t0 -> result.localQueryPartMapping.put(t0, t));
|
||||
|
||||
result.from.add(t);
|
||||
return result;
|
||||
@ -1345,7 +1355,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
final Select<?> distinctOnEmulation() {
|
||||
private final Select<?> distinctOnEmulation() {
|
||||
|
||||
// [#3564] TODO: Extract and merge this with getSelectResolveSomeAsterisks0()
|
||||
List<Field<?>> partitionBy = new ArrayList<>(distinctOn.size());
|
||||
@ -1378,6 +1388,39 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
return limit.offset != null ? s1.offset((Param) limit.offset) : s1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
Table<?> dmlTable;
|
||||
@ -1391,7 +1434,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
ctx.visit(DSL.select(asterisk()).from(asTable("t")));
|
||||
}
|
||||
|
||||
// [#3564] Emulate DISINTCT ON queries at the top level
|
||||
// [#3564] Emulate DISTINCT ON queries at the top level
|
||||
else if (Tools.isNotEmpty(distinctOn) && EMULATE_DISTINCT_ON.contains(ctx.dialect())) {
|
||||
ctx.visit(distinctOnEmulation());
|
||||
}
|
||||
@ -1418,6 +1461,11 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2020,7 +2068,7 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
context.scopeRegister(t, true);
|
||||
});
|
||||
|
||||
for (Entry<Table<?>, Table<?>> entry : localTableMapping.entrySet())
|
||||
for (Entry<QueryPart, QueryPart> entry : localQueryPartMapping.entrySet())
|
||||
context.scopeRegister(entry.getKey(), true, entry.getValue());
|
||||
|
||||
// SELECT clause
|
||||
@ -2317,15 +2365,6 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
context.end(SELECT_HAVING);
|
||||
|
||||
// QUALIFY clause
|
||||
// -------------
|
||||
|
||||
if (getQualify().hasWhere())
|
||||
context.formatSeparator()
|
||||
.visit(K_QUALIFY)
|
||||
.sql(' ')
|
||||
.visit(getQualify());
|
||||
|
||||
// WINDOW clause
|
||||
// -------------
|
||||
context.start(SELECT_WINDOW);
|
||||
@ -2338,6 +2377,15 @@ final class SelectQueryImpl<R extends Record> extends AbstractResultQuery<R> imp
|
||||
|
||||
context.end(SELECT_WINDOW);
|
||||
|
||||
// QUALIFY clause
|
||||
// -------------
|
||||
|
||||
if (getQualify().hasWhere())
|
||||
context.formatSeparator()
|
||||
.visit(K_QUALIFY)
|
||||
.sql(' ')
|
||||
.visit(getQualify());
|
||||
|
||||
// ORDER BY clause for local subselect
|
||||
// -----------------------------------
|
||||
toSQLOrderBy(
|
||||
|
||||
@ -84,7 +84,7 @@ import org.jooq.tools.StringUtils;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@org.jooq.Internal
|
||||
public class TableImpl<R extends Record> extends AbstractTable<R> {
|
||||
public class TableImpl<R extends Record> extends AbstractTable<R> implements ScopeMappable, ScopeNestable {
|
||||
|
||||
private static final long serialVersionUID = 261033315221985068L;
|
||||
private static final Clause[] CLAUSES_TABLE_REFERENCE = { TABLE, TABLE_REFERENCE };
|
||||
@ -305,15 +305,6 @@ public class TableImpl<R extends Record> extends AbstractTable<R> {
|
||||
}
|
||||
|
||||
private void accept0(Context<?> ctx) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (ctx.declareTables())
|
||||
ctx.scopeMarkStart(this);
|
||||
|
||||
|
||||
@ -6090,6 +6090,9 @@ final class Tools {
|
||||
: field;
|
||||
}
|
||||
|
||||
// TODO: In a new expression tree model, we'll support generic visitors of some sort
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
static final void traverseJoins(Iterable<? extends Table<?>> i, Consumer<? super Table<?>> consumer) {
|
||||
for (Table<?> t : i)
|
||||
traverseJoins(t, consumer);
|
||||
@ -6103,4 +6106,53 @@ final class Tools {
|
||||
else
|
||||
consumer.accept(t);
|
||||
}
|
||||
|
||||
static final void traverseSelectList(SelectFieldList<?> list, Consumer<? super Field<?>> consumer) {
|
||||
|
||||
// TODO: Traverse expressions as well
|
||||
for (SelectFieldOrAsterisk f : list)
|
||||
if (f instanceof Field)
|
||||
consumer.accept((Field<?>) f);
|
||||
}
|
||||
|
||||
static final void traverseOrderBy(SortFieldList list, Consumer<? super Field<?>> consumer) {
|
||||
|
||||
// TODO: Traverse expressions as well
|
||||
for (SortField<?> f : list)
|
||||
consumer.accept(((SortFieldImpl<?>) f).getField());
|
||||
}
|
||||
|
||||
static final void traverseConditions(Condition condition, Consumer<? super Field<?>> consumer) {
|
||||
if (condition instanceof CombinedCondition) {
|
||||
for (Condition c : ((CombinedCondition) condition).conditions)
|
||||
traverseConditions(c, consumer);
|
||||
}
|
||||
else if (condition instanceof NotCondition) {
|
||||
traverseConditions(((NotCondition) condition).condition, consumer);
|
||||
}
|
||||
else if (condition instanceof BetweenCondition) {
|
||||
consumer.accept(((BetweenCondition<?>) condition).field);
|
||||
consumer.accept(((BetweenCondition<?>) condition).minValue);
|
||||
consumer.accept(((BetweenCondition<?>) condition).maxValue);
|
||||
}
|
||||
else if (condition instanceof CompareCondition) {
|
||||
consumer.accept(((CompareCondition) condition).field1);
|
||||
consumer.accept(((CompareCondition) condition).field2);
|
||||
}
|
||||
else if (condition instanceof FieldCondition) {
|
||||
consumer.accept(((FieldCondition) condition).field);
|
||||
}
|
||||
else if (condition instanceof InCondition) {
|
||||
consumer.accept(((InCondition<?>) condition).field);
|
||||
|
||||
for (Field<?> f : ((InCondition<?>) condition).values)
|
||||
consumer.accept(f);
|
||||
}
|
||||
else if (condition instanceof IsDistinctFrom) {
|
||||
consumer.accept(((IsDistinctFrom<?>) condition).lhs);
|
||||
consumer.accept(((IsDistinctFrom<?>) condition).rhs);
|
||||
}
|
||||
|
||||
// TODO: Other conditions
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user