ADR 0012: pg_catalog and information_schema are real catalog schemas
ADR 0012: pg_catalog and information_schema are real catalog schemas
Status: Accepted Date: 2026-10-24 Scope: orbit-rs Deciders: Ravindra Boddipalli Amends: ADR 0003 (item 6, and its open item 2)
Context
ADR 0003 gave schemas a place in the catalog but left pg_catalog and information_schema virtual: the engine matches their relation names (pg_namespace, pg_class, information_schema.columns, and so on) before it looks at the catalog (sql/durable/pg_catalog.rs, sql/durable/information_schema.rs), and reports fixed values for current_schema() and search_path. The owner decided on 2026-10-24 that they become real schemas now, in the same step as user schemas, not later.
If they stay special-cased by name, name resolution has two code paths. A user table called pg_class in public, an explicit pg_catalog.pg_class, and a search_path that omits pg_catalog would each behave differently from PostgreSQL, and tools that introspect (psql \d, ORMs, pg_dump) depend on those rules.
Decision
pg_catalogandinformation_schemaare entries in the schema set with fixed oids (pg_catalog11,public2200,information_schemaa fixed oid), owned by the bootstrap superuser, and listed inpg_namespacelike any other schema.- Their relations are built-in relations registered in the catalog under their schema, with rows computed from the current
State. They resolve through the same resolver as user relations. The by-name special case is removed. pg_catalogis implicitly first in everysearch_path, as in PostgreSQL, unless the path names it explicitly.information_schemais reachable by qualification or by putting it in the path.- Users cannot create, alter or drop objects in either schema (
42501), and cannot drop the schemas. - A user relation never shadows a
pg_catalogrelation of the same name unless the path putspublicbefore an explicitpg_catalog, matching PostgreSQL. - Nothing is stored for them: replay is unaffected, and the rolling-upgrade guard in ADR 0003 item 4 does not apply to them.
Consequences
- One resolution path for every relation; fewer name-based exceptions to maintain.
- A large part of
pg_catalog.rs(1.5k lines) andinformation_schema.rs(0.9k lines) changes shape, from name-matched generators to registered built-ins. Their behaviour must not change: the existing catalog tests and the introspection corpus file (15_introspection.slt, 42 of 47 today) must not fall. - Work order inside the schema change: user schemas and the resolver first, then migrate the catalog relations onto it.
Verification
Corpus records for qualified and unqualified catalog access, shadowing, search_path without pg_catalog, and the 42501 errors, recorded from PostgreSQL 18; the existing catalog tests; 15_introspection.slt and 06_catalog.slt do not fall.