PostgreSQL Extensibility — Section Overview
Contents:
- What this section covers
- The substrate: one pattern, many plug points
- Reading order
- Detail-doc summaries
- Adjacent sections
What this section covers
Section titled “What this section covers”This is the router for the extensibility subcategory — the plug points
that, taken together, are the reason the PostgreSQL codebase is shaped the
way it is. Extensibility is not a bolt-on: the core is built around fixed
indirection points so that third-party code can extend the engine without
patching it. Each plug point is the same shape — a struct-of-callbacks or
a function-pointer global that the core checks at a known spot — and an
extension ships a shared library, fills the struct (or sets the global), and
registers it.
The plug points this subcategory owns:
- Foreign data wrappers — the
FdwRoutinecallback struct (fdwapi.h) and the catalog plumbing (foreign/foreign.c,commands/foreigncmds.c) that lets a query plan, scan, and modify data living in another system as if it were a local table. - Extensions — the
CREATE EXTENSIONpackaging system (commands/extension.c): control files, version scripts, dependency resolution, andpg_extensionbookkeeping that turn a pile of SQL + a shared library into one installable, droppable unit. - Hook globals — the function-pointer globals scattered across the
engine (
planner_hook,ExecutorStart_hook,ProcessUtility_hook,shmem_request_hook/shmem_startup_hook, and their siblings) that a loaded module can chain to intercept planning, execution, utility-command dispatch, and shared-memory reservation. - Procedural languages + SPI — how a
LANGUAGE plpgsqlfunction is dispatched throughpg_language.lanplcallfoidto a call handler (pl_handler.c), and how that handler re-enters the SQL engine through the Server Programming Interface (executor/spi.c) to run queries from inside a function. - Custom scan providers — the
CustomScanMethods/CustomPathMethods/CustomExecMethodstriple (nodes/extensible.h,executor/nodeCustom.c) that lets an extension inject its own plan node into the planner’s path search and the executor’s node tree.
Sharp boundaries — what this subcategory hands off. Three plug points are architecturally identical in pattern (a registered struct of callbacks) but are owned elsewhere because they belong to a deeper subsystem:
- Table and index access methods (
TableAmRoutine,IndexAmRoutine) are the storage layer’s plug point — owned by storage-engine (postgres-table-am.md,postgres-index-am.md). FDWs are the query-time analog of a table AM; custom scans are the planner-time analog. - Custom WAL resource managers (
RegisterCustomRmgr) extend the WAL’s self-describing record set — owned by txn-recovery (postgres-wal-records-rmgr.md). - Background workers (
RegisterBackgroundWorker) are the process-model plug point — owned by server-architecture (postgres-background-workers.md); PLs and parallel query are clients of it, not owners.
The architecture overview’s Axis 7 names all seven plug points together;
this router covers the five that are user-facing extension surfaces and
points at the other three. Mechanism is in core; implementations are
mostly contrib. contrib/postgres_fdw, pg_stat_statements (a
planner_hook + shared memory user), and the in-tree index AMs are all
instances of these patterns — but contrib/ is out of scope for this tree.
These docs analyze the in-core mechanism and may name contrib modules only
as canonical examples.
The substrate: one pattern, many plug points
Section titled “The substrate: one pattern, many plug points”Every plug point in this subcategory is the core consulting an extension-set indirection at a fixed spot. The diagram groups the five user-facing surfaces this subcategory owns (solid) and the three it hands off to adjacent subcategories (dashed).
flowchart TB
CORE["PostgreSQL core<br/>(checks each indirection at a fixed spot)"]
subgraph OWNED["plug points owned by this subcategory"]
direction TB
FDW["foreign data wrappers<br/>FdwRoutine<br/>postgres-fdw.md"]
EXT["extension packaging<br/>CREATE EXTENSION / control files<br/>postgres-extensions.md"]
HOOK["hook globals<br/>planner / ExecutorStart /<br/>ProcessUtility / shmem_*<br/>postgres-hooks.md"]
PL["procedural languages<br/>pg_language -> call handler<br/>postgres-plpgsql.md"]
SPI["Server Programming Interface<br/>SPI_connect / SPI_execute<br/>postgres-spi.md"]
CS["custom scan providers<br/>CustomScanMethods<br/>postgres-custom-scan.md"]
end
subgraph HANDOFF["same pattern, owned by adjacent subcategories"]
direction TB
TAM["table / index AMs<br/>(storage-engine)"]
RMGR["custom WAL rmgrs<br/>(txn-recovery)"]
BGW["background workers<br/>(server-architecture)"]
end
CORE --> FDW
CORE --> EXT
CORE --> HOOK
CORE --> PL
CORE --> CS
PL --> SPI
CORE -.-> TAM
CORE -.-> RMGR
CORE -.-> BGW
EXT -. "packages + loads" .-> FDW
EXT -. "packages + loads" .-> PL
EXT -. "packages + loads" .-> CS
Two relationships in this diagram are load-bearing:
CREATE EXTENSIONis the packaging layer, not a plug point itself. The other surfaces are what an extension delivers;postgres-extensions.mdis how it is delivered, versioned, and tracked. An FDW, a PL, or a custom scan provider is typically shipped as an extension.- PLs and SPI are two halves of one round trip. A PL call handler is how the engine enters extension code; SPI is how that extension code re-enters the engine to run SQL. They are split into two docs because SPI is used by far more than PLs (triggers, the rule system, and C functions all use it), but they are read together.
Reading order
Section titled “Reading order”Cross-referenced-first, so each doc leans on the one before it:
postgres-hooks.md— start here. The hook-global pattern is the simplest instance of the whole subcategory’s thesis (set a function pointer; the core calls it at a fixed spot), and it is the substrate the other docs reference when they say “registered indirection.”postgres-extensions.md— the packaging system that delivers and loads everything else. Read before the concrete plug points, because FDWs, PLs, and custom scans all arrive as extensions.postgres-fdw.md— the richest callback struct (FdwRoutine), and the cleanest illustration of “extend the query path without patching it.” Pairs with the planner/executor docs in query-processing.postgres-custom-scan.md— the planner-and-executor plug point; read after FDW, since it solves the same “inject a scan” problem one layer lower (a raw plan node rather than a foreign-table abstraction).postgres-plpgsql.md— the canonical procedural-language implementation and thepg_languagedispatch path.postgres-spi.md— the re-entry API PLs (and triggers, rules, C functions) use to run SQL from inside the engine. Read last, since it is the seam every server-side-code mechanism shares.
Detail-doc summaries
Section titled “Detail-doc summaries”Forward references — these module docs may not exist yet; the summaries are predictive.
| Module doc | One-line scope |
|---|---|
postgres-fdw.md | The in-core foreign-data-wrapper mechanism: the FdwRoutine callback struct (GetForeignRelSize → GetForeignPaths → IterateForeignScan, plus the modify callbacks), how GetFdwRoutineForRelation / GetFdwRoutineByRelId resolve a foreign table to its wrapper handler (and GetFdwRoutine calls that handler to get the struct), and the foreigncmds.c DDL for servers/user-mappings/foreign tables — contrib’s postgres_fdw named only as the canonical example. |
postgres-extensions.md | The CREATE EXTENSION packaging system: control files (read_extension_control_file), version-upgrade scripts, dependency resolution and CASCADE (CreateExtensionInternal), and the pg_extension / pg_depend bookkeeping that makes an extension one installable, version-tracked, droppable unit. |
postgres-hooks.md | The function-pointer hook globals: planner_hook, ExecutorStart_hook (and the rest of the executor hooks), ProcessUtility_hook, and the shmem_request_hook / shmem_startup_hook pair an extension must use to reserve shared memory before the segment is sized — the chaining convention (save the previous pointer, call through it) and the fixed call sites. |
postgres-plpgsql.md | The reference procedural language: dispatch from pg_language.lanplcallfoid to plpgsql_call_handler / plpgsql_inline_handler / plpgsql_validator, compilation of a function body to a PL tree (pl_comp.c), and execution (pl_exec.c) — including how it calls back into the engine via SPI. |
postgres-spi.md | The Server Programming Interface: SPI_connect / SPI_execute / SPI_prepare / SPI_cursor_open, the SPI memory-context and snapshot management that lets server-side code run SQL safely inside an outer transaction, and the clients (PLs, triggers, the rule system, C functions) that depend on it. |
postgres-custom-scan.md | The custom-scan provider interface: the CustomPathMethods / CustomScanMethods / CustomExecMethods triple (extensible.h), how a provider injects a CustomPath into the planner’s path list and the executor instantiates it via ExecInitCustomScan / ExecCustomScan (nodeCustom.c), and RegisterCustomScanMethods for plan serialization. |
Adjacent sections
Section titled “Adjacent sections”This subcategory borders four others, because extensibility is a cross-cutting surface rather than a self-contained subsystem:
- storage-engine (
postgres-overview-storage-engine.md) — owns the table/index AM plug points (TableAmRoutine,IndexAmRoutine). FDWs and custom scans are the query-time relatives of a table AM; read those AM docs to see the deepest instance of the registered-callbacks pattern. - query-processing (
postgres-overview-query-processing.md) — owns the planner and executor that the FDW, custom-scan, andplanner_hook/ExecutorStart_hookplug points hang off. The hooks and custom scans are only meaningful against the path-search and node-tree mechanism documented there. - txn-recovery (
postgres-overview-txn-recovery.md) — owns custom WAL resource managers (RegisterCustomRmgr), the durability-layer instance of this subcategory’s pattern. - server-architecture (
postgres-overview-server-architecture.md) — owns the background-worker framework (RegisterBackgroundWorker) and the shared-memory substrate thatshmem_request_hookreserves into; a PL or parallel-query extension is a client of both.