BUG #17355: Server crashes on ExecReScanForeignScan in postgres_fdw when accessing foreign partition

The Post Office <noreply@postgresql.org>

From: PG Bug reporting form <noreply@postgresql.org>
To: pgsql-bugs@lists.postgresql.org
Cc: exclusion@gmail.com
Date: 2022-01-06T08:00:00Z
Lists: pgsql-bugs
The following bug has been logged on the website:

Bug reference:      17355
Logged by:          Alexander Lakhin
Email address:      exclusion@gmail.com
PostgreSQL version: 14.1
Operating system:   Ubuntu 20.04
Description:        

When running the following script (with 20 concurrent insert/update/delete
queries):
cat << 'EOF' | psql postgres
CREATE EXTENSION postgres_fdw;

CREATE SERVER testserver1 FOREIGN DATA WRAPPER postgres_fdw;
DO $d$
    BEGIN
        EXECUTE $$CREATE SERVER loopback FOREIGN DATA WRAPPER postgres_fdw
            OPTIONS (dbname '$$||current_database()||$$',
                     port '$$||current_setting('port')||$$'
            )$$;
    END;
$d$;

CREATE USER MAPPING FOR CURRENT_USER SERVER loopback;
CREATE TABLE async_pt (a int, b int) PARTITION BY RANGE (a);
CREATE TABLE base_tbl2 (a int, b int);
CREATE FOREIGN TABLE async_p2 PARTITION OF async_pt FOR VALUES FROM (2000)
TO (3000)
  SERVER loopback OPTIONS (table_name 'base_tbl2');
CREATE TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO
(4000);
EOF

for i in `seq 20`; do
cat << 'EOF' | psql postgres >psql-$i.log &
INSERT INTO async_pt SELECT i FROM generate_series(3000, 3100) i;
DELETE FROM async_pt;
UPDATE async_pt SET a = a;
EOF
done
wait

I get crashes with the following stacktrace:
Core was generated by `postgres: law postgres [local] DELETE                
                        '.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f0f438e6c42 in postgresReScanForeignScan (node=0x5580b57f23b8) at
postgres_fdw.c:1651
1651            if (!fsstate->cursor_exists)
(gdb) bt
#0  0x00007f0f438e6c42 in postgresReScanForeignScan (node=0x5580b57f23b8) at
postgres_fdw.c:1651
#1  0x00005580b4987bf9 in ExecReScanForeignScan (node=0x5580b57f23b8) at
nodeForeignscan.c:326
#2  0x00005580b4942c0a in ExecReScan (node=0x5580b57f23b8) at
execAmi.c:235
#3  0x00005580b49815bb in ExecProcNode (node=0x5580b57f23b8) at
../../../src/include/executor/executor.h:255
#4  0x00005580b4981e3b in ExecAppend (pstate=0x5580b57f1f48) at
nodeAppend.c:360
#5  0x00005580b4967c88 in ExecProcNodeFirst (node=0x5580b57f1f48) at
execProcnode.c:463
#6  0x00005580b495b774 in ExecProcNode (node=0x5580b57f1f48) at
../../../src/include/executor/executor.h:257
#7  0x00005580b4960373 in EvalPlanQualNext (epqstate=0x5580b57cf360) at
execMain.c:2612
#8  0x00005580b495fc99 in EvalPlanQual (epqstate=0x5580b57cf360,
relation=0x7f0f37b3d598, rti=3, 
    inputslot=0x5580b57d0540) at execMain.c:2383
#9  0x00005580b49a70ed in ExecDelete (mtstate=0x5580b57cf278,
resultRelInfo=0x5580b57cf5c8, tupleid=0x7ffdf2fa6002, 
    oldtuple=0x0, planSlot=0x5580b57dc9a8, epqstate=0x5580b57cf360,
estate=0x5580b57ceff0, processReturning=true, 
    canSetTag=true, changingPart=false, tupleDeleted=0x0, epqreturnslot=0x0)
at nodeModifyTable.c:1243
#10 0x00005580b49a95b3 in ExecModifyTable (pstate=0x5580b57cf278) at
nodeModifyTable.c:2599
#11 0x00005580b4967c88 in ExecProcNodeFirst (node=0x5580b57cf278) at
execProcnode.c:463
#12 0x00005580b495b774 in ExecProcNode (node=0x5580b57cf278) at
../../../src/include/executor/executor.h:257
#13 0x00005580b495e392 in ExecutePlan (estate=0x5580b57ceff0,
planstate=0x5580b57cf278, use_parallel_mode=false, 
    operation=CMD_DELETE, sendTuples=false, numberTuples=0,
direction=ForwardScanDirection, dest=0x5580b57dad98, 
    execute_once=true) at execMain.c:1551
#14 0x00005580b495beab in standard_ExecutorRun (queryDesc=0x5580b5711f80,
direction=ForwardScanDirection, count=0, 
    execute_once=true) at execMain.c:361
#15 0x00005580b495bc96 in ExecutorRun (queryDesc=0x5580b5711f80,
direction=ForwardScanDirection, count=0, 
    execute_once=true) at execMain.c:305
#16 0x00005580b4bd7cf8 in ProcessQuery (plan=0x5580b57d9ac0,
sourceText=0x5580b56e9440 "DELETE FROM async_pt;", 
    params=0x0, queryEnv=0x0, dest=0x5580b57dad98, qc=0x7ffdf2fa64b0) at
pquery.c:160
#17 0x00005580b4bd98b7 in PortalRunMulti (portal=0x5580b574d090,
isTopLevel=true, setHoldSnapshot=false, 
    dest=0x5580b57dad98, altdest=0x5580b57dad98, qc=0x7ffdf2fa64b0) at
pquery.c:1274
#18 0x00005580b4bd8d9d in PortalRun (portal=0x5580b574d090,
count=9223372036854775807, isTopLevel=true, run_once=true, 
    dest=0x5580b57dad98, altdest=0x5580b57dad98, qc=0x7ffdf2fa64b0) at
pquery.c:788
#19 0x00005580b4bd1bd9 in exec_simple_query (query_string=0x5580b56e9440
"DELETE FROM async_pt;") at postgres.c:1214
#20 0x00005580b4bd6ac8 in PostgresMain (argc=1, argv=0x7ffdf2fa66d0,
dbname=0x5580b5714f78 "postgres", 
    username=0x5580b5714f58 "law") at postgres.c:4486
#21 0x00005580b4afb357 in BackendRun (port=0x5580b570dab0) at
postmaster.c:4530
#22 0x00005580b4afabb2 in BackendStartup (port=0x5580b570dab0) at
postmaster.c:4252
#23 0x00005580b4af69a7 in ServerLoop () at postmaster.c:1745
#24 0x00005580b4af6104 in PostmasterMain (argc=3, argv=0x5580b56e34b0) at
postmaster.c:1417
#25 0x00005580b49e566a in main (argc=3, argv=0x5580b56e34b0) at main.c:209

postmaster.log contains:
2022-01-06 10:46:20.145 MSK [403022] ERROR:  cannot re-evaluate a Foreign
Update or Delete during EvalPlanQual
2022-01-06 10:46:20.145 MSK [403022] STATEMENT:  UPDATE async_pt SET a =
a;
2022-01-06 10:46:20.320 MSK [403059] LOG:  unexpected EOF on client
connection with an open transaction
2022-01-06 10:46:20.320 MSK [402977] LOG:  server process (PID 403043) was
terminated by signal 11: Segmentation fault
2022-01-06 10:46:20.320 MSK [402977] DETAIL:  Failed process was running:
DELETE FROM async_pt;

Commits

  1. Further fix for EvalPlanQual with mix of local and foreign partitions.

  2. Fix segfault during EvalPlanQual with mix of local and foreign partitions.

  3. Rework planning and execution of UPDATE and DELETE.