[jOOQ/jOOQ#11473] Use AliasedSelect instead of DerivedTable for MULTISET
A DerivedTable with table aliases produces a UNION subquery, and then we run into this limitation in some dialects: [jOOQ/jOOQ#3791], where UNION subqueries are not allowed to contain ORDER BY. The limitation can be worked around by using AliasedSelect instead of a DerivedTable, though again, there's a limitation that we can run into, though a less severe one: [jOOQ/jOOQ#11473], where AliasedSelect doesn't work correctly yet if original aliases (prior to re-aliasing) are referenced from ORDER BY
This commit is contained in:
parent
954e2acea5
commit
3d9e87f1c0
@ -63,17 +63,19 @@ final class AliasedSelect<R extends Record> extends AbstractTable<R> {
|
||||
|
||||
private final Select<R> query;
|
||||
private final boolean subquery;
|
||||
private final boolean ignoreOrderBy;
|
||||
private final Name[] aliases;
|
||||
|
||||
AliasedSelect(Select<R> query, boolean subquery) {
|
||||
this(query, subquery, Tools.fieldNames(Tools.degree(query)));
|
||||
AliasedSelect(Select<R> query, boolean subquery, boolean ignoreOrderBy) {
|
||||
this(query, subquery, ignoreOrderBy, Tools.fieldNames(Tools.degree(query)));
|
||||
}
|
||||
|
||||
AliasedSelect(Select<R> query, boolean subquery, Name... aliases) {
|
||||
AliasedSelect(Select<R> query, boolean subquery, boolean ignoreOrderBy, Name... aliases) {
|
||||
super(TableOptions.expression(), N_SELECT);
|
||||
|
||||
this.query = query;
|
||||
this.subquery = subquery;
|
||||
this.ignoreOrderBy = ignoreOrderBy;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
@ -85,7 +87,9 @@ final class AliasedSelect<R extends Record> extends AbstractTable<R> {
|
||||
public final Table<R> as(Name alias) {
|
||||
SelectQueryImpl<R> q = selectQueryImpl(query);
|
||||
|
||||
if (q != null && (!q.getOrderBy().isEmpty() || Tools.hasEmbeddedFields(q.getSelect())))
|
||||
// [#11473] In the presence of ORDER BY, AliasedSelect tends not to work
|
||||
// correctly if ORDER BY references names available prior to the aliasing only
|
||||
if (q != null && (ignoreOrderBy && !q.getOrderBy().isEmpty() || Tools.hasEmbeddedFields(q.getSelect())))
|
||||
return query.asTable(alias, aliases);
|
||||
else
|
||||
return new TableAlias<>(this, alias, c -> true);
|
||||
|
||||
@ -65,7 +65,7 @@ final class FetchCount extends AbstractResultQuery<Record1<Integer>> {
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
ctx.visit(select(count).from(new AliasedSelect<>(query, true).as("t")));
|
||||
ctx.visit(select(count).from(new AliasedSelect<>(query, true, true).as("t")));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
|
||||
@ -65,6 +65,7 @@ import static org.jooq.impl.Tools.emulateMultiset;
|
||||
import static org.jooq.impl.Tools.fieldName;
|
||||
import static org.jooq.impl.Tools.fieldNameString;
|
||||
import static org.jooq.impl.Tools.fieldNameStrings;
|
||||
import static org.jooq.impl.Tools.fieldNames;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_MULTISET_CONDITION;
|
||||
@ -81,6 +82,7 @@ import org.jooq.JSONArrayAggOrderByStep;
|
||||
import org.jooq.JSONArrayAggReturningStep;
|
||||
import org.jooq.JSONArrayReturningStep;
|
||||
import org.jooq.JSONB;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.Result;
|
||||
@ -96,8 +98,9 @@ import org.jooq.XMLAggOrderByStep;
|
||||
*/
|
||||
final class Multiset<R extends Record> extends AbstractField<Result<R>> {
|
||||
|
||||
static final Set<SQLDialect> NO_SUPPORT_JSON_COMPARE = SQLDialect.supportedBy(POSTGRES);
|
||||
static final Set<SQLDialect> NO_SUPPORT_XML_COMPARE = SQLDialect.supportedBy(POSTGRES);
|
||||
static final Set<SQLDialect> NO_SUPPORT_JSON_COMPARE = SQLDialect.supportedBy(POSTGRES);
|
||||
static final Set<SQLDialect> NO_SUPPORT_JSONB_COMPARE = SQLDialect.supportedBy();
|
||||
static final Set<SQLDialect> NO_SUPPORT_XML_COMPARE = SQLDialect.supportedBy(POSTGRES);
|
||||
|
||||
final Select<R> select;
|
||||
|
||||
@ -134,7 +137,7 @@ final class Multiset<R extends Record> extends AbstractField<Result<R>> {
|
||||
private final void accept0(Context<?> ctx, boolean multisetCondition) {
|
||||
switch (emulateMultiset(ctx.configuration())) {
|
||||
case JSON: {
|
||||
Table<?> t = select.asTable("t", fieldNameStrings(select.getSelect().size()));
|
||||
Table<?> t = new AliasedSelect<>(select, true, false, fieldNames(select.getSelect().size())).as(DSL.name("t"), (Name[]) null);
|
||||
|
||||
switch (ctx.family()) {
|
||||
|
||||
@ -177,7 +180,7 @@ final class Multiset<R extends Record> extends AbstractField<Result<R>> {
|
||||
}
|
||||
|
||||
case JSONB: {
|
||||
Table<?> t = select.asTable("t", fieldNameStrings(select.getSelect().size()));
|
||||
Table<?> t = new AliasedSelect<>(select, true, false, fieldNames(select.getSelect().size())).as(DSL.name("t"), (Name[]) null);
|
||||
|
||||
switch (ctx.family()) {
|
||||
|
||||
@ -207,7 +210,10 @@ final class Multiset<R extends Record> extends AbstractField<Result<R>> {
|
||||
)).from(t)
|
||||
);
|
||||
|
||||
visitSubquery(ctx, s, true);
|
||||
if (multisetCondition && NO_SUPPORT_JSONB_COMPARE.contains(ctx.dialect()))
|
||||
ctx.visit(DSL.field(s).cast(VARCHAR));
|
||||
else
|
||||
visitSubquery(ctx, s, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -217,7 +223,7 @@ final class Multiset<R extends Record> extends AbstractField<Result<R>> {
|
||||
|
||||
case XML: {
|
||||
List<Field<?>> fields = select.getSelect();
|
||||
Table<?> t = select.asTable("t", fieldNameStrings(fields.size()));
|
||||
Table<?> t = new AliasedSelect<>(select, true, false, fieldNames(fields.size())).as(DSL.name("t"), (Name[]) null);
|
||||
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
@ -39,12 +39,9 @@ package org.jooq.impl;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.jsonArrayAgg;
|
||||
import static org.jooq.impl.DSL.jsonObject;
|
||||
import static org.jooq.impl.DSL.jsonbArrayAgg;
|
||||
import static org.jooq.impl.DSL.xmlagg;
|
||||
import static org.jooq.impl.DSL.xmlelement;
|
||||
import static org.jooq.impl.DSL.xmlserializeContent;
|
||||
import static org.jooq.impl.Multiset.NO_SUPPORT_JSONB_COMPARE;
|
||||
import static org.jooq.impl.Multiset.NO_SUPPORT_JSON_COMPARE;
|
||||
import static org.jooq.impl.Multiset.NO_SUPPORT_XML_COMPARE;
|
||||
import static org.jooq.impl.Multiset.jsonArrayaggEmulation;
|
||||
@ -52,12 +49,9 @@ import static org.jooq.impl.Multiset.jsonbArrayaggEmulation;
|
||||
import static org.jooq.impl.Multiset.returningClob;
|
||||
import static org.jooq.impl.Multiset.xmlaggEmulation;
|
||||
import static org.jooq.impl.Names.N_MULTISET_AGG;
|
||||
import static org.jooq.impl.Names.N_RECORD;
|
||||
import static org.jooq.impl.Names.N_RESULT;
|
||||
import static org.jooq.impl.SQLDataType.VARCHAR;
|
||||
import static org.jooq.impl.Tools.emulateMultiset;
|
||||
import static org.jooq.impl.Tools.fieldName;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_MULTISET_CONDITION;
|
||||
|
||||
import org.jooq.Context;
|
||||
@ -71,8 +65,6 @@ import org.jooq.SelectField;
|
||||
import org.jooq.XML;
|
||||
import org.jooq.XMLAggOrderByStep;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@ -134,7 +126,12 @@ final class MultisetAgg<R extends Record> extends DefaultAggregateFunction<Resul
|
||||
? fo((AbstractAggregateFunction<?>) returningClob(ctx, order.orderBy(row.fields())))
|
||||
: ofo((AbstractAggregateFunction<?>) returningClob(ctx, order));
|
||||
|
||||
ctx.visit(f);
|
||||
|
||||
if (multisetCondition && NO_SUPPORT_JSONB_COMPARE.contains(ctx.dialect()))
|
||||
ctx.visit(f.cast(VARCHAR));
|
||||
else
|
||||
ctx.visit(f);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -212,7 +212,7 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L
|
||||
|
||||
Table<?> t = query.array != null
|
||||
? new ArrayTable(query.array).asTable("t", "pattern")
|
||||
: new AliasedSelect<>(query.query, true, name("pattern")).as("t");
|
||||
: new AliasedSelect<>(query.query, true, true, name("pattern")).as("t");
|
||||
Select<Record1<Boolean>> select = select(DSL.field(cond)).from(t);
|
||||
ctx.visit(lhs.eq(query.quantifier.apply(select)));
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ final class RowIsNull extends AbstractCondition {
|
||||
acceptStandard(ctx);
|
||||
}
|
||||
else {
|
||||
Table<?> t = new AliasedSelect<>(select, true).as("t");
|
||||
Table<?> t = new AliasedSelect<>(select, true, true).as("t");
|
||||
ctx.visit(inline(1).eq(selectCount().from(t).where(condition(t.fields()))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ final class RowSubqueryCondition extends AbstractCondition {
|
||||
Name[] names = fieldNames(l.size());
|
||||
|
||||
return select()
|
||||
.from(new AliasedSelect<>(s, true, names).as(table))
|
||||
.from(new AliasedSelect<>(s, true, true, names).as(table))
|
||||
.where(c == null
|
||||
? noCondition()
|
||||
: new RowCondition(l, row(fieldsByName(table, names)), c));
|
||||
|
||||
@ -5551,7 +5551,7 @@ final class Tools {
|
||||
List<Field<?>> result = collect(flattenCollection(select, false, false));
|
||||
Name tableName = name("t");
|
||||
Name[] fieldNames = fieldNames(result.size());
|
||||
Table<?> t = new AliasedSelect<>(field.query, true, fieldNames).as("t");
|
||||
Table<?> t = new AliasedSelect<>(field.query, true, true, fieldNames).as("t");
|
||||
for (int i = 0; i < result.size(); i++)
|
||||
result.set(i, DSL.field(DSL.select(DSL.field(tableName.append(fieldNames[i]), result.get(i).getDataType())).from(t)));
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user