ext/pdo_pgsql: Fix several lazy fetch defects - #23065
Open
KentarouTakeda wants to merge 4 commits into
Open
Conversation
KentarouTakeda
force-pushed
the
pdo-pgsql-lazy-fetch-drain
branch
from
August 5, 2026 16:13
1f18350 to
df8d70e
Compare
KentarouTakeda
force-pushed
the
pdo-pgsql-lazy-fetch-drain
branch
3 times, most recently
from
August 5, 2026 16:28
a698573 to
1a30f7e
Compare
Contributor
Author
|
Converting to draft: the drain loop this restores can hang when the statement left the connection in a COPY state. I will update once that is sorted out. |
KentarouTakeda
marked this pull request as draft
August 5, 2026 17:04
KentarouTakeda
force-pushed
the
pdo-pgsql-lazy-fetch-drain
branch
from
August 7, 2026 13:24
1a30f7e to
e3fbdf7
Compare
KentarouTakeda
force-pushed
the
pdo-pgsql-lazy-fetch-drain
branch
2 times, most recently
from
August 7, 2026 23:51
8fe3542 to
1f17859
Compare
KentarouTakeda
force-pushed
the
pdo-pgsql-lazy-fetch-drain
branch
from
August 8, 2026 00:01
1f17859 to
7f2e240
Compare
KentarouTakeda
marked this pull request as ready for review
August 8, 2026 00:19
Contributor
Author
|
Sorted out: the COPY hang is now fixed first, and the connection state fixes follow it. The change is four commits and the description is rewritten. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With
PDO::ATTR_PREFETCH => 0a statement streams its result set, and the cleanup reads the rest of it by callingPQgetResult()until it returns NULL. That never happens while the connection is copying:PQgetResult()hands out a fresh COPY result every time. ACOPYrun through a lazy fetch has therefore spun at 100% CPU since 8.5.0, as soon as another lazy fetch takes the connection over. The copy has to be ended first: a copy in withPQputCopyEnd(), a copy out by drainingPQgetCopyData().The drain was skipped as well, because
is_running_unbufferedwas cleared first, both in the cleanup's own abort path and inpgsql_stmt_fetch()before it calls the cleanup. WithPDO::ATTR_EMULATE_PREPARESorPdo\Pgsql::ATTR_DISABLE_PREPARESthe connection then stayed busy and the next lazy fetch failed with "another command is already in progress". Only the statement the connection still points at cancels and drains. A buffered query drains a pending stream as a side effect, and anything read after that belongs to the next statement.The connection's pointer to the statement streaming on it was only cleared while closing a server-side prepared statement, which those two modes do not create, so destroying one left the pointer dangling for the next lazy fetch to read. And a statement whose stream was taken over kept its row counters after its result had been freed, so
fetch()returned a row of NULLs rather thanfalse.The COPY fix comes first because the drain fix is what makes the other cleanup paths reach that loop. The pointer fix comes second because the drain tests destroy a statement and execute the next one. Without it they would read the freed statement and crash under an allocator that poisons freed memory. Every test fails, or hangs, on the commit before the one that adds it.