diff --git a/src/postgres/src/backend/executor/execIndexing.c b/src/postgres/src/backend/executor/execIndexing.c index 3d7974416904..87c5e0fa1cdf 100644 --- a/src/postgres/src/backend/executor/execIndexing.c +++ b/src/postgres/src/backend/executor/execIndexing.c @@ -1019,7 +1019,7 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index, if (violationOK) { conflict = true; - if (IsYugaByteEnabled()) { + if (IsYBRelation(heap)) { estate->yb_conflict_slot = existing_slot; } if (conflictTid) diff --git a/src/postgres/src/backend/executor/nodeModifyTable.c b/src/postgres/src/backend/executor/nodeModifyTable.c index 5bc6f91f1a8e..031d870bd1e9 100644 --- a/src/postgres/src/backend/executor/nodeModifyTable.c +++ b/src/postgres/src/backend/executor/nodeModifyTable.c @@ -2988,8 +2988,8 @@ ExecOnConflictUpdate(ModifyTableContext *context, ExprContext *econtext = mtstate->ps.ps_ExprContext; Relation relation = resultRelInfo->ri_RelationDesc; ExprState *onConflictSetWhere = resultRelInfo->ri_onConflict->oc_WhereClause; - HeapTuple oldtuple = NULL; - bool shouldFree = true; + HeapTuple ybOldTuple = NULL; + bool ybShouldFree = false; TupleTableSlot *existing = resultRelInfo->ri_onConflict->oc_Existing; TM_FailureData tmfd; LockTupleMode lockmode; @@ -3011,7 +3011,7 @@ ExecOnConflictUpdate(ModifyTableContext *context, * However, YugaByte writes the conflict tuple including its "ybctid" to execution state "estate" * and then frees the slot when done. */ - if (IsYBBackedRelation(relation)) { + if (IsYBRelation(relation)) { /* Initialize result without calling postgres. */ test = TM_Ok; ItemPointerSetInvalid(&tmfd.ctid); @@ -3139,13 +3139,13 @@ ExecOnConflictUpdate(ModifyTableContext *context, * snapshot. This is in line with the way UPDATE deals with newer tuple * versions. */ - if (!IsYugaByteEnabled()) + if (!IsYBRelation(relation)) ExecCheckTupleVisible(context->estate, relation, existing); else { - oldtuple = ExecFetchSlotHeapTuple(context->estate->yb_conflict_slot, true, &shouldFree); - ExecStoreBufferHeapTuple(oldtuple, existing, InvalidBuffer); - TABLETUPLE_YBCTID(context->planSlot) = HEAPTUPLE_YBCTID(oldtuple); + ybOldTuple = ExecFetchSlotHeapTuple(context->estate->yb_conflict_slot, true, &ybShouldFree); + ExecStoreBufferHeapTuple(ybOldTuple, existing, InvalidBuffer); + TABLETUPLE_YBCTID(context->planSlot) = HEAPTUPLE_YBCTID(ybOldTuple); } /* @@ -3200,15 +3200,15 @@ ExecOnConflictUpdate(ModifyTableContext *context, * wCTE in the ON CONFLICT's SET. */ - ItemPointer tid = IsYugaByteEnabled() ? NULL : conflictTid; + ItemPointer ybTid = IsYBRelation(relation) ? NULL : conflictTid; /* Execute UPDATE with projection */ *returning = ExecUpdate(context, resultRelInfo, - tid, oldtuple, + ybTid, ybOldTuple, resultRelInfo->ri_onConflict->oc_ProjSlot, canSetTag); - if (shouldFree) - pfree(oldtuple); + if (ybShouldFree) + pfree(ybOldTuple); /* * Clear out existing tuple, as there might not be another conflict among diff --git a/src/postgres/src/test/regress/expected/yb_pg15.out b/src/postgres/src/test/regress/expected/yb_pg15.out index 6acf6e0a26d5..e7f5586c5009 100644 --- a/src/postgres/src/test/regress/expected/yb_pg15.out +++ b/src/postgres/src/test/regress/expected/yb_pg15.out @@ -509,6 +509,40 @@ SELECT * FROM tlateral1 t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t2.c AS t2c, t 550 | 0 | 0002 | | | | | (12 rows) +-- Insert with on conflict on temp table +create temporary table mytmp (id int primary key, name text, count int); +insert into mytmp values (1, 'foo', 0); +insert into mytmp values (1, 'foo') on conflict ON CONSTRAINT mytmp_pkey do update set id = mytmp.id+1; +select * from mytmp; + id | name | count +----+------+------- + 2 | foo | 0 +(1 row) + +CREATE OR REPLACE FUNCTION update_count() RETURNS trigger LANGUAGE plpgsql AS +$func$ +BEGIN + NEW.count := NEW.count+1; + RETURN NEW; +END +$func$; +CREATE TRIGGER update_count_trig BEFORE UPDATE ON mytmp FOR ROW EXECUTE PROCEDURE update_count(); +insert into mytmp values (2, 'foo') on conflict ON CONSTRAINT mytmp_pkey do update set id = mytmp.id+1; +select * from mytmp; + id | name | count +----+------+------- + 3 | foo | 1 +(1 row) + +create view myview as select * from mytmp; +NOTICE: view "myview" will be a temporary view +insert into myview values (3, 'foo') on conflict (id) do update set id = myview.id + 1; +select * from myview; + id | name | count +----+------+------- + 4 | foo | 2 +(1 row) + -- Cleanup DROP TABLE IF EXISTS address, address2, emp, emp2, emp_par1, emp_par1_1_100, emp_par2, emp_par3, fastpath, myemp, myemp2, myemp2_101_200, myemp2_1_100, p1, p2, pk_range_int_asc, diff --git a/src/postgres/src/test/regress/sql/yb_pg15.sql b/src/postgres/src/test/regress/sql/yb_pg15.sql index 51d3287b7bbb..d80bda551613 100644 --- a/src/postgres/src/test/regress/sql/yb_pg15.sql +++ b/src/postgres/src/test/regress/sql/yb_pg15.sql @@ -202,6 +202,29 @@ ANALYZE tlateral1, tlateral2; -- YB_TODO: pg15 used merge join, whereas hash join is expected. -- EXPLAIN (COSTS FALSE) SELECT * FROM tlateral1 t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM tlateral1 t2 JOIN tlateral2 t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss ON t1.a = ss.t2a WHERE t1.b = 0 ORDER BY t1.a; SELECT * FROM tlateral1 t1 LEFT JOIN LATERAL (SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM tlateral1 t2 JOIN tlateral2 t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss ON t1.a = ss.t2a WHERE t1.b = 0 ORDER BY t1.a; + +-- Insert with on conflict on temp table +create temporary table mytmp (id int primary key, name text, count int); +insert into mytmp values (1, 'foo', 0); +insert into mytmp values (1, 'foo') on conflict ON CONSTRAINT mytmp_pkey do update set id = mytmp.id+1; +select * from mytmp; + +CREATE OR REPLACE FUNCTION update_count() RETURNS trigger LANGUAGE plpgsql AS +$func$ +BEGIN + NEW.count := NEW.count+1; + RETURN NEW; +END +$func$; + +CREATE TRIGGER update_count_trig BEFORE UPDATE ON mytmp FOR ROW EXECUTE PROCEDURE update_count(); +insert into mytmp values (2, 'foo') on conflict ON CONSTRAINT mytmp_pkey do update set id = mytmp.id+1; +select * from mytmp; + +create view myview as select * from mytmp; +insert into myview values (3, 'foo') on conflict (id) do update set id = myview.id + 1; +select * from myview; + -- Cleanup DROP TABLE IF EXISTS address, address2, emp, emp2, emp_par1, emp_par1_1_100, emp_par2, emp_par3, fastpath, myemp, myemp2, myemp2_101_200, myemp2_1_100, p1, p2, pk_range_int_asc,