Skip to content

Reparse unnamed statements before cursor binding - #1364

Merged
elprans merged 1 commit into
masterfrom
fix-cursor-binding
Sep 20, 2026
Merged

elprans merged 1 commit into
masterfrom
fix-cursor-binding

Conversation

@elprans

@elprans elprans commented Sep 19, 2026

Copy link
Copy Markdown
Member

With statement_cache_size=0, type introspection can replace the unnamed
statement created by prepare(). The statement is marked unprepared, but
awaiting PreparedStatement.cursor() binds it without reparsing, so the
server receives arguments for the introspection query instead.

Make bind() honor the unprepared flag, as bind_execute() already does
to fix this.

Fixes #1335.
Closes #1345.

With `statement_cache_size=0`, type introspection can replace the unnamed
statement created by `prepare()`. The statement is marked unprepared, but
awaiting `PreparedStatement.cursor()` binds it without reparsing, so the
server receives arguments for the introspection query instead.

Make `bind()` honor the unprepared flag, as `bind_execute()` already does
to fix this.

Fixes #1335.
Closes #1345.
Copilot AI lite review requested due to automatic review settings September 19, 2026 23:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The fix aligns bind() behavior with the already-correct bind_execute() path, updates the protocol state machine accordingly, and includes a focused regression test for the reported failure mode.

Review effort: Lite
Findings: None

What changed in this PR

This PR fixes a regression where, with statement_cache_size=0, a PreparedStatement marked as unprepared (due to internal type-introspection clobbering the unnamed statement) could still be cursor-bound without reparsing, causing server-side cursor binds to target the wrong unnamed statement.

Changes:

  • Make BaseProtocol.bind() re-Parse the statement when PreparedStatementState.prepared is false (matching existing bind_execute() behavior).
  • Teach the core protocol bind state machine to accept ParseComplete during the bind flow when reparsing occurs.
  • Add a regression test covering the unnamed-statement + enum-introspection + cursor path with cache disabled.
File Description
tests/​test_cursor.py Adds a regression test ensuring cursor bind reparses unnamed statements when introspection clobbers them under statement_cache_size=0.
asyncpg/​protocol/​protocol.pyx Updates bind() to honor the prepared flag by sending a Parse when needed before binding.
asyncpg/​protocol/​coreproto.pyx Allows ParseComplete to be handled during PROTOCOL_BIND processing when a reparse is emitted ahead of Bind.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@elprans
elprans merged commit 302ba49 into master Sep 20, 2026
93 of 95 checks passed
@elprans
elprans deleted the fix-cursor-binding branch September 20, 2026 00:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants