Skip to content

fix(plugin-postgresql): resolve the oid of a type created after connect from the catalog - #2617

Merged
datlechin merged 1 commit into
mainfrom
fix/postgres-lazy-type-oids
Sep 3, 2026
Merged

fix(plugin-postgresql): resolve the oid of a type created after connect from the catalog#2617
datlechin merged 1 commit into
mainfrom
fix/postgres-lazy-type-oids

Conversation

@datlechin

Copy link
Copy Markdown
Member

Root cause

libpq reports each result column as a type oid, and the PostgreSQL plugin turned an oid into a type name from two tables: its built-in list of standard types, and an enum map read once at connect. A type created after that, in the same session or by any other client, had an oid in neither, so its columns came back as unknown and rendered as text until the next reconnect. Found as a collateral item while working on #2484, which added a Create Type flow that runs into exactly this.

Fix

  • Every result whose columns leave an oid unresolved runs one lookup on the same connection once the result has been fully read, which is the one point libpq allows another statement, and remembers the answer for the rest of the session. An enum spells as ENUM(name) and an enum array as ENUM[](name), the spellings the connect-time probe already used and the classifier reads; a domain reads as its base type so the cell edits as one; a composite, a range or a base type the built-in list lacks (money) keeps its own name. An oid the catalog does not know is remembered as unresolved so it is not asked about again, except when the lookup failed inside an aborted transaction, where it will succeed after the rollback.
  • A streaming result sends its header with the first row, before anything could be looked up. A CREATE TYPE command tag therefore refreshes the enum map right after the statement, so a SELECT streamed after a CREATE TYPE in the same tab reads the new enum on first sight.
  • The array test is typelem on a variable-length type rather than typcategory, which Redshift's catalog predates; measured against PostgreSQL 17, the two agree on every type but the pseudo-type _record.

Evidence

A swiftc harness running the plugin's real sources against a throwaway PostgreSQL 17:

buffered: ["ENUM(lazy_mood)", "ENUM[](lazy_mood)", "integer", "money", "integer[]"]
bounded: ["ENUM(lazy_mood2)", "ENUM(lazy_mood)"]
stream header after a CREATE TYPE tag: ["ENUM(lazy_mood3)"]
stream header, type from another client, first sight: ["unknown"]
stream header after a streamed CREATE TYPE: ["ENUM(lazy_mood6)"]
stream header, second: ["ENUM(lazy_mood3)"]
inside transaction: ["ENUM(lazy_mood4)"]

The one remaining unknown is a type another client created, seen first through a streaming header; the next result on that connection reads it correctly.

Tests

PostgreSQLCatalogTypeNamesTests covers the spellings for every type kind, the lookup query shape, row parsing, negative caching and the enum probe parser. 17 cases pass with the column resolver suite.

Changelog

Fixed: Columns of a PostgreSQL enum created during the session shown as text until the next reconnect.

https://claude.ai/code/session_014THhVdsUjbCboxNLnQB1dR

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@datlechin
datlechin merged commit 155ffe9 into main Sep 3, 2026
8 checks passed
@datlechin
datlechin deleted the fix/postgres-lazy-type-oids branch September 3, 2026 06:28
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