diff options
author | Robert Haas <rhaas@postgresql.org> | 2018-01-19 15:33:06 -0500 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2018-01-19 15:33:06 -0500 |
commit | 2f178441044be430f6b4d626e4dae68a9a6f6cec (patch) | |
tree | 131e7547b169b2bc42f638f1ca1b50ae6e146b70 /doc/src | |
parent | 7f17fd6fc7125b41218bc99ccfa8165e2d730cd9 (diff) |
Allow UPDATE to move rows between partitions.
When an UPDATE causes a row to no longer match the partition
constraint, try to move it to a different partition where it does
match the partition constraint. In essence, the UPDATE is split into
a DELETE from the old partition and an INSERT into the new one. This
can lead to surprising behavior in concurrency scenarios because
EvalPlanQual rechecks won't work as they normally did; the known
problems are documented. (There is a pending patch to improve the
situation further, but it needs more review.)
Amit Khandekar, reviewed and tested by Amit Langote, David Rowley,
Rajkumar Raghuwanshi, Dilip Kumar, Amul Sul, Thomas Munro, Álvaro
Herrera, Amit Kapila, and me. A few final revisions by me.
Discussion: http://postgr.es/m/CAJ3gD9do9o2ccQ7j7+tSgiE1REY65XRiMb=yJO3u3QhyP8EEPQ@mail.gmail.com
Diffstat (limited to 'doc/src')
-rw-r--r-- | doc/src/sgml/ddl.sgml | 24 | ||||
-rw-r--r-- | doc/src/sgml/ref/update.sgml | 13 | ||||
-rw-r--r-- | doc/src/sgml/trigger.sgml | 23 |
3 files changed, 53 insertions, 7 deletions
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index b1167a40e6a..3244399782f 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -3005,6 +3005,11 @@ VALUES ('Albany', NULL, NULL, 'NY'); foreign table partitions. </para> + <para> + Updating the partition key of a row might cause it to be moved into a + different partition where this row satisfies its partition constraint. + </para> + <sect3 id="ddl-partitioning-declarative-example"> <title>Example</title> @@ -3302,9 +3307,22 @@ ALTER TABLE measurement ATTACH PARTITION measurement_y2008m02 <listitem> <para> - An <command>UPDATE</command> that causes a row to move from one partition to - another fails, because the new value of the row fails to satisfy the - implicit partition constraint of the original partition. + When an <command>UPDATE</command> causes a row to move from one + partition to another, there is a chance that another concurrent + <command>UPDATE</command> or <command>DELETE</command> misses this row. + Suppose session 1 is performing an <command>UPDATE</command> on a + partition key, and meanwhile a concurrent session 2 for which this row + is visible performs an <command>UPDATE</command> or + <command>DELETE</command> operation on this row. Session 2 can silently + miss the row if the row is deleted from the partition due to session + 1's activity. In such case, session 2's + <command>UPDATE</command> or <command>DELETE</command>, being unaware of + the row movement thinks that the row has just been deleted and concludes + that there is nothing to be done for this row. In the usual case where + the table is not partitioned, or where there is no row movement, + session 2 would have identified the newly updated row and carried out + the <command>UPDATE</command>/<command>DELETE</command> on this new row + version. </para> </listitem> diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml index c0d0f7134d3..c8ac8a335b8 100644 --- a/doc/src/sgml/ref/update.sgml +++ b/doc/src/sgml/ref/update.sgml @@ -282,10 +282,15 @@ UPDATE <replaceable class="parameter">count</replaceable> <para> In the case of a partitioned table, updating a row might cause it to no - longer satisfy the partition constraint. Since there is no provision to - move the row to the partition appropriate to the new value of its - partitioning key, an error will occur in this case. This can also happen - when updating a partition directly. + longer satisfy the partition constraint of the containing partition. In that + case, if there is some other partition in the partition tree for which this + row satisfies its partition constraint, then the row is moved to that + partition. If there is no such partition, an error will occur. Behind the + scenes, the row movement is actually a <command>DELETE</command> and + <command>INSERT</command> operation. However, there is a possibility that a + concurrent <command>UPDATE</command> or <command>DELETE</command> on the + same row may miss this row. For details see the section + <xref linkend="ddl-partitioning-declarative-limitations"/>. </para> </refsect1> diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml index bf5d3f90888..8f83e6a47c8 100644 --- a/doc/src/sgml/trigger.sgml +++ b/doc/src/sgml/trigger.sgml @@ -154,6 +154,29 @@ </para> <para> + If an <command>UPDATE</command> on a partitioned table causes a row to move + to another partition, it will be performed as a <command>DELETE</command> + from the original partition followed by an <command>INSERT</command> into + the new partition. In this case, all row-level <literal>BEFORE</literal> + <command>UPDATE</command> triggers and all row-level + <literal>BEFORE</literal> <command>DELETE</command> triggers are fired on + the original partition. Then all row-level <literal>BEFORE</literal> + <command>INSERT</command> triggers are fired on the destination partition. + The possibility of surprising outcomes should be considered when all these + triggers affect the row being moved. As far as <literal>AFTER ROW</literal> + triggers are concerned, <literal>AFTER</literal> <command>DELETE</command> + and <literal>AFTER</literal> <command>INSERT</command> triggers are + applied; but <literal>AFTER</literal> <command>UPDATE</command> triggers + are not applied because the <command>UPDATE</command> has been converted to + a <command>DELETE</command> and an <command>INSERT</command>. As far as + statement-level triggers are concerned, none of the + <command>DELETE</command> or <command>INSERT</command> triggers are fired, + even if row movement occurs; only the <command>UPDATE</command> triggers + defined on the target table used in the <command>UPDATE</command> statement + will be fired. + </para> + + <para> Trigger functions invoked by per-statement triggers should always return <symbol>NULL</symbol>. Trigger functions invoked by per-row triggers can return a table row (a value of |