diff --git a/jOOQ/src/main/java/org/jooq/Field.java b/jOOQ/src/main/java/org/jooq/Field.java index 87b2bab356..1a843a939f 100644 --- a/jOOQ/src/main/java/org/jooq/Field.java +++ b/jOOQ/src/main/java/org/jooq/Field.java @@ -85,8 +85,7 @@ extends GroupField, OrderField, FieldOrRow, - FieldOrConstraint, - Named { + FieldOrConstraint { // ------------------------------------------------------------------------ // API diff --git a/jOOQ/src/main/java/org/jooq/FieldOrConstraint.java b/jOOQ/src/main/java/org/jooq/FieldOrConstraint.java index 0e435da934..ad8f98a599 100644 --- a/jOOQ/src/main/java/org/jooq/FieldOrConstraint.java +++ b/jOOQ/src/main/java/org/jooq/FieldOrConstraint.java @@ -45,6 +45,6 @@ package org.jooq; * * @author Lukas Eder */ -public interface FieldOrConstraint extends QueryPart { +public interface FieldOrConstraint extends Named { } diff --git a/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java b/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java index 50d9bc3c81..50c4a3c858 100644 --- a/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java +++ b/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java @@ -74,19 +74,19 @@ public interface InsertOnDuplicateStep extends InsertReturning /** * Add a ON CONFLICT ON CONSTRAINT clause to this query. */ - @Support({ POSTGRES_9_5 }) + @Support({ CUBRID, FIREBIRD_3_0, HSQLDB, POSTGRES_9_5 }) InsertOnConflictDoUpdateStep onConflictOnConstraint(Constraint constraint); /** * Add a ON CONFLICT ON CONSTRAINT clause to this query. */ - @Support({ POSTGRES_9_5 }) + @Support({ CUBRID, FIREBIRD_3_0, HSQLDB, POSTGRES_9_5 }) InsertOnConflictDoUpdateStep onConflictOnConstraint(Name constraint); /** * Add a ON CONFLICT ON CONSTRAINT clause to this query. */ - @Support({ POSTGRES_9_5 }) + @Support({ CUBRID, FIREBIRD_3_0, HSQLDB, POSTGRES_9_5 }) InsertOnConflictDoUpdateStep onConflictOnConstraint(UniqueKey constraint); /** diff --git a/jOOQ/src/main/java/org/jooq/InsertQuery.java b/jOOQ/src/main/java/org/jooq/InsertQuery.java index c50022f11c..365a7f5890 100644 --- a/jOOQ/src/main/java/org/jooq/InsertQuery.java +++ b/jOOQ/src/main/java/org/jooq/InsertQuery.java @@ -123,7 +123,7 @@ public interface InsertQuery extends StoreQuery, Insert * ON CONFLICT ON CONSTRAINT clause in this INSERT * statement. */ - @Support({ POSTGRES_9_5 }) + @Support({ CUBRID, FIREBIRD_3_0, HSQLDB, POSTGRES_9_5 }) void onConflictOnConstraint(Constraint constraint); /** @@ -131,7 +131,7 @@ public interface InsertQuery extends StoreQuery, Insert * ON CONFLICT ON CONSTRAINT clause in this INSERT * statement. */ - @Support({ POSTGRES_9_5 }) + @Support({ CUBRID, FIREBIRD_3_0, HSQLDB, POSTGRES_9_5 }) void onConflictOnConstraint(UniqueKey constraint); /** @@ -139,7 +139,7 @@ public interface InsertQuery extends StoreQuery, Insert * ON CONFLICT ON CONSTRAINT clause in this INSERT * statement. */ - @Support({ POSTGRES_9_5 }) + @Support({ CUBRID, FIREBIRD_3_0, HSQLDB, POSTGRES_9_5 }) void onConflictOnConstraint(Name constraint); /** diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractName.java b/jOOQ/src/main/java/org/jooq/impl/AbstractName.java index 9afca12bab..b8e41205b6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractName.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractName.java @@ -64,6 +64,7 @@ abstract class AbstractName extends AbstractQueryPart implements Name { * Generated UID */ private static final long serialVersionUID = 8562325639223483938L; + static final Name NO_NAME = DSL.name(""); @Override public final Name append(String name) { diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractNamed.java b/jOOQ/src/main/java/org/jooq/impl/AbstractNamed.java index 4a55efef04..0d3ee20c5e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractNamed.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractNamed.java @@ -53,7 +53,7 @@ abstract class AbstractNamed extends AbstractQueryPart implements Named { private final Comment comment; AbstractNamed(Name name, Comment comment) { - this.name = name; + this.name = name == null ? AbstractName.NO_NAME : name; this.comment = comment == null ? CommentImpl.NO_COMMENT : comment; } diff --git a/jOOQ/src/main/java/org/jooq/impl/ConstraintImpl.java b/jOOQ/src/main/java/org/jooq/impl/ConstraintImpl.java index ceb4dd4e5a..8c91818258 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ConstraintImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ConstraintImpl.java @@ -97,7 +97,7 @@ import org.jooq.exception.DataAccessException; * @author Lukas Eder */ @SuppressWarnings("rawtypes") -final class ConstraintImpl extends AbstractQueryPart +final class ConstraintImpl extends AbstractNamed implements ConstraintTypeStep , ConstraintForeignKeyOnStep @@ -137,7 +137,6 @@ implements private static final long serialVersionUID = 1018023703769802616L; private static final Clause[] CLAUSES = { CONSTRAINT }; - private final Name name; private Field[] unique; private Field[] primaryKey; private Field[] foreignKey; @@ -152,9 +151,13 @@ implements } ConstraintImpl(Name name) { - this.name = name; + super(name, null); } + // ------------------------------------------------------------------------ + // XXX: QueryPart API + // ------------------------------------------------------------------------ + @Override public final Clause[] clauses(Context ctx) { return CLAUSES; @@ -163,18 +166,18 @@ implements @Override public final void accept(Context ctx) { if (ctx.data(DATA_CONSTRAINT_REFERENCE) != null) { - if (name == null) + if (getQualifiedName() == AbstractName.NO_NAME) throw new DataAccessException("Cannot ALTER or DROP CONSTRAINT without name"); - ctx.visit(name); + ctx.visit(getQualifiedName()); } else { boolean qualify = ctx.qualify(); - if (name != null) + if (getQualifiedName() == AbstractName.NO_NAME) ctx.visit(K_CONSTRAINT) .sql(' ') - .visit(name) + .visit(getQualifiedName()) .formatIndentStart() .formatSeparator(); @@ -230,11 +233,15 @@ implements .sql(')'); } - if (name != null) + if (getQualifiedName() == AbstractName.NO_NAME) ctx.formatIndentEnd(); } } + // ------------------------------------------------------------------------ + // XXX: Constraint API + // ------------------------------------------------------------------------ + @Override public final ConstraintImpl unique(String... fields) { return unique(fieldsByName(fields)); diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java index e81f6264fa..c136672777 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java @@ -120,6 +120,7 @@ final class InsertQueryImpl extends AbstractStoreQuery impl private boolean onDuplicateKeyUpdate; private boolean onDuplicateKeyIgnore; private Constraint onConstraint; + private UniqueKey onConstraintUniqueKey; private QueryPartList> onConflict; private final ConditionProviderImpl condition; @@ -160,6 +161,15 @@ final class InsertQueryImpl extends AbstractStoreQuery impl @Override public final void onConflictOnConstraint(Constraint constraint) { this.onConstraint = constraint; + + if (onConstraintUniqueKey == null) { + for (UniqueKey key : table.getKeys()) { + if (constraint.getName().equals(key.getName())) { + onConstraintUniqueKey = key; + break; + } + } + } } @Override @@ -167,6 +177,7 @@ final class InsertQueryImpl extends AbstractStoreQuery impl if (StringUtils.isEmpty(constraint.getName())) throw new IllegalArgumentException("UniqueKey's name is not specified"); + this.onConstraintUniqueKey = constraint; onConflictOnConstraint(name(constraint.getName())); } @@ -632,8 +643,9 @@ final class InsertQueryImpl extends AbstractStoreQuery impl } private final Merge toMerge(Configuration configuration) { - if ((onConflict != null && onConflict.size() > 0) || - table.getPrimaryKey() != null) { + if ((onConflict != null && onConflict.size() > 0) + || onConstraint != null + || table.getPrimaryKey() != null) { // [#6375] INSERT .. VALUES and INSERT .. SELECT distinction also in MERGE Table t = select == null @@ -681,12 +693,19 @@ final class InsertQueryImpl extends AbstractStoreQuery impl private final Condition matchByConflictingKey(Map, Field> map) { Condition result = null; - // [#6462] The ON DUPLICATE KEY UPDATE clause is emulated using the primary key. - // To properly reflect MySQL behaviour, it should use all the known unique keys. // [#7365] The ON CONFLICT clause can be emulated using MERGE by joining // the MERGE's target and source tables on the conflict columns + // [#7409] The ON CONFLICT ON CONSTRAINT clause can be emulated using MERGE by + // joining the MERGE's target and source tables on the constraint columns + // [#6462] The ON DUPLICATE KEY UPDATE clause is emulated using the primary key. + // To properly reflect MySQL behaviour, it should use all the known unique keys. + if (onConstraint != null && onConstraintUniqueKey == null) + return DSL.condition("[ cannot create predicate from constraint with unknown columns ]"); + for (Field f : (onConflict != null && onConflict.size() > 0) ? onConflict + : onConstraintUniqueKey != null + ? onConstraintUniqueKey.getFields() : table.getPrimaryKey().getFields()) { Field field = (Field) f; Field value = (Field) map.get(field); @@ -706,12 +725,19 @@ final class InsertQueryImpl extends AbstractStoreQuery impl private final Condition matchByConflictingKey(Table s) { Condition result = null; + // [#7365] The ON CONFLICT (column list) clause can be emulated using MERGE by + // joining the MERGE's target and source tables on the conflict columns + // [#7409] The ON CONFLICT ON CONSTRAINT clause can be emulated using MERGE by + // joining the MERGE's target and source tables on the constraint columns // [#6462] The ON DUPLICATE KEY UPDATE clause is emulated using the primary key. // To properly reflect MySQL behaviour, it should use all the known unique keys. - // [#7365] The ON CONFLICT clause can be emulated using MERGE by joining - // the MERGE's target and source tables on the conflict columns + if (onConstraint != null && onConstraintUniqueKey == null) + return DSL.condition("[ cannot create predicate from constraint with unknown columns ]"); + for (Field f : (onConflict != null && onConflict.size() > 0) ? onConflict + : onConstraintUniqueKey != null + ? onConstraintUniqueKey.getFields() : table.getPrimaryKey().getFields()) { Field field = (Field) f; Field value = s.field(field);