Skip to content

fix: resolve cross-shard type OIDs on first use instead of failing the query - #1514

Draft
rlittlefield wants to merge 1 commit into
pgdogdev:mainfrom
rlittlefield:type-ddl-oid-refresh
Draft

fix: resolve cross-shard type OIDs on first use instead of failing the query#1514
rlittlefield wants to merge 1 commit into
pgdogdev:mainfrom
rlittlefield:type-ddl-oid-refresh

Conversation

@rlittlefield

@rlittlefield rlittlefield commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

First of two PRs closing gaps in canonicalize_type_information for types whose OIDs differ across shards (e.g. shards created with pg_dump/restore). The follow-up handles OIDs embedded in binary array/composite values.

Motivation: Postgrex (Elixir) keeps one type cache per pool, learned from whichever shard answers its bootstrap query. Any CREATE TYPE that happens after PgDog loaded its OID mappings (a migration, DDL on another PgDog instance, or DDL run directly against the database) produced a RowDescription with an unmapped OID and the client failed with oid(s) ... lack type information.

Behavior:

  • RowDescription / ParameterDescription with a user-type OID the mappings don't know about is held back while the mappings are refreshed from shard 0 and the shard (via a spare pooled connection), then rewritten and forwarded, so the client never sees the shard's OID. The wait is cancel-safe (the message is parked on the server connection) and capped at 5s; on failure the old behavior (forward as-is, request a config reload) is the fallback.
  • Parse / Bind / Describe carrying a canonical OID the shard's mappings don't know about trigger the same refresh before being sent, so the shard doesn't reject the statement.
  • CREATE/DROP of enums, composites, ranges, domains, base types and extensions now set the schema-changed flag, so reload_schema_on_ddl covers type DDL too.
  • A type present on a shard but missing on shard 0 is logged and left unmapped, instead of failing that shard's schema load (which previously retried forever and kept the cluster unready).
  • Server::send/read are split into client-facing and internal variants: PgDog's own catalog queries must not go through the refresh path, both to avoid recursion and so a refresh can't trigger another refresh.

Testing: unit tests cover the DDL parser, mapping construction (including types missing on shard 0), held-back RowDescriptions, the reload fallback, and the unknown-canonical-OID checks for Parse/Bind. integration/rust gains a test in cross_shard_oid_drift.rs: a type created after PgDog loaded its mappings (with DDL reloads disabled) is inserted with a typed parameter and read back from every shard without a single failure, and the RowDescription OID matches shard 0's. Ran locally against a two-shard setup; cargo fmt and cargo clippy are clean.

@rlittlefield rlittlefield changed the title fix: resolve cross-shard type OIDs on first use and inside binary array/composite values fix: resolve cross-shard type OIDs on first use instead of failing the query Sep 9, 2026
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.

1 participant