Skip to content

Commit

Permalink
[#5799] Add support for the SQL Standard WITH ORDINALITY clause
Browse files Browse the repository at this point in the history
This includes:
- [#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
- [#14409] Refactor Values to implement AutoAlias
- [#13971] Use DataType::array internally
- [#14388] Fix data type of ArrayConcat expression
  • Loading branch information
lukaseder committed Dec 15, 2022
1 parent b7c2c5e commit ad66b4e
Show file tree
Hide file tree
Showing 31 changed files with 808 additions and 301 deletions.
6 changes: 3 additions & 3 deletions jOOQ/src/main/java/org/jooq/SQLDialect.java
Expand Up @@ -985,7 +985,7 @@ public static final Set<SQLDialect> predecessors(SQLDialect... dialects) {
for (SQLDialect dialect : dialects)
result.addAll(dialect.predecessors());

return Collections.unmodifiableSet(result);
return result;
}

/**
Expand Down Expand Up @@ -1026,7 +1026,7 @@ public static final Set<SQLDialect> supportedUntil(SQLDialect... dialects) {
public static final Set<SQLDialect> supportedBy(SQLDialect dialect) {
EnumSet<SQLDialect> result = EnumSet.noneOf(SQLDialect.class);
addSupportedBy(dialect, result);
return Collections.unmodifiableSet(result);
return result;
}

/**
Expand All @@ -1044,7 +1044,7 @@ public static final Set<SQLDialect> supportedBy(SQLDialect... dialects) {
for (SQLDialect dialect : dialects)
addSupportedBy(dialect, result);

return Collections.unmodifiableSet(result);
return result;
}

private static final void addSupportedBy(SQLDialect dialect, EnumSet<SQLDialect> supported) {
Expand Down
9 changes: 9 additions & 0 deletions jOOQ/src/main/java/org/jooq/Table.java
Expand Up @@ -50,6 +50,7 @@
// ...
import static org.jooq.SQLDialect.FIREBIRD;
// ...
// ...
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
Expand All @@ -63,6 +64,7 @@
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
Expand Down Expand Up @@ -3021,6 +3023,13 @@ public non-sealed interface Table<R extends Record>













Expand Down
119 changes: 119 additions & 0 deletions jOOQ/src/main/java/org/jooq/impl/AbstractAutoAliasTable.java
@@ -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;
}
}
8 changes: 4 additions & 4 deletions jOOQ/src/main/java/org/jooq/impl/AbstractRowAsField.java
Expand Up @@ -229,19 +229,19 @@ static final void acceptMultisetContent(Context<?> ctx, Row row, Field<?> field,
}

@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) {
Expand Down
6 changes: 6 additions & 0 deletions jOOQ/src/main/java/org/jooq/impl/AbstractTable.java
Expand Up @@ -1112,6 +1112,12 @@ public final Table<R> as(Table<?> otherTable, BiFunction<? super Field<?>, ? sup
return as(otherTable.getUnqualifiedName(), (f, i) -> aliasFunction.apply(f, i).getUnqualifiedName());
}

@SuppressWarnings("unchecked")
@Override
public final Table<Record> withOrdinality() {
return new OrdinalityTable<>(this);
}




Expand Down
5 changes: 3 additions & 2 deletions jOOQ/src/main/java/org/jooq/impl/Alias.java
Expand Up @@ -80,6 +80,7 @@
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;
Expand Down Expand Up @@ -230,7 +231,7 @@ private final void acceptDeclareAliasStandard(Context<?> context) {
&& (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".
Expand Down Expand Up @@ -258,7 +259,7 @@ else if (fieldAliases != null && (
? 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();

Expand Down
4 changes: 2 additions & 2 deletions jOOQ/src/main/java/org/jooq/impl/ArrayAppend.java
Expand Up @@ -81,10 +81,10 @@ final class ArrayAppend<T>
) {
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);
}

Expand Down
6 changes: 3 additions & 3 deletions jOOQ/src/main/java/org/jooq/impl/ArrayConcat.java
Expand Up @@ -81,11 +81,11 @@ final class ArrayConcat<T>
) {
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());
}

// -------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion jOOQ/src/main/java/org/jooq/impl/ArrayGet.java
Expand Up @@ -84,7 +84,7 @@ final class ArrayGet<T>
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);
}

Expand Down

0 comments on commit ad66b4e

Please sign in to comment.