From cf993c0b67a159f80939597cd168af458a6ad549 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 28 May 2020 15:36:27 +0200 Subject: [PATCH] [jOOQ/jOOQ#681] Add interpreter support for DOMAINS (WIP) This change includes: - DDLExportConfiguration instructions - DDLFlag.DOMAIN and Meta.ddl() export implementation - Meta.getDomains() and Schema.getDomains() API - Interpreter implementation (WIP) --- .../java/org/jooq/DDLExportConfiguration.java | 109 +++++++++ jOOQ/src/main/java/org/jooq/DDLFlag.java | 5 + jOOQ/src/main/java/org/jooq/Meta.java | 28 +++ jOOQ/src/main/java/org/jooq/Schema.java | 18 ++ .../main/java/org/jooq/impl/AbstractMeta.java | 45 ++++ jOOQ/src/main/java/org/jooq/impl/DDL.java | 31 +++ .../main/java/org/jooq/impl/DomainImpl.java | 2 +- .../main/java/org/jooq/impl/Interpreter.java | 227 +++++++++++------- .../main/java/org/jooq/impl/SchemaImpl.java | 50 ++-- jOOQ/src/main/java/org/jooq/impl/Tools.java | 2 + 10 files changed, 410 insertions(+), 107 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/DDLExportConfiguration.java b/jOOQ/src/main/java/org/jooq/DDLExportConfiguration.java index 06a2be31c0..8539723318 100644 --- a/jOOQ/src/main/java/org/jooq/DDLExportConfiguration.java +++ b/jOOQ/src/main/java/org/jooq/DDLExportConfiguration.java @@ -56,6 +56,7 @@ public final class DDLExportConfiguration { private final boolean createSchemaIfNotExists; private final boolean createTableIfNotExists; private final boolean createIndexIfNotExists; + private final boolean createDomainIfNotExists; private final boolean createSequenceIfNotExists; private final boolean createViewIfNotExists; private final boolean createOrReplaceView; @@ -66,6 +67,7 @@ public final class DDLExportConfiguration { private final boolean respectColumnOrder; private final boolean respectConstraintOrder; private final boolean respectIndexOrder; + private final boolean respectDomainOrder; private final boolean respectSequenceOrder; private final boolean defaultSequenceFlags; @@ -83,6 +85,7 @@ public final class DDLExportConfiguration { false, false, false, + false, false, false, @@ -91,6 +94,7 @@ public final class DDLExportConfiguration { false, false, false, + false, false ); @@ -102,6 +106,7 @@ public final class DDLExportConfiguration { boolean createSchemaIfNotExists, boolean createTableIfNotExists, boolean createIndexIfNotExists, + boolean createDomainIfNotExists, boolean createSequenceIfNotExists, boolean createViewIfNotExists, boolean createOrReplaceView, @@ -112,6 +117,7 @@ public final class DDLExportConfiguration { boolean respectColumnOrder, boolean respectConstraintOrder, boolean respectIndexOrder, + boolean respectDomainOrder, boolean respectSequenceOrder, boolean defaultSequenceFlags @@ -121,6 +127,7 @@ public final class DDLExportConfiguration { this.createSchemaIfNotExists = createSchemaIfNotExists; this.createTableIfNotExists = createTableIfNotExists; this.createIndexIfNotExists = createIndexIfNotExists; + this.createDomainIfNotExists = createDomainIfNotExists; this.createSequenceIfNotExists = createSequenceIfNotExists; this.createViewIfNotExists = createViewIfNotExists; this.createOrReplaceView = createOrReplaceView; @@ -131,7 +138,9 @@ public final class DDLExportConfiguration { this.respectColumnOrder = respectColumnOrder; this.respectConstraintOrder = respectConstraintOrder; this.respectIndexOrder = respectIndexOrder; + this.respectDomainOrder = respectDomainOrder; this.respectSequenceOrder = respectSequenceOrder; + this.defaultSequenceFlags = defaultSequenceFlags; } @@ -158,6 +167,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -167,6 +177,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -192,6 +203,7 @@ public final class DDLExportConfiguration { newCreateSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -201,6 +213,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -226,6 +239,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, newCreateTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -235,6 +249,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -260,6 +275,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, newCreateIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -269,6 +285,43 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, + respectSequenceOrder, + defaultSequenceFlags + ); + } + + /** + * Whether to generate CREATE DOMAIN IF NOT EXISTS statements. + *

+ * Not all RDBMS support this flag. Check + * {@link DSLContext#createDomainIfNotExists(Domain)} to see if your + * {@link SQLDialect} supports the clause. + */ + public final boolean createDomainIfNotExists() { + return createDomainIfNotExists; + } + + /** + * Whether to generate CREATE DOMAIN IF NOT EXISTS statements. + */ + public final DDLExportConfiguration createDomainIfNotExists(boolean newCreateDomainIfNotExists) { + return new DDLExportConfiguration( + flags, + createSchemaIfNotExists, + createTableIfNotExists, + createIndexIfNotExists, + newCreateDomainIfNotExists, + createSequenceIfNotExists, + createViewIfNotExists, + createOrReplaceView, + respectCatalogOrder, + respectSchemaOrder, + respectTableOrder, + respectColumnOrder, + respectConstraintOrder, + respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -294,6 +347,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, newCreateSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -303,6 +357,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -328,6 +383,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, newCreateViewIfNotExists, createOrReplaceView, @@ -337,6 +393,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -362,6 +419,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, newCreateOrReplaceView, @@ -371,6 +429,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -394,6 +453,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -403,6 +463,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -426,6 +487,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -435,6 +497,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -458,6 +521,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -467,6 +531,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -490,6 +555,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -499,6 +565,7 @@ public final class DDLExportConfiguration { newRespectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -522,6 +589,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -531,6 +599,7 @@ public final class DDLExportConfiguration { respectColumnOrder, newRespectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -554,6 +623,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -563,6 +633,41 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, newRespectIndexOrder, + respectDomainOrder, + respectSequenceOrder, + defaultSequenceFlags + ); + } + + /** + * Whether to respect the domain order produced by the {@link Meta} source + * when generated domain DDL. + */ + public final boolean respectDomainOrder() { + return respectDomainOrder; + } + + /** + * Whether to respect the sequence order produced by the {@link Meta} source + * when generated sequence DDL. + */ + public final DDLExportConfiguration respectDomainOrder(boolean newRespectDomainOrder) { + return new DDLExportConfiguration( + flags, + createSchemaIfNotExists, + createTableIfNotExists, + createIndexIfNotExists, + createDomainIfNotExists, + createSequenceIfNotExists, + createViewIfNotExists, + createOrReplaceView, + respectCatalogOrder, + respectSchemaOrder, + respectTableOrder, + respectColumnOrder, + respectConstraintOrder, + respectIndexOrder, + newRespectDomainOrder, respectSequenceOrder, defaultSequenceFlags ); @@ -586,6 +691,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -595,6 +701,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, newRespectSequenceOrder, defaultSequenceFlags ); @@ -618,6 +725,7 @@ public final class DDLExportConfiguration { createSchemaIfNotExists, createTableIfNotExists, createIndexIfNotExists, + createDomainIfNotExists, createSequenceIfNotExists, createViewIfNotExists, createOrReplaceView, @@ -627,6 +735,7 @@ public final class DDLExportConfiguration { respectColumnOrder, respectConstraintOrder, respectIndexOrder, + respectDomainOrder, respectSequenceOrder, newDefaultSequenceFlags ); diff --git a/jOOQ/src/main/java/org/jooq/DDLFlag.java b/jOOQ/src/main/java/org/jooq/DDLFlag.java index e19e1b73dd..c416de87f2 100644 --- a/jOOQ/src/main/java/org/jooq/DDLFlag.java +++ b/jOOQ/src/main/java/org/jooq/DDLFlag.java @@ -77,6 +77,11 @@ public enum DDLFlag { */ INDEX, + /** + * Whether DOMAIN statements should be generated. + */ + DOMAIN, + /** * Whether SEQUENCE statements should be generated. */ diff --git a/jOOQ/src/main/java/org/jooq/Meta.java b/jOOQ/src/main/java/org/jooq/Meta.java index 767a99d140..d8dcca47cc 100644 --- a/jOOQ/src/main/java/org/jooq/Meta.java +++ b/jOOQ/src/main/java/org/jooq/Meta.java @@ -52,6 +52,7 @@ import static org.jooq.SQLDialect.HSQLDB; import static org.jooq.SQLDialect.POSTGRES; // ... // ... +// ... import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -169,6 +170,33 @@ public interface Meta extends Scope { @Support List> getTables(Name name) throws DataAccessException; + /** + * Get all domain objects from the underlying meta data source. + * + * @throws DataAccessException If something went wrong fetching the meta + * objects + */ + @Support({ H2, POSTGRES }) + List> getDomains() throws DataAccessException; + + /** + * Get all domain objects by name from the underlying meta data source. + * + * @throws DataAccessException If something went wrong fetching the meta + * objects + */ + @Support({ H2, POSTGRES }) + List> getDomains(String name) throws DataAccessException; + + /** + * Get all domain objects by name from the underlying meta data source. + * + * @throws DataAccessException If something went wrong fetching the meta + * objects + */ + @Support({ H2, POSTGRES }) + List> getDomains(Name name) throws DataAccessException; + /** * Get all sequence objects from the underlying meta data source. * diff --git a/jOOQ/src/main/java/org/jooq/Schema.java b/jOOQ/src/main/java/org/jooq/Schema.java index 5c1e0ed795..7ef4c2a98e 100644 --- a/jOOQ/src/main/java/org/jooq/Schema.java +++ b/jOOQ/src/main/java/org/jooq/Schema.java @@ -119,6 +119,24 @@ public interface Schema extends Named { */ UDT getUDT(String name); + /** + * Stream all domains contained in this schema. + */ + + Stream> domainStream(); + + + /** + * List all domains contained in this schema. + */ + List> getDomains(); + + /** + * Get a domain by its name (case-sensitive) in this schema, or + * null if no such domain exists. + */ + Domain getDomain(String name); + /** * Stream all sequences contained in this schema. */ diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractMeta.java b/jOOQ/src/main/java/org/jooq/impl/AbstractMeta.java index be90edc1f7..06d2dcd781 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractMeta.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractMeta.java @@ -51,6 +51,7 @@ import java.util.Map; import org.jooq.Catalog; import org.jooq.Configuration; import org.jooq.DDLExportConfiguration; +import org.jooq.Domain; import org.jooq.Index; import org.jooq.Meta; import org.jooq.Name; @@ -74,9 +75,11 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable private Map cachedCatalogs; private Map cachedQualifiedSchemas; private Map> cachedQualifiedTables; + private Map> cachedQualifiedDomains; private Map> cachedQualifiedSequences; private Map> cachedUnqualifiedSchemas; private Map>> cachedUnqualifiedTables; + private Map>> cachedUnqualifiedDomains; private Map>> cachedUnqualifiedSequences; private List> cachedPrimaryKeys; private List cachedIndexes; @@ -196,6 +199,48 @@ abstract class AbstractMeta extends AbstractScope implements Meta, Serializable return result; } + @Override + public final List> getDomains(String name) { + return getDomains(name(name)); + } + + @Override + public final List> getDomains(Name name) { + initDomains(); + return get(name, new Iterable>() { + @Override + public Iterator> iterator() { + return getDomains().iterator(); + } + }, cachedQualifiedDomains, cachedUnqualifiedDomains); + } + + @Override + public final List> getDomains() { + initDomains(); + return Collections.unmodifiableList(new ArrayList<>(cachedQualifiedDomains.values())); + } + + private final void initDomains() { + if (cachedQualifiedDomains == null) { + cachedQualifiedDomains = new LinkedHashMap<>(); + cachedUnqualifiedDomains = new LinkedHashMap<>(); + get(name(""), new Iterable>() { + @Override + public Iterator> iterator() { + return getDomains0().iterator(); + } + }, cachedQualifiedDomains, cachedUnqualifiedDomains); + } + } + + protected List> getDomains0() { + List> result = new ArrayList<>(); + for (Schema schema : getSchemas()) + result.addAll(schema.getDomains()); + return result; + } + @Override public final List> getSequences(String name) { return getSequences(name(name)); diff --git a/jOOQ/src/main/java/org/jooq/impl/DDL.java b/jOOQ/src/main/java/org/jooq/impl/DDL.java index 6dc6aae530..2312a48a80 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DDL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DDL.java @@ -39,6 +39,7 @@ package org.jooq.impl; import static org.jooq.DDLFlag.CHECK; import static org.jooq.DDLFlag.COMMENT; +import static org.jooq.DDLFlag.DOMAIN; import static org.jooq.DDLFlag.FOREIGN_KEY; import static org.jooq.DDLFlag.INDEX; import static org.jooq.DDLFlag.PRIMARY_KEY; @@ -59,11 +60,15 @@ import java.util.List; import org.jooq.Check; import org.jooq.Constraint; import org.jooq.ConstraintEnforcementStep; +import org.jooq.CreateDomainAsStep; +import org.jooq.CreateDomainConstraintStep; +import org.jooq.CreateDomainDefaultStep; import org.jooq.CreateSequenceFlagsStep; import org.jooq.CreateTableOnCommitStep; import org.jooq.DDLExportConfiguration; import org.jooq.DDLFlag; import org.jooq.DSLContext; +import org.jooq.Domain; import org.jooq.Field; import org.jooq.ForeignKey; import org.jooq.Index; @@ -171,6 +176,27 @@ final class DDL { return result; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + final Query createDomain(Domain domain) { + CreateDomainAsStep s1 = configuration.createDomainIfNotExists() + ? ctx.createDomainIfNotExists(domain) + : ctx.createDomain(domain); + + CreateDomainDefaultStep s2 = s1.as(domain.getDataType()); + CreateDomainConstraintStep s3 = domain.getDataType().defaulted() + ? s2.default_(domain.getDataType().default_()) + : s2; + + if (domain.checks().isEmpty()) + return s3; + + List constraints = new ArrayList<>(); + for (Check check : domain.checks()) + constraints.add(check.constraint()); + + return s3.constraints(constraints); + } + private final Query createTable(Table table) { return createTable(table, constraints(table)); } @@ -345,6 +371,11 @@ final class DDL { for (Constraint constraint : foreignKeys(table)) queries.add(ctx.alterTable(table).add(constraint)); + if (configuration.flags().contains(DOMAIN)) + for (Schema schema : schemas) + for (Domain domain : sortIf(schema.getDomains(), !configuration.respectDomainOrder())) + queries.add(createDomain(domain)); + if (configuration.flags().contains(SEQUENCE)) for (Schema schema : schemas) for (Sequence sequence : sortIf(schema.getSequences(), !configuration.respectSequenceOrder())) diff --git a/jOOQ/src/main/java/org/jooq/impl/DomainImpl.java b/jOOQ/src/main/java/org/jooq/impl/DomainImpl.java index d362b3c023..dc9d1107af 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DomainImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/DomainImpl.java @@ -52,7 +52,7 @@ import org.jooq.Schema; /** * @author Lukas Eder */ -final class DomainImpl extends AbstractTypedNamed implements Domain { +class DomainImpl extends AbstractTypedNamed implements Domain { /** * Generated UID diff --git a/jOOQ/src/main/java/org/jooq/impl/Interpreter.java b/jOOQ/src/main/java/org/jooq/impl/Interpreter.java index a67c702eb2..b2d154a86a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Interpreter.java +++ b/jOOQ/src/main/java/org/jooq/impl/Interpreter.java @@ -49,6 +49,7 @@ import static org.jooq.impl.ConstraintType.PRIMARY_KEY; import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.schema; import static org.jooq.impl.SQLDataType.BIGINT; +import static org.jooq.impl.Tools.EMPTY_CHECK; import static org.jooq.impl.Tools.EMPTY_FIELD; import static org.jooq.impl.Tools.intersect; import static org.jooq.impl.Tools.normaliseNameCase; @@ -74,6 +75,7 @@ import org.jooq.Configuration; import org.jooq.Constraint; import org.jooq.DataType; import org.jooq.Delete; +import org.jooq.Domain; import org.jooq.Field; import org.jooq.FieldOrConstraint; import org.jooq.ForeignKey; @@ -127,6 +129,7 @@ final class Interpreter { private final Map> interpretedUniqueKeys = new HashMap<>(); private final Map> interpretedForeignKeys = new HashMap<>(); private final Map interpretedIndexes = new HashMap<>(); + private final Map interpretedDomains = new HashMap<>(); private final Map interpretedSequences = new HashMap<>(); Interpreter(Configuration configuration) { @@ -205,6 +208,9 @@ final class Interpreter { else if (query instanceof DropIndexImpl) accept0((DropIndexImpl) query); + else if (query instanceof CreateDomainImpl) + accept0((CreateDomainImpl) query); + else if (query instanceof CommentOnImpl) accept0((CommentOnImpl) query); @@ -248,7 +254,7 @@ final class Interpreter { if (getSchema(schema, false) != null) { if (!query.$createSchemaIfNotExists()) - throw schemaAlreadyExists(schema); + throw alreadyExists(schema); return; } @@ -263,14 +269,14 @@ final class Interpreter { MutableSchema oldSchema = getSchema(schema); if (oldSchema == null) { if (!query.$alterSchemaIfExists()) - throw schemaNotExists(schema); + throw notExists(schema); return; } if (renameTo != null) { if (getSchema(renameTo, false) != null) - throw schemaAlreadyExists(renameTo); + throw alreadyExists(renameTo); oldSchema.name((UnqualifiedName) renameTo.getUnqualifiedName()); return; @@ -285,7 +291,7 @@ final class Interpreter { if (mutableSchema == null) { if (!query.$dropSchemaIfExists()) - throw schemaNotExists(schema); + throw notExists(schema); return; } @@ -358,7 +364,7 @@ final class Interpreter { MutableUniqueKey mu = null; if (mrf == null) - throw tableNotExists(impl.$referencesTable()); + throw notExists(impl.$referencesTable()); List mfs = mt.fields(impl.$foreignKey(), true); List mrfs = mrf.fields(impl.$references(), true); @@ -472,7 +478,7 @@ final class Interpreter { MutableTable existing = schema.table(table); if (existing == null) { if (!query.$ifExists()) - throw tableNotExists(table); + throw notExists(table); return; } @@ -482,9 +488,9 @@ final class Interpreter { if (query.$add() != null) { for (FieldOrConstraint fc : query.$add()) if (fc instanceof Field && find(existing.fields, (Field) fc) != null) - throw fieldAlreadyExists((Field) fc); + throw alreadyExists(fc); else if (fc instanceof Constraint && !fc.getUnqualifiedName().empty() && existing.constraint((Constraint) fc) != null) - throw constraintAlreadyExists((Constraint) fc); + throw alreadyExists(fc); // TODO: ReverseIterable is not a viable approach if we also allow constraints to be added this way if (query.$addFirst()) { @@ -516,7 +522,7 @@ final class Interpreter { else if (query.$addColumn() != null) { if (find(existing.fields, query.$addColumn()) != null) if (!query.$ifNotExistsColumn()) - throw fieldAlreadyExists(query.$addColumn()); + throw alreadyExists(query.$addColumn()); else return; @@ -540,7 +546,7 @@ final class Interpreter { if (existingField == null) if (!query.$ifExistsColumn()) - throw columnNotExists(query.$alterColumn()); + throw notExists(query.$alterColumn()); else return; @@ -566,9 +572,9 @@ final class Interpreter { MutableField mf = find(existing.fields, query.$renameColumn()); if (mf == null) - throw fieldNotExists(query.$renameColumn()); + throw notExists(query.$renameColumn()); else if (find(existing.fields, query.$renameColumnTo()) != null) - throw fieldAlreadyExists(query.$renameColumnTo()); + throw alreadyExists(query.$renameColumnTo()); else mf.name((UnqualifiedName) query.$renameColumnTo().getUnqualifiedName()); } @@ -576,7 +582,7 @@ final class Interpreter { MutableConstraint mc = existing.constraint(query.$renameConstraint(), true); if (existing.constraint(query.$renameConstraintTo()) != null) - throw constraintAlreadyExists(query.$renameConstraintTo()); + throw alreadyExists(query.$renameConstraintTo()); else mc.name((UnqualifiedName) query.$renameConstraintTo().getUnqualifiedName()); } @@ -672,7 +678,7 @@ final class Interpreter { } if (!query.$ifExistsConstraint()) - throw constraintNotExists(query.$dropConstraint()); + throw notExists(query.$dropConstraint()); } else if (query.$dropConstraintType() == PRIMARY_KEY) { if (existing.primaryKey != null) @@ -732,11 +738,12 @@ final class Interpreter { private final void addConstraint(Query query, ConstraintImpl impl, MutableTable existing) { if (!impl.getUnqualifiedName().empty() && existing.constraint(impl) != null) - throw constraintAlreadyExists(impl); + throw alreadyExists(impl); + boolean enforced = true ; if (impl.$primaryKey() != null) if (existing.primaryKey != null) - throw constraintAlreadyExists(impl); + throw alreadyExists(impl); else existing.primaryKey = new MutableUniqueKey((UnqualifiedName) impl.getUnqualifiedName(), existing, existing.fields(impl.$primaryKey(), true), enforced); else if (impl.$unique() != null) @@ -756,7 +763,7 @@ final class Interpreter { MutableTable existing = schema.table(table); if (existing == null) { if (!query.$ifExists()) - throw tableNotExists(table); + throw notExists(table); return; } @@ -775,7 +782,7 @@ final class Interpreter { MutableTable existing = schema.table(table); if (existing == null) - throw tableNotExists(table); + throw notExists(table); else if (!existing.options.type().isTable()) throw objectNotTable(table); else if (!query.$cascade() && existing.hasReferencingKeys()) @@ -850,7 +857,7 @@ final class Interpreter { MutableSequence existing = schema.sequence(sequence); if (existing != null) { if (!query.$createSequenceIfNotExists()) - throw sequenceAlreadyExists(sequence); + throw alreadyExists(sequence); return; } @@ -872,7 +879,7 @@ final class Interpreter { MutableSequence existing = schema.sequence(sequence); if (existing == null) { if (!query.$ifExists()) - throw sequenceNotExists(sequence); + throw notExists(sequence); return; } @@ -880,7 +887,7 @@ final class Interpreter { Sequence renameTo = query.$renameTo(); if (renameTo != null) { if (schema.sequence(renameTo) != null) - throw sequenceAlreadyExists(renameTo); + throw alreadyExists(renameTo); existing.name((UnqualifiedName) renameTo.getUnqualifiedName()); } @@ -932,7 +939,7 @@ final class Interpreter { MutableSequence existing = schema.sequence(sequence); if (existing == null) { if (!query.$dropSequenceIfExists()) - throw sequenceNotExists(sequence); + throw notExists(sequence); return; } @@ -947,14 +954,14 @@ final class Interpreter { MutableTable mt = schema.table(table); if (mt == null) - throw tableNotExists(table); + throw notExists(table); MutableIndex existing = find(mt.indexes, index); List mtf = mt.sortFields(query.$sortFields()); if (existing != null) { if (!query.$ifNotExists()) - throw indexAlreadyExists(index); + throw alreadyExists(index); return; } @@ -972,7 +979,7 @@ final class Interpreter { if (index(query.$renameTo(), table, false, false) == null) existing.name((UnqualifiedName) query.$renameTo().getUnqualifiedName()); else - throw indexAlreadyExists(query.$renameTo()); + throw alreadyExists(query.$renameTo()); else throw unsupportedQuery(query); } @@ -987,6 +994,39 @@ final class Interpreter { existing.table.indexes.remove(existing); } + @SuppressWarnings({ "rawtypes", "unchecked" }) + private final void accept0(CreateDomainImpl query) { + Domain domain = query.$domain(); + MutableSchema schema = getSchema(domain.getSchema(), true); + + MutableDomain existing = schema.domain(domain); + if (existing != null) { + if (!query.$createDomainIfNotExists()) + throw alreadyExists(domain); + + return; + } + + MutableDomain md = new MutableDomain((UnqualifiedName) domain.getUnqualifiedName(), schema, query.$dataType()); + + if (query.$default_() != null) + md.dataType = md.dataType.default_((Field) query.$default_()); + + // TODO: Support NOT NULL constraints + if (query.$constraints() != null) { + md.checks = new ArrayList<>(); + + for (Constraint constraint : query.$constraints()) + if (((ConstraintImpl) constraint).$check() != null) + md.checks.add(new CheckImpl( + null, + constraint.getQualifiedName(), + ((ConstraintImpl) constraint).$check(), + true + )); + } + } + private final void accept0(CommentOnImpl query) { Table table = query.$table(); Field field = query.$field(); @@ -1002,7 +1042,7 @@ final class Interpreter { private final void accept0(SetSchema query) { MutableSchema schema = getSchema(query.$schema()); if (schema == null) - throw schemaNotExists(query.$schema()); + throw notExists(query.$schema()); currentSchema = schema; } @@ -1022,27 +1062,14 @@ final class Interpreter { // Exceptions // ------------------------------------------------------------------------- - // TODO: Surely, these exception utilities can be refactored / improved? private static final DataDefinitionException unsupportedQuery(Query query) { return new DataDefinitionException("Unsupported query: " + query.getSQL()); } - private static final DataDefinitionException schemaNotExists(Schema schema) { - return new DataDefinitionException("Schema does not exist: " + schema.getQualifiedName()); - } - - private static final DataDefinitionException schemaAlreadyExists(Schema schema) { - return new DataDefinitionException("Schema already exists: " + schema.getQualifiedName()); - } - private static final DataDefinitionException schemaNotEmpty(Schema schema) { return new DataDefinitionException("Schema is not empty: " + schema.getQualifiedName()); } - private static final DataDefinitionException tableNotExists(Table table) { - return new DataDefinitionException("Table does not exist: " + table.getQualifiedName()); - } - private static final DataDefinitionException objectNotTable(Table table) { return new DataDefinitionException("Object is not a table: " + table.getQualifiedName()); } @@ -1055,10 +1082,6 @@ final class Interpreter { return new DataDefinitionException("Object is not a view: " + table.getQualifiedName()); } - private static final DataDefinitionException tableAlreadyExists(Table table) { - return new DataDefinitionException("Table already exists: " + table.getQualifiedName()); - } - private static final DataDefinitionException viewNotExists(Table view) { return new DataDefinitionException("View does not exist: " + view.getQualifiedName()); } @@ -1067,58 +1090,22 @@ final class Interpreter { return new DataDefinitionException("View already exists: " + view.getQualifiedName()); } - private static final DataDefinitionException columnNotExists(Field field) { - return new DataDefinitionException("Column does not exist: " + field.getQualifiedName()); - } - - private static final DataDefinitionException columnAlreadyExists(Field field) { - return columnAlreadyExists(field.getQualifiedName()); - } - private static final DataDefinitionException columnAlreadyExists(Name name) { return new DataDefinitionException("Column already exists: " + name); } - private static final DataDefinitionException sequenceNotExists(Sequence sequence) { - return new DataDefinitionException("Sequence does not exist: " + sequence.getQualifiedName()); + private static final DataDefinitionException notExists(Named named) { + return new DataDefinitionException(named.getClass().getSimpleName() + " does not exist: " + named.getQualifiedName()); } - private static final DataDefinitionException sequenceAlreadyExists(Sequence sequence) { - return new DataDefinitionException("Sequence already exists: " + sequence.getQualifiedName()); + private static final DataDefinitionException alreadyExists(Named named) { + return new DataDefinitionException(named.getClass().getSimpleName() + " already exists: " + named.getQualifiedName()); } private static final DataDefinitionException primaryKeyNotExists() { return new DataDefinitionException("Primary key does not exist"); } - private static final DataDefinitionException constraintAlreadyExists(Constraint constraint) { - return new DataDefinitionException("Constraint already exists: " + constraint.getQualifiedName()); - } - - private static final DataDefinitionException constraintNotExists(Constraint constraint) { - return new DataDefinitionException("Constraint does not exist: " + constraint.getQualifiedName()); - } - - private static final DataDefinitionException indexNotExists(Index index) { - return new DataDefinitionException("Index does not exist: " + index.getQualifiedName()); - } - - private static final DataDefinitionException indexAlreadyExists(Index index) { - return new DataDefinitionException("Index already exists: " + index.getQualifiedName()); - } - - private static final DataDefinitionException fieldNotExists(Field field) { - return new DataDefinitionException("Field does not exist: " + field.getQualifiedName()); - } - - private static final DataDefinitionException fieldAlreadyExists(Field field) { - return new DataDefinitionException("Field already exists: " + field.getQualifiedName()); - } - - private static final DataDefinitionException objectNotExists(Named named) { - return new DataDefinitionException("Object does not exist: " + named.getQualifiedName()); - } - // ------------------------------------------------------------------------- // Auxiliary methods // ------------------------------------------------------------------------- @@ -1206,7 +1193,7 @@ final class Interpreter { private final MutableTable table(Table table, boolean throwIfNotExists) { MutableTable result = getSchema(table.getSchema()).table(table); if (result == null && throwIfNotExists) - throw tableNotExists(table); + throw notExists(table); return result; } @@ -1233,10 +1220,10 @@ final class Interpreter { if (mt != null) mi = find(mt.indexes, index); else if (table != null && throwIfNotExists) - throw tableNotExists(table); + throw notExists(table); if (mi == null && !ifExists && throwIfNotExists) - throw indexNotExists(index); + throw notExists(index); return mi; } @@ -1254,7 +1241,7 @@ final class Interpreter { if (mt.options.type().isView()) return viewAlreadyExists(t); else - return tableAlreadyExists(t); + return alreadyExists(t); } private final MutableField field(Field field) { @@ -1270,7 +1257,7 @@ final class Interpreter { MutableField result = find(table.fields, field); if (result == null && throwIfNotExists) - throw fieldNotExists(field); + throw notExists(field); return result; } @@ -1312,7 +1299,7 @@ final class Interpreter { } if (result == -1) - throw objectNotExists(named); + throw notExists(named); return result; } @@ -1484,6 +1471,7 @@ final class Interpreter { private final class MutableSchema extends MutableNamed { MutableCatalog catalog; List tables = new MutableNamedList<>(); + List domains = new MutableNamedList<>(); List sequences = new MutableNamedList<>(); MutableSchema(UnqualifiedName name, MutableCatalog catalog) { @@ -1499,7 +1487,10 @@ final class Interpreter { for (MutableForeignKey referencingKey : table.referencingKeys()) referencingKey.table.foreignKeys.remove(referencingKey); + // TODO: Cascade domains? + tables.clear(); + domains.clear(); sequences.clear(); } @@ -1526,6 +1517,10 @@ final class Interpreter { return find(tables, t); } + final MutableDomain domain(Domain d) { + return find(domains, d); + } + final MutableSequence sequence(Sequence s) { return find(sequences, s); } @@ -1545,6 +1540,16 @@ final class Interpreter { return result; } + @Override + public final List> getDomains() { + List> result = new ArrayList<>(domains.size()); + + for (MutableDomain domain : domains) + result.add(domain.interpretedDomain()); + + return result; + } + @Override public final List> getSequences() { List> result = new ArrayList<>(sequences.size()); @@ -1641,7 +1646,7 @@ final class Interpreter { return result; if (failIfNotFound) - throw constraintNotExists(constraint); + throw notExists(constraint); return null; } @@ -1754,6 +1759,48 @@ final class Interpreter { } } + private final class MutableDomain extends MutableNamed { + MutableSchema schema; + DataType dataType; + List> checks; + + MutableDomain(UnqualifiedName name, MutableSchema schema, DataType dataType) { + super(name); + + this.schema = schema; + this.dataType = dataType; + schema.domains.add(this); + } + + @Override + final void onDrop() { + // TODO: Cascade + } + + @Override + final MutableNamed parent() { + return schema; + } + + + final InterpretedDomain interpretedDomain() { + Name qualifiedName = qualifiedName(); + InterpretedDomain result = interpretedDomains.get(qualifiedName); + + if (result == null) + interpretedDomains.put(qualifiedName, result = new InterpretedDomain(schema.interpretedSchema())); + + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private final class InterpretedDomain extends DomainImpl { + InterpretedDomain(Schema schema) { + super(schema, MutableDomain.this.name(), dataType, checks != null ? checks.toArray(EMPTY_CHECK) : EMPTY_CHECK); + } + } + } + private final class MutableSequence extends MutableNamed { MutableSchema schema; Field startWith; diff --git a/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java b/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java index e3d31c6e73..ceb511ae08 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java @@ -49,7 +49,9 @@ import org.jooq.Catalog; import org.jooq.Clause; import org.jooq.Comment; import org.jooq.Context; +import org.jooq.Domain; import org.jooq.Name; +import org.jooq.Named; import org.jooq.Schema; import org.jooq.Sequence; import org.jooq.Table; @@ -126,31 +128,32 @@ public class SchemaImpl extends AbstractNamed implements Schema { return CLAUSES; } - @Override - public final Table getTable(String tableName) { - for (Table table : getTables()) - if (table.getName().equals(tableName)) - return table; + private final N getNamed(List list, String name) { + for (N named : list) + if (named.getName().equals(name)) + return named; return null; } @Override - public final UDT getUDT(String udtName) { - for (UDT udt : getUDTs()) - if (udt.getName().equals(udtName)) - return udt; - - return null; + public final Table getTable(String name) { + return getNamed(getTables(), name); } @Override - public final Sequence getSequence(String sequenceName) { - for (Sequence sequence : getSequences()) - if (sequence.getName().equals(sequenceName)) - return sequence; + public final UDT getUDT(String name) { + return getNamed(getUDTs(), name); + } - return null; + @Override + public final Domain getDomain(String name) { + return getNamed(getDomains(), name); + } + + @Override + public final Sequence getSequence(String name) { + return getNamed(getSequences(), name); } /** @@ -173,6 +176,16 @@ public class SchemaImpl extends AbstractNamed implements Schema { return Collections.emptyList(); } + /** + * {@inheritDoc} + *

+ * Subclasses should override this method + */ + @Override + public List> getDomains() { + return Collections.emptyList(); + } + /** * {@inheritDoc} *

@@ -194,6 +207,11 @@ public class SchemaImpl extends AbstractNamed implements Schema { return getUDTs().stream(); } + @Override + public final Stream> domainStream() { + return getDomains().stream(); + } + @Override public final Stream> sequenceStream() { return getSequences().stream(); diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 25e219b5ad..273e8a3a43 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -217,6 +217,7 @@ import org.jooq.Asterisk; import org.jooq.Attachable; import org.jooq.BindContext; import org.jooq.Catalog; +import org.jooq.Check; import org.jooq.Clause; import org.jooq.CommonTableExpression; import org.jooq.Condition; @@ -298,6 +299,7 @@ final class Tools { // ------------------------------------------------------------------------ static final byte[] EMPTY_BYTE = {}; + static final Check[] EMPTY_CHECK = {}; static final Clause[] EMPTY_CLAUSE = {}; static final Collection[] EMPTY_COLLECTION = {}; static final CommonTableExpression[] EMPTY_COMMON_TABLE_EXPRESSION = {};