| From: | "Yilin Zhang" <jiezhilove(at)126(dot)com> |
|---|---|
| To: | "Rafia Sabih" <rafia(dot)pghackers(at)gmail(dot)com> |
| Cc: | "Robert Haas" <robertmhaas(at)gmail(dot)com>, "KENAN YILMAZ" <kenan(dot)yilmaz(at)localus(dot)com(dot)tr>, "Andy Fan" <zhihuifan1213(at)163(dot)com>, "PostgreSQL Hackers" <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | Re: Bypassing cursors in postgres_fdw to enable parallel plans |
| Date: | 2026-07-06 06:14:46 |
| Message-ID: | 5b24d348.42ba.19f36109f2b.Coremail.jiezhilove@126.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
At 2026-07-03 20:51:12,"Rafia Sabih" <rafia(dot)pghackers(at)gmail(dot)com> wrote :
>
> No, but I don't understand why you think they can be different in the
> current implementation.
> Currently, as per init_scan fsstate->conn_state->active_scan = fsstate, and
> it is never reassigned or anything.
> So they cannot have different conn_state.
> Am I missing something?
>
This is the reproduction procedure for the crash caused by clearing active_scan that I mentioned last week.
Data preparation:
CREATE TABLE local_big (id int, val text);
CREATE TABLE local_big2 (id int, val text);
INSERT INTO local_big SELECT i, 'val_' || i FROM generate_series(1, 300000) i;
INSERT INTO local_big2 SELECT i, 'val_' || i FROM generate_series(1, 300000) i;
CREATE SERVER test_srv FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'localhost', port '55436', dbname 'test_bug2');
CREATE USER MAPPING FOR CURRENT_USER SERVER test_srv;
CREATE FOREIGN TABLE ft_big (id int, val text)
SERVER test_srv
OPTIONS (schema_name 'public', table_name 'local_big',
streaming_fetch 'true', fetch_size '1');
CREATE FOREIGN TABLE ft_small (id int, val text)
SERVER test_srv
OPTIONS (schema_name 'public', table_name 'local_big2',
streaming_fetch 'true', fetch_size '1');
session-1
DROP TABLE IF EXISTS bug2_pid;
CREATE TEMP TABLE bug2_pid (pid int);
INSERT INTO bug2_pid VALUES (pg_backend_pid()); -- pid_1
DO $$
DECLARE cnt int;
BEGIN
SET LOCAL enable_hashjoin = off;
SET LOCAL enable_mergejoin = off;
SELECT count(*) INTO cnt
FROM ft_big b, ft_small s
WHERE b.id = s.id
AND pg_backend_pid() > 0;
RAISE NOTICE 'completed: cnt=%', cnt;
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'caught: %', SQLERRM;
END;
$$;
SELECT 'post_check' AS phase, count(*) FROM ft_big; -- CRASH HERE
session-2
SELECT pid FROM bug2_pid;
SELECT pg_cancel_backend(pid); -- After Session 1 enters the drain loop, execute pg_cancel_backend(pid) in Session 2.
I believe the issue regarding fsstate->conn and active_fsstate->conn that you've been discussing with Robert is related to this crash.
If only one PgFdwScanState* (active_fsstate) is available inside save_to_tuplestore, the assignment active_scan = NULL will clearly not be executed prior to draining.
The draining logic operates on data from active_fsstate, and we can only clear it after draining completes successfully.
Best regards,
--
Yilin Zhang
| From | Date | Subject | |
|---|---|---|---|
| Next Message | torikoshia | 2026-07-06 06:21:44 | Re: RFC: Logging plan of the running query |
| Previous Message | Amit Kapila | 2026-07-06 06:12:42 | Re: Proposal: Conflict log history table for Logical Replication |