BUG #17809: MERGE ... UPDATE fails with BEFORE ROW UPDATE trigger when target row updated concurrently - Mailing list pgsql-bugs
From | PG Bug reporting form |
---|---|
Subject | BUG #17809: MERGE ... UPDATE fails with BEFORE ROW UPDATE trigger when target row updated concurrently |
Date | |
Msg-id | 17809-9e6650bef133f0fe@postgresql.org Whole thread Raw |
Responses |
Re: BUG #17809: MERGE ... UPDATE fails with BEFORE ROW UPDATE trigger when target row updated concurrently
|
List | pgsql-bugs |
The following bug has been logged on the website: Bug reference: 17809 Logged by: Alexander Lakhin Email address: exclusion@gmail.com PostgreSQL version: 15.2 Operating system: Ubuntu 22.04 Description: When executing the following script: cat << "EOF" | psql CREATE TABLE target (tid integer, val integer); INSERT INTO target VALUES (1, 0); CREATE OR REPLACE FUNCTION brut_func() RETURNS trigger LANGUAGE plpgsql AS 'BEGIN RETURN NEW; END;'; CREATE TRIGGER brut BEFORE UPDATE ON target FOR EACH ROW EXECUTE PROCEDURE brut_func(); EOF for ((i=1;i<=10;i++)); do echo "iteration $i" psql -c "UPDATE TARGET SET val = 0" & psql -c "MERGE INTO target t1 USING target t2 ON t1.tid = t2.tid WHEN MATCHED THEN UPDATE SET val = 0" & wait ls tmpdb/core* && break coredumpctl --no-pager && break done I get a server crash with the following stack trace: Program terminated with signal SIGSEGV, Segmentation fault. warning: Section `.reg-xstate/1808258' in core file too small. #0 0x000055e66490440e in internalGetUpdateNewTuple (relinfo=0x55e66595e040, planSlot=0x55e665998288, oldSlot=0x55e665969978, relaction=0x0) at nodeModifyTable.c:741 741 econtext = newProj->pi_exprContext; (gdb) bt #0 0x000055e66490440e in internalGetUpdateNewTuple (relinfo=0x55e66595e040, planSlot=0x55e665998288, oldSlot=0x55e665969978, relaction=0x0) at nodeModifyTable.c:741 #1 0x000055e6649043e0 in ExecGetUpdateNewTuple (relinfo=0x55e66595e040, planSlot=0x55e665998288, oldSlot=0x55e665969978) at nodeModifyTable.c:726 #2 0x000055e66487e835 in ExecBRUpdateTriggers (estate=0x55e66595dba0, epqstate=0x55e66595df10, relinfo=0x55e66595e040, tupleid=0x7ffec9335002, fdw_trigtuple=0x0, newslot=0x55e665969748, tmfd=0x7ffec93350b0) at trigger.c:3037 #3 0x000055e66490622e in ExecUpdatePrologue (context=0x7ffec9335080, resultRelInfo=0x55e66595e040, tupleid=0x7ffec9335002, oldtuple=0x0, slot=0x55e665969748) at nodeModifyTable.c:1912 #4 0x000055e6649078b2 in ExecMergeMatched (context=0x7ffec9335080, resultRelInfo=0x55e66595e040, tupleid=0x7ffec9335002, canSetTag=true) at nodeModifyTable.c:2884 #5 0x000055e6649075da in ExecMerge (context=0x7ffec9335080, resultRelInfo=0x55e66595e040, tupleid=0x7ffec9335002, canSetTag=true) at nodeModifyTable.c:2750 #6 0x000055e6649097f2 in ExecModifyTable (pstate=0x55e66595de28) at nodeModifyTable.c:3866 #7 0x000055e6648c60d7 in ExecProcNodeFirst (node=0x55e66595de28) at execProcnode.c:464 #8 0x000055e6648b9353 in ExecProcNode (node=0x55e66595de28) at ../../../src/include/executor/executor.h:259 #9 0x000055e6648bc25a in ExecutePlan (estate=0x55e66595dba0, planstate=0x55e66595de28, use_parallel_mode=false, operation=CMD_MERGE, sendTuples=false, numberTuples=0, direction=ForwardScanDirection, dest=0x55e665955bf8, execute_once=true) at execMain.c:1636 #10 0x000055e6648b9a8a in standard_ExecutorRun (queryDesc=0x55e66594c960, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:363 #11 0x000055e6648b9875 in ExecutorRun (queryDesc=0x55e66594c960, direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:307 #12 0x000055e664b31952 in ProcessQuery (plan=0x55e665955b08, sourceText=0x55e6658593b0 "MERGE INTO target t1 USING target t2 ON t1.tid = t2.tid WHEN MATCHED THEN UPDATE SET val = 0", params=0x0, queryEnv=0x0, dest=0x55e665955bf8, qc=0x7ffec93354e0) at pquery.c:160 #13 0x000055e664b33545 in PortalRunMulti (portal=0x55e6658d5190, isTopLevel=true, setHoldSnapshot=false, dest=0x55e665955bf8, altdest=0x55e665955bf8, qc=0x7ffec93354e0) at pquery.c:1277 #14 0x000055e664b32a28 in PortalRun (portal=0x55e6658d5190, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x55e665955bf8, altdest=0x55e665955bf8, qc=0x7ffec93354e0) at pquery.c:791 #15 0x000055e664b2b803 in exec_simple_query ( query_string=0x55e6658593b0 "MERGE INTO target t1 USING target t2 ON t1.tid = t2.tid WHEN MATCHED THEN UPDATE SET val = 0") at postgres.c:1250 #16 0x000055e664b30722 in PostgresMain (dbname=0x55e665885938 "regression", username=0x55e665885918 "law") at postgres.c:4593 #17 0x000055e664a55c23 in BackendRun (port=0x55e66587d420) at postmaster.c:4511 #18 0x000055e664a554aa in BackendStartup (port=0x55e66587d420) at postmaster.c:4239 #19 0x000055e664a51437 in ServerLoop () at postmaster.c:1806 #20 0x000055e664a50b94 in PostmasterMain (argc=3, argv=0x55e665853610) at postmaster.c:1478 #21 0x000055e664944ad5 in main (argc=3, argv=0x55e665853610) at main.c:202 At first sight it appeared like another manifestation of bug #17798, but it seems that this is a distinct defect. As I can see, ExecModifyTable() for the "case CMD_MERGE" can pass to ExecMerge() the resultRelInfo structure with ri_projectNew == null (but ri_projectNewInfoValid == true (set in ExecInitMergeTupleSlots)). This is not an issue till GetTupleForTrigger() in ExecBRUpdateTriggers() gets a tuple. But when a concurrent update occurs, GetTupleForTrigger() fails and ExecGetUpdateNewTuple() gets called, where internalGetUpdateNewTuple() tries to get relinfo->ri_projectNew->pi_exprContext... The issue appeared with the MERGE introduction (7103ebb7a).
pgsql-bugs by date: