Summary
ProxySQL's PostgreSQL frontend rejects a spec-valid extended-protocol Bind message: when a client sends num_param_formats = 1 with num_params = 0, ProxySQL raises "Invalid param format count" and fails the exchange. Real PostgreSQL accepts this.
Wire-protocol background
Per the PostgreSQL protocol spec for Bind, the parameter-format-code count may be:
0 — all parameters use text format,
1 — the single format code applies to all parameters (valid regardless of the parameter count, including 0 — it is simply a no-op),
N — one code per parameter.
PostgreSQL's own exec_bind_message only errors when numPFormats > 1 && numPFormats != numParams.
Where
lib/PgSQL_Connection.cpp, stmt_execute_start() (~lines 1918–1928): the format-expansion branch is gated on param_values.size() > 1, so the param_formats.size()==1, param_values.size()==0 case falls through to the else if (param_formats.size() != param_values.size()) branch and is rejected.
Reproduction
Send Parse/Bind/Execute for a 0-parameter statement (e.g. SELECT 1) with a Bind carrying one format code (C=1, e.g. binary). Client libraries that always emit a single "apply-to-all" format code trip this.
Found by the SP-1 test suite (PR #5894): test/tap/tests/pgsql-datatype_matrix-t.cpp and test/tap/tests/pgsql-server_side_cursors-t.cpp had to work around it by sending an explicit empty paramFormats array (num_param_formats=0) for 0-param binds — see the in-test comments referencing this issue.
Expected
num_param_formats=1 accepted for any num_params, matching PostgreSQL: reject only numPFormats > 1 && numPFormats != numParams.
Suggested fix + regression test
Adjust the guard in stmt_execute_start() accordingly. A minimal regression test: 0-param Parse/Bind with a single format code must complete (once fixed, the workaround in the two SP-1 tests can also be reverted to bindStatementSingleFormat).
Summary
ProxySQL's PostgreSQL frontend rejects a spec-valid extended-protocol
Bindmessage: when a client sendsnum_param_formats = 1withnum_params = 0, ProxySQL raises "Invalid param format count" and fails the exchange. Real PostgreSQL accepts this.Wire-protocol background
Per the PostgreSQL protocol spec for
Bind, the parameter-format-code count may be:0— all parameters use text format,1— the single format code applies to all parameters (valid regardless of the parameter count, including 0 — it is simply a no-op),N— one code per parameter.PostgreSQL's own
exec_bind_messageonly errors whennumPFormats > 1 && numPFormats != numParams.Where
lib/PgSQL_Connection.cpp,stmt_execute_start()(~lines 1918–1928): the format-expansion branch is gated onparam_values.size() > 1, so theparam_formats.size()==1, param_values.size()==0case falls through to theelse if (param_formats.size() != param_values.size())branch and is rejected.Reproduction
Send Parse/Bind/Execute for a 0-parameter statement (e.g.
SELECT 1) with a Bind carrying one format code (C=1, e.g. binary). Client libraries that always emit a single "apply-to-all" format code trip this.Found by the SP-1 test suite (PR #5894):
test/tap/tests/pgsql-datatype_matrix-t.cppandtest/tap/tests/pgsql-server_side_cursors-t.cpphad to work around it by sending an explicit emptyparamFormatsarray (num_param_formats=0) for 0-param binds — see the in-test comments referencing this issue.Expected
num_param_formats=1accepted for anynum_params, matching PostgreSQL: reject onlynumPFormats > 1 && numPFormats != numParams.Suggested fix + regression test
Adjust the guard in
stmt_execute_start()accordingly. A minimal regression test: 0-param Parse/Bind with a single format code must complete (once fixed, the workaround in the two SP-1 tests can also be reverted tobindStatementSingleFormat).