Skip to content

PostgreSQL's Extended Query Protocol Support in ProxySQL - P2#5078

Merged
renecannao merged 39 commits intov3.0from
v3.0_extended_query_protocol_phase_2
Sep 15, 2025
Merged

PostgreSQL's Extended Query Protocol Support in ProxySQL - P2#5078
renecannao merged 39 commits intov3.0from
v3.0_extended_query_protocol_phase_2

Conversation

@rahim-kanji
Copy link
Collaborator

@rahim-kanji rahim-kanji commented Aug 20, 2025

Closes #5079
Closes #5080
Closes #5081
Closes #5082
Closes #5084
Closes #5089
Closes #5091
Closes #5092

The PQsendQueryPrepared function transmits the sequence BIND ->
DESCRIBE(PORTAL) -> EXECUTE -> SYNC. However, libpq does not indicate
whether the DESCRIBE PORTAL step produces a NoData packet for commands
such as INSERT, DELETE, or UPDATE. In these cases, libpq returns
PGRES_COMMAND_OK, whereas SELECT statements yield PGRES_SINGLE_TUPLE or
PGRES_TUPLES_OK.

This update explicitly appends a NoData packet to the result in order to
provide consistent behavior across query types.
… messages

In extended query mode, ReadyForQuery is normally deferred when there are
pending messages in the queue; it is sent only after the entire extended
query frame has been processed.

Edge case: if a message fails with an error while the queue still contains
pending messages, the queue is cleared later in the session and those
pending messages are discarded. In that case, ReadyForQuery would never be
sent.

Change: when a result indicates an error, send ReadyForQuery immediately.
The extended-query flag will still be reset later in the session. This
ensures ReadyForQuery is always emitted and prevents clients from waiting
indefinitely.
Previously, any packet received while a query was still running was
considered unexpected, and the session was terminated. This often
occurred with pgJDBC, which pipelines commands (e.g., sending `BEGIN`
immediately followed by another statement).

Now, new packets are placed in a FIFO queue and processed only after the
current query finishes and its response is sent. This preserves correct
ordering, prevents unnecessary session termination, and improves
compatibility with connectors like pgJDBC.
PQsendQueryPrepared always emits Bind -> Describe Portal -> Execute, which led
to RowDescription being included in the result set even when the client never
sent a Describe message. This caused clients to receive row descriptions they
did not request.

Changes:
- Skip including RowDescription when the client did not send Describe.
- If the client explicitly sent Describe followed by Execute, continue to
  skip redundant execution of Describe but include RowDescription once.

This ensures RowDescription is only sent when requested, aligning behavior
with protocol expectations.
… released when ProxySQL shuts down or restarts.
…ckend

RequestEnd was applying state changes (session variable restore,
rollback-to-savepoint, multiplexing toggle for temp tables/sequences)
even when the query failed to execute on the backend connection.
This caused internal state to diverge from the actual backend state.

Fix:
- Add success/failure flag to RequestEnd calls.
- Restrict state-changing logic to Simple Query and Prepared Execute.
- Ensure logic only runs when the query executed successfully on backend.

This keeps internal state aligned with the backend connection state.
…cle is completed

When a simple query arrives while extended query messages are pending,
we now:
- inject an implicit Sync,
- process all extended query messages,
- then execute the simple query,
- and send ReadyForQuery only after the simple query completes.
Remove the `DESCRIBE` (statement) cache option and related cache code.
…ded to on.

Added scram_iterations in ProxySQL staup parameters status, hardcoded to
4096 (SCRAM_SHA_256_DEFAULT_ITERATIONS)
…ed via options=), the connection must be destroyed instead of returned to the pool.
ProxySQL currently does not support PostgreSQL's LISTEN command.
When clients attempt to use it, we now intercept the command and return
an appropriate "not supported" response instead of passing it through.

This behavior is implemented for both:
- Simple query flow
- Extended (prepared) query flow
Previously, Parse and Describe each had their own query result handling
paths. This duplicated a lot of logic and also failed to handle some
cases correctly—for example, Notice messages returned by the server
during extended-protocol queries. Keeping these separate paths would
be hard to maintain and prone to bugs.

The simple-query result handling is already mature, optimized, and
covers all the necessary cases. Reusing it for Parse and Describe
makes behavior consistent across simple and extended query flows,
while also reducing duplicate code.
Previously, deleting `PgSQL_Errors_stats` instances in TUs with only a forward
declaration caused the destructor to be skipped, leaking member allocations.
The fix ensures the full class definition is visible at delete sites.
@sonarqubecloud
Copy link

sonarqubecloud bot commented Sep 9, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
23.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@rahim-kanji rahim-kanji marked this pull request as ready for review September 11, 2025 21:13
@rahim-kanji rahim-kanji changed the title PostgreSQL's Extended Query Protocol Support in ProxySQL - P2 [WIP] PostgreSQL's Extended Query Protocol Support in ProxySQL - P2 Sep 11, 2025
@renecannao renecannao merged commit 1dd572b into v3.0 Sep 15, 2025
17 of 162 checks passed
@noizu noizu added this to the Release 3.0.3 milestone Sep 30, 2025
@renecannao renecannao deleted the v3.0_extended_query_protocol_phase_2 branch March 7, 2026 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants