From e8c7e5e423495d34be33ceb2b437316be011e506 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 28 May 2020 18:01:16 +0200 Subject: [PATCH] [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 --- jOOQ/src/main/java/org/jooq/DataType.java | 3 +- .../java/org/jooq/impl/ConvertedDataType.java | 1 + jOOQ/src/main/java/org/jooq/impl/DSL.java | 2 +- .../java/org/jooq/impl/DefaultDataType.java | 50 ++++++--- .../java/org/jooq/impl/DomainDataType.java | 101 ++++++++++++++++++ .../main/java/org/jooq/impl/Interpreter.java | 26 +++-- 6 files changed, 156 insertions(+), 27 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/impl/DomainDataType.java diff --git a/jOOQ/src/main/java/org/jooq/DataType.java b/jOOQ/src/main/java/org/jooq/DataType.java index 427b156d09..7b6bbe3f4e 100644 --- a/jOOQ/src/main/java/org/jooq/DataType.java +++ b/jOOQ/src/main/java/org/jooq/DataType.java @@ -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 The Java type associated with this SQL data type * @author Lukas Eder */ -public interface DataType extends Serializable { +public interface DataType extends Named { /** * Get the standard SQL data type of this (dialect-specific) data type if diff --git a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java index df89f76e88..a9d8212871 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/ConvertedDataType.java @@ -76,6 +76,7 @@ final class ConvertedDataType extends DefaultDataType { null, binding.converter().toType(), binding, + delegate.getQualifiedName(), delegate.getTypeName(), delegate.getCastTypeName(), delegate.precisionDefined() ? delegate.precision() : null, diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 8fe8de2f27..80a2fe06f6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -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)); } /** diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java index 6de6e60536..b8e09be33a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDataType.java @@ -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 implements DataType { +public class DefaultDataType extends AbstractNamed implements DataType { /** * Generated UID @@ -265,6 +269,7 @@ public class DefaultDataType implements DataType { dialect, sqlDataType, sqlDataType.getType(), + sqlDataType.getQualifiedName(), typeName, castTypeName, sqlDataType.precisionDefined() ? sqlDataType.precision() : null, @@ -276,30 +281,35 @@ public class DefaultDataType implements DataType { } public DefaultDataType(SQLDialect dialect, Class 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 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 type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { - this(dialect, null, type, typeName, castTypeName, precision, scale, length, nullability, defaultValue); + DefaultDataType(SQLDialect dialect, Class type, Name qualifiedTypeName) { + this(dialect, null, type, qualifiedTypeName, qualifiedTypeName.last(), qualifiedTypeName.last(), null, null, null, Nullability.DEFAULT, null); } - DefaultDataType(SQLDialect dialect, Class type, Binding binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { - this(dialect, null, type, binding, typeName, castTypeName, precision, scale, length, nullability, defaultValue); + DefaultDataType(SQLDialect dialect, Class type, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { + this(dialect, null, type, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, defaultValue); } - DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { - this(dialect, sqlDataType, type, null, typeName, castTypeName, precision, scale, length, nullability, defaultValue); + DefaultDataType(SQLDialect dialect, Class type, Binding binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { + this(dialect, null, type, binding, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, defaultValue); } - DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { - this(dialect, sqlDataType, type, binding, typeName, castTypeName, precision, scale, length, nullability, null, null, false, defaultValue); + DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { + this(dialect, sqlDataType, type, null, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, defaultValue); } - DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field defaultValue) { + DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field defaultValue) { + this(dialect, sqlDataType, type, binding, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, null, null, false, defaultValue); + } + + DefaultDataType(SQLDialect dialect, DataType sqlDataType, Class type, Binding binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Collation collation, CharacterSet characterSet, boolean identity, Field defaultValue) { + super(qualifiedTypeName, NO_COMMENT); // Initialise final instance members // --------------------------------- @@ -382,6 +392,8 @@ public class DefaultDataType implements DataType { boolean identity, Field 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 implements DataType { } @Override - public boolean lengthDefined() { + public final boolean lengthDefined() { return length != null && hasLength(); } @@ -796,7 +808,7 @@ public class DefaultDataType implements DataType { } @Override - public String getTypeName(Configuration configuration) { + public /* non-final */ String getTypeName(Configuration configuration) { return getDataType(configuration).getTypeName(); } @@ -819,7 +831,7 @@ public class DefaultDataType implements DataType { } @Override - public String getCastTypeName(Configuration configuration) { + public /* non-final */ String getCastTypeName(Configuration configuration) { return getDataType(configuration).getCastTypeName(); } @@ -839,8 +851,9 @@ public class DefaultDataType implements DataType { @SuppressWarnings("rawtypes") @Override public final DataType asEnumDataType(Class enumDataType) { + // TODO: Make EnumTypes implement Named String enumTypeName = Tools.enums(enumDataType)[0].getName(); - return new DefaultDataType<>(dialect, (DataType) null, enumDataType, enumTypeName, enumTypeName, precision, scale, length, nullability, (Field) defaultValue); + return new DefaultDataType<>(dialect, (DataType) null, enumDataType, unquotedName(enumTypeName), enumTypeName, enumTypeName, precision, scale, length, nullability, (Field) defaultValue); } @Override @@ -1249,4 +1262,9 @@ public class DefaultDataType implements DataType { 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()); + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/DomainDataType.java b/jOOQ/src/main/java/org/jooq/impl/DomainDataType.java new file mode 100644 index 0000000000..6843d33e0f --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/DomainDataType.java @@ -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 DataType used for {@link Domain} types. + * + * @author Lukas Eder + */ +final class DomainDataType extends DefaultDataType { + + /** + * Generated UID + */ + private static final long serialVersionUID = -6943059152215232010L; + + private final Domain domain; + private final DataType baseType; + + DomainDataType(Domain domain, DataType 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 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); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/Interpreter.java b/jOOQ/src/main/java/org/jooq/impl/Interpreter.java index 089e0d9b6e..b16e833dcc 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Interpreter.java +++ b/jOOQ/src/main/java/org/jooq/impl/Interpreter.java @@ -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> checks; + MutableSchema schema; + DataType dataType; + List> checks; + List 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() {