From 82e27ce8708fcfd003037ca7103fc1e742214232 Mon Sep 17 00:00:00 2001 From: Timur Shaidullin Date: Thu, 14 Dec 2017 17:58:06 +0300 Subject: [PATCH] [#6906] Added support for PostgreSQL ON CONFLICT .. ON CONSTRAINT .. --- .../java/org/jooq/InsertOnDuplicateStep.java | 18 ++++ jOOQ/src/main/java/org/jooq/InsertQuery.java | 24 +++++ .../main/java/org/jooq/impl/InsertImpl.java | 26 +++++ .../java/org/jooq/impl/InsertQueryImpl.java | 102 +++++++++++++----- .../src/main/java/org/jooq/impl/Keywords.java | 1 + 5 files changed, 144 insertions(+), 27 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java b/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java index 510d82e5b2..8883db4849 100644 --- a/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java +++ b/jOOQ/src/main/java/org/jooq/InsertOnDuplicateStep.java @@ -69,6 +69,24 @@ import java.util.Collection; */ public interface InsertOnDuplicateStep extends InsertReturningStep { + /** + * Add a ON CONFLICT ON CONSTRAINT clause to this query. + */ + @Support({ POSTGRES_9_5 }) + InsertOnConflictDoUpdateStep onConflictOnConstraint(Constraint constraint); + + /** + * Add a ON CONFLICT ON CONSTRAINT clause to this query. + */ + @Support({ POSTGRES_9_5 }) + InsertOnConflictDoUpdateStep onConflictOnConstraint(Name constraint); + + /** + * Add a ON CONFLICT ON CONSTRAINT clause to this query. + */ + @Support({ POSTGRES_9_5 }) + InsertOnConflictDoUpdateStep onConflictOnConstraint(UniqueKey constraint); + /** * Add an ON CONFLICT clause to this insert query. */ diff --git a/jOOQ/src/main/java/org/jooq/InsertQuery.java b/jOOQ/src/main/java/org/jooq/InsertQuery.java index c74562f5e0..f9da2b20f4 100644 --- a/jOOQ/src/main/java/org/jooq/InsertQuery.java +++ b/jOOQ/src/main/java/org/jooq/InsertQuery.java @@ -117,6 +117,30 @@ public interface InsertQuery extends StoreQuery, Insert @Support({ POSTGRES_9_5 }) void onConflict(Collection> fields); + /** + * Whether use a On CONFLICT or + * ON CONFLICT ON CONSTRAINT clause in this INSERT + * statement. + */ + @Support({ POSTGRES_9_5 }) + void onConflictOnConstraint(Constraint constraint); + + /** + * Whether use a On CONFLICT or + * ON CONFLICT ON CONSTRAINT clause in this INSERT + * statement. + */ + @Support({ POSTGRES_9_5 }) + void onConflictOnConstraint(UniqueKey constraint); + + /** + * Whether use a On CONFLICT or + * ON CONFLICT ON CONSTRAINT clause in this INSERT + * statement. + */ + @Support({ POSTGRES_9_5 }) + void onConflictOnConstraint(Name constraint); + /** * Whether a ON DUPLICATE KEY UPDATE clause should be added to * this INSERT statement. diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java index 0a166aa6db..b770cf4d3a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertImpl.java @@ -38,7 +38,9 @@ package org.jooq.impl; import static org.jooq.impl.DSL.condition; +import static org.jooq.impl.DSL.constraint; import static org.jooq.impl.DSL.exists; +import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.not; import static org.jooq.impl.DSL.notExists; import static org.jooq.impl.Tools.EMPTY_FIELD; @@ -53,6 +55,7 @@ import javax.annotation.Generated; import org.jooq.Condition; import org.jooq.Configuration; +import org.jooq.Constraint; import org.jooq.Field; import org.jooq.FieldLike; import org.jooq.InsertOnConflictConditionStep; @@ -85,6 +88,7 @@ import org.jooq.InsertValuesStep7; import org.jooq.InsertValuesStep8; import org.jooq.InsertValuesStep9; import org.jooq.InsertValuesStepN; +import org.jooq.Name; import org.jooq.Operator; import org.jooq.QueryPart; import org.jooq.Record; @@ -93,6 +97,7 @@ import org.jooq.Result; import org.jooq.SQL; import org.jooq.Select; import org.jooq.Table; +import org.jooq.UniqueKey; /** * @author Lukas Eder @@ -604,6 +609,27 @@ class InsertImpl constraint) { + if (constraint.getName() == null) + throw new IllegalStateException("UniqueKey's name is not specified"); + + onConflictOnConstraint(name(constraint.getName())); + return this; + } + @Override public final InsertImpl onConflict(Field... keys) { return onConflict(Arrays.asList(keys)); diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java index d3baa4cdf1..d5544ac0dd 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java @@ -47,7 +47,9 @@ import static org.jooq.Clause.INSERT_SELECT; import static org.jooq.SQLDialect.MARIADB; import static org.jooq.SQLDialect.MYSQL; // ... +import static org.jooq.impl.DSL.constraint; import static org.jooq.impl.DSL.dual; +import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.select; import static org.jooq.impl.DSL.selectFrom; import static org.jooq.impl.DSL.selectOne; @@ -60,6 +62,7 @@ import static org.jooq.impl.Keywords.K_IGNORE; import static org.jooq.impl.Keywords.K_INSERT; import static org.jooq.impl.Keywords.K_INTO; import static org.jooq.impl.Keywords.K_ON_CONFLICT; +import static org.jooq.impl.Keywords.K_ON_CONSTRAINT; import static org.jooq.impl.Keywords.K_ON_DUPLICATE_KEY_UPDATE; import static org.jooq.impl.Keywords.K_OR; import static org.jooq.impl.Keywords.K_SET; @@ -69,6 +72,7 @@ import static org.jooq.impl.Tools.EMPTY_FIELD; import static org.jooq.impl.Tools.aliasedFields; import static org.jooq.impl.Tools.fieldNameStrings; import static org.jooq.impl.Tools.fieldNames; +import static org.jooq.impl.Tools.DataKey.DATA_CONSTRAINT_REFERENCE; import static org.jooq.impl.Tools.DataKey.DATA_INSERT_SELECT_WITHOUT_INSERT_COLUMN_LIST; import java.util.Arrays; @@ -79,6 +83,7 @@ import java.util.Map; import org.jooq.Clause; import org.jooq.Condition; import org.jooq.Configuration; +import org.jooq.Constraint; import org.jooq.Context; import org.jooq.Field; import org.jooq.Identity; @@ -93,6 +98,7 @@ import org.jooq.Record; import org.jooq.SQLDialect; import org.jooq.Select; import org.jooq.Table; +import org.jooq.UniqueKey; import org.jooq.exception.SQLDialectNotSupportedException; /** @@ -110,6 +116,7 @@ final class InsertQueryImpl extends AbstractStoreQuery impl private boolean defaultValues; private boolean onDuplicateKeyUpdate; private boolean onDuplicateKeyIgnore; + private Constraint onConstraint; private QueryPartList> onConflict; private final ConditionProviderImpl condition; @@ -147,6 +154,24 @@ final class InsertQueryImpl extends AbstractStoreQuery impl this.onConflict = new QueryPartList>(fields); } + @Override + public final void onConflictOnConstraint(Constraint constraint) { + this.onConstraint = constraint; + } + + @Override + public void onConflictOnConstraint(UniqueKey constraint) { + if (constraint.getName() == null) + throw new IllegalStateException("UniqueKey's name is not specified"); + + onConflictOnConstraint(name(constraint.getName())); + } + + @Override + public final void onConflictOnConstraint(Name constraint) { + onConflictOnConstraint(constraint(constraint)); + } + @Override public final void onDuplicateKeyUpdate(boolean flag) { this.onDuplicateKeyIgnore = false; @@ -248,30 +273,41 @@ final class InsertQueryImpl extends AbstractStoreQuery impl case POSTGRES: { toSQLInsert(ctx); ctx.formatSeparator() - .start(INSERT_ON_DUPLICATE_KEY_UPDATE) - .visit(K_ON_CONFLICT) - .sql(" ("); + .start(INSERT_ON_DUPLICATE_KEY_UPDATE); - if (onConflict != null && onConflict.size() > 0) { - boolean qualify = ctx.qualify(); + if (onConstraint != null) { + ctx.data(DATA_CONSTRAINT_REFERENCE, true); + ctx.visit(K_ON_CONSTRAINT) + .sql(' ') + .visit(onConstraint) + .sql(' '); - ctx.qualify(false) - .visit(onConflict) - .qualify(qualify); - } - else if (table.getPrimaryKey() == null) { - ctx.sql("[unknown primary key]"); + ctx.data().remove(DATA_CONSTRAINT_REFERENCE); } else { - boolean qualify = ctx.qualify(); + ctx.visit(K_ON_CONFLICT) + .sql(" ("); - ctx.qualify(false) - .visit(new Fields(table.getPrimaryKey().getFields())) - .qualify(qualify); + if (onConflict != null && onConflict.size() > 0) { + boolean qualify = ctx.qualify(); + + ctx.qualify(false) + .visit(onConflict) + .qualify(qualify); + } else if (table.getPrimaryKey() == null) { + ctx.sql("[unknown primary key]"); + } else { + boolean qualify = ctx.qualify(); + + ctx.qualify(false) + .visit(new Fields(table.getPrimaryKey().getFields())) + .qualify(qualify); + } + + ctx.sql(") "); } - ctx.sql(") ") - .visit(K_DO_UPDATE) + ctx.visit(K_DO_UPDATE) .formatSeparator() .visit(K_SET) .sql(' ') @@ -335,18 +371,30 @@ final class InsertQueryImpl extends AbstractStoreQuery impl case POSTGRES: { toSQLInsert(ctx); ctx.formatSeparator() - .start(INSERT_ON_DUPLICATE_KEY_UPDATE) - .visit(K_ON_CONFLICT) - .sql(' '); + .start(INSERT_ON_DUPLICATE_KEY_UPDATE); - if (onConflict != null && onConflict.size() > 0) { - boolean qualify = ctx.qualify(); + if (onConstraint != null) { + ctx.data(DATA_CONSTRAINT_REFERENCE, true); + ctx.visit(K_ON_CONSTRAINT) + .sql(' ') + .visit(onConstraint) + .sql(' '); - ctx.sql('(') - .qualify(false) - .visit(onConflict) - .qualify(qualify) - .sql(") "); + ctx.data().remove(DATA_CONSTRAINT_REFERENCE); + } + else { + ctx.visit(K_ON_CONFLICT) + .sql(' '); + + if (onConflict != null && onConflict.size() > 0) { + boolean qualify = ctx.qualify(); + + ctx.sql('(') + .qualify(false) + .visit(onConflict) + .qualify(qualify) + .sql(") "); + } } ctx.visit(K_DO_NOTHING) diff --git a/jOOQ/src/main/java/org/jooq/impl/Keywords.java b/jOOQ/src/main/java/org/jooq/impl/Keywords.java index 4c5eb393b6..e8174f9329 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Keywords.java +++ b/jOOQ/src/main/java/org/jooq/impl/Keywords.java @@ -187,6 +187,7 @@ final class Keywords { static final Keyword K_ON_COMMIT_DROP = keyword("on commit drop"); static final Keyword K_ON_COMMIT_PRESERVE_ROWS = keyword("on commit preserve rows"); static final Keyword K_ON_CONFLICT = keyword("on conflict"); + static final Keyword K_ON_CONSTRAINT = keyword("on constraint"); static final Keyword K_ON_DELETE = keyword("on delete"); static final Keyword K_ON_DUPLICATE_KEY_UPDATE = keyword("on duplicate key update"); static final Keyword K_ON_UPDATE = keyword("on update");