aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeModifyTable.c11
-rw-r--r--src/test/regress/expected/triggers.out8
-rw-r--r--src/test/regress/expected/with.out10
-rw-r--r--src/test/regress/sql/triggers.sql2
-rw-r--r--src/test/regress/sql/with.sql5
5 files changed, 25 insertions, 11 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index dabaea99109..9db4c917435 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1181,8 +1181,17 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
/* Project the new tuple version */
ExecProject(resultRelInfo->ri_onConflictSetProj, NULL);
+ /*
+ * Note that it is possible that the target tuple has been modified in
+ * this session, after the above heap_lock_tuple. We choose to not error
+ * out in that case, in line with ExecUpdate's treatment of similar
+ * cases. This can happen if an UPDATE is triggered from within
+ * ExecQual(), ExecWithCheckOptions() or ExecProject() above, e.g. by
+ * selecting from a wCTE in the ON CONFLICT's SET.
+ */
+
/* Execute UPDATE with projection */
- *returning = ExecUpdate(&tuple.t_data->t_ctid, NULL,
+ *returning = ExecUpdate(&tuple.t_self, NULL,
mtstate->mt_conflproj, planSlot,
&mtstate->mt_epqstate, mtstate->ps.state,
canSetTag);
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index dd4a99bff1b..a7bf5dc159d 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -1703,7 +1703,7 @@ create function upsert_after_func()
$$
begin
if (TG_OP = 'UPDATE') then
- raise warning 'after update (old): %', new.*::text;
+ raise warning 'after update (old): %', old.*::text;
raise warning 'after update (new): %', new.*::text;
elsif (TG_OP = 'INSERT') then
raise warning 'after insert (new): %', new.*::text;
@@ -1724,7 +1724,7 @@ insert into upsert values(3, 'orange') on conflict (key) do update set color = '
WARNING: before insert (new): (3,orange)
WARNING: before update (old): (3,"red trig modified")
WARNING: before update (new): (3,"updated red trig modified")
-WARNING: after update (old): (3,"updated red trig modified")
+WARNING: after update (old): (3,"red trig modified")
WARNING: after update (new): (3,"updated red trig modified")
insert into upsert values(4, 'green') on conflict (key) do update set color = 'updated ' || upsert.color;
WARNING: before insert (new): (4,green)
@@ -1734,7 +1734,7 @@ insert into upsert values(5, 'purple') on conflict (key) do update set color = '
WARNING: before insert (new): (5,purple)
WARNING: before update (old): (5,"green trig modified")
WARNING: before update (new): (5,"updated green trig modified")
-WARNING: after update (old): (5,"updated green trig modified")
+WARNING: after update (old): (5,"green trig modified")
WARNING: after update (new): (5,"updated green trig modified")
insert into upsert values(6, 'white') on conflict (key) do update set color = 'updated ' || upsert.color;
WARNING: before insert (new): (6,white)
@@ -1744,7 +1744,7 @@ insert into upsert values(7, 'pink') on conflict (key) do update set color = 'up
WARNING: before insert (new): (7,pink)
WARNING: before update (old): (7,"white trig modified")
WARNING: before update (new): (7,"updated white trig modified")
-WARNING: after update (old): (7,"updated white trig modified")
+WARNING: after update (old): (7,"white trig modified")
WARNING: after update (new): (7,"updated white trig modified")
insert into upsert values(8, 'yellow') on conflict (key) do update set color = 'updated ' || upsert.color;
WARNING: before insert (new): (8,yellow)
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index 2c9226c3db5..137420d9b7e 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -1875,8 +1875,9 @@ ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 'a' L
WITH aa AS (SELECT 1 a, 2 b)
INSERT INTO z VALUES(1, (SELECT b || ' insert' FROM aa WHERE a = 1 ))
ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
--- This shows an attempt to update an invisible row, which should really be
--- reported as a cardinality violation, but it doesn't seem worth fixing:
+-- Update a row more than once, in different parts of a wCTE. That is
+-- an allowed, presumably very rare, edge case, but since it was
+-- broken in the past, having a test seems worthwhile.
WITH simpletup AS (
SELECT 2 k, 'Green' v),
upsert_cte AS (
@@ -1886,7 +1887,10 @@ upsert_cte AS (
INSERT INTO z VALUES(2, 'Red') ON CONFLICT (k) DO
UPDATE SET (k, v) = (SELECT k, v FROM upsert_cte WHERE upsert_cte.k = z.k)
RETURNING k, v;
-ERROR: attempted to update invisible tuple
+ k | v
+---+---
+(0 rows)
+
DROP TABLE z;
-- check that run to completion happens in proper ordering
TRUNCATE TABLE y;
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 9f66702ceef..b6de1b32560 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -1215,7 +1215,7 @@ create function upsert_after_func()
$$
begin
if (TG_OP = 'UPDATE') then
- raise warning 'after update (old): %', new.*::text;
+ raise warning 'after update (old): %', old.*::text;
raise warning 'after update (new): %', new.*::text;
elsif (TG_OP = 'INSERT') then
raise warning 'after insert (new): %', new.*::text;
diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql
index 3fd55f96b3f..133ff0b1957 100644
--- a/src/test/regress/sql/with.sql
+++ b/src/test/regress/sql/with.sql
@@ -838,8 +838,9 @@ WITH aa AS (SELECT 1 a, 2 b)
INSERT INTO z VALUES(1, (SELECT b || ' insert' FROM aa WHERE a = 1 ))
ON CONFLICT (k) DO UPDATE SET v = (SELECT b || ' update' FROM aa WHERE a = 1 LIMIT 1);
--- This shows an attempt to update an invisible row, which should really be
--- reported as a cardinality violation, but it doesn't seem worth fixing:
+-- Update a row more than once, in different parts of a wCTE. That is
+-- an allowed, presumably very rare, edge case, but since it was
+-- broken in the past, having a test seems worthwhile.
WITH simpletup AS (
SELECT 2 k, 'Green' v),
upsert_cte AS (