bool partition_constraint_failed;
bool update_indexes;
+ /*
+ * If we generate a new candidate tuple after EvalPlanQual testing, we
+ * must loop back here to try again. (We don't need to redo triggers,
+ * however. If there are any BEFORE triggers then trigger.c will have
+ * done table_tuple_lock to lock the correct tuple, so there's no need
+ * to do them again.)
+ */
+lreplace:
+
/*
* Constraints and GENERATED expressions might reference the tableoid
* column, so (re-)initialize tts_tableOid before evaluating them.
ExecComputeStoredGenerated(resultRelInfo, estate, slot,
CMD_UPDATE);
- /*
- * Check any RLS UPDATE WITH CHECK policies
- *
- * If we generate a new candidate tuple after EvalPlanQual testing, we
- * must loop back here and recheck any RLS policies and constraints.
- * (We don't need to redo triggers, however. If there are any BEFORE
- * triggers then trigger.c will have done table_tuple_lock to lock the
- * correct tuple, so there's no need to do them again.)
- */
-lreplace:;
-
/* ensure slot is independent, consider e.g. EPQ */
ExecMaterializeSlot(slot);
resultRelationDesc->rd_rel->relispartition &&
!ExecPartitionCheck(resultRelInfo, slot, estate, false);
+ /* Check any RLS UPDATE WITH CHECK policies */
if (!partition_constraint_failed &&
resultRelInfo->ri_WithCheckOptions != NIL)
{
/*
* For INSERT and UPDATE, prepare to evaluate any generated columns.
- * We must do this now, even if we never insert or update any rows,
- * because we have to fill resultRelInfo->ri_extraUpdatedCols for
- * possible use by the trigger machinery.
+ * (This is probably not necessary any longer, but we'll refrain from
+ * changing it in back branches, in case extension code expects it.)
*/
if (operation == CMD_INSERT || operation == CMD_UPDATE)
ExecInitStoredGenerated(resultRelInfo, estate, operation);
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 850
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 850| 1700
+savings | 600| 1200
(2 rows)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1100
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1100| 2200
+savings | 600| 1200
(2 rows)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1050
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1050| 2100
+savings | 600| 1200
(2 rows)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1600
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1600| 3200
+savings | 600| 1200
(2 rows)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+savings | 600| 1200
(1 row)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+savings | 600| 1200
(1 row)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1500
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1500| 3000
+savings | 600| 1200
(2 rows)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+savings | 600| 1200
(1 row)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1050
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1050| 2100
+savings | 600| 1200
(2 rows)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+savings | 600| 1200
(1 row)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+savings | 600| 1200
(1 row)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+savings | 600| 1200
(1 row)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+savings | 600| 1200
(1 row)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1050
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1050| 2100
+savings | 600| 1200
(2 rows)
step c1: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | -600
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | -600| -1200
+savings | 600| 1200
(2 rows)
step wnested2: <... completed>
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | -800
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | -800| -1600
+savings | 600| 1200
(2 rows)
step wnested2: <... completed>
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 200
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 200| 400
+savings | 600| 1200
(2 rows)
step wnested2: <... completed>
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 200
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 200| 400
+savings | 600| 1200
(2 rows)
step wnested2: <... completed>
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 400
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 400| 800
+savings | 600| 1200
(2 rows)
step wnested2: <... completed>
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-cds | 400
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+cds | 400| 800
+savings | 600| 1200
(2 rows)
step wnested2: <... completed>
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 400
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 400| 800
+savings | 600| 1200
(2 rows)
step updwcte: WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) UPDATE accounts a SET balance = doup.balance + 100 FROM doup RETURNING *;
step c1: COMMIT;
step updwcte: <... completed>
-accountid|balance|accountid|balance
----------+-------+---------+-------
-savings | 1600|checking | 1500
+accountid|balance|balance2|accountid|balance|balance2
+---------+-------+--------+---------+-------+--------
+savings | 1600| 3200|checking | 1500| 3000
(1 row)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1500
-savings | 1600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1500| 3000
+savings | 1600| 3200
(2 rows)
ERROR: tuple to be updated was already modified by an operation triggered by the current command
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 400
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 400| 800
+savings | 600| 1200
(2 rows)
step delwcte: WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) DELETE FROM accounts a USING doup RETURNING *;
step c1: COMMIT;
step delwcte: <... completed>
-accountid|balance|accountid|balance
----------+-------+---------+-------
-savings | 600|checking | 1500
+accountid|balance|balance2|accountid|balance|balance2
+---------+-------+--------+---------+-------+--------
+savings | 600| 1200|checking | 1500| 3000
(1 row)
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1500
+accountid|balance|balance2
+---------+-------+--------
+checking | 1500| 3000
(1 row)
ERROR: tuple to be deleted was already modified by an operation triggered by the current command
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 400
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 400| 800
+savings | 600| 1200
(2 rows)
step upsert2: <... completed>
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 600
-savings | 2334
+accountid|balance|balance2
+---------+-------+--------
+checking | 600| 1200
+savings | 2334| 4668
(2 rows)
step c2: COMMIT;
step partiallock: <... completed>
-accountid|balance|accountid|balance
----------+-------+---------+-------
-checking | 1050|checking | 600
-savings | 600|savings | 600
+accountid|balance|balance2|accountid|balance|balance2
+---------+-------+--------+---------+-------+--------
+checking | 1050| 2100|checking | 600| 1200
+savings | 600| 1200|savings | 600| 1200
(2 rows)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1050
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1050| 2100
+savings | 600| 1200
(2 rows)
step c2: COMMIT;
step lockwithvalues: <... completed>
-accountid|balance|id
----------+-------+--------
-checking | 1050|checking
-savings | 600|savings
+accountid|balance|balance2|id
+---------+-------+--------+--------
+checking | 1050| 2100|checking
+savings | 600| 1200|savings
(2 rows)
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
-accountid|balance
----------+-------
-checking | 1050
-savings | 600
+accountid|balance|balance2
+---------+-------+--------
+checking | 1050| 2100
+savings | 600| 1200
(2 rows)
(1 row)
-starting permutation: simplepartupdate complexpartupdate c1 c2
+starting permutation: simplepartupdate complexpartupdate c1 c2 read_part
step simplepartupdate:
- update parttbl set a = a;
+ update parttbl set b = b + 10;
step complexpartupdate:
- with u as (update parttbl set a = a returning parttbl.*)
- update parttbl set a = u.a from u;
+ with u as (update parttbl set b = b + 1 returning parttbl.*)
+ update parttbl set b = u.b + 100 from u;
step c1: COMMIT;
step complexpartupdate: <... completed>
step c2: COMMIT;
+step read_part: SELECT * FROM parttbl ORDER BY a;
+a| b|c| d
+-+--+-+--
+1|12|1|13
+(1 row)
+
-starting permutation: simplepartupdate_route1to2 complexpartupdate_route_err1 c1 c2
+starting permutation: simplepartupdate_route1to2 complexpartupdate_route_err1 c1 c2 read_part
step simplepartupdate_route1to2:
update parttbl set a = 2 where c = 1 returning *;
-a|b|c
--+-+-
-2|1|1
+a|b|c|d
+-+-+-+-
+2|1|1|3
(1 row)
step complexpartupdate_route_err1:
step complexpartupdate_route_err1: <... completed>
ERROR: tuple to be locked was already moved to another partition due to concurrent update
step c2: COMMIT;
+step read_part: SELECT * FROM parttbl ORDER BY a;
+a|b|c|d
+-+-+-+-
+2|1|1|3
+(1 row)
+
-starting permutation: simplepartupdate_noroute complexpartupdate_route c1 c2
+starting permutation: simplepartupdate_noroute complexpartupdate_route c1 c2 read_part
step simplepartupdate_noroute:
update parttbl set b = 2 where c = 1 returning *;
-a|b|c
--+-+-
-1|2|1
+a|b|c|d
+-+-+-+-
+1|2|1|3
(1 row)
step complexpartupdate_route:
step c1: COMMIT;
step complexpartupdate_route: <... completed>
-a|b|c
--+-+-
-2|2|1
+a|b|c|d
+-+-+-+-
+2|2|1|4
(1 row)
step c2: COMMIT;
+step read_part: SELECT * FROM parttbl ORDER BY a;
+a|b|c|d
+-+-+-+-
+2|2|1|4
+(1 row)
+
-starting permutation: simplepartupdate_noroute complexpartupdate_doesnt_route c1 c2
+starting permutation: simplepartupdate_noroute complexpartupdate_doesnt_route c1 c2 read_part
step simplepartupdate_noroute:
update parttbl set b = 2 where c = 1 returning *;
-a|b|c
--+-+-
-1|2|1
+a|b|c|d
+-+-+-+-
+1|2|1|3
(1 row)
step complexpartupdate_doesnt_route:
step c1: COMMIT;
step complexpartupdate_doesnt_route: <... completed>
-a|b|c
--+-+-
-1|2|1
+a|b|c|d
+-+-+-+-
+1|2|1|3
(1 row)
step c2: COMMIT;
+step read_part: SELECT * FROM parttbl ORDER BY a;
+a|b|c|d
+-+-+-+-
+1|2|1|3
+(1 row)
+
setup
{
- CREATE TABLE accounts (accountid text PRIMARY KEY, balance numeric not null);
+ CREATE TABLE accounts (accountid text PRIMARY KEY, balance numeric not null,
+ balance2 numeric GENERATED ALWAYS AS (balance * 2) STORED);
INSERT INTO accounts VALUES ('checking', 600), ('savings', 600);
CREATE FUNCTION update_checking(int) RETURNS bool LANGUAGE sql AS $$
CREATE TABLE jointest AS SELECT generate_series(1,10) AS id, 0 AS data;
CREATE INDEX ON jointest(id);
- CREATE TABLE parttbl (a int, b int, c int) PARTITION BY LIST (a);
+ CREATE TABLE parttbl (a int, b int, c int,
+ d int GENERATED ALWAYS AS (a + b) STORED) PARTITION BY LIST (a);
CREATE TABLE parttbl1 PARTITION OF parttbl FOR VALUES IN (1);
CREATE TABLE parttbl2 PARTITION OF parttbl FOR VALUES IN (2);
INSERT INTO parttbl VALUES (1, 1, 1);
# test for EPQ on a partitioned result table
step simplepartupdate {
- update parttbl set a = a;
+ update parttbl set b = b + 10;
}
# test scenarios where update may cause row movement
step wrtwcte { UPDATE table_a SET value = 'tableAValue2' WHERE id = 1; }
step wrjt { UPDATE jointest SET data = 42 WHERE id = 7; }
step complexpartupdate {
- with u as (update parttbl set a = a returning parttbl.*)
- update parttbl set a = u.a from u;
+ with u as (update parttbl set b = b + 1 returning parttbl.*)
+ update parttbl set b = u.b + 100 from u;
}
step complexpartupdate_route_err1 {
step read { SELECT * FROM accounts ORDER BY accountid; }
step read_ext { SELECT * FROM accounts_ext ORDER BY accountid; }
step read_a { SELECT * FROM table_a ORDER BY id; }
+step read_part { SELECT * FROM parttbl ORDER BY a; }
# this test exercises EvalPlanQual with a CTE, cf bug #14328
step readwcte {
permutation wrjt selectresultforupdate c2 c1
permutation wrtwcte multireadwcte c1 c2
-permutation simplepartupdate complexpartupdate c1 c2
-permutation simplepartupdate_route1to2 complexpartupdate_route_err1 c1 c2
-permutation simplepartupdate_noroute complexpartupdate_route c1 c2
-permutation simplepartupdate_noroute complexpartupdate_doesnt_route c1 c2
+permutation simplepartupdate complexpartupdate c1 c2 read_part
+permutation simplepartupdate_route1to2 complexpartupdate_route_err1 c1 c2 read_part
+permutation simplepartupdate_noroute complexpartupdate_route c1 c2 read_part
+permutation simplepartupdate_noroute complexpartupdate_doesnt_route c1 c2 read_part