Skip to content

PostgreSQL Extensibility — Section Overview

Contents:

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 FdwRoutine callback 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 EXTENSION packaging system (commands/extension.c): control files, version scripts, dependency resolution, and pg_extension bookkeeping 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 plpgsql function is dispatched through pg_language.lanplcallfoid to 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 / CustomExecMethods triple (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 EXTENSION is the packaging layer, not a plug point itself. The other surfaces are what an extension delivers; postgres-extensions.md is 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.

Cross-referenced-first, so each doc leans on the one before it:

  1. 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.”
  2. 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.
  3. 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.
  4. 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).
  5. postgres-plpgsql.md — the canonical procedural-language implementation and the pg_language dispatch path.
  6. 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.

Forward references — these module docs may not exist yet; the summaries are predictive.

Module docOne-line scope
postgres-fdw.mdThe in-core foreign-data-wrapper mechanism: the FdwRoutine callback struct (GetForeignRelSizeGetForeignPathsIterateForeignScan, 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.mdThe 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.mdThe 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.mdThe 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.mdThe 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.mdThe 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.

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, and planner_hook / ExecutorStart_hook plug 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 that shmem_request_hook reserves into; a PL or parallel-query extension is a client of both.