<listitem>
<para>
Using the <literal>ON CONFLICT</literal> clause with partitioned tables
- will cause an error, because unique or exclusion constraints can only be
- created on individual partitions. There is no support for enforcing
- uniqueness (or an exclusion constraint) across an entire partitioning
- hierarchy.
+ will cause an error if the conflict target is specified (see
+ <xref linkend="sql-on-conflict" /> for more details on how the clause
+ works). Therefore, it is not possible to specify
+ <literal>DO UPDATE</literal> as the alternative action, because
+ specifying the conflict target is mandatory in that case. On the other
+ hand, specifying <literal>DO NOTHING</literal> as the alternative action
+ works fine provided the conflict target is not specified. In that case,
+ unique constraints (or exclusion constraints) of the individual leaf
+ partitions are considered.
</para>
</listitem>
int num_parted,
num_partitions;
- ExecSetupPartitionTupleRouting(cstate->rel,
+ ExecSetupPartitionTupleRouting(NULL,
+ cstate->rel,
1,
estate,
&partition_dispatch_info,
* RowExclusiveLock mode upon return from this function.
*/
void
-ExecSetupPartitionTupleRouting(Relation rel,
+ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
+ Relation rel,
Index resultRTindex,
EState *estate,
PartitionDispatch **pd,
CheckValidResultRel(leaf_part_rri, CMD_INSERT);
/*
- * Open partition indices (remember we do not support ON CONFLICT in
- * case of partitioned tables, so we do not need support information
- * for speculative insertion)
+ * Open partition indices. The user may have asked to check for
+ * conflicts within this leaf partition and do "nothing" instead of
+ * throwing an error. Be prepared in that case by initializing the
+ * index information needed by ExecInsert() to perform speculative
+ * insertions.
*/
if (leaf_part_rri->ri_RelationDesc->rd_rel->relhasindex &&
leaf_part_rri->ri_IndexRelationDescs == NULL)
- ExecOpenIndices(leaf_part_rri, false);
+ ExecOpenIndices(leaf_part_rri,
+ mtstate != NULL &&
+ mtstate->mt_onconflict != ONCONFLICT_NONE);
estate->es_leaf_result_relations =
lappend(estate->es_leaf_result_relations, leaf_part_rri);
int num_parted,
num_partitions;
- ExecSetupPartitionTupleRouting(rel,
+ ExecSetupPartitionTupleRouting(mtstate,
+ rel,
node->nominalRelation,
estate,
&partition_dispatch_info,
/* Process ON CONFLICT, if any. */
if (stmt->onConflictClause)
- {
- /* Bail out if target relation is partitioned table */
- if (pstate->p_target_rangetblentry->relkind == RELKIND_PARTITIONED_TABLE)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("ON CONFLICT clause is not supported with partitioned tables")));
-
qry->onConflict = transformOnConflictClause(pstate,
stmt->onConflictClause);
- }
/*
* If we have a RETURNING clause, we need to add the target relation to
typedef struct PartitionDispatchData *PartitionDispatch;
-extern void ExecSetupPartitionTupleRouting(Relation rel,
+extern void ExecSetupPartitionTupleRouting(ModifyTableState *mtstate,
+ Relation rel,
Index resultRTindex,
EState *estate,
PartitionDispatch **pd,
(3 rows)
drop table selfconflict;
+-- check that the following works:
+-- insert into partitioned_table on conflict do nothing
+create table parted_conflict_test (a int, b char) partition by list (a);
+create table parted_conflict_test_1 partition of parted_conflict_test (b unique) for values in (1);
+insert into parted_conflict_test values (1, 'a') on conflict do nothing;
+insert into parted_conflict_test values (1, 'a') on conflict do nothing;
+-- however, on conflict do update is not supported yet
+insert into parted_conflict_test values (1) on conflict (b) do update set a = excluded.a;
+ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
+-- but it works OK if we target the partition directly
+insert into parted_conflict_test_1 values (1) on conflict (b) do
+update set a = excluded.a;
+drop table parted_conflict_test;
select * from selfconflict;
drop table selfconflict;
+
+-- check that the following works:
+-- insert into partitioned_table on conflict do nothing
+create table parted_conflict_test (a int, b char) partition by list (a);
+create table parted_conflict_test_1 partition of parted_conflict_test (b unique) for values in (1);
+insert into parted_conflict_test values (1, 'a') on conflict do nothing;
+insert into parted_conflict_test values (1, 'a') on conflict do nothing;
+-- however, on conflict do update is not supported yet
+insert into parted_conflict_test values (1) on conflict (b) do update set a = excluded.a;
+-- but it works OK if we target the partition directly
+insert into parted_conflict_test_1 values (1) on conflict (b) do
+update set a = excluded.a;
+drop table parted_conflict_test;