Alexander Korotkov писал(а) 2026-07-04 01:00:
Hi!

ExecReScanAppend() unconditionally resets callback_pending for all
AsyncRequests.  The problem is that postgres_fdw keeps its own
knowledge for the same fact: PgFdwConnState.pendingAreq – a pointer
to "pending async request" for a given connection.  That connection
can be shared by several partitions/foreign tables (postgres_fdw
caches one connection per server+usermapping pair). The blind reset in
nodeAppend.c only touches the local AsyncRequest.callback_pending; it
never touches PgFdwConnState.pendingAreq, which correctly points to
the still-dangling request.

Later, when another partition sharing that same connection gets its
own ReScan (for instance, its chgParam changed because of the LATERAL
parameter, and it already has a cursor open), it sends "CLOSE cursor"
via pgfdw_exec_query().  Before sending any new command on the
connection, that function first drains whatever request is still
outstanding on it:

if (state && state->pendingAreq)
    process_pending_request(state->pendingAreq);

And process_pending_request() starts with:

Assert(areq->callback_pending);

– which fails, because the flag was corrupted some rounds earlier.

The attached patch contains both the reproduction case and the fix.
The fix postpones the reset of the callback_pending flag to
ExecAppendAsyncBegin().  ExecAppendAsyncBegin() performs this cleanup
along with ExecReScan(), which completes the async fetch.



Hi. The analysis seems correct to me as well as fix.
--
Best regards,
Alexander Pyhalov,
Postgres Professional


Reply via email to