[jOOQ/jOOQ#681] [jOOQ/jOOQ#10230] Interpreter support for DOMAINS (WIP)

This change includes:

- [jOOQ/jOOQ#10230] Let DataType extend Named
- Support interpreting DROP DOMAIN .. RESTRICT
This commit is contained in:
Lukas Eder 2020-05-28 18:01:16 +02:00
parent 8e15f27682
commit e8c7e5e423
6 changed files with 156 additions and 27 deletions

View File

@ -50,7 +50,6 @@ import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
// ...
import java.io.Serializable;
import java.sql.Types;
import java.util.Collection;
import java.util.List;
@ -76,7 +75,7 @@ import org.jooq.types.YearToSecond;
* @param <T> The Java type associated with this SQL data type
* @author Lukas Eder
*/
public interface DataType<T> extends Serializable {
public interface DataType<T> extends Named {
/**
* Get the standard SQL data type of this (dialect-specific) data type if

View File

@ -76,6 +76,7 @@ final class ConvertedDataType<T, U> extends DefaultDataType<U> {
null,
binding.converter().toType(),
binding,
delegate.getQualifiedName(),
delegate.getTypeName(),
delegate.getCastTypeName(),
delegate.precisionDefined() ? delegate.precision() : null,

View File

@ -11958,7 +11958,7 @@ public class DSL {
*/
@Support({ H2, POSTGRES })
public static Domain<?> domain(Name name) {
return new DomainImpl<>(null, name, new DefaultDataType<>(null, SQLDataType.OTHER, name.last()));
return new DomainImpl<>(null, name, new DefaultDataType<>(null, Object.class, name));
}
/**

View File

@ -42,6 +42,8 @@ import static org.jooq.Nullability.NOT_NULL;
// ...
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.impl.CommentImpl.NO_COMMENT;
import static org.jooq.impl.DSL.unquotedName;
import static org.jooq.impl.DefaultBinding.binding;
import static org.jooq.impl.SQLDataType.BLOB;
import static org.jooq.impl.SQLDataType.CLOB;
@ -72,6 +74,7 @@ import org.jooq.Binding;
import org.jooq.CharacterSet;
import org.jooq.Collation;
import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.Converter;
import org.jooq.DataType;
import org.jooq.Domain;
@ -79,6 +82,7 @@ import org.jooq.EnumType;
import org.jooq.Field;
import org.jooq.JSON;
import org.jooq.JSONB;
import org.jooq.Name;
import org.jooq.Nullability;
// ...
import org.jooq.Result;
@ -107,7 +111,7 @@ import org.jooq.types.UShort;
*/
@SuppressWarnings({"unchecked"})
@org.jooq.Internal
public class DefaultDataType<T> implements DataType<T> {
public class DefaultDataType<T> extends AbstractNamed implements DataType<T> {
/**
* Generated UID
@ -265,6 +269,7 @@ public class DefaultDataType<T> implements DataType<T> {
dialect,
sqlDataType,
sqlDataType.getType(),
sqlDataType.getQualifiedName(),
typeName,
castTypeName,
sqlDataType.precisionDefined() ? sqlDataType.precision() : null,
@ -276,30 +281,35 @@ public class DefaultDataType<T> implements DataType<T> {
}
public DefaultDataType(SQLDialect dialect, Class<T> type, String typeName) {
this(dialect, null, type, typeName, typeName, null, null, null, Nullability.DEFAULT, null);
this(dialect, null, type, unquotedName(typeName), typeName, typeName, null, null, null, Nullability.DEFAULT, null);
}
public DefaultDataType(SQLDialect dialect, Class<T> type, String typeName, String castTypeName) {
this(dialect, null, type, typeName, castTypeName, null, null, null, Nullability.DEFAULT, null);
this(dialect, null, type, unquotedName(typeName), typeName, castTypeName, null, null, null, Nullability.DEFAULT, null);
}
DefaultDataType(SQLDialect dialect, Class<T> type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, null, type, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
DefaultDataType(SQLDialect dialect, Class<T> type, Name qualifiedTypeName) {
this(dialect, null, type, qualifiedTypeName, qualifiedTypeName.last(), qualifiedTypeName.last(), null, null, null, Nullability.DEFAULT, null);
}
DefaultDataType(SQLDialect dialect, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, null, type, binding, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
DefaultDataType(SQLDialect dialect, Class<T> type, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, null, type, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
}
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, sqlDataType, type, null, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
DefaultDataType(SQLDialect dialect, Class<T> type, Binding<?, T> binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, null, type, binding, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
}
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, sqlDataType, type, binding, typeName, castTypeName, precision, scale, length, nullability, null, null, false, defaultValue);
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, sqlDataType, type, null, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, defaultValue);
}
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field<T> defaultValue) {
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
this(dialect, sqlDataType, type, binding, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, null, null, false, defaultValue);
}
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field<T> defaultValue) {
super(qualifiedTypeName, NO_COMMENT);
// Initialise final instance members
// ---------------------------------
@ -382,6 +392,8 @@ public class DefaultDataType<T> implements DataType<T> {
boolean identity,
Field<T> defaultValue
) {
super(t.getQualifiedName(), NO_COMMENT);
this.dialect = t.dialect;
this.sqlDataType = t.sqlDataType;
this.uType = t.uType;
@ -613,7 +625,7 @@ public class DefaultDataType<T> implements DataType<T> {
}
@Override
public boolean lengthDefined() {
public final boolean lengthDefined() {
return length != null && hasLength();
}
@ -796,7 +808,7 @@ public class DefaultDataType<T> implements DataType<T> {
}
@Override
public String getTypeName(Configuration configuration) {
public /* non-final */ String getTypeName(Configuration configuration) {
return getDataType(configuration).getTypeName();
}
@ -819,7 +831,7 @@ public class DefaultDataType<T> implements DataType<T> {
}
@Override
public String getCastTypeName(Configuration configuration) {
public /* non-final */ String getCastTypeName(Configuration configuration) {
return getDataType(configuration).getCastTypeName();
}
@ -839,8 +851,9 @@ public class DefaultDataType<T> implements DataType<T> {
@SuppressWarnings("rawtypes")
@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<>(dialect, (DataType<E>) null, enumDataType, enumTypeName, enumTypeName, precision, scale, length, nullability, (Field) defaultValue);
return new DefaultDataType<>(dialect, (DataType<E>) null, enumDataType, unquotedName(enumTypeName), enumTypeName, enumTypeName, precision, scale, length, nullability, (Field) defaultValue);
}
@Override
@ -1249,4 +1262,9 @@ public class DefaultDataType<T> implements DataType<T> {
private static final boolean eq(Integer i1, Integer i2) {
return (i1 == i2) || (i1 != null && i2 != null && i1.intValue() == i2.intValue());
}
@Override
public final void accept(Context<?> ctx) {
ctx.visit(getQualifiedName());
}
}

View File

@ -0,0 +1,101 @@
/*
* 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.Configuration;
import org.jooq.DataType;
import org.jooq.Domain;
/**
* A <code>DataType</code> used for {@link Domain} types.
*
* @author Lukas Eder
*/
final class DomainDataType<T> extends DefaultDataType<T> {
/**
* Generated UID
*/
private static final long serialVersionUID = -6943059152215232010L;
private final Domain<T> domain;
private final DataType<T> baseType;
DomainDataType(Domain<T> domain, DataType<T> baseType) {
super(
null,
baseType.getSQLDataType(),
baseType.getType(),
baseType.getBinding(),
baseType.getQualifiedName(),
baseType.getTypeName(),
baseType.getCastTypeName(),
baseType.precisionDefined() ? baseType.precision() : null,
baseType.scaleDefined() ? baseType.scale() : null,
baseType.lengthDefined() ? baseType.length() : null,
baseType.nullability(),
null, // TODO: Collation
null, // TODO: CharacterSet (?)
false,
baseType.default_()
);
this.domain = domain;
this.baseType = baseType;
}
@Override
public final Domain<T> getDomain() {
return domain;
}
@Override
public final int getSQLType() {
return baseType.getSQLType();
}
@Override
public final String getTypeName(Configuration configuration) {
return baseType.getTypeName(configuration);
}
@Override
public final String getCastTypeName(Configuration configuration) {
return baseType.getCastTypeName(configuration);
}
}

View File

@ -1041,6 +1041,9 @@ final class Interpreter {
return;
}
if (!TRUE.equals(query.$cascade()) && !existing.fields.isEmpty())
throw new DataDefinitionException("Domain " + domain.getQualifiedName() + " is still being referenced by fields.");
schema.domains.remove(existing);
}
@ -1530,15 +1533,15 @@ final class Interpreter {
return tables.isEmpty();
}
final MutableTable table(Table<?> t) {
final MutableTable table(Named t) {
return find(tables, t);
}
final MutableDomain domain(Domain<?> d) {
final MutableDomain domain(Named d) {
return find(domains, d);
}
final MutableSequence sequence(Sequence<?> s) {
final MutableSequence sequence(Named s) {
return find(sequences, s);
}
@ -1777,9 +1780,10 @@ final class Interpreter {
}
private final class MutableDomain extends MutableNamed {
MutableSchema schema;
DataType<?> dataType;
List<Check<?>> checks;
MutableSchema schema;
DataType<?> dataType;
List<Check<?>> checks;
List<MutableField> fields = new MutableNamedList<>();
MutableDomain(UnqualifiedName name, MutableSchema schema, DataType<?> dataType) {
super(name);
@ -1791,6 +1795,7 @@ final class Interpreter {
@Override
final void onDrop() {
schema.domains.remove(this);
// TODO: Cascade
}
@ -2089,12 +2094,17 @@ final class Interpreter {
this.table = table;
this.type = type;
this.domain = table.schema.domain(type);
// TODO: Link type to domain
if (this.domain != null)
this.domain.fields.add(this);
}
@Override
final void onDrop() {}
final void onDrop() {
if (this.domain != null)
this.domain.fields.remove(this);
}
@Override
final MutableNamed parent() {