From b5b5bc4f6b9a2df191f487d98a023a7d896c7b4c Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 5 Dec 2019 20:49:29 +0100 Subject: [PATCH] [jOOQ/jOOQ#9633] Add a new Settings.interpreterNameLookupCaseSensitivity (WIP, see new TODOs) --- .../InterpreterNameLookupCaseSensitivity.java | 42 +++++++ .../src/main/java/org/jooq/conf/Settings.java | 39 ++++++ .../java/org/jooq/impl/DDLInterpreter.java | 115 ++++++++++++------ .../resources/xsd/jooq-runtime-3.13.0.xsd | 21 ++++ 4 files changed, 182 insertions(+), 35 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/conf/InterpreterNameLookupCaseSensitivity.java diff --git a/jOOQ/src/main/java/org/jooq/conf/InterpreterNameLookupCaseSensitivity.java b/jOOQ/src/main/java/org/jooq/conf/InterpreterNameLookupCaseSensitivity.java new file mode 100644 index 0000000000..a2bd8756cb --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/conf/InterpreterNameLookupCaseSensitivity.java @@ -0,0 +1,42 @@ + +package org.jooq.conf; + +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for InterpreterNameLookupCaseSensitivity. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ *

+ * <simpleType name="InterpreterNameLookupCaseSensitivity">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="DEFAULT"/>
+ *     <enumeration value="ALWAYS"/>
+ *     <enumeration value="WHEN_QUOTED"/>
+ *     <enumeration value="NEVER"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "InterpreterNameLookupCaseSensitivity") +@XmlEnum +public enum InterpreterNameLookupCaseSensitivity { + + DEFAULT, + ALWAYS, + WHEN_QUOTED, + NEVER; + + public String value() { + return name(); + } + + public static InterpreterNameLookupCaseSensitivity fromValue(String v) { + return valueOf(v); + } + +} diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 08ad75ff73..ab7f48231d 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -190,6 +190,9 @@ public class Settings @XmlElement(type = String.class, defaultValue = "DEFAULT") @XmlJavaTypeAdapter(SQLDialectAdapter.class) protected SQLDialect interpreterDialect; + @XmlElement(defaultValue = "DEFAULT") + @XmlSchemaType(name = "string") + protected InterpreterNameLookupCaseSensitivity interpreterNameCaseSensitivity = InterpreterNameLookupCaseSensitivity.DEFAULT; @XmlElement(type = String.class, defaultValue = "DEFAULT") @XmlJavaTypeAdapter(SQLDialectAdapter.class) protected SQLDialect parseDialect; @@ -1610,6 +1613,22 @@ public class Settings this.interpreterDialect = value; } + /** + * [#9633] The case sensitivity of identifiers used when interpreting SQL DDL statements. + * + */ + public InterpreterNameLookupCaseSensitivity getInterpreterNameCaseSensitivity() { + return interpreterNameCaseSensitivity; + } + + /** + * [#9633] The case sensitivity of identifiers used when interpreting SQL DDL statements. + * + */ + public void setInterpreterNameCaseSensitivity(InterpreterNameLookupCaseSensitivity value) { + this.interpreterNameCaseSensitivity = value; + } + /** * [#7337] The input dialect that should be chosen to disambiguate ambiguous SQL syntax. * @@ -2273,6 +2292,15 @@ public class Settings return this; } + /** + * [#9633] The case sensitivity of identifiers used when interpreting SQL DDL statements. + * + */ + public Settings withInterpreterNameCaseSensitivity(InterpreterNameLookupCaseSensitivity value) { + setInterpreterNameCaseSensitivity(value); + return this; + } + /** * [#7337] The input dialect that should be chosen to disambiguate ambiguous SQL syntax. * @@ -2428,6 +2456,7 @@ public class Settings builder.append("executeUpdateWithoutWhere", executeUpdateWithoutWhere); builder.append("executeDeleteWithoutWhere", executeDeleteWithoutWhere); builder.append("interpreterDialect", interpreterDialect); + builder.append("interpreterNameCaseSensitivity", interpreterNameCaseSensitivity); builder.append("parseDialect", parseDialect); builder.append("parseNameCase", parseNameCase); builder.append("parseWithMetaLookups", parseWithMetaLookups); @@ -3034,6 +3063,15 @@ public class Settings return false; } } + if (interpreterNameCaseSensitivity == null) { + if (other.interpreterNameCaseSensitivity!= null) { + return false; + } + } else { + if (!interpreterNameCaseSensitivity.equals(other.interpreterNameCaseSensitivity)) { + return false; + } + } if (parseDialect == null) { if (other.parseDialect!= null) { return false; @@ -3186,6 +3224,7 @@ public class Settings result = ((prime*result)+((executeUpdateWithoutWhere == null)? 0 :executeUpdateWithoutWhere.hashCode())); result = ((prime*result)+((executeDeleteWithoutWhere == null)? 0 :executeDeleteWithoutWhere.hashCode())); result = ((prime*result)+((interpreterDialect == null)? 0 :interpreterDialect.hashCode())); + result = ((prime*result)+((interpreterNameCaseSensitivity == null)? 0 :interpreterNameCaseSensitivity.hashCode())); result = ((prime*result)+((parseDialect == null)? 0 :parseDialect.hashCode())); result = ((prime*result)+((parseNameCase == null)? 0 :parseNameCase.hashCode())); result = ((prime*result)+((parseWithMetaLookups == null)? 0 :parseWithMetaLookups.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/DDLInterpreter.java b/jOOQ/src/main/java/org/jooq/impl/DDLInterpreter.java index c1702f911e..9f75da1ae5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DDLInterpreter.java +++ b/jOOQ/src/main/java/org/jooq/impl/DDLInterpreter.java @@ -37,6 +37,7 @@ */ package org.jooq.impl; +import static org.jooq.Name.Quoted.QUOTED; import static org.jooq.impl.AbstractName.NO_NAME; import static org.jooq.impl.Cascade.CASCADE; import static org.jooq.impl.Cascade.RESTRICT; @@ -86,6 +87,7 @@ import org.jooq.TableOptions; import org.jooq.TableOptions.TableType; import org.jooq.UniqueKey; import org.jooq.Update; +import org.jooq.conf.InterpreterNameLookupCaseSensitivity; import org.jooq.exception.DataAccessException; import org.jooq.exception.DataDefinitionException; import org.jooq.impl.ConstraintImpl.Action; @@ -105,7 +107,7 @@ final class DDLInterpreter { DDLInterpreter(Configuration configuration) { this.configuration = configuration; this.defaultCatalog = new MutableCatalog(NO_NAME); - this.catalogs.put(defaultCatalog.name, defaultCatalog); + this.catalogs.put(defaultCatalog.name(), defaultCatalog); this.defaultSchema = new MutableSchema(NO_NAME, defaultCatalog); this.currentSchema = defaultSchema; } @@ -219,7 +221,7 @@ final class DDLInterpreter { if (getSchema(renameTo, false) != null) throw schemaAlreadyExists(renameTo); - oldSchema.name = (UnqualifiedName) renameTo.getUnqualifiedName(); + oldSchema.name((UnqualifiedName) renameTo.getUnqualifiedName()); return; } else @@ -317,7 +319,7 @@ final class DDLInterpreter { Iterator it = tables.iterator(); while (it.hasNext()) { - if (it.next().name.equals(table.name)) { + if (it.next().nameEquals(table.name())) { it.remove(); break; } @@ -489,7 +491,7 @@ final class DDLInterpreter { throw unsupportedQuery(query); } else if (query.$renameTo() != null && checkNotExists(schema, query.$renameTo())) { - existing.name = (UnqualifiedName) query.$renameTo().getUnqualifiedName(); + existing.name((UnqualifiedName) query.$renameTo().getUnqualifiedName()); } else if (query.$renameColumn() != null) { MutableField mf = find(existing.fields, query.$renameColumn()); @@ -499,7 +501,7 @@ final class DDLInterpreter { else if (find(existing.fields, query.$renameColumnTo()) != null) throw fieldAlreadyExists(query.$renameColumnTo()); else - mf.name = (UnqualifiedName) query.$renameColumnTo().getUnqualifiedName(); + mf.name((UnqualifiedName) query.$renameColumnTo().getUnqualifiedName()); } else if (query.$renameConstraint() != null) { MutableNamed mk = existing.constraint(query.$renameConstraint()); @@ -509,7 +511,7 @@ final class DDLInterpreter { else if (existing.constraint(query.$renameConstraintTo()) != null) throw constraintAlreadyExists(query.$renameConstraintTo()); else - mk.name = (UnqualifiedName) query.$renameConstraintTo().getUnqualifiedName(); + mk.name((UnqualifiedName) query.$renameConstraintTo().getUnqualifiedName()); } else if (query.$dropColumns() != null) { List fields = existing.fields(query.$dropColumns().toArray(EMPTY_FIELD), false); @@ -525,7 +527,7 @@ final class DDLInterpreter { removal: { Iterator fks = existing.foreignKeys.iterator(); while (fks.hasNext()) { - if (fks.next().name.equals(impl.getUnqualifiedName())) { + if (fks.next().nameEquals((UnqualifiedName) impl.getUnqualifiedName())) { fks.remove(); break removal; } @@ -537,7 +539,7 @@ final class DDLInterpreter { while (uks.hasNext()) { MutableUniqueKey key = uks.next(); - if (key.name.equals(impl.getUnqualifiedName())) { + if (key.nameEquals((UnqualifiedName) impl.getUnqualifiedName())) { cascade(key, null, query.$dropCascade()); uks.remove(); break removal; @@ -549,14 +551,14 @@ final class DDLInterpreter { while (chks.hasNext()) { MutableCheck check = chks.next(); - if (check.name.equals(impl.getUnqualifiedName())) { + if (check.nameEquals((UnqualifiedName) impl.getUnqualifiedName())) { chks.remove(); break removal; } } if (existing.primaryKey != null) { - if (existing.primaryKey.name.equals(impl.getUnqualifiedName())) { + if (existing.primaryKey.nameEquals((UnqualifiedName) impl.getUnqualifiedName())) { cascade(existing.primaryKey, null, query.$dropCascade()); existing.primaryKey = null; break removal; @@ -708,7 +710,7 @@ final class DDLInterpreter { Table renameTo = query.$renameTo(); if (renameTo != null && checkNotExists(schema, renameTo)) - existing.name = (UnqualifiedName) renameTo.getUnqualifiedName(); + existing.name((UnqualifiedName) renameTo.getUnqualifiedName()); else throw unsupportedQuery(query); } @@ -769,7 +771,7 @@ final class DDLInterpreter { if (schema.sequence(renameTo) != null) throw sequenceAlreadyExists(renameTo); - existing.name = (UnqualifiedName) renameTo.getUnqualifiedName(); + existing.name((UnqualifiedName) renameTo.getUnqualifiedName()); } else { Field startWith = query.$startWith(); @@ -857,7 +859,7 @@ final class DDLInterpreter { if (existing != null) { if (query.$renameTo() != null) if (index(query.$renameTo(), table, false, false) == null) - existing.name = (UnqualifiedName) query.$renameTo().getUnqualifiedName(); + existing.name((UnqualifiedName) query.$renameTo().getUnqualifiedName()); else throw indexAlreadyExists(query.$renameTo()); else @@ -879,9 +881,9 @@ final class DDLInterpreter { Field field = query.$field(); if (table != null) - table(table).comment = query.$comment(); + table(table).comment(query.$comment()); else if (field != null) - field(field).comment = query.$comment(); + field(field).comment(query.$comment()); else throw unsupportedQuery(query); } @@ -1128,19 +1130,26 @@ final class DDLInterpreter { return result; } - private static final M find(M m, Named named) { - if (m != null && m.name.equals(named.getUnqualifiedName())) + private static final M find(M m, UnqualifiedName name) { + if (m == null) + return null; + + if (m.nameEquals(name)) return m; else return null; } + private static final M find(M m, Named named) { + return find(m, (UnqualifiedName) named.getUnqualifiedName()); + } + private static final M find(List list, Named named) { UnqualifiedName n = (UnqualifiedName) named.getUnqualifiedName(); // TODO Avoid O(N) lookups. Use Maps instead for (M m : list) - if (m.name.equals(n)) + if ((m = find(m, n)) != null) return m; return null; @@ -1151,7 +1160,7 @@ final class DDLInterpreter { // TODO Avoid O(N) lookups. Use Maps instead for (int i = 0; i < list.size(); i++) { - if (list.get(i).name.equals(named.getUnqualifiedName())) { + if (list.get(i).nameEquals((UnqualifiedName) named.getUnqualifiedName())) { result = i; break; } @@ -1168,16 +1177,52 @@ final class DDLInterpreter { // ------------------------------------------------------------------------- private static abstract class MutableNamed { - UnqualifiedName name; - Comment comment; + private UnqualifiedName name; + private String upper; + private Comment comment; + + // TODO: Access this from Settings + private InterpreterNameLookupCaseSensitivity caseSensitive = InterpreterNameLookupCaseSensitivity.WHEN_QUOTED; MutableNamed(UnqualifiedName name) { this(name, null); } MutableNamed(UnqualifiedName name, Comment comment) { - this.name = name; this.comment = comment; + + name(name); + } + + UnqualifiedName name() { + return name; + } + + void name(UnqualifiedName n) { + this.name = n; + + // TODO: Use Settings.renderLocale() + this.upper = name.last().toUpperCase(); + } + + Comment comment() { + return comment; + } + + void comment(Comment c) { + this.comment = c; + } + + boolean nameEquals(UnqualifiedName other) { + + // TODO: Implement InterpreterNameLookupCaseSensitivity.DEFAULT + if (caseSensitive == InterpreterNameLookupCaseSensitivity.ALWAYS || + (caseSensitive == InterpreterNameLookupCaseSensitivity.WHEN_QUOTED && (name.quoted() == QUOTED || other.quoted() == QUOTED))) + return name.last().equals(other.last()); + else + + // TODO: Use Settings.renderLocale() + return upper.equalsIgnoreCase(other.last().toUpperCase()); } abstract void drop(); @@ -1202,7 +1247,7 @@ final class DDLInterpreter { private final class InterpretedCatalog extends CatalogImpl { InterpretedCatalog() { - super(MutableCatalog.this.name, MutableCatalog.this.comment); + super(MutableCatalog.this.name(), MutableCatalog.this.comment()); } @Override @@ -1249,7 +1294,7 @@ final class DDLInterpreter { private final class InterpretedSchema extends SchemaImpl { InterpretedSchema(MutableCatalog.InterpretedCatalog catalog) { - super(MutableSchema.this.name, catalog, MutableSchema.this.comment); + super(MutableSchema.this.name(), catalog, MutableSchema.this.comment()); } @Override @@ -1375,10 +1420,10 @@ final class DDLInterpreter { private final class InterpretedTable extends TableImpl { InterpretedTable(MutableSchema.InterpretedSchema schema) { - super(MutableTable.this.name, schema, null, null, null, null, MutableTable.this.comment, MutableTable.this.options); + super(MutableTable.this.name(), schema, null, null, null, null, MutableTable.this.comment(), MutableTable.this.options); for (MutableField field : MutableTable.this.fields) - createField(field.name, field.type, field.comment != null ? field.comment.getComment() : null); + createField(field.name(), field.type, field.comment() != null ? field.comment().getComment() : null); } @Override @@ -1415,7 +1460,7 @@ final class DDLInterpreter { List> result = new ArrayList<>(); for (MutableCheck c : MutableTable.this.checks) - result.add(new CheckImpl<>(this, c.name, c.condition)); + result.add(new CheckImpl<>(this, c.name(), c.condition)); return result; } @@ -1441,10 +1486,10 @@ final class DDLInterpreter { InterpretedTable t = key.keyTable.new InterpretedTable(key.keyTable.schema.new InterpretedSchema(key.keyTable.schema.catalog.new InterpretedCatalog())); for (int i = 0; i < f.length; i++) - f[i] = (TableField) t.field(key.keyFields.get(i).name); + f[i] = (TableField) t.field(key.keyFields.get(i).name()); // TODO: Cache these? - return new UniqueKeyImpl(t, key.name.last(), f); + return new UniqueKeyImpl(t, key.name().last(), f); } @SuppressWarnings("unchecked") @@ -1455,11 +1500,11 @@ final class DDLInterpreter { TableField[] f = new TableField[key.keyFields.size()]; for (int i = 0; i < f.length; i++) - f[i] = (TableField) field(key.keyFields.get(i).name); + f[i] = (TableField) field(key.keyFields.get(i).name()); // TODO: Refactor these constructor calls // TODO: Cache these? - return new ReferenceImpl<>(key.referencedKey.keyTable.new InterpretedTable((MutableSchema.InterpretedSchema) getSchema()).interpretedKey(key.referencedKey), this, key.name.last(), f); + return new ReferenceImpl<>(key.referencedKey.keyTable.new InterpretedTable((MutableSchema.InterpretedSchema) getSchema()).interpretedKey(key.referencedKey), this, key.name().last(), f); } private final Index interpretedIndex(MutableIndex idx) { @@ -1470,10 +1515,10 @@ final class DDLInterpreter { for (int i = 0; i < f.length; i++) { MutableSortField msf = idx.fields.get(i); - f[i] = field(msf.name).sort(msf.sort); + f[i] = field(msf.name()).sort(msf.sort); } - return new IndexImpl(idx.name, this, f, null, idx.unique); + return new IndexImpl(idx.name(), this, f, null, idx.unique); } } } @@ -1501,7 +1546,7 @@ final class DDLInterpreter { private final class InterpretedSequence extends SequenceImpl { @SuppressWarnings("unchecked") InterpretedSequence(Schema schema) { - super(MutableSequence.this.name, schema, BIGINT, false, + super(MutableSequence.this.name(), schema, BIGINT, false, (Field) MutableSequence.this.startWith, (Field) MutableSequence.this.incrementBy, (Field) MutableSequence.this.minvalue, @@ -1617,7 +1662,7 @@ final class DDLInterpreter { SortOrder sort; MutableSortField(MutableField field, SortOrder sort) { - super(field.name); + super(field.name()); this.field = field; this.sort = sort; diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd index 123a1fd548..8e4abc9d9f 100644 --- a/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd +++ b/jOOQ/src/main/resources/xsd/jooq-runtime-3.13.0.xsd @@ -391,6 +391,10 @@ jOOQ queries, for which no specific fetchSize value was specified.]]> + + + + @@ -803,6 +807,23 @@ Either <input/> or <inputExpression/> must be provided]]> + + + + + + + + + + + + + + + + +