How the Catalog System Functions in the pgrust Project: A Technical Deep Dive
The pgrust catalog system implements PostgreSQL's system-catalog layer in pure Rust, providing OID lookups, MVCC snapshot management, and runtime catalog-driven dispatch through the types_catalog and snapmgr crates.
The pgrust project reimplements PostgreSQL's architecture in Rust, including its essential catalog system that serves as the single source of truth for database metadata. This system manages built-in objects like tables, types, and functions while enabling runtime lookup of relation metadata and OID resolution without relying on hard-coded identifiers.
Core Catalog Definitions in types_catalog
The foundation of the catalog system resides in the _support/types/types_catalog crate, which defines Rust modules that mirror PostgreSQL's header files (catalog/*.h). In crates/_support/types/types_catalog/src/lib.rs, the crate re-exports a module for each catalog relation:
// crates/_support/types/types_catalog/src/lib.rs
pub mod catalog;
pub mod catalog_dependency;
pub mod pg_attrdef;
pub mod pg_attribute;
pub mod pg_cast;
pub mod pg_class;
pub mod pg_constraint;
pub mod pg_conversion;
pub mod pg_enum;
pub mod pg_extension;
pub mod pg_proc;
pub mod pg_type;
// ...
Each sub-module contains Rust structs that correspond to rows in PostgreSQL catalog tables (e.g., pg_class, pg_type, pg_proc). These definitions follow the same field ordering and types as the original C structs, ensuring binary-compatible access when the runtime reads a catalog snapshot.
OID Constants and Base Vocabulary in types_core
The _support/types/types_core crate builds on the catalog vocabulary to provide higher-level constants and utilities. Located in crates/_support/types/types_core/src/lib.rs, this crate centralizes OID values and command-tag enums that the rest of the codebase imports:
// crates/_support/types/types_core/src/lib.rs
pub mod catalog; // re-exports everything from `types_catalog`
pub mod cmdtag;
pub mod fmgr;
pub mod primitive;
pub mod xact;
// ...
pub use catalog::*;
pub use fmgr::*;
By centralizing constants like TYPTYPE_PSEUDO, F_OIDEQ, and BTREE_AM_OID, the core crate allows other modules to reference catalog objects without magic numbers. This pattern appears throughout the PL/pgSQL compiler in crates/pl/plpgsql/src/comp/src/lib.rs, which uses these constants during compilation.
Runtime Catalog Snapshots via snapmgr
Runtime code accesses catalog data through catalog snapshots—MVCC-consistent views of the system catalogs produced by backend utilities. The snapshot logic lives in backend/utils/time/snapmgr:
// backend/utils/time/snapmgr/src/lib.rs
pub fn get_catalog_snapshot(relid: Oid) -> Result<Snapshot, Error> { … }
pub fn get_non_historic_catalog_snapshot(relid: Oid) -> Result<Snapshot, Error> { … }
pub fn invalidate_catalog_snapshot() { … }
These functions support relation caches, syscache lookups, and the PL/pgSQL compiler by fetching the latest catalog state and invalidating stale snapshots when catalog-changing commands execute.
Catalog-Driven Dispatch for Extensions
Extension modules in pgrust do not embed hard-coded OIDs. Instead, they obtain identifiers from the catalog at runtime through a generic dispatch mechanism. This pattern appears across contrib/* crates such as pg_trgm, where GiST and GIN op-class implementations read their support functions from the catalog:
// Example from pg_trgm/src/lib.rs
/// Reached through pgrust's GENERIC, catalog-driven GiST opclass dispatch
The dispatch mechanism reads the catalog entry for an op-class, extracts its support functions, and wires them into the Rust implementation. This approach eliminates magic numbers and ensures compatibility with PostgreSQL's catalog structure.
Heap Access and Catalog Drivers
Heap access code in backend/access/heap/heapam uses a dedicated catalog_drivers module to translate catalog rows into low-level storage parameters. In crates/backend/access/heap/heapam/src/lib.rs, these drivers read the catalog snapshot to obtain column definitions, type OIDs, and storage options required for heap operations:
// backend/access/heap/heapam/src/lib.rs
pub mod catalog_drivers;
This integration ensures that tuple descriptors and storage parameters remain synchronized with the system catalog state.
Practical Code Examples
Looking Up a Type OID
To retrieve the OID of the built-in text type from the catalog constants:
use types_core::catalog::pg_type;
/// Get the OID of the built-in `text` type from the catalog.
fn text_oid() -> Oid {
// `pg_type` exposes constants generated from the catalog.
pg_type::TEXT_TYPE_OID
}
Relevant source: crates/_support/types/types_catalog/src/pg_type.rs
Fetching a Catalog Snapshot
To retrieve the current MVCC snapshot for a given relation OID:
use backend::utils::time::snapmgr;
/// Retrieve the current MVCC snapshot for a given relation OID.
fn current_snapshot(relid: Oid) -> Result<Snapshot, Error> {
snapmgr::get_catalog_snapshot(relid)
}
Relevant source: crates/backend/utils/time/snapmgr/src/lib.rs
Using Catalog-Driven GiST Op-Classes
To build a GiST op-class instance that reads its support functions from the catalog:
use contrib::pg_trgm::TrgmGist;
/// Build a GiST op-class instance that reads its support functions from the catalog.
let gist = TrgmGist::new_from_catalog();
Relevant source: crates/contrib/pg_trgm/src/gist.rs
Summary
- The catalog system resides primarily in
types_catalogandtypes_corecrates, which define binary-compatible structs and OID constants mirroring PostgreSQL's system catalogs. - Runtime access uses MVCC snapshots via functions in
snapmgr, providing consistent views of catalog data for relation caches and compilers. - Extension modules leverage catalog-driven dispatch rather than hard-coded OIDs, enabling generic GiST/GIN op-class implementations in crates like
pg_trgm. - Heap access layers translate catalog metadata into storage parameters using the
catalog_driversmodule inheapam.
Frequently Asked Questions
What is the primary crate for catalog definitions in pgrust?
The _support/types/types_catalog crate serves as the primary source for catalog definitions. It contains Rust modules like pg_type, pg_class, and pg_proc that structurally mirror PostgreSQL's catalog tables, ensuring binary-compatible access to system catalog data.
How does pgrust handle runtime catalog lookups?
Runtime code uses the snapmgr crate to obtain MVCC-consistent catalog snapshots. Functions like get_catalog_snapshot() and invalidate_catalog_snapshot() manage these views, allowing subsystems to query current metadata while maintaining consistency with concurrent catalog updates.
Why does pgrust avoid hard-coded OIDs in extension modules?
Extension modules use catalog-driven dispatch to obtain OIDs and support function pointers at runtime. This approach eliminates magic numbers, reduces maintenance burden when OIDs change, and ensures that op-class implementations in crates like pg_trgm remain compatible with the underlying PostgreSQL catalog structure.
What role does the catalog_drivers module play in heap access?
The catalog_drivers module in backend/access/heap/heapam translates catalog rows into heap access parameters. It reads column definitions, type OIDs, and storage options from the catalog snapshot to configure tuple descriptors and storage handlers for heap operations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →