[jOOQ/jOOQ#5799] Add support for the SQL Standard WITH ORDINALITY clause
This includes: - [jOOQ/jOOQ#14406] The AutoAlias feature isn't applied from within the JOIN tree, only from the TableList - Update AutoAlias to allow for auto-aliasing other tables than this - Add NoAutoAlias to prevent aliasing in derived column list emulations - Removed TableWithOrdinalityStep again, all Table types are supported - Implement emulations - Added an AbstractAutoAliasTable base implementation for AliasTable - [jOOQ/jOOQ#14409] Refactor Values to implement AutoAlias - [jOOQ/jOOQ#13971] Use DataType::array internally - [jOOQ/jOOQ#14388] Fix data type of ArrayConcat expression
This commit is contained in:
parent
b7c2c5e347
commit
ad66b4ec3b
@ -985,7 +985,7 @@ public enum SQLDialect {
|
||||
for (SQLDialect dialect : dialects)
|
||||
result.addAll(dialect.predecessors());
|
||||
|
||||
return Collections.unmodifiableSet(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1026,7 +1026,7 @@ public enum SQLDialect {
|
||||
public static final Set<SQLDialect> supportedBy(SQLDialect dialect) {
|
||||
EnumSet<SQLDialect> result = EnumSet.noneOf(SQLDialect.class);
|
||||
addSupportedBy(dialect, result);
|
||||
return Collections.unmodifiableSet(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1044,7 +1044,7 @@ public enum SQLDialect {
|
||||
for (SQLDialect dialect : dialects)
|
||||
addSupportedBy(dialect, result);
|
||||
|
||||
return Collections.unmodifiableSet(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final void addSupportedBy(SQLDialect dialect, EnumSet<SQLDialect> supported) {
|
||||
|
||||
@ -50,6 +50,7 @@ import static org.jooq.SQLDialect.DERBY;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
@ -63,6 +64,7 @@ import static org.jooq.SQLDialect.MYSQL;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
// ...
|
||||
// ...
|
||||
@ -3021,6 +3023,13 @@ extends
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
119
jOOQ/src/main/java/org/jooq/impl/AbstractAutoAliasTable.java
Normal file
119
jOOQ/src/main/java/org/jooq/impl/AbstractAutoAliasTable.java
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableOptions;
|
||||
|
||||
/**
|
||||
* A base implementation for {@link AutoAlias} and {@link Table}.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
abstract class AbstractAutoAliasTable<R extends Record>
|
||||
extends
|
||||
AbstractTable<R>
|
||||
implements
|
||||
AutoAlias<Table<R>>
|
||||
{
|
||||
|
||||
final Name alias;
|
||||
final Name[] fieldAliases;
|
||||
|
||||
AbstractAutoAliasTable(Name alias) {
|
||||
this(alias, null);
|
||||
}
|
||||
|
||||
AbstractAutoAliasTable(Name alias, Name[] fieldAliases) {
|
||||
super(TableOptions.expression(), alias != null ? alias : DSL.name("t"));
|
||||
|
||||
this.alias = alias;
|
||||
this.fieldAliases = fieldAliases;
|
||||
}
|
||||
|
||||
abstract AbstractAutoAliasTable<R> construct(Name newAlias, Name[] newFieldAliases);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Table API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final boolean declaresTables() {
|
||||
|
||||
// Always true, because unnested tables are always aliased
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<R> autoAlias(Context<?> ctx, Table<R> t) {
|
||||
|
||||
// TODO [#5799] Possibly, add dialect specific behaviour?
|
||||
return t.as(alias, fieldAliases);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: DSL API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Table<R> as(Name as) {
|
||||
return new TableAlias<>(construct(as, null), as, fieldAliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<R> as(Name as, Name... fields) {
|
||||
return new TableAlias<>(construct(as, fields), as, fields);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Table<R> $aliased() {
|
||||
return construct(alias, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Name $alias() {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
@ -229,19 +229,19 @@ implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SelectField<R> autoAlias(Context<?> ctx) {
|
||||
public final SelectField<R> autoAlias(Context<?> ctx, SelectField<R> s) {
|
||||
|
||||
// [#13843] Re-aliasing only applies if at least ROW() projection is supported natively
|
||||
if (RowAsField.NO_NATIVE_SUPPORT.contains(ctx.dialect()))
|
||||
return this;
|
||||
return s;
|
||||
|
||||
// [#13843] Within MULTISET(), re-aliasing isn't required, while it leads to new edge cases
|
||||
else if (forceMultisetContent(ctx, () -> getDataType().getRow().size() > 1))
|
||||
return this;
|
||||
return s;
|
||||
|
||||
// [#13843] With native support, re-alias the table as field projection
|
||||
else
|
||||
return new FieldAlias<>(this, getUnqualifiedName());
|
||||
return new FieldAlias<>(DSL.field(s), getUnqualifiedName());
|
||||
}
|
||||
|
||||
private static final Field<?> alias(Context<?> ctx, Name alias, Field<?> field) {
|
||||
|
||||
@ -1112,6 +1112,12 @@ implements
|
||||
return as(otherTable.getUnqualifiedName(), (f, i) -> aliasFunction.apply(f, i).getUnqualifiedName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Table<Record> withOrdinality() {
|
||||
return new OrdinalityTable<>(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -80,6 +80,7 @@ import static org.jooq.impl.DSL.falseCondition;
|
||||
import static org.jooq.impl.DSL.field;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.Keywords.K_AS;
|
||||
import static org.jooq.impl.NoAutoAlias.noAutoAlias;
|
||||
import static org.jooq.impl.QueryPartListView.wrap;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.DERIVED_TABLE;
|
||||
import static org.jooq.impl.Tools.EMPTY_NAME;
|
||||
@ -230,7 +231,7 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart implements UEmp
|
||||
&& (SUPPORT_DERIVED_COLUMN_NAMES_SPECIAL1.contains(dialect))
|
||||
&& (wrapped instanceof TableImpl || wrapped instanceof CommonTableExpressionImpl)) {
|
||||
|
||||
visitSubquery(context, select(asterisk()).from(((Table<?>) wrapped).as(alias)), DERIVED_TABLE);
|
||||
visitSubquery(context, select(asterisk()).from(noAutoAlias((Table<?>) wrapped).as(alias)), DERIVED_TABLE);
|
||||
}
|
||||
|
||||
// [#1801] Some databases do not support "derived column names".
|
||||
@ -258,7 +259,7 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart implements UEmp
|
||||
? s
|
||||
: wrapped instanceof DerivedTable<?> d
|
||||
? d.query()
|
||||
: select(asterisk()).from(((Table<?>) wrapped).as(alias));
|
||||
: select(asterisk()).from(noAutoAlias((Table<?>) wrapped).as(alias));
|
||||
|
||||
List<Field<?>> select = wrappedAsSelect.getSelect();
|
||||
|
||||
|
||||
@ -81,10 +81,10 @@ implements
|
||||
) {
|
||||
super(
|
||||
N_ARRAY_APPEND,
|
||||
allNotNull(((DataType) OTHER).getArrayDataType(), arg1, arg2)
|
||||
allNotNull((DataType) dataType(((DataType) OTHER).array(), arg1, false), arg1, arg2)
|
||||
);
|
||||
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).getArrayDataType());
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).array());
|
||||
this.arg2 = nullSafeNotNull(arg2, (DataType) OTHER);
|
||||
}
|
||||
|
||||
|
||||
@ -81,11 +81,11 @@ implements
|
||||
) {
|
||||
super(
|
||||
N_ARRAY_CONCAT,
|
||||
allNotNull(((DataType) OTHER).getArrayDataType(), arg1, arg2)
|
||||
allNotNull((DataType) dataType(((DataType) OTHER).array(), arg1, false), arg1, arg2)
|
||||
);
|
||||
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).getArrayDataType());
|
||||
this.arg2 = nullSafeNotNull(arg2, ((DataType) OTHER).getArrayDataType());
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).array());
|
||||
this.arg2 = nullSafeNotNull(arg2, ((DataType) OTHER).array());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -84,7 +84,7 @@ implements
|
||||
allNotNull((DataType<T>) StringUtils.defaultIfNull(array.getDataType().getArrayComponentDataType(), OTHER), array, index)
|
||||
);
|
||||
|
||||
this.array = nullSafeNotNull(array, ((DataType) OTHER).getArrayDataType());
|
||||
this.array = nullSafeNotNull(array, ((DataType) OTHER).array());
|
||||
this.index = nullSafeNotNull(index, INTEGER);
|
||||
}
|
||||
|
||||
|
||||
@ -46,9 +46,7 @@ import static org.jooq.impl.Tools.isEmpty;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableOptions;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
import org.jooq.impl.QOM.UTransient;
|
||||
@ -58,12 +56,15 @@ import org.jooq.impl.QOM.UTransient;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class ArrayOfValues extends AbstractTable<Record> implements UNotYetImplemented {
|
||||
final class ArrayOfValues
|
||||
extends
|
||||
AbstractAutoAliasTable<Record>
|
||||
implements
|
||||
UNotYetImplemented
|
||||
{
|
||||
|
||||
private final Field<?>[] array;
|
||||
private final FieldsImpl<Record> field;
|
||||
private final Name alias;
|
||||
private final Name[] fieldAliases;
|
||||
|
||||
ArrayOfValues(Field<?>[] array) {
|
||||
this(array, N_ARRAY_TABLE);
|
||||
@ -74,37 +75,37 @@ final class ArrayOfValues extends AbstractTable<Record> implements UNotYetImplem
|
||||
}
|
||||
|
||||
ArrayOfValues(Field<?>[] array, Name alias, Name[] fieldAliases) {
|
||||
super(TableOptions.expression(), alias);
|
||||
super(alias, ArrayTable.fieldAliases(fieldAliases));
|
||||
|
||||
Class<?> arrayType = !isEmpty(array) ? array[0].getType() : Object.class;
|
||||
|
||||
this.array = array;
|
||||
this.alias = alias;
|
||||
this.fieldAliases = isEmpty(fieldAliases) ? new Name[] { N_COLUMN_VALUE } : fieldAliases;
|
||||
this.field = ArrayTable.init(arrayType, this.alias, this.fieldAliases[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
final ArrayOfValues construct(Name newAlias, Name[] newFieldAliases) {
|
||||
return new ArrayOfValues(array, newAlias, newFieldAliases);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Table API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Class<? extends Record> getRecordType() {
|
||||
// TODO: [#4695] Calculate the correct Record[B] type
|
||||
return RecordImplN.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record> as(Name as) {
|
||||
return new ArrayOfValues(array, as);
|
||||
final FieldsImpl<Record> fields0() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record> as(Name as, Name... fields) {
|
||||
return new ArrayOfValues(array, as, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean declaresTables() {
|
||||
|
||||
// Always true, because unnested tables are always aliased
|
||||
return true;
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
@ -133,16 +134,16 @@ final class ArrayOfValues extends AbstractTable<Record> implements UNotYetImplem
|
||||
case MARIADB:
|
||||
case MYSQL:
|
||||
case SQLITE:
|
||||
ctx.visit(new ArrayTableEmulation(array).as(alias, fieldAliases));
|
||||
ctx.visit(new ArrayTableEmulation(array, fieldAliases));
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx.visit(new PostgresHSQLDBTable().as(alias, fieldAliases));
|
||||
ctx.visit(new StandardUnnest());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private class PostgresHSQLDBTable extends DialectArrayTable {
|
||||
private class StandardUnnest extends DialectArrayTable {
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
@ -166,23 +167,4 @@ final class ArrayOfValues extends AbstractTable<Record> implements UNotYetImplem
|
||||
return ArrayOfValues.this.fields0();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<Record> fields0() {
|
||||
return field;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Table<Record> $aliased() {
|
||||
return new ArrayOfValues(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Name $alias() {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,8 +80,8 @@ implements
|
||||
Field<T[]> arg2
|
||||
) {
|
||||
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).getArrayDataType());
|
||||
this.arg2 = nullSafeNotNull(arg2, ((DataType) OTHER).getArrayDataType());
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).array());
|
||||
this.arg2 = nullSafeNotNull(arg2, ((DataType) OTHER).array());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -81,11 +81,11 @@ implements
|
||||
) {
|
||||
super(
|
||||
N_ARRAY_PREPEND,
|
||||
allNotNull(((DataType) OTHER).getArrayDataType(), arg1, arg2)
|
||||
allNotNull((DataType) dataType(((DataType) OTHER).array(), arg2, false), arg1, arg2)
|
||||
);
|
||||
|
||||
this.arg1 = nullSafeNotNull(arg1, (DataType) OTHER);
|
||||
this.arg2 = nullSafeNotNull(arg2, ((DataType) OTHER).getArrayDataType());
|
||||
this.arg2 = nullSafeNotNull(arg2, ((DataType) OTHER).array());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -81,10 +81,10 @@ implements
|
||||
) {
|
||||
super(
|
||||
N_ARRAY_REMOVE,
|
||||
allNotNull(((DataType) OTHER).getArrayDataType(), arg1, arg2)
|
||||
allNotNull((DataType) dataType(((DataType) OTHER).array(), arg1, false), arg1, arg2)
|
||||
);
|
||||
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).getArrayDataType());
|
||||
this.arg1 = nullSafeNotNull(arg1, ((DataType) OTHER).array());
|
||||
this.arg2 = nullSafeNotNull(arg2, (DataType) OTHER);
|
||||
}
|
||||
|
||||
|
||||
@ -48,30 +48,32 @@ import static org.jooq.impl.Tools.map;
|
||||
// ...
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Param;
|
||||
// ...
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableOptions;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
import org.jooq.impl.QOM.UTransient;
|
||||
import org.jooq.util.h2.H2DataType;
|
||||
|
||||
/**
|
||||
* An unnested array
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class ArrayTable extends AbstractTable<Record> implements UNotYetImplemented {
|
||||
final class ArrayTable
|
||||
extends
|
||||
AbstractAutoAliasTable<Record>
|
||||
implements
|
||||
UNotYetImplemented
|
||||
{
|
||||
|
||||
private final Field<?> array;
|
||||
private final FieldsImpl<Record> field;
|
||||
private final Name alias;
|
||||
private final Name[] fieldAliases;
|
||||
|
||||
ArrayTable(Field<?> array) {
|
||||
this(array, N_ARRAY_TABLE);
|
||||
@ -85,7 +87,7 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
ArrayTable(Field<?> array, Name alias, Name[] fieldAliases) {
|
||||
super(TableOptions.expression(), alias);
|
||||
super(alias, fieldAliases(fieldAliases));
|
||||
|
||||
Class<?> arrayType;
|
||||
|
||||
@ -111,11 +113,13 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
arrayType = Object.class;
|
||||
|
||||
this.array = array;
|
||||
this.alias = alias;
|
||||
this.fieldAliases = Tools.isEmpty(fieldAliases) ? new Name[] { N_COLUMN_VALUE } : fieldAliases;
|
||||
this.field = init(arrayType, this.alias, this.fieldAliases[0]);
|
||||
}
|
||||
|
||||
static Name[] fieldAliases(Name[] fieldAliases) {
|
||||
return isEmpty(fieldAliases) ? new Name[] { N_COLUMN_VALUE } : fieldAliases;
|
||||
}
|
||||
|
||||
static final FieldsImpl<Record> init(Class<?> arrayType, Name alias, Name fieldAlias) {
|
||||
|
||||
// [#1114] [#7863] VARRAY/TABLE of OBJECT have more than one field
|
||||
@ -136,34 +140,36 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
return new FieldsImpl<>(DSL.field(alias.unqualifiedName().append(fieldAlias.unqualifiedName()), DSL.getDataType(arrayType)));
|
||||
}
|
||||
|
||||
@Override
|
||||
final ArrayTable construct(Name newAlias, Name[] newFieldAliases) {
|
||||
return new ArrayTable(array, newAlias, newFieldAliases);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Table API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Class<? extends Record> getRecordType() {
|
||||
// TODO: [#4695] Calculate the correct Record[B] type
|
||||
return RecordImplN.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record> as(Name as) {
|
||||
return new ArrayTable(array, as);
|
||||
final FieldsImpl<Record> fields0() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record> as(Name as, Name... fields) {
|
||||
return new ArrayTable(array, as, fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean declaresTables() {
|
||||
|
||||
// Always true, because unnested tables are always aliased
|
||||
return true;
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
ctx.visit(table(ctx.configuration()));
|
||||
}
|
||||
|
||||
private final Table<Record> table(Configuration configuration) {
|
||||
private final QueryPart table(Configuration configuration) {
|
||||
switch (configuration.family()) {
|
||||
|
||||
|
||||
@ -173,8 +179,6 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
|
||||
|
||||
|
||||
case H2:
|
||||
return new H2ArrayTable().as(alias);
|
||||
|
||||
// Most dialects can simulate unnested arrays using UNION ALL
|
||||
|
||||
@ -215,11 +219,11 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
|
||||
// [#756] The standard SQL behaviour
|
||||
default:
|
||||
return new PostgresHSQLDBTable().as(alias, fieldAliases);
|
||||
return new StandardUnnest();
|
||||
}
|
||||
}
|
||||
|
||||
private class PostgresHSQLDBTable extends DialectArrayTable {
|
||||
private class StandardUnnest extends DialectArrayTable {
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
@ -227,25 +231,6 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
}
|
||||
}
|
||||
|
||||
private class H2ArrayTable extends DialectArrayTable {
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
ctx.visit(K_TABLE)
|
||||
.sql('(')
|
||||
.visit(fieldAliases == null || fieldAliases.length == 0 ? N_COLUMN_VALUE : fieldAliases[0])
|
||||
.sql(' ');
|
||||
|
||||
// If the array type is unknown (e.g. because it's returned from
|
||||
// a stored function), then a reasonable choice for arbitrary types is varchar
|
||||
if (array.getDataType().getType() == Object[].class)
|
||||
ctx.sql(H2DataType.VARCHAR.getTypeName());
|
||||
else
|
||||
ctx.sql(array.getDataType().getArrayComponentDataType().getTypeName(ctx.configuration()));
|
||||
|
||||
ctx.sql(" = ").visit(array).sql(')');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -257,13 +242,23 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
|
||||
|
||||
|
||||
|
||||
private abstract class DialectArrayTable extends AbstractTable<Record> implements UTransient {
|
||||
private abstract class DialectArrayTable
|
||||
extends
|
||||
AbstractTable<Record>
|
||||
implements
|
||||
AutoAlias<Table<Record>>,
|
||||
UTransient
|
||||
{
|
||||
|
||||
DialectArrayTable() {
|
||||
super(TableOptions.expression(), alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean declaresTables() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Class<? extends Record> getRecordType() {
|
||||
return RecordImplN.class;
|
||||
@ -273,29 +268,15 @@ final class ArrayTable extends AbstractTable<Record> implements UNotYetImplement
|
||||
final FieldsImpl<Record> fields0() {
|
||||
return ArrayTable.this.fields0();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record> autoAlias(Context<?> ctx, Table<Record> t) {
|
||||
return t.as(alias, fieldAliases);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final Table<Record> emulate() {
|
||||
return new ArrayTableEmulation(((Param<Object[]>) array).getValue()).as(alias, fieldAliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<Record> fields0() {
|
||||
return field;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Table<Record> $aliased() {
|
||||
return new ArrayTable(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Name $alias() {
|
||||
return alias;
|
||||
private final QueryPart emulate() {
|
||||
return new ArrayTableEmulation(((Param<Object[]>) array).getValue(), fieldAliases);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,19 +40,16 @@ package org.jooq.impl;
|
||||
import static org.jooq.impl.DSL.falseCondition;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.using;
|
||||
import static org.jooq.impl.Names.N_ARRAY_TABLE;
|
||||
import static org.jooq.impl.Names.N_COLUMN_VALUE;
|
||||
import static org.jooq.impl.Tools.componentDataType;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableOptions;
|
||||
import org.jooq.impl.QOM.UTransient;
|
||||
|
||||
/**
|
||||
@ -61,79 +58,49 @@ import org.jooq.impl.QOM.UTransient;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class ArrayTableEmulation extends AbstractTable<Record> implements UTransient {
|
||||
final class ArrayTableEmulation
|
||||
extends
|
||||
AbstractQueryPart
|
||||
implements
|
||||
UTransient
|
||||
{
|
||||
|
||||
private final Object[] array;
|
||||
private final FieldsImpl<Record> field;
|
||||
private final Name alias;
|
||||
private final Name fieldAlias;
|
||||
private final Object[] array;
|
||||
private final DataType<?> type;
|
||||
private final Name fieldAlias;
|
||||
|
||||
private transient Table<Record> table;
|
||||
private transient Select<?> table;
|
||||
|
||||
ArrayTableEmulation(Object[] array) {
|
||||
this(array, N_ARRAY_TABLE, null);
|
||||
}
|
||||
|
||||
ArrayTableEmulation(Object[] array, Name alias) {
|
||||
this(array, alias, null);
|
||||
}
|
||||
|
||||
ArrayTableEmulation(Object[] array, Name alias, Name fieldAlias) {
|
||||
super(TableOptions.expression(), alias);
|
||||
ArrayTableEmulation(Object[] array, Name[] fieldAliases) {
|
||||
if (Tools.isEmpty(fieldAliases))
|
||||
this.fieldAlias = N_COLUMN_VALUE;
|
||||
else if (fieldAliases.length == 1)
|
||||
this.fieldAlias = fieldAliases[0];
|
||||
else
|
||||
throw new IllegalArgumentException("Array table simulations can only have a single field alias");
|
||||
|
||||
this.array = array;
|
||||
this.alias = alias;
|
||||
this.fieldAlias = fieldAlias == null ? N_COLUMN_VALUE : fieldAlias;
|
||||
this.field = new FieldsImpl<>(DSL.field(name(alias.last(), this.fieldAlias.last()), componentDataType(array)));
|
||||
this.type = componentDataType(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Class<? extends Record> getRecordType() {
|
||||
return RecordImplN.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record> as(Name as) {
|
||||
return new ArrayTableEmulation(array, as);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record> as(Name as, Name... fieldAliases) {
|
||||
if (fieldAliases == null)
|
||||
return new ArrayTableEmulation(array, as);
|
||||
else if (fieldAliases.length == 1)
|
||||
return new ArrayTableEmulation(array, as, fieldAliases[0]);
|
||||
|
||||
throw new IllegalArgumentException("Array table simulations can only have a single field alias");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean declaresTables() {
|
||||
|
||||
// [#1055] Always true, because unnested tables are always aliased.
|
||||
// This is particularly important for simulated unnested arrays
|
||||
return true;
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
ctx.visit(table(ctx.configuration()));
|
||||
visitSubquery(ctx, table(), SubqueryCharacteristics.DERIVED_TABLE, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<Record> fields0() {
|
||||
return field;
|
||||
}
|
||||
|
||||
private final Table<Record> table(Configuration configuration) {
|
||||
private final Select<?> table() {
|
||||
if (table == null) {
|
||||
Select<Record> select = null;
|
||||
|
||||
for (Object element : array) {
|
||||
|
||||
// [#1081] Be sure to get the correct cast type also for null
|
||||
Field<?> val = DSL.val(element, field.fields[0].getDataType());
|
||||
Select<Record> subselect = using(configuration).select(val.as(fieldAlias)).select();
|
||||
Field<?> val = DSL.val(element, type);
|
||||
Select<Record> subselect = DSL.select(val.as(fieldAlias)).select();
|
||||
|
||||
if (select == null)
|
||||
select = subselect;
|
||||
@ -143,9 +110,9 @@ final class ArrayTableEmulation extends AbstractTable<Record> implements UTransi
|
||||
|
||||
// Empty arrays should result in empty tables
|
||||
if (select == null)
|
||||
select = using(configuration).select(one().as(fieldAlias)).select().where(falseCondition());
|
||||
select = DSL.select(one().as(fieldAlias)).select().where(falseCondition());
|
||||
|
||||
table = select.asTable(alias);
|
||||
table = select;
|
||||
}
|
||||
|
||||
return table;
|
||||
|
||||
@ -40,8 +40,6 @@ package org.jooq.impl;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
|
||||
/**
|
||||
* [#11564] A table that produces auto table and column aliases, if no explicit alias is
|
||||
@ -55,5 +53,5 @@ interface AutoAlias<Q extends QueryPart> extends QueryPartInternal {
|
||||
* Create the aliased table expression or <code>null</code> if no auto-alias
|
||||
* is required.
|
||||
*/
|
||||
Q autoAlias(Context<?> ctx);
|
||||
Q autoAlias(Context<?> ctx, Q unaliased);
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ implements
|
||||
allNotNull(INTEGER, array)
|
||||
);
|
||||
|
||||
this.array = nullSafeNotNull(array, OTHER.getArrayDataType());
|
||||
this.array = nullSafeNotNull(array, OTHER.array());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -129,11 +129,11 @@ implements
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Field<T> autoAlias(Context<?> ctx) {
|
||||
public final Field<T> autoAlias(Context<?> ctx, Field<T> f) {
|
||||
if (field instanceof AutoAlias)
|
||||
return ((AutoAlias<Field<T>>) field).autoAlias(ctx).coerce(getDataType());
|
||||
return ((AutoAlias<Field<T>>) field).autoAlias(ctx, (Field<T>) field).coerce(getDataType());
|
||||
else
|
||||
return this;
|
||||
return f;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -32798,7 +32798,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1> Table<Record1<T1>> values(Row1<T1>... rows) {
|
||||
return new Values<Record1<T1>>(rows).as("v", "c1");
|
||||
return new Values<Record1<T1>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32833,7 +32833,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2> Table<Record2<T1, T2>> values(Row2<T1, T2>... rows) {
|
||||
return new Values<Record2<T1, T2>>(rows).as("v", "c1", "c2");
|
||||
return new Values<Record2<T1, T2>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32868,7 +32868,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3> Table<Record3<T1, T2, T3>> values(Row3<T1, T2, T3>... rows) {
|
||||
return new Values<Record3<T1, T2, T3>>(rows).as("v", "c1", "c2", "c3");
|
||||
return new Values<Record3<T1, T2, T3>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32903,7 +32903,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4> Table<Record4<T1, T2, T3, T4>> values(Row4<T1, T2, T3, T4>... rows) {
|
||||
return new Values<Record4<T1, T2, T3, T4>>(rows).as("v", "c1", "c2", "c3", "c4");
|
||||
return new Values<Record4<T1, T2, T3, T4>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32938,7 +32938,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5> Table<Record5<T1, T2, T3, T4, T5>> values(Row5<T1, T2, T3, T4, T5>... rows) {
|
||||
return new Values<Record5<T1, T2, T3, T4, T5>>(rows).as("v", "c1", "c2", "c3", "c4", "c5");
|
||||
return new Values<Record5<T1, T2, T3, T4, T5>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -32973,7 +32973,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6> Table<Record6<T1, T2, T3, T4, T5, T6>> values(Row6<T1, T2, T3, T4, T5, T6>... rows) {
|
||||
return new Values<Record6<T1, T2, T3, T4, T5, T6>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6");
|
||||
return new Values<Record6<T1, T2, T3, T4, T5, T6>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33008,7 +33008,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7> Table<Record7<T1, T2, T3, T4, T5, T6, T7>> values(Row7<T1, T2, T3, T4, T5, T6, T7>... rows) {
|
||||
return new Values<Record7<T1, T2, T3, T4, T5, T6, T7>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7");
|
||||
return new Values<Record7<T1, T2, T3, T4, T5, T6, T7>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33043,7 +33043,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8> Table<Record8<T1, T2, T3, T4, T5, T6, T7, T8>> values(Row8<T1, T2, T3, T4, T5, T6, T7, T8>... rows) {
|
||||
return new Values<Record8<T1, T2, T3, T4, T5, T6, T7, T8>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8");
|
||||
return new Values<Record8<T1, T2, T3, T4, T5, T6, T7, T8>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33078,7 +33078,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9> Table<Record9<T1, T2, T3, T4, T5, T6, T7, T8, T9>> values(Row9<T1, T2, T3, T4, T5, T6, T7, T8, T9>... rows) {
|
||||
return new Values<Record9<T1, T2, T3, T4, T5, T6, T7, T8, T9>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9");
|
||||
return new Values<Record9<T1, T2, T3, T4, T5, T6, T7, T8, T9>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33113,7 +33113,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Table<Record10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>> values(Row10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>... rows) {
|
||||
return new Values<Record10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10");
|
||||
return new Values<Record10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33148,7 +33148,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Table<Record11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>> values(Row11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>... rows) {
|
||||
return new Values<Record11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11");
|
||||
return new Values<Record11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33183,7 +33183,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Table<Record12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>> values(Row12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>... rows) {
|
||||
return new Values<Record12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12");
|
||||
return new Values<Record12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33218,7 +33218,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Table<Record13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>> values(Row13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>... rows) {
|
||||
return new Values<Record13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13");
|
||||
return new Values<Record13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33253,7 +33253,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Table<Record14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>> values(Row14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>... rows) {
|
||||
return new Values<Record14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14");
|
||||
return new Values<Record14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33288,7 +33288,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> Table<Record15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>> values(Row15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>... rows) {
|
||||
return new Values<Record15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15");
|
||||
return new Values<Record15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33323,7 +33323,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> Table<Record16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>> values(Row16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>... rows) {
|
||||
return new Values<Record16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15", "c16");
|
||||
return new Values<Record16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33358,7 +33358,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17> Table<Record17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17>> values(Row17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17>... rows) {
|
||||
return new Values<Record17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17");
|
||||
return new Values<Record17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33393,7 +33393,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18> Table<Record18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18>> values(Row18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18>... rows) {
|
||||
return new Values<Record18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17", "c18");
|
||||
return new Values<Record18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33428,7 +33428,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19> Table<Record19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>> values(Row19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>... rows) {
|
||||
return new Values<Record19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17", "c18", "c19");
|
||||
return new Values<Record19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33463,7 +33463,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20> Table<Record20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>> values(Row20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>... rows) {
|
||||
return new Values<Record20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17", "c18", "c19", "c20");
|
||||
return new Values<Record20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33498,7 +33498,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21> Table<Record21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>> values(Row21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>... rows) {
|
||||
return new Values<Record21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17", "c18", "c19", "c20", "c21");
|
||||
return new Values<Record21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>>(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -33533,7 +33533,7 @@ public class DSL {
|
||||
@NotNull
|
||||
@Support
|
||||
public static <T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> Table<Record22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>> values(Row22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>... rows) {
|
||||
return new Values<Record22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>>(rows).as("v", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", "c13", "c14", "c15", "c16", "c17", "c18", "c19", "c20", "c21", "c22");
|
||||
return new Values<Record22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>>(rows);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -195,8 +195,8 @@ implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<R> autoAlias(Context<?> ctx) {
|
||||
return as(alias);
|
||||
public final Table<R> autoAlias(Context<?> ctx, Table<R> t) {
|
||||
return t.as(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -52,7 +52,12 @@ import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class FunctionTable<R extends Record> extends AbstractTable<R> implements UNotYetImplemented {
|
||||
final class FunctionTable<R extends Record>
|
||||
extends
|
||||
AbstractTable<R>
|
||||
implements
|
||||
UNotYetImplemented
|
||||
{
|
||||
|
||||
private final Field<?> function;
|
||||
|
||||
@ -62,6 +67,10 @@ final class FunctionTable<R extends Record> extends AbstractTable<R> implements
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Table API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Class<? extends R> getRecordType() {
|
||||
@ -69,6 +78,15 @@ final class FunctionTable<R extends Record> extends AbstractTable<R> implements
|
||||
return (Class<? extends R>) RecordImplN.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<R> fields0() {
|
||||
return new FieldsImpl<>();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: DSL API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Table<R> as(Name as) {
|
||||
return new TableAlias<>(new FunctionTable<>(function), as);
|
||||
@ -79,6 +97,10 @@ final class FunctionTable<R extends Record> extends AbstractTable<R> implements
|
||||
return new TableAlias<>(new FunctionTable<>(function), as, fieldAliases);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
@ -101,9 +123,4 @@ final class FunctionTable<R extends Record> extends AbstractTable<R> implements
|
||||
throw new SQLDialectNotSupportedException("FUNCTION TABLE is not supported for " + ctx.dialect());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<R> fields0() {
|
||||
return new FieldsImpl<>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,11 +247,11 @@ implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record1<Integer>> autoAlias(Context<?> ctx) {
|
||||
public final Table<Record1<Integer>> autoAlias(Context<?> ctx, Table<Record1<Integer>> t) {
|
||||
if (EMULATE_WITH_RECURSIVE.contains(ctx.dialect()))
|
||||
return as(name);
|
||||
return t.as(name);
|
||||
else if (EMULATE_SYSTEM_RANGE.contains(ctx.dialect()))
|
||||
return as(name, name);
|
||||
return t.as(name, name);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -109,6 +109,7 @@ import static org.jooq.impl.Names.N_JOIN;
|
||||
import static org.jooq.impl.QueryPartListView.wrap;
|
||||
import static org.jooq.impl.Tools.containsUnaliasedTable;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.impl.Tools.visitAutoAliased;
|
||||
import static org.jooq.impl.Tools.BooleanDataKey.DATA_COLLECT_SEMI_ANTI_JOIN;
|
||||
import static org.jooq.impl.Tools.SimpleDataKey.DATA_COLLECTED_SEMI_ANTI_JOIN;
|
||||
|
||||
@ -467,7 +468,7 @@ implements
|
||||
if (wrap)
|
||||
ctx.sqlIndentStart('(');
|
||||
|
||||
ctx.visit(table);
|
||||
visitAutoAliased(ctx, table, Context::declareTables, (c, t) -> c.visit(t));
|
||||
|
||||
if (wrap)
|
||||
ctx.sqlIndentEnd(')');
|
||||
|
||||
@ -231,6 +231,7 @@ final class Names {
|
||||
static final Name N_NTILE = systemName("ntile");
|
||||
static final Name N_NULL = systemName("null");
|
||||
static final Name N_NVL2 = systemName("nvl2");
|
||||
static final Name N_OFFSET = systemName("offset");
|
||||
static final Name N_OPENJSON = systemName("openjson");
|
||||
static final Name N_OPENXML = systemName("openxml");
|
||||
static final Name N_ORDINAL = systemName("ordinal");
|
||||
|
||||
76
jOOQ/src/main/java/org/jooq/impl/NoAutoAlias.java
Normal file
76
jOOQ/src/main/java/org/jooq/impl/NoAutoAlias.java
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.impl.QOM.UTransient;
|
||||
|
||||
/**
|
||||
* A delegating table that un-{@link AutoAlias}-es a wrapped table.
|
||||
* <p>
|
||||
* When emulating the derived column list feature, the auto-aliasing feature
|
||||
* would re-alias the table again and again, leading to a
|
||||
* {@link StackOverflowError}. This helps prevent it.
|
||||
*/
|
||||
final class NoAutoAlias<R extends Record>
|
||||
extends
|
||||
AbstractDelegatingTable<R>
|
||||
implements
|
||||
UTransient
|
||||
{
|
||||
|
||||
NoAutoAlias(AbstractTable<R> delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
static final <R extends Record> Table<R> noAutoAlias(Table<R> table) {
|
||||
return table instanceof AutoAlias ? new NoAutoAlias<>((AbstractTable<R>) table) : table;
|
||||
}
|
||||
|
||||
@Override
|
||||
final <O extends Record> NoAutoAlias<O> construct(AbstractTable<O> newDelegate) {
|
||||
return new NoAutoAlias<>(newDelegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
ctx.visit(delegate);
|
||||
}
|
||||
}
|
||||
266
jOOQ/src/main/java/org/jooq/impl/OrdinalityTable.java
Normal file
266
jOOQ/src/main/java/org/jooq/impl/OrdinalityTable.java
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* https://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: https://www.jooq.org/legal/licensing
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.DERBY;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.FIREBIRD;
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
// ...
|
||||
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 static org.jooq.SQLDialect.YUGABYTEDB;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.rowNumber;
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.table;
|
||||
import static org.jooq.impl.Keywords.K_ORDINALITY;
|
||||
import static org.jooq.impl.Keywords.K_WITH;
|
||||
import static org.jooq.impl.Names.N_OFFSET;
|
||||
import static org.jooq.impl.Names.N_ORDINAL;
|
||||
import static org.jooq.impl.SQLDataType.BIGINT;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.DERIVED_TABLE;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.ForeignKey;
|
||||
import org.jooq.Name;
|
||||
// ...
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Record;
|
||||
// ...
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.Table;
|
||||
// ...
|
||||
import org.jooq.impl.QOM.Aliasable;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class OrdinalityTable<R extends Record>
|
||||
extends
|
||||
AbstractTable<R>
|
||||
implements
|
||||
AutoAlias<Table<R>>,
|
||||
QOM.OrdinalityTable<R>
|
||||
{
|
||||
|
||||
static final Set<SQLDialect> NO_SUPPORT_STANDARD = SQLDialect.supportedBy(DERBY, FIREBIRD, MARIADB, MYSQL, SQLITE);
|
||||
static final Set<SQLDialect> NO_SUPPORT_TVF = SQLDialect.supportedBy(H2, HSQLDB);
|
||||
static final Set<SQLDialect> NO_SUPPORT_TABLE_EXPRESSIONS = SQLDialect.supportedBy(POSTGRES, YUGABYTEDB);
|
||||
|
||||
static {
|
||||
NO_SUPPORT_TVF.addAll(NO_SUPPORT_STANDARD);
|
||||
NO_SUPPORT_TABLE_EXPRESSIONS.addAll(NO_SUPPORT_TVF);
|
||||
}
|
||||
|
||||
final AbstractTable<?> delegate;
|
||||
|
||||
OrdinalityTable(AbstractTable<?> delegate) {
|
||||
super(delegate.getOptions(), delegate.getQualifiedName(), delegate.getSchema());
|
||||
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Table API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// [#5799] TODO: Maybe share some logic with AbstractDelegatingTable
|
||||
|
||||
@Override
|
||||
public final boolean declaresTables() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Class<? extends R> getRecordType() {
|
||||
// TODO: [#4695] Calculate the correct Record[B] type
|
||||
return (Class<? extends R>) RecordImplN.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<ForeignKey<R, ?>> getReferences() {
|
||||
return (List) delegate.getReferences();
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<R> fields0() {
|
||||
FieldsImpl<R> r = new FieldsImpl<>(delegate.fields0().fields);
|
||||
r.add(DSL.field(N_ORDINAL, BIGINT));
|
||||
return r;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Table<R> autoAlias(Context<?> ctx, Table<R> t) {
|
||||
if (t != this && t instanceof AutoAlias<?> a) {
|
||||
return ((AutoAlias<Table<R>>) a).autoAlias(ctx, t);
|
||||
}
|
||||
else if (t instanceof Aliasable<?> a) {
|
||||
Name alias = a.$alias();
|
||||
if (alias == null)
|
||||
alias = ((Table<?>) a.$aliased()).getUnqualifiedName();
|
||||
|
||||
Field<?>[] fields = t.fields();
|
||||
if (Tools.isEmpty(fields))
|
||||
return t.as(alias);
|
||||
else
|
||||
return t.as(table(alias), fields);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
if ((delegate instanceof ArrayTable || delegate instanceof ArrayOfValues) && NO_SUPPORT_STANDARD.contains(ctx.dialect()))
|
||||
acceptEmulation(ctx);
|
||||
else if (delegate instanceof FunctionTable && NO_SUPPORT_TVF.contains(ctx.dialect()))
|
||||
acceptEmulation(ctx);
|
||||
else if (delegate instanceof TableImpl && ((TableImpl<?>) delegate).parameters != null && NO_SUPPORT_TVF.contains(ctx.dialect()))
|
||||
acceptEmulation(ctx);
|
||||
else if (NO_SUPPORT_TABLE_EXPRESSIONS.contains(ctx.dialect()))
|
||||
acceptEmulation(ctx);
|
||||
|
||||
|
||||
|
||||
|
||||
else
|
||||
ctx.visit(delegate).sql(' ').visit(K_WITH).sql(' ').visit(K_ORDINALITY);
|
||||
}
|
||||
|
||||
private final void acceptEmulation(Context<?> ctx) {
|
||||
Select<?> s;
|
||||
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
s = select(delegate.fields()).select(rowNumber().over().as(N_ORDINAL)).from(delegate);
|
||||
break;
|
||||
}
|
||||
|
||||
visitSubquery(ctx, s, DERIVED_TABLE, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final Table<?> $table() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final OrdinalityTable<?> $table(Table<?> newTable) {
|
||||
return new OrdinalityTable<>((AbstractTable<Record>) newTable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public final Table<R> $aliased() {
|
||||
return new OrdinalityTable<>((AbstractTable<?>) ((Aliasable<? extends Table<?>>) delegate).$aliased());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Name $alias() {
|
||||
return ((Aliasable<? extends Table<?>>) delegate).$alias();
|
||||
}
|
||||
}
|
||||
@ -721,6 +721,21 @@ public final class QOM {
|
||||
@NotNull <O extends Record> HintedTable<O> $table(Table<O> newTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection derived table or table valued function with a
|
||||
* <code>WITH ORDINALITY</code> clause.
|
||||
*/
|
||||
public sealed interface OrdinalityTable<R extends Record>
|
||||
extends
|
||||
Table<R>
|
||||
permits
|
||||
org.jooq.impl.OrdinalityTable
|
||||
{
|
||||
@NotNull Table<?> $table();
|
||||
@CheckReturnValue
|
||||
@NotNull OrdinalityTable<?> $table(Table<?> newTable);
|
||||
}
|
||||
|
||||
public interface PrimaryKey extends Constraint {
|
||||
@NotNull UnmodifiableList<? extends Field<?>> $fields();
|
||||
}
|
||||
|
||||
@ -38,7 +38,8 @@
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Condition;
|
||||
import static org.jooq.impl.Tools.visitAutoAliased;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.SelectFieldOrAsterisk;
|
||||
|
||||
@ -88,13 +89,7 @@ final class SelectFieldList<F extends SelectFieldOrAsterisk> extends QueryPartLi
|
||||
acceptElement0(ctx, part);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void acceptElement0(Context<?> ctx, F part) {
|
||||
F alternative;
|
||||
|
||||
if (ctx.declareFields() && part instanceof AutoAlias && (alternative = ((AutoAlias<F>) part).autoAlias(ctx)) != null)
|
||||
super.acceptElement(ctx, alternative);
|
||||
else
|
||||
super.acceptElement(ctx, part);
|
||||
visitAutoAliased(ctx, part, Context::declareFields, (c, t) -> super.acceptElement(c, t));
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,11 +46,11 @@ import static org.jooq.SQLDialect.H2;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
import static org.jooq.impl.Tools.flatMap;
|
||||
import static org.jooq.impl.Tools.visitAutoAliased;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
@ -82,15 +82,9 @@ final class TableList extends QueryPartList<Table<?>> {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void acceptElement(Context<?> ctx, Table<?> part) {
|
||||
Table<?> alternative;
|
||||
|
||||
if (ctx.declareTables() && part instanceof AutoAlias && (alternative = ((AutoAlias<Table<?>>) part).autoAlias(ctx)) != null)
|
||||
super.acceptElement(ctx, alternative);
|
||||
else
|
||||
super.acceptElement(ctx, part);
|
||||
visitAutoAliased(ctx, part, Context::declareTables, (c, t) -> super.acceptElement(c, t));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -240,6 +240,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinPool.ManagedBlocker;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -1614,12 +1615,16 @@ final class Tools {
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static final int FIELD_NAME_CACHE_SIZE = 128;
|
||||
private static final String[] FIELD_NAME_STRINGS;
|
||||
private static final Name[] FIELD_NAMES;
|
||||
private static final String[] V_FIELD_NAME_STRINGS;
|
||||
private static final String[] C_FIELD_NAME_STRINGS;
|
||||
private static final Name[] V_FIELD_NAMES;
|
||||
private static final Name[] C_FIELD_NAMES;
|
||||
|
||||
static {
|
||||
FIELD_NAME_STRINGS = IntStream.range(0, FIELD_NAME_CACHE_SIZE).mapToObj(Tools::fieldNameString0).toArray(String[]::new);
|
||||
FIELD_NAMES = IntStream.range(0, FIELD_NAME_CACHE_SIZE).mapToObj(i -> name(FIELD_NAME_STRINGS[i])).toArray(Name[]::new);
|
||||
V_FIELD_NAME_STRINGS = IntStream.range(0, FIELD_NAME_CACHE_SIZE).mapToObj(Tools::fieldNameStringV0).toArray(String[]::new);
|
||||
C_FIELD_NAME_STRINGS = IntStream.range(0, FIELD_NAME_CACHE_SIZE).mapToObj(Tools::fieldNameStringC0).toArray(String[]::new);
|
||||
V_FIELD_NAMES = IntStream.range(0, FIELD_NAME_CACHE_SIZE).mapToObj(i -> name(V_FIELD_NAME_STRINGS[i])).toArray(Name[]::new);
|
||||
C_FIELD_NAMES = IntStream.range(0, FIELD_NAME_CACHE_SIZE).mapToObj(i -> name(C_FIELD_NAME_STRINGS[i])).toArray(Name[]::new);
|
||||
}
|
||||
|
||||
static final <T> SortField<T> sortField(OrderField<T> field) {
|
||||
@ -1642,16 +1647,29 @@ final class Tools {
|
||||
return Tools.map(fields, (OrderField<?> o) -> sortField(o));
|
||||
}
|
||||
|
||||
private static final String fieldNameString0(int index) {
|
||||
// TODO: Check if these field names are ever really needed, or if we can just use the C field names
|
||||
private static final String fieldNameStringV0(int index) {
|
||||
return "v" + index;
|
||||
}
|
||||
|
||||
private static final String fieldNameStringC0(int index) {
|
||||
return "c" + (index + 1);
|
||||
}
|
||||
|
||||
static final String fieldNameString(int index) {
|
||||
return index < FIELD_NAME_CACHE_SIZE ? FIELD_NAME_STRINGS[index] : fieldNameString0(index);
|
||||
return index < FIELD_NAME_CACHE_SIZE ? V_FIELD_NAME_STRINGS[index] : fieldNameStringV0(index);
|
||||
}
|
||||
|
||||
static final String fieldNameStringC(int index) {
|
||||
return index < FIELD_NAME_CACHE_SIZE ? C_FIELD_NAME_STRINGS[index] : fieldNameStringC0(index);
|
||||
}
|
||||
|
||||
static final Name fieldName(int index) {
|
||||
return index < FIELD_NAME_CACHE_SIZE ? FIELD_NAMES[index] : name(fieldNameString0(index));
|
||||
return index < FIELD_NAME_CACHE_SIZE ? V_FIELD_NAMES[index] : name(fieldNameStringV0(index));
|
||||
}
|
||||
|
||||
static final Name fieldNameC(int index) {
|
||||
return index < FIELD_NAME_CACHE_SIZE ? C_FIELD_NAMES[index] : name(fieldNameStringC0(index));
|
||||
}
|
||||
|
||||
static final Name[] fieldNames(int length) {
|
||||
@ -1672,6 +1690,24 @@ final class Tools {
|
||||
return result;
|
||||
}
|
||||
|
||||
static final Name[] fieldNamesC(int length) {
|
||||
Name[] result = new Name[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
result[i] = fieldNameC(i);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static final String[] fieldNameStringsC(int length) {
|
||||
String[] result = new String[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
result[i] = fieldNameStringC(i);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static final Field<?>[] fields(int length) {
|
||||
return fields(length, SQLDataType.OTHER);
|
||||
}
|
||||
@ -2752,6 +2788,21 @@ final class Tools {
|
||||
return e;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static final <Q extends QueryPart> void visitAutoAliased(
|
||||
Context<?> ctx,
|
||||
Q q,
|
||||
Predicate<? super Context<?>> declaring,
|
||||
BiConsumer<? super Context<?>, ? super Q> visit
|
||||
) {
|
||||
Q alternative;
|
||||
|
||||
if (declaring.test(ctx) && q instanceof AutoAlias && (alternative = ((AutoAlias<Q>) q).autoAlias(ctx, q)) != null)
|
||||
visit.accept(ctx, alternative);
|
||||
else
|
||||
visit.accept(ctx, q);
|
||||
}
|
||||
|
||||
static final void visitSubquery(
|
||||
Context<?> ctx,
|
||||
QueryPart query
|
||||
|
||||
@ -59,6 +59,7 @@ import static org.jooq.SQLDialect.MYSQL;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.conf.ParamType.INLINED;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.Keywords.K_MULTISET;
|
||||
import static org.jooq.impl.Keywords.K_ROW;
|
||||
import static org.jooq.impl.Keywords.K_STRUCT;
|
||||
@ -69,6 +70,9 @@ import static org.jooq.impl.Names.N_VALUES;
|
||||
import static org.jooq.impl.QueryPartListView.wrap;
|
||||
import static org.jooq.impl.SubqueryCharacteristics.DERIVED_TABLE;
|
||||
import static org.jooq.impl.Tools.EMPTY_ROW;
|
||||
import static org.jooq.impl.Tools.fieldNamesC;
|
||||
import static org.jooq.impl.Tools.isEmpty;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.impl.Tools.visitSubquery;
|
||||
|
||||
import java.util.Set;
|
||||
@ -93,39 +97,77 @@ import org.jooq.impl.QOM.UnmodifiableList;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class Values<R extends Record> extends AbstractTable<R> implements QOM.Values<R> {
|
||||
final class Values<R extends Record>
|
||||
extends
|
||||
AbstractAutoAliasTable<R>
|
||||
implements
|
||||
QOM.Values<R>
|
||||
{
|
||||
|
||||
static final Set<SQLDialect> NO_SUPPORT_VALUES = SQLDialect.supportedUntil(FIREBIRD, MARIADB);
|
||||
static final Set<SQLDialect> REQUIRE_ROWTYPE_CAST = SQLDialect.supportedBy(FIREBIRD);
|
||||
static final Set<SQLDialect> NO_SUPPORT_PARENTHESES = SQLDialect.supportedBy();
|
||||
static final Set<SQLDialect> NO_SUPPORT_VALUES = SQLDialect.supportedUntil(FIREBIRD, MARIADB);
|
||||
static final Set<SQLDialect> REQUIRE_ROWTYPE_CAST = SQLDialect.supportedBy(FIREBIRD);
|
||||
static final Set<SQLDialect> NO_SUPPORT_PARENTHESES = SQLDialect.supportedBy();
|
||||
|
||||
private final QueryPartListView<Row> rows;
|
||||
private transient DataType<?>[] types;
|
||||
private final Row[] rows;
|
||||
private transient DataType<?>[] types;
|
||||
|
||||
Values(Row[] rows) {
|
||||
super(TableOptions.expression(), N_VALUES);
|
||||
this(rows, name("v"), fieldNamesC(degree(rows)));
|
||||
}
|
||||
|
||||
Values(Row[] rows, Name alias, Name[] fieldAliases) {
|
||||
super(alias, fieldAliases);
|
||||
|
||||
this.rows = assertNotEmpty(rows);
|
||||
}
|
||||
|
||||
static final QueryPartListView<Row> assertNotEmpty(Row[] rows) {
|
||||
if (rows == null || rows.length == 0)
|
||||
private static final int degree(Row[] rows) {
|
||||
return isEmpty(rows) ? 0 : rows[0].size();
|
||||
}
|
||||
|
||||
static final Row[] assertNotEmpty(Row[] rows) {
|
||||
if (isEmpty(rows))
|
||||
throw new IllegalArgumentException("Cannot create a VALUES() constructor with an empty set of rows");
|
||||
|
||||
return QueryPartListView.wrap(rows);
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
final Values<R> construct(Name newAlias, Name[] newFieldAliases) {
|
||||
return new Values<R>(rows, newAlias, newFieldAliases);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Table API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Class<? extends R> getRecordType() {
|
||||
// TODO: [#4695] Calculate the correct Record[B] type
|
||||
return (Class<? extends R>) RecordImplN.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<R> fields0() {
|
||||
return new FieldsImpl<>(map(fieldAliases, (n, i) -> DSL.field(n, rows[0].dataType(i))));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private final DataType<?>[] rowType() {
|
||||
if (types == null) {
|
||||
types = new DataType[rows.get(0).size()];
|
||||
types = new DataType[rows[0].size()];
|
||||
|
||||
typeLoop:
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
types[i] = rows.get(0).dataType(i);
|
||||
types[i] = rows[0].dataType(i);
|
||||
|
||||
if (types[i].getType() == Object.class) {
|
||||
for (int j = 1; j < rows.size(); j++) {
|
||||
DataType<?> type = rows.get(j).dataType(i);
|
||||
for (int j = 1; j < rows.length; j++) {
|
||||
DataType<?> type = rows[j].dataType(i);
|
||||
|
||||
if (type.getType() != Object.class) {
|
||||
types[i] = type;
|
||||
@ -150,25 +192,9 @@ final class Values<R extends Record> extends AbstractTable<R> implements QOM.Val
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Class<? extends R> getRecordType() {
|
||||
// TODO: [#4695] Calculate the correct Record[B] type
|
||||
return (Class<? extends R>) RecordImplN.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<R> as(Name alias) {
|
||||
return new TableAlias<>(this, alias, c -> !NO_SUPPORT_PARENTHESES.contains(c.dialect()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<R> as(Name alias, Name... fieldAliases) {
|
||||
return new TableAlias<>(this, alias, fieldAliases, c -> !NO_SUPPORT_PARENTHESES.contains(c.dialect()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
|
||||
// [#915] Emulate VALUES(..) with SELECT .. UNION ALL SELECT ..
|
||||
// for those dialects that do not support a VALUES() constructor
|
||||
if (NO_SUPPORT_VALUES.contains(ctx.dialect())) {
|
||||
@ -184,7 +210,7 @@ final class Values<R extends Record> extends AbstractTable<R> implements QOM.Val
|
||||
selects = selects.unionAll(select);
|
||||
}
|
||||
|
||||
visitSubquery(ctx, selects, DERIVED_TABLE, false);
|
||||
visitSubquery(ctx, selects, DERIVED_TABLE, true);
|
||||
}
|
||||
|
||||
|
||||
@ -197,6 +223,9 @@ final class Values<R extends Record> extends AbstractTable<R> implements QOM.Val
|
||||
else {
|
||||
ctx.start(TABLE_VALUES);
|
||||
|
||||
if (!NO_SUPPORT_PARENTHESES.contains(ctx.dialect()))
|
||||
ctx.sqlIndentStart('(');
|
||||
|
||||
|
||||
|
||||
|
||||
@ -213,13 +242,13 @@ final class Values<R extends Record> extends AbstractTable<R> implements QOM.Val
|
||||
|
||||
ctx.visit(K_VALUES);
|
||||
|
||||
if (rows.size() > 1)
|
||||
if (rows.length > 1)
|
||||
ctx.formatIndentStart()
|
||||
.formatSeparator();
|
||||
else
|
||||
ctx.sql(' ');
|
||||
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
if (i > 0)
|
||||
ctx.sql(',')
|
||||
.formatSeparator();
|
||||
@ -231,10 +260,10 @@ final class Values<R extends Record> extends AbstractTable<R> implements QOM.Val
|
||||
|
||||
|
||||
|
||||
ctx.visit(rows.get(i));
|
||||
ctx.visit(rows[i]);
|
||||
}
|
||||
|
||||
if (rows.size() > 1)
|
||||
if (rows.length > 1)
|
||||
ctx.formatIndentEnd()
|
||||
.formatNewLine();
|
||||
|
||||
@ -247,15 +276,14 @@ final class Values<R extends Record> extends AbstractTable<R> implements QOM.Val
|
||||
|
||||
|
||||
|
||||
|
||||
if (!NO_SUPPORT_PARENTHESES.contains(ctx.dialect()))
|
||||
ctx.sqlIndentEnd(')');
|
||||
|
||||
ctx.end(TABLE_VALUES);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final FieldsImpl<R> fields0() {
|
||||
return new FieldsImpl<>(rows.get(0).fields());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX: Query Object Model
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user