[jOOQ/jOOQ#10277] CAST to PostgreSQL enum type lacks type qualification

This includes:

- [jOOQ/jOOQ#9347] DataType#getCastTypeName() does not respect rendering settings
This commit is contained in:
Lukas Eder 2022-03-29 14:05:14 +02:00
parent 9e55e636bc
commit 8fc7748af0
3 changed files with 214 additions and 12 deletions

View File

@ -51,8 +51,10 @@ import static org.jooq.impl.SQLDataType.CLOB;
import static org.jooq.impl.SQLDataType.NCHAR;
import static org.jooq.impl.SQLDataType.NCLOB;
import static org.jooq.impl.SQLDataType.NVARCHAR;
import static org.jooq.impl.Tools.CONFIG;
import static org.jooq.impl.Tools.NO_SUPPORT_BINARY_TYPE_LENGTH;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.visitMappedSchema;
import java.lang.reflect.Array;
import java.math.BigDecimal;
@ -99,6 +101,7 @@ import org.jooq.Record;
import org.jooq.Result;
import org.jooq.Row;
import org.jooq.SQLDialect;
import org.jooq.Schema;
import org.jooq.XML;
import org.jooq.impl.QOM.GenerationLocation;
import org.jooq.impl.QOM.GenerationOption;
@ -498,21 +501,32 @@ implements
@Override
public /* non-final */ String getTypeName(Configuration configuration) {
return getDataType(configuration).getTypeName();
// [#10277] Enum types
if (isEnum())
return renderedTypeName0(configuration);
else
return getDataType(configuration).getTypeName();
}
@Override
public /* final */ String getCastTypeName() {
return getCastTypeName0(SQLDialect.DEFAULT);
return getCastTypeName0(CONFIG);
}
private String getCastTypeName0(SQLDialect dialect) {
private final String getCastTypeName0(Configuration configuration) {
SQLDialect dialect = configuration.dialect();
// [#10277] Enum types
if (isEnum()) {
return renderedTypeName0(configuration);
}
// [#9958] We should be able to avoid checking for x > 0, but there may
// be a lot of data types constructed with a 0 value instead of
// a null value, historically, so removing this check would
// introduce a lot of regressions!
if (lengthDefined() && length() > 0) {
else if (lengthDefined() && length() > 0) {
if (isBinary() && NO_SUPPORT_BINARY_TYPE_LENGTH.contains(dialect))
return castTypeName0();
@ -548,7 +562,11 @@ implements
@Override
public /* non-final */ String getCastTypeName(Configuration configuration) {
return ((AbstractDataType<T>) getDataType(configuration)).getCastTypeName0(configuration.dialect());
return ((AbstractDataType<T>) getDataType(configuration)).getCastTypeName0(configuration);
}
private final String renderedTypeName0(Configuration configuration) {
return configuration.dsl().render(this);
}
@Override
@ -597,9 +615,19 @@ implements
@Override
public final <E extends EnumType> DataType<E> asEnumDataType(Class<E> enumDataType) {
// TODO: Make EnumTypes implement Named
String enumTypeName = Tools.enums(enumDataType)[0].getName();
return new DefaultDataType<>(getDialect(), (DataType<E>) null, enumDataType, unquotedName(enumTypeName), enumTypeName, enumTypeName, precision0(), scale0(), length0(), nullability(), (Field) defaultValue());
// [#10476] TODO: EnumType should extend Qualified
E e = Tools.enums(enumDataType)[0];
return new DefaultDataType<>(getDialect(), (DataType<E>) null, enumDataType, name(e), e.getName(), e.getName(), precision0(), scale0(), length0(), nullability(), (Field) defaultValue());
}
private static final <E extends EnumType> Name name(E e) {
return new LazyName(() -> {
// [#10277] The schema may not yet have been initialised in generated code
Schema s = e.getSchema();
return s == null ? DSL.name(e.getName()) : s.getQualifiedName().append(e.getName());
});
}
@Override
@ -817,9 +845,10 @@ implements
default:
ctx.visit(getQualifiedName());
default: {
visitMappedSchema(ctx, getQualifiedName());
break;
}
}
}

View File

@ -0,0 +1,153 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import org.jooq.Context;
import org.jooq.Name;
import org.jooq.QueryPart;
import org.jooq.QueryPartInternal;
// ...
import org.jooq.Schema;
// ...
/**
* A qualified {@link Name} that is evaluated lazily, e.g. to prevent cycles in
* static initialisation of generated code, when the {@link Schema} instance may
* not yet be available.
*
* @author Lukas Eder
*/
final class LazyName extends AbstractName {
final LazySupplier<Name> supplier;
transient Name name;
LazyName(LazySupplier<Name> supplier) {
this.supplier = supplier;
}
private final Name name() {
if (name == null)
name = supplier.get();
return name;
}
// -------------------------------------------------------------------------
// XXX: Name API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
((QueryPartInternal) name()).accept(ctx);
}
@Override
public final String first() {
return name().first();
}
@Override
public final String last() {
return name().last();
}
@Override
public final boolean empty() {
return name().empty();
}
@Override
public final boolean qualified() {
return name().qualified();
}
@Override
public final boolean qualifierQualified() {
return name().qualifierQualified();
}
@Override
public final Name qualifier() {
return name().qualifier();
}
@Override
public final Name unqualifiedName() {
return name().unqualifiedName();
}
@Override
public final Quoted quoted() {
return name().quoted();
}
@Override
public final Name quotedName() {
return name().quotedName();
}
@Override
public final Name unquotedName() {
return name().unquotedName();
}
@Override
public final Name[] parts() {
return name().parts();
}
@Override
public final String[] getName() {
return name().getName();
}
}

View File

@ -313,6 +313,7 @@ import org.jooq.conf.BackslashEscaping;
import org.jooq.conf.NestedCollectionEmulation;
import org.jooq.conf.ParseNameCase;
import org.jooq.conf.RenderDefaultNullability;
import org.jooq.conf.RenderMapping;
import org.jooq.conf.RenderQuotedNames;
import org.jooq.conf.Settings;
import org.jooq.conf.SettingsTools;
@ -2529,7 +2530,7 @@ final class Tools {
/**
* Visit each query part from a collection, given a context.
*/
static final <C extends Context<? super C>> C visitAll(C ctx, Collection<? extends QueryPart> parts) {
static final <C extends Context<?>> C visitAll(C ctx, Collection<? extends QueryPart> parts) {
if (parts != null)
for (QueryPart part : parts)
ctx.visit(part);
@ -2540,7 +2541,7 @@ final class Tools {
/**
* Visit each query part from an array, given a context.
*/
static final <C extends Context<? super C>> C visitAll(C ctx, QueryPart[] parts) {
static final <C extends Context<?>> C visitAll(C ctx, QueryPart[] parts) {
if (parts != null)
for (QueryPart part : parts)
ctx.visit(part);
@ -2548,6 +2549,25 @@ final class Tools {
return ctx;
}
/**
* Apply {@link RenderMapping} to a qualified {@link Name}, assuming the
* {@link Name#qualifier()} describes the schema, if available.
*/
static final <C extends Context<?>> C visitMappedSchema(C ctx, Name qualifiedName) {
if (qualifiedName.qualified()) {
Schema s = getMappedSchema(ctx, new SchemaImpl(qualifiedName.qualifier()));
if (s != null)
ctx.visit(s).sql('.');
ctx.visit(qualifiedName.unqualifiedName());
}
else
ctx.visit(qualifiedName);
return ctx;
}
/**
* Render and bind a list of {@link QueryPart} to plain SQL
* <p>