Allow ON CONFLICT .. DO NOTHING on a partitioned table.
authorRobert Haas <rhaas@postgresql.org>
Mon, 27 Mar 2017 14:37:29 +0000 (10:37 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 27 Mar 2017 14:37:41 +0000 (10:37 -0400)
ON CONFLICT .. DO UPDATE still doesn't work, for lack of a way of
enforcing uniqueness across partitions, but we can still allow this
case.

Amit Langote, per discussion with Peter Geoghegan.  Additional
wordsmithing by me.

Discussion: http://postgr.es/m/CAA-aLv7Z4uygtq-Q5CvDi9Y=VZxUyEnuWjL=EwCfOof=L04hgg@mail.gmail.com

doc/src/sgml/ddl.sgml
src/backend/parser/analyze.c
src/test/regress/expected/insert_conflict.out
src/test/regress/sql/insert_conflict.sql

index 09b5b3ff70d9ca800e33519d27c284296826b759..d1e915c11aa9ea92daeca57f232734d4e285622c 100644 (file)
@@ -3854,8 +3854,12 @@ ANALYZE measurement;
 
     <listitem>
      <para>
-      <command>INSERT</command> statements with <literal>ON CONFLICT</>
-      clause are currently not allowed on partitioned tables.
+      Using the <literal>ON CONFLICT</literal> clause with partitioned tables
+      will cause an error if <literal>DO UPDATE</literal> is specified as the
+      alternative action, 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.
      </para>
     </listitem>
 
index 3571e50aea4372875d366930440f872841295340..25699fbc4aab04c2fce07cc50356b865a4ad55cd 100644 (file)
@@ -842,16 +842,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 
        /* 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
index 8d005fddd46c4c56840a59ade08d3f71c00c8983..c90d381b34f92a452448d33aa291931b6fc9675d 100644 (file)
@@ -786,3 +786,13 @@ select * from selfconflict;
 (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 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 not supported yet
+insert into parted_conflict_test values (1) on conflict (a) do update set b = excluded.b where excluded.a = 1;
+ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
+drop table parted_conflict_test, parted_conflict_test_1;
index df3a9b59b5b0882549c1d9aa70b6330fee2f7064..78bffc783dcc71aa6e37037f6812d3662f1f64f5 100644 (file)
@@ -471,3 +471,13 @@ commit;
 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 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 not supported yet
+insert into parted_conflict_test values (1) on conflict (a) do update set b = excluded.b where excluded.a = 1;
+drop table parted_conflict_test, parted_conflict_test_1;