Skip to content

Fix query macros against CockroachDB by gating plan_cache_mode on EXPLAIN support#4286

Open
BastienClement wants to merge 1 commit into
transact-rs:mainfrom
BastienClement:fix-crdb-plan-cache-mode
Open

Fix query macros against CockroachDB by gating plan_cache_mode on EXPLAIN support#4286
BastienClement wants to merge 1 commit into
transact-rs:mainfrom
BastienClement:fix-crdb-plan-cache-mode

Conversation

@BastienClement
Copy link
Copy Markdown

Problem

Since 0.9.0 the compile-time query macros (query!, query_as!,
query_scalar!) fail against CockroachDB:

error: error returned from database: unimplemented: SET usage inside a
function definition (SQLSTATE 0A000)

#3541 prepares the macros' describe connection by running
SET plan_cache_mode = 'force_generic_plan' inside a DO $$ … $$ block.
CockroachDB rejects SET inside a function/DO body at parse time, so the
block fails before its IF EXISTS guard runs. Closes #4274.

Fix

plan_cache_mode = force_generic_plan exists solely to keep EXPLAIN-based
nullability inference from being skewed by the NULL placeholder arguments
bound during describe. That inference already runs only when
is_explain_available() is true — false for CockroachDB, Materialize and
QuestDB (detected via their crdb_version / mz_version / questdb_version
parameter statuses).

The setting is moved out of the generic macro layer into PgConnection,
behind that same is_explain_available() check (plus a
server_version_num() >= 12 guard in place of the old pg_settings probe).
The macro layer now calls a per-database DatabaseExt::prepare_describe_connection
hook (a no-op for MySQL/SQLite). The setting is therefore skipped, by
construction, on every database that cannot use it — fixing CockroachDB and
pre-empting the same breakage on Materialize/QuestDB — while behaving exactly
as before on PostgreSQL.

Behaviour on standard PostgreSQL

Unchanged: the dedicated describe connection still gets force_generic_plan
(verified by the existing describe tests). describe() itself is untouched,
so no reused connection is affected.

Testing

  • Existing tests/postgres/describe.rs suite passes, plus a new
    it_forces_generic_plan_for_describe regression test.
  • Verified manually against CockroachDB v26.2.1: before this change a query!
    macro fails with SQLSTATE 0A000; afterwards it compiles and plan_cache_mode
    is left untouched. CockroachDB is not in the CI matrix, so that half cannot
    be covered by an automated test; the fix is structural (gated on the
    pre-existing, already-tested CockroachDB detection).
  • cargo clippy -- -D warnings and rustfmt --check are clean.

The query macros set `plan_cache_mode = 'force_generic_plan'` on their
describe connection (transact-rs#3541) to keep nullability inference from being skewed
by the NULL placeholder arguments. It was issued inside a `DO` block, which
CockroachDB rejects at parse time -- `SET` inside a function body, SQLSTATE
0A000 -- breaking the query macros against CockroachDB since 0.9.0 (transact-rs#4274).

The setting only benefits the EXPLAIN-based inference, which already runs
only when `is_explain_available()` is true (false for CockroachDB,
Materialize and QuestDB). Gate the setting on that same check so it is never
issued on a database that cannot use it, replacing the `pg_settings` probe
with a `server_version_num() >= 12` guard.
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.

query! macros fail against CockroachDB in 0.9.0: SET inside DO block not supported

1 participant