Open-Source Wikis

/

PostgreSQL

/

Systems

/

Catalog

postgres/postgres

Catalog

Everything PostgreSQL knows about the database — tables, columns, types, functions, indexes, roles, statistics — lives in system catalog tables. The catalog is bootstrapped at initdb time and is itself queried using the same access methods that user tables use. Source: src/backend/catalog/, src/include/catalog/.

Directory layout

src/backend/catalog/
├── Catalog.pm           # Perl module: parses pg_*.dat files
├── genbki.pl            # generates postgres.bki + per-table headers
├── postgres.bki.in      # input template for the bootstrap data
├── system_views.sql     # SQL run after bootstrap to create the views
├── information_schema.sql
├── sql_features.txt     # tracking of which SQL standards features are supported
├── pg_aggregate.c, pg_collation.c, pg_proc.c, ...
├── catalog.c, dependency.c, indexing.c, namespace.c, objectaccess.c
└── partition.c, storage.c, ...

src/include/catalog/
├── pg_aggregate.h, pg_attribute.h, pg_class.h, pg_proc.h, ...   # row formats
├── pg_*.dat                                                      # initial contents
├── catalog.h, indexing.h, namespace.h, dependency.h
├── pg_attribute.dat, pg_proc.dat, pg_type.dat, ...               # data
└── unused_oids                                                   # script for assigning new OIDs

Anatomy of a system catalog

Each catalog is just a regular table with a fixed name (pg_class, pg_attribute, pg_proc, ...) and a fixed OID. Its row format is described in a pg_*.h header that contains a Form_pg_* C struct, plus annotations that genbki.pl reads to produce the bootstrap .bki file:

/* src/include/catalog/pg_class.h */
CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,RelationRelation_Rowtype_Id) BKI_SCHEMA_MACRO
{
    Oid     oid;
    NameData relname;
    Oid     relnamespace;
    Oid     reltype;
    /* ... */
};
typedef FormData_pg_class *Form_pg_class;

The CATALOG(name, oid, ...) macro is interpreted both by the C compiler (becoming a regular struct) and by genbki.pl (becoming a catalog-table definition). The pg_class.dat file alongside the header contains the bootstrap rows.

genbki.pl

src/backend/catalog/genbki.pl is the hub. It reads pg_*.h and pg_*.dat, validates them, assigns OIDs to entries that don't pin one, and emits:

  • postgres.bki — the bootstrap data file.
  • schemapg.h — C definitions of the catalog schemas, used by the relcache.
  • pg_*_d.h — derived headers with macros for column attributes.

The .bki file is a tiny declarative script that initdb feeds to a stripped-down "bootstrap" backend, which physically lays out the on-disk representation of each catalog and inserts its rows. After bootstrap, initdb runs system_views.sql and information_schema.sql to create the SQL-level views and informational schema.

Catalogs you'll meet

Table Purpose
pg_class All "relations": tables, views, indexes, sequences, etc. One row each.
pg_attribute Columns. One row per (relation, attno).
pg_type Data types: built-in, user-defined, composite, domain, enum.
pg_proc Functions and procedures.
pg_operator Operators, with their function references.
pg_namespace Schemas.
pg_database Databases (cluster-wide; shared across DBs).
pg_authid / pg_auth_members Roles and group membership (cluster-wide).
pg_index Index metadata.
pg_constraint Check, unique, foreign-key, primary-key, exclusion constraints.
pg_depend, pg_shdepend Dependency graph between catalog objects.
pg_amproc, pg_amop Index AM support functions and operator strategies.
pg_extension Installed extensions.
pg_statistic Per-column statistics (planner input).
pg_stat_* Cumulative statistics (live in shared memory, exposed as views).
pg_subscription, pg_publication, pg_publication_rel Logical replication.
pg_replication_slots Replication slot state.

There are dozens more; \dS pg_* in psql shows the full list.

OID assignment

Every catalog row has a 32-bit OID. OIDs below FirstUnpinnedObjectId (currently 12000) are pinned — they are assigned by hand in pg_*.dat and baked into the source. The src/include/catalog/unused_oids script lists currently-free OIDs for new pinned objects; running src/include/catalog/duplicate_oids checks for accidental collisions.

OIDs ≥ 12000 are auto-assigned at bootstrap. After bootstrap, new objects get OIDs from a per-cluster counter (varsup.c::GetNewObjectId).

Sys cache and rel cache

Direct heap scans of catalog tables would be slow, so the backend has two caches in front of them:

Sys cache

Source: src/backend/utils/cache/syscache.c. A set of per-catalog hash tables keyed by common lookup keys (PROCOID, RELNAMENSP, TYPEOID, etc.). Entries are loaded lazily on first lookup. The list of registered caches is in cacheinfo[] in syscache.c.

Usage:

HeapTuple tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tup))
{
    Form_pg_class pgcform = (Form_pg_class) GETSTRUCT(tup);
    /* use pgcform->relname etc. */
    ReleaseSysCache(tup);
}

Sys cache reference counts are owned by the resource manager; abort cleans them up.

Rel cache

src/backend/utils/cache/relcache.c. A cache of RelationData structs — fully assembled descriptors of each relation, including the TupleDesc, index info, partition descriptor, etc. Building a Relation is expensive; the rel cache amortizes it. Eviction happens when the relation is dropped or schema-altered, signaled via cache invalidation.

Cache invalidation

When a backend modifies a catalog row (e.g., ALTER TABLE adds a column), it queues invalidation messages describing the affected entries. At commit, those messages are broadcast to all other backends through shared memory, which evict the relevant sys-cache and rel-cache entries. Source: src/backend/utils/cache/inval.c.

Without this, a peer backend could keep using an out-of-date relcache entry and miss the new column.

Dependency tracking

pg_depend and pg_shdepend record dependencies between catalog objects. When you DROP TABLE, the engine walks the dependency graph and prevents the drop (or cascades) based on the edge types. Source: src/backend/catalog/dependency.c. Everything that creates a catalog object is expected to record its dependencies via recordDependencyOn*.

This is also how pg_dump figures out which order to emit CREATE statements in.

Namespace and search_path

pg_namespace is the schema catalog. The search_path setting tells the backend which schemas to look in, in order, for an unqualified name. Source: src/backend/catalog/namespace.c. Functions like RangeVarGetRelid resolve a RangeVar (potentially schema-qualified) to an OID.

Special schemas: pg_catalog (always implicit at the front of search*path; holds the system catalogs), pg_temp*\*(per-session temporary),information_schema (SQL-standard read-only views).

Object addresses

Many DDL operations work in terms of an ObjectAddress — the (catalog OID, object OID, sub-id) triple identifying any catalog object. Source: src/backend/catalog/objectaddress.c. The dispatcher translates between SQL syntax (schema.table.column) and ObjectAddress.

DDL execution path

A typical DDL command like CREATE TABLE:

  1. Parser: produces CreateStmt (gram.yparsenodes.h).
  2. Parse analysis: transformCreateStmt in src/backend/parser/parse_utilcmd.c.
  3. Utility command: ProcessUtility (in src/backend/tcop/utility.c) dispatches to ExecCreateStmt in src/backend/commands/tablecmds.c.
  4. The command code uses catalog helpers — heap_create_with_catalog, index_create, recordDependencyOn, etc. — to insert the necessary catalog rows.
  5. WAL records describe the catalog inserts (just like any other heap modification) so recovery can reproduce them.
  6. Cache invalidation messages are queued.
  7. Commit flushes WAL, broadcasts invalidations.

For other DDLs (ALTER, DROP, CREATE INDEX, etc.) the code is in src/backend/commands/ — one file per command family.

Bootstrap process

The first phase of initdb runs the backend in --boot mode. It reads postgres.bki and:

  1. Lays down pg_class, pg_attribute, pg_type, pg_proc files manually (no catalog yet to consult).
  2. Inserts the bootstrap rows.
  3. Builds the indexes on those tables.

Once that's done, the backend is "live" enough to read SQL scripts. initdb then runs system_views.sql and information_schema.sql over a normal connection to create the rest.

src/backend/bootstrap/ contains the bootstrap-mode entry points. They are minimal — most of the work is just running INSERT statements with reduced safety nets.

Entry points for modification

  • Add a column to a catalog: edit the pg_*.h to extend FormData, update the pg_*.dat if it pins rows, regenerate (just rebuild). Update any code that reads the catalog to handle the new column. Bumping CATALOG_VERSION_NO in catversion.h forces existing clusters to fail to start, signaling that a new initdb is needed.
  • Add a new catalog table: a sizable patch. New .h/.dat, new C file, register in genbki.pl's expected list, add cache-info entries, etc.
  • Add a system view: append to system_views.sql.

For the access-method layer underneath, see Access methods. For how DDL is parsed and dispatched, see Parser.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Catalog – PostgreSQL wiki | Factory