4.4 System Catalogs & Information Schema
Key Takeaways
- PostgreSQL stores all database and cluster metadata in relational tables within the pg_catalog schema, which is automatically searched before user schemas on the search_path.
- pg_class serves as the central relation catalog, recording tables, indexes, sequences, views, and composite types classified by the single-character relkind attribute.
- Authentication metadata is maintained in pg_authid (restricted to superusers due to hashed password storage) and exposed safely to regular users through the password-masking pg_roles view.
- The ANSI SQL information_schema provides standardized, portable views of metadata across relational database management systems, but incurs higher query overhead than pg_catalog.
- psql meta-commands (such as \d and \dt) internally execute queries against pg_catalog rather than information_schema, which can be inspected directly using the psql -E flag.
4.4 System Catalogs & Information Schema
[!NOTE] Self-Describing Database Engine: In PostgreSQL, metadata is treated as first-class relational data. The database describes itself using regular tables and views that can be queried with standard
SELECTstatements. Understanding the physical system catalogs (pg_catalog) and the ANSI SQL standard views (information_schema) provides the foundation for deep diagnostics and administrative mastery.
A central topic on the PostgreSQL Associate certification is navigating these system catalogs, interpreting key metadata columns, and understanding why and when to query pg_catalog versus information_schema.
System Catalog Architecture: The pg_catalog Schema
Every PostgreSQL database automatically provisions the pg_catalog schema. This schema houses the core system catalog tables, built-in data types, built-in functions, operators, and aggregate definitions.
Special Namespace Rules
- Precedence on
search_path: Even if an administrator setssearch_path = public, custom, PostgreSQL implicitly searchespg_catalogfirst before any user-defined schema, unlesspg_catalogis explicitly placed later in thesearch_pathstring. This guarantees that built-in system functions and operators are always resolvable. - Catalog Mutability: System catalogs are standard tables, but direct DML (
INSERT,UPDATE,DELETE) against them is strictly disabled for normal users and strongly discouraged even for superusers. Modifying catalog tables directly bypasses integrity checks and can cause immediate cluster corruption. DDL statements (CREATE TABLE,ALTER ROLE,DROP INDEX) safely manage catalog mutations on the user's behalf.
Foundational Catalog Tables in pg_catalog
While PostgreSQL contains dozens of catalog tables, certification candidates must thoroughly understand the foundational catalogs that manage relations, databases, namespaces, roles, and columns:
+-------------------+
| pg_database |
| (Cluster DB list) |
+-------------------+
│ (datname)
▼
+-------------------+ +-------------------+
| pg_tablespace | | pg_namespace |
| (Storage paths) | | (Schema/Namespace)|
+-------------------+ +-------------------+
│ │ (oid = relnamespace)
└───────────────┬───────────────┘
▼
+-------------------+
| pg_class | <─── Core relation catalog
| (Tables, Indexes) | (relkind, reltuples, relpages)
+-------------------+
│ │
(attrelid = oid)│ │ (indrelid / indexrelid)
▼ ▼
+----------------+ +----------------+
| pg_attribute | | pg_index |
| (Table Columns)| | (Index Details)|
+----------------+ +----------------+
1. pg_class: The Relation Catalog
pg_class is the central catalog relation. Every database entity that has columns or disk storage—including regular tables, indexes, sequences, views, materialized views, composite types, and TOAST tables—has a corresponding row in pg_class.
Key Columns in pg_class
oid: The unique Object Identifier assigned to the relation.relname: Name of the relation (table, index, view, sequence).relnamespace: OID referencingpg_namespace(the schema containing the relation).reltype: OID referencingpg_type(the composite data type representing rows of this table).relowner: OID referencingpg_authid(the owning role).relkind: A single character identifying the specific relation type:'r': Ordinary heap table (relation)'i': Index'S': Sequence'v': View'm': Materialized view'c': Composite type't': TOAST table (oversized attribute storage table)'f': Foreign table'p': Partitioned table'I': Partitioned index
reltuples: Estimated number of rows in the relation (updated byVACUUMandANALYZE). Used directly by the query planner.relpages: Size of the relation's on-disk image measured in 8KB pages.relfilenode: Physical filename on the filesystem under$PGDATA/base/DB_OID/.
-- Query the largest tables and their disk footprints from pg_class
SELECT relname, relkind, reltuples::bigint, relpages,
pg_size_pretty(relpages::bigint * 8192) AS total_size
FROM pg_catalog.pg_class
WHERE relkind = 'r'
ORDER BY relpages DESC
LIMIT 5;
2. pg_database: Database Cluster Catalog
Located in the pg_global shared tablespace, pg_database stores metadata for all databases provisioned across the cluster:
datname: Database name.datdba: OID of the database owner role.encoding: Character encoding integer ID (e.g.,UTF8= 6).datcollate: Collation rules used for sorting text.datctype: Character classification rules (upper/lowercase conversion).dattablespace: Default tablespace OID used to store this database's files.
3. pg_tablespace: Physical Tablespaces
Also stored globally across the cluster, pg_tablespace records storage locations:
spcname: Tablespace name (e.g.,pg_default,pg_global,fast_nvme).spcowner: OID of the owning role.spcoptions: Storage parameters (such asseq_page_costandrandom_page_costoverrides).
4. pg_namespace: Schema Namespaces
pg_namespace stores schemas (namespaces) within the active database:
nspname: Name of the schema (e.g.,public,pg_catalog,information_schema,sales).nspowner: OID of the schema owner.nspacl: Access control list (privileges granted viaGRANT).
5. pg_authid vs. pg_roles: Role Metadata & Password Protection
PostgreSQL manages user accounts and security groups through roles. However, it strictly separates physical storage from unprivileged access:
pg_authid: The underlying physical catalog table. Storesrolname,rolsuper(superuser),rolinherit,rolcreaterole,rolcreatedb,rolcanlogin,rolconnlimit, androlpassword(the encrypted SCRAM-SHA-256 or MD5 password hash).[!CAUTION] Access Restriction: Read access to
pg_authidis strictly restricted to superusers. Unprivileged database users cannot readpg_authidto prevent offline brute-force attacks against password hashes.pg_roles: A public system view defined on top ofpg_authid. For non-superusers,pg_rolesmasks therolpasswordcolumn with********(or null) while exposing non-sensitive attributes (rolname,rolsuper,rolcreatedb,rolcanlogin). This allows regular users to inspect role privileges safely.
6. pg_attribute: Table Columns
Defines every column across every relation in pg_class:
attrelid: OID of the relation inpg_classto which this column belongs.attname: Column name.atttypid: OID referencingpg_type(data type).attnum: Column position number (1 for the first user column, 2 for the second). Note: Negative numbers denote PostgreSQL system columns (e.g.,-1forctid,-3forxmin,-4forcmin,-5forxmax).attnotnull: Boolean flag indicating if aNOT NULLconstraint applies.
7. pg_index: Index Specifications
Records index mechanics:
indexrelid: OID of the index inpg_class.indrelid: OID of the indexed table inpg_class.indisunique: Boolean flag indicating if the index enforces aUNIQUEconstraint.indisprimary: Boolean flag indicating if the index enforces aPRIMARY KEY.indkey: An array of column numbers (attnumvalues) included in the index key.
The ANSI SQL information_schema
While pg_catalog is PostgreSQL-specific, the information_schema is an ANSI SQL standard metadata schema (defined by ISO/IEC 9075). It provides standardized, portable views that present database metadata in a vendor-neutral structure identical across PostgreSQL, MySQL, Microsoft SQL Server, and Oracle.
Standard Views in information_schema
information_schema.tables: Lists tables and views with standard columns:table_catalog,table_schema,table_name,table_type(BASE TABLE,VIEW,LOCAL TEMPORARY).information_schema.columns: Column metadata:table_name,column_name,ordinal_position,column_default,is_nullable,data_type.information_schema.schemata: Schemas:catalog_name,schema_name,schema_owner.information_schema.table_constraints: Constraints:constraint_name,constraint_type(PRIMARY KEY,FOREIGN KEY,UNIQUE,CHECK).information_schema.views: Text definitions of views (view_definition).
-- ANSI-compliant query to find all nullable columns in the customers table
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'customers';
Deep Comparison: pg_catalog vs. information_schema
Understanding the architectural tradeoffs between these two metadata systems is a common certification topic:
| Evaluation Dimension | pg_catalog | information_schema |
|---|---|---|
| Standardization | Proprietary to PostgreSQL. | Standardized under ANSI/ISO SQL (SQL-92 through SQL:2023). |
| Portability | Low: queries break on non-Postgres databases. | High: identical queries run across diverse RDBMS platforms. |
| Completeness | 100% Comprehensive: reflects all PostgreSQL-specific features (inheritance, table partitioning, GIN/GiST/BRIN indexes, TOAST, storage parameters, foreign data wrappers). | Selective: limited to features standardized by ANSI SQL. Omits PostgreSQL-specific indexing, physical storage, and engine internals. |
| Query Performance | High Performance: queries direct underlying base tables and lightweight views with optimal index usage. | Slower: views involve complex multi-table joins, subqueries, and security filtering functions. |
| Security Visibility | Non-superusers can see relation names, but sensitive attributes (like passwords) are strictly guarded. | Automatically filters rows so users only see objects on which they hold explicit privileges. |
| Tool Usage | Used internally by psql slash commands (\d, \dt), pg_dump, and native drivers. | Used by generic ORMs (Hibernate, Prisma, SQLAlchemy) and multi-database GUI clients (DBeaver, DataGrip). |
Reverse-Engineering psql: The psql -E Flag
How does psql implement its informational backslash commands? It executes standard SQL queries against pg_catalog.
Administrators can inspect these underlying queries by launching psql with the -E (or --echo-hidden) flag:
psql -E -U postgres -d sales
When -E is active, typing any meta-command (such as \dt) prints the exact SQL query executed by psql before printing the formatted output:
sales=> \dt
********* QUERY **********
SELECT n.nspname as "Schema",
c.relname as "Name",
CASE c.relkind
WHEN 'r' THEN 'table'
WHEN 'v' THEN 'view'
WHEN 'm' THEN 'materialized view'
WHEN 'i' THEN 'index'
WHEN 'S' THEN 'sequence'
WHEN 's' THEN 'special'
WHEN 'f' THEN 'foreign table'
WHEN 'p' THEN 'partitioned table'
END as "Type",
pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','p','')
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND n.nspname !~ '^pg_toast'
AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
**************************
List of relations
Schema | Name | Type | Owner
--------+---------------+--------------+----------
public | customers | table | postgres
public | orders | table | postgres
(2 rows)
Using psql -E is a proven technique for mastering PostgreSQL catalogs, as it reveals production-tested joins across pg_class, pg_namespace, and internal utility functions like pg_table_is_visible().
Exam Tips and Common Pitfalls
- Exam Trap: Relkind Identifiers: Know the single-character codes in
pg_class.relkind:'r'= regular table,'i'= index,'S'= sequence,'v'= view,'m'= materialized view,'p'= partitioned table. A question asking for all base tables and partitioned tables requiresWHERE relkind IN ('r', 'p'). - Exam Trap:
pg_authidvs.pg_roles: Remember thatpg_authidcontains the actual hashed password (rolpassword) and can only be accessed by superusers. Non-superusers queryingpg_rolessee a masked placeholder. - Exam Trap:
pg_catalogvs.information_schemaSpeed: If an exam question asks why an administrative tool queriespg_catalograther thaninformation_schema, the reasons are comprehensive coverage of PostgreSQL-specific engine features and faster query execution.
An administrator queries the pg_class catalog table and observes a row where relkind = 'r'. What type of database relation does this record represent?
Why does PostgreSQL maintain both the pg_authid catalog table and the pg_roles system catalog view?
When comparing PostgreSQL's native pg_catalog system tables with the standard information_schema views, which statement accurately describes their differences?