If UPDATE is forced to retry after an EvalPlanQual check, it neglected
to repeat GENERATED-column computations, even though those might well
have changed since we're dealing with a different tuple than before.
Fixing this is mostly a matter of looping back a bit further when
we retry. In v15 and HEAD that's most easily done by altering the API
of ExecUpdateAct so that it includes computing GENERATED expressions.
Also, if an UPDATE in a partitioned table turns into a cross-partition
INSERT operation, we failed to recompute GENERATED columns. That's a
bug since 8bf6ec3ba allowed partitions to have different generation
expressions; although it seems to have no ill effects before that.
Fixing this is messier because we can now have situations where the same
query needs both the UPDATE-aligned set of GENERATED columns and the
INSERT-aligned set, and it's unclear which set will be generated first
(else we could hack things by forcing the INSERT-aligned set to be
generated, which is indeed how fe9e658f4 made it work for MERGE).
The best fix seems to be to build and store separate sets of expressions
for the INSERT and UPDATE cases. That would create ABI issues in the
back branches, but so far it seems we can leave this alone in the back
branches.
Per bug #17823 from Hisahiro Kauchi. The first part of this affects all
branches back to v12 where GENERATED columns were added.
Discussion: https://postgr.es/m/17823-b64909cf7d63de84@postgresql.org
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 850
checking | 850| 1700
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -40,10 +40,10 @@ balance
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 1100
checking | 1100| 2200
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -64,10 +64,10 @@ balance
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 1050
checking | 1050| 2100
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -88,10 +88,10 @@ balance
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 1600
checking | 1600| 3200
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -117,9 +117,9 @@ balance
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
savings | 600
savings | 600| 1200
(1 row)
(1 row)
@ -140,9 +140,9 @@ balance
step c1: COMMIT;
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
savings | 600
savings | 600| 1200
(1 row)
(1 row)
@ -168,10 +168,10 @@ balance
step c1: COMMIT;
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 1500
checking | 1500| 3000
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -192,9 +192,9 @@ balance
step c1: COMMIT;
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
savings | 600
savings | 600| 1200
(1 row)
(1 row)
@ -221,10 +221,10 @@ balance
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 1050
checking | 1050| 2100
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -245,9 +245,9 @@ balance
step c1: COMMIT;
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
savings | 600
savings | 600| 1200
(1 row)
(1 row)
@ -274,9 +274,9 @@ balance
step c1: COMMIT;
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
savings | 600
savings | 600| 1200
(1 row)
(1 row)
@ -298,9 +298,9 @@ balance
step c1: COMMIT;
step c1: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
savings | 600
savings | 600| 1200
(1 row)
(1 row)
@ -320,9 +320,9 @@ balance
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
savings | 600
savings | 600| 1200
(1 row)
(1 row)
@ -343,10 +343,10 @@ balance
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 1050
checking | 1050| 2100
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -371,10 +371,10 @@ step wnested2:
step c1: COMMIT;
step c1: COMMIT;
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | -600
checking | -600| -1200
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -420,10 +420,10 @@ s2: NOTICE: upid: text savings = text checking: f
step wnested2: <... completed>
step wnested2: <... completed>
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | -800
checking | -800| -1600
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -471,10 +471,10 @@ s2: NOTICE: upid: text savings = text checking: f
step wnested2: <... completed>
step wnested2: <... completed>
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 200
checking | 200| 400
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -527,10 +527,10 @@ s2: NOTICE: upid: text savings = text checking: f
step wnested2: <... completed>
step wnested2: <... completed>
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 200
checking | 200| 400
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -577,10 +577,10 @@ s2: NOTICE: upid: text savings = text checking: f
step wnested2: <... completed>
step wnested2: <... completed>
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 400
checking | 400| 800
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -614,10 +614,10 @@ s2: NOTICE: upid: text savings = text checking: f
step wnested2: <... completed>
step wnested2: <... completed>
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
cds | 400
cds | 400| 800
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -652,10 +652,10 @@ s2: NOTICE: upid: text savings = text checking: f
step wnested2: <... completed>
step wnested2: <... completed>
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 400
checking | 400| 800
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -669,17 +669,17 @@ balance
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 *; <waiting ...>
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 *; <waiting ...>
ERROR: tuple to be updated was already modified by an operation triggered by the current command
ERROR: tuple to be updated was already modified by an operation triggered by the current command
step c2: COMMIT;
step c2: COMMIT;
step read: SELECT * FROM accounts ORDER BY accountid;
step read: SELECT * FROM accounts ORDER BY accountid;
accountid|balance
accountid|balance|balance2
---------+-------
---------+-------+--------
checking | 400
checking | 400| 800
savings | 600
savings | 600| 1200
(2 rows)
(2 rows)
@ -713,16 +713,16 @@ balance
step delwcte: WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) DELETE FROM accounts a USING doup RETURNING *; <waiting ...>
step delwcte: WITH doup AS (UPDATE accounts SET balance = balance + 1100 WHERE accountid = 'checking' RETURNING *) DELETE FROM accounts a USING doup RETURNING *; <waiting ...>