↑↓ select ↵ open ⌫ change scope Open full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

Wiki / Table AM / Core table AM

heap

Core table AM

The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL.

Reading PostgreSQL 18.6.

Description

The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL.

Interface family
Table access method
Handler or routine
heapam_methods
Recorded callbacks
43

Interface and capability boundaries

The matrix records callbacks actually registered in this source build. Registration identifies an implemented interface hook; options, query shape, privileges and provider rules determine whether an operation is allowed.

The complete same-version manual below retains configuration, constraints and examples. No runtime capability test is claimed.

Heap storage, visibility and WAL

This inventory starts with the Table AM interface in PostgreSQL 12. Earlier PostgreSQL heap storage is not relabeled as a Table AM implementation.

Heap visibility follows PostgreSQL snapshots. WAL and crash-recovery behavior depend on relation persistence; temporary and unlogged tables differ from permanent tables. Index access methods remain separate from the table storage interface.

Registered implementation in core source

{
	.type = T_TableAmRoutine,

	.slot_callbacks = heapam_slot_callbacks,

	.scan_begin = heap_beginscan,
	.scan_end = heap_endscan,
	.scan_rescan = heap_rescan,
	.scan_getnextslot = heap_getnextslot,

	.scan_set_tidrange = heap_set_tidrange,
	.scan_getnextslot_tidrange = heap_getnextslot_tidrange,

	.parallelscan_estimate = table_block_parallelscan_estimate,
	.parallelscan_initialize = table_block_parallelscan_initialize,
	.parallelscan_reinitialize = table_block_parallelscan_reinitialize,

	.index_fetch_begin = heapam_index_fetch_begin,
	.index_fetch_reset = heapam_index_fetch_reset,
	.index_fetch_end = heapam_index_fetch_end,
	.index_fetch_tuple = heapam_index_fetch_tuple,

	.tuple_insert = heapam_tuple_insert,
	.tuple_insert_speculative = heapam_tuple_insert_speculative,
	.tuple_complete_speculative = heapam_tuple_complete_speculative,
	.multi_insert = heap_multi_insert,
	.tuple_delete = heapam_tuple_delete,
	.tuple_update = heapam_tuple_update,
	.tuple_lock = heapam_tuple_lock,

	.tuple_fetch_row_version = heapam_fetch_row_version,
	.tuple_get_latest_tid = heap_get_latest_tid,
	.tuple_tid_valid = heapam_tuple_tid_valid,
	.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,
	.index_delete_tuples = heap_index_delete_tuples,

	.relation_set_new_filelocator = heapam_relation_set_new_filelocator,
	.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,
	.relation_copy_data = heapam_relation_copy_data,
	.relation_copy_for_cluster = heapam_relation_copy_for_cluster,
	.relation_vacuum = heap_vacuum_rel,
	.scan_analyze_next_block = heapam_scan_analyze_next_block,
	.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,
	.index_build_range_scan = heapam_index_build_range_scan,
	.index_validate_scan = heapam_index_validate_scan,

	.relation_size = table_block_relation_size,
	.relation_needs_toast_table = heapam_relation_needs_toast_table,
	.relation_toast_am = heapam_relation_toast_am,
	.relation_fetch_toast_slice = heap_fetch_toast_slice,

	.relation_estimate_size = heapam_estimate_rel_size,

	.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,
	.scan_sample_next_block = heapam_scan_sample_next_block,
	.scan_sample_next_tuple = heapam_scan_sample_next_tuple
}

Registered interface handlers

Interface operationSource observationCallbackImplementation
Tuple slotHandler registered; conditions applyslot_callbacksheapam_slot_callbacks
Begin scanHandler registered; conditions applyscan_beginheap_beginscan
Parallel scan initializationHandler registered; conditions applyparallelscan_initializetable_block_parallelscan_initialize
Begin index lookupHandler registered; conditions applyindex_fetch_beginheapam_index_fetch_begin
Fetch identified tupleHandler registered; conditions applyindex_fetch_tupleheapam_index_fetch_tuple
Insert tupleHandler registered; conditions applytuple_insertheapam_tuple_insert
Update tupleHandler registered; conditions applytuple_updateheapam_tuple_update
Delete tupleHandler registered; conditions applytuple_deleteheapam_tuple_delete
Vacuum relationHandler registered; conditions applyrelation_vacuumheap_vacuum_rel
Analyze blockHandler registered; conditions applyscan_analyze_next_blockheapam_scan_analyze_next_block
TOAST decisionHandler registered; conditions applyrelation_needs_toast_tableheapam_relation_needs_toast_table

Manual definition

Chapter 62. Table Access Method Interface Definition

This chapter explains the interface between the core PostgreSQL system and table access methods, which manage the storage for tables. The core system knows little about these access methods beyond what is specified here, so it is possible to develop entirely new access method types by writing add-on code.

Each table access method is described by a row in the pg_am system catalog. The pg_am entry specifies a name and a handler function for the table access method. These entries can be created and deleted using the CREATE ACCESS METHOD and DROP ACCESS METHOD SQL commands.

A table access method handler function must be declared to accept a single argument of type internal and to return the pseudo-type table_am_handler. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.

Here is how an extension SQL script file might create a table access method handler:

CREATE OR REPLACE FUNCTION my_tableam_handler(internal)
  RETURNS table_am_handler AS 'my_extension', 'my_tableam_handler'
  LANGUAGE C STRICT;

CREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;

The result of the function must be a pointer to a struct of type TableAmRoutine, which contains everything that the core code needs to know to make use of the table access method. The return value needs to be of server lifetime, which is typically achieved by defining it as a static const variable in global scope.

Here is how a source file with the table access method handler might look like:

#include "postgres.h"

#include "access/tableam.h"
#include "fmgr.h"

PG_MODULE_MAGIC;

static const TableAmRoutine my_tableam_methods = {
    .type = T_TableAmRoutine,

    /* Methods of TableAmRoutine omitted from example, add them here. */
};

PG_FUNCTION_INFO_V1(my_tableam_handler);

Datum
my_tableam_handler(PG_FUNCTION_ARGS)
{
    PG_RETURN_POINTER(&my_tableam_methods);
}

The TableAmRoutine struct, also called the access method's API struct, defines the behavior of the access method using callbacks. These callbacks are pointers to plain C functions and are not visible or callable at the SQL level. All the callbacks and their behavior is defined in the TableAmRoutine structure (with comments inside the struct defining the requirements for callbacks). Most callbacks have wrapper functions, which are documented from the point of view of a user (rather than an implementor) of the table access method. For details, please refer to the src/include/access/tableam.h file.

To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see src/include/executor/tuptable.h), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.

Currently, the way an AM actually stores data is fairly unconstrained. For example, it's possible, but not required, to use postgres' shared buffer cache. In case it is used, it likely makes sense to use PostgreSQL's standard page layout as described in Section 66.6.

One fairly large constraint of the table access method API is that, currently, if the AM wants to support modifications and/or indexes, it is necessary for each tuple to have a tuple identifier (TID) consisting of a block number and an item number (see also Section 66.6). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for heap, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.

For crash safety, an AM can use postgres' WAL, or a custom implementation. If WAL is chosen, either Generic WAL Records can be used, or a Custom WAL Resource Manager can be implemented.

To implement transactional support in a manner that allows different table access methods be accessed within a single transaction, it likely is necessary to closely integrate with the machinery in src/backend/access/transam/xlog.c.

Any developer of a new table access method can refer to the existing heap implementation present in src/backend/access/heap/heapam_handler.c for details of its implementation.

Related entries

Documentation and source

Source build
Version
18.6
Build
PostgreSQL 18.6 source archive
Source fingerprint
555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f

Compare versions

PostgreSQL 19 → 20: changed.

--- PostgreSQL 19
+++ PostgreSQL 20
@@ -1,11 +1,11 @@
 {
   "callbacks": {
+    "fetch_tid": "heapam_fetch_tid",
     "index_build_range_scan": "heapam_index_build_range_scan",
     "index_delete_tuples": "heap_index_delete_tuples",
-    "index_fetch_begin": "heapam_index_fetch_begin",
-    "index_fetch_end": "heapam_index_fetch_end",
-    "index_fetch_reset": "heapam_index_fetch_reset",
-    "index_fetch_tuple": "heapam_index_fetch_tuple",
+    "index_scan_begin": "heapam_index_scan_begin",
+    "index_scan_end": "heapam_index_scan_end",
+    "index_scan_reset": "heapam_index_scan_reset",
     "index_validate_scan": "heapam_index_validate_scan",
     "multi_insert": "heap_multi_insert",
     "parallelscan_estimate": "table_block_parallelscan_estimate",

Compares recorded interfaces and attributes. Source fingerprints and build metadata are excluded; an absent sample is not proof of the introduction or removal release.

Export JSON · Back to Table AM · Recorded in PostgreSQL 12 through 20; the first sample is not necessarily its introduction.