{"kind": "tableam", "major": "18", "item": {"slug": "heap", "name": "heap", "name_zh": "Core table AM", "category": "Core table AM", "summary": "The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL.", "aliases": [], "content_hash": "1612ad33787d9f68db16cce2bce26afa690606249036105dea14c90c64b68b36", "versions": {"12": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "41"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=12", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=12", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=12", "label": "Index AM"}], "release": {"ref": "PostgreSQL 12.22 source archive", "label": "12.22", "major": "12", "channel": "historical", "revision": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b", "source_url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/12/tableam.html", "path": "tableam.html", "label": "PostgreSQL 12 English manual", "sha256": "4a2f5484c66207255d238dc6a312b1fecf991782c97cbe20e2522b8e33eaf341"}, {"url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "line": 2659, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2659", "sha256": "30b90707d75ec73d6b8aa8d939d372120d59e4e2cb470e77e51164af45b41138", "archive_sha256": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b"}, {"url": "/docs/12/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 12 English manual", "sha256": "519cbfd791ca57455e33efd709a1fc8ae8164a3fc3efef28613a95aeed398d8e"}, {"url": "/docs/12/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 12 English manual", "sha256": "7210cf3ff82ffa37ef81ebbbc252e4807649dcb86050eaa3ea5fcba40a768656"}, {"url": "/docs/12/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 12 English manual", "sha256": "86a0c5de06e0271f0c1cc357c7060578b66260bf785fb78d02abd36afb5ea1f3"}, {"url": "/docs/12/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 12 English manual", "sha256": "93b1cac9d6535f34e389d3ba8488f21d9c5a7812ffba495b3d838b58548b547a"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\t.finish_bulk_insert = heapam_finish_bulk_insert,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.compute_xid_horizon_for_tuples = heap_compute_xid_horizon_for_tuples,\n\n\t.relation_set_new_filenode = heapam_relation_set_new_filenode,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = heapam_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_block = heapam_scan_bitmap_next_block,\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "heapam_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "finish_bulk_insert": "heapam_finish_bulk_insert", "relation_copy_data": "heapam_relation_copy_data", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "compute_xid_horizon_for_tuples": "heap_compute_xid_horizon_for_tuples", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a060.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/12/catalog-pg-am.html\" title=\"51.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/12/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/12/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands. The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope. The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/12/storage-page-layout.html\" title=\"69.6.\u00a0Database Page Layout\">Section\u00a069.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/12/storage-page-layout.html\" title=\"69.6.\u00a0Database Page Layout\">Section\u00a069.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/12/wal.html\" title=\"Chapter\u00a029.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/12/generic-wal.html\" title=\"Chapter\u00a062.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a new type of WAL records can be implemented. Generic WAL Records are easy, but imply higher WAL volume. Implementation of a new type of WAL record currently requires modifications to core code (specifically, <code class=\"filename\">src/include/access/rmgrlist.h</code>).</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/12/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "heapam_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "finish_bulk_insert": "heapam_finish_bulk_insert", "relation_copy_data": "heapam_relation_copy_data", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "compute_xid_horizon_for_tuples": "heap_compute_xid_horizon_for_tuples", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "cdc168038f8a0930454c83eead818d36c8fbfe842d4d6e716a39e36c6a09d9cc", "runtime_verified": false}, "13": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "42"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=13", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=13", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=13", "label": "Index AM"}], "release": {"ref": "PostgreSQL 13.23 source archive", "label": "13.23", "major": "13", "channel": "historical", "revision": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6", "source_url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/13/tableam.html", "path": "tableam.html", "label": "PostgreSQL 13 English manual", "sha256": "7207b1654a8740007f663a820269f764f8b566f9f6bbbf739f768970658e4f52"}, {"url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "line": 2536, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2536", "sha256": "7504b49b1b306583d631e5608e081b280b7e72362f280e8db5490871727e8660", "archive_sha256": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6"}, {"url": "/docs/13/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 13 English manual", "sha256": "a970ff541c86fe8f48eabf49dcda92879e1db437223c629d6c83d38c0cd70180"}, {"url": "/docs/13/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 13 English manual", "sha256": "912dd15faaa243438f33082160f2848636d1940afea42c36cf6d21a2a46c8cb8"}, {"url": "/docs/13/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 13 English manual", "sha256": "c8cdd4e67dcc28e8f62ed22b8a6c3e8e2762359267655bea2c9c5b3dcb3a9efe"}, {"url": "/docs/13/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 13 English manual", "sha256": "a5a599fab10fbcdbd5dd963e70f41868984db33c061716372b9957b9c111ce7a"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.compute_xid_horizon_for_tuples = heap_compute_xid_horizon_for_tuples,\n\n\t.relation_set_new_filenode = heapam_relation_set_new_filenode,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_block = heapam_scan_bitmap_next_block,\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "relation_copy_data": "heapam_relation_copy_data", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "compute_xid_horizon_for_tuples": "heap_compute_xid_horizon_for_tuples", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a060.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/13/catalog-pg-am.html\" title=\"51.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/13/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/13/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands. The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope. The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/13/storage-page-layout.html\" title=\"69.6.\u00a0Database Page Layout\">Section\u00a069.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/13/storage-page-layout.html\" title=\"69.6.\u00a0Database Page Layout\">Section\u00a069.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/13/wal.html\" title=\"Chapter\u00a029.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/13/generic-wal.html\" title=\"Chapter\u00a062.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a new type of WAL records can be implemented. Generic WAL Records are easy, but imply higher WAL volume. Implementation of a new type of WAL record currently requires modifications to core code (specifically, <code class=\"filename\">src/include/access/rmgrlist.h</code>).</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/13/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "relation_copy_data": "heapam_relation_copy_data", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "compute_xid_horizon_for_tuples": "heap_compute_xid_horizon_for_tuples", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "850336e9baa50632ce39bf1c3673c2fdc1c6f0c399d99c8ead229845b7a7c8d4", "runtime_verified": false}, "14": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "44"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=14", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=14", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=14", "label": "Index AM"}], "release": {"ref": "PostgreSQL 14.24 source archive", "label": "14.24", "major": "14", "channel": "stable", "revision": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897", "source_url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/14/tableam.html", "path": "tableam.html", "label": "PostgreSQL 14 English manual", "sha256": "935eb557dd2605cec6a969afe4739666db36be6dfb09557293f096a59ea9525a"}, {"url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "line": 2539, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2539", "sha256": "13ab8be6d597a85414e7d921717eb959d3516e362acb94c3e67926a5b3715e2a", "archive_sha256": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897"}, {"url": "/docs/14/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 14 English manual", "sha256": "5007d7da5abbae92e3dbda5590c9171ed73c22a171a29bea875c93464cdcfafa"}, {"url": "/docs/14/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 14 English manual", "sha256": "2d92d1040e37f5d94ce279dc9f1555a720179397fcf3aa8412f5278ec1d943e8"}, {"url": "/docs/14/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 14 English manual", "sha256": "3c8ae732adb6e03978d28407de3a25552b338da62859ddb3c70ca7d7c60d1239"}, {"url": "/docs/14/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 14 English manual", "sha256": "a7431722a73e39d7ca74d4d0fa8c51435a442e5cd66564907330493a7b80edd5"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filenode = heapam_relation_set_new_filenode,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_block = heapam_scan_bitmap_next_block,\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a061.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/14/catalog-pg-am.html\" title=\"52.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/14/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/14/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands. The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope. The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/14/storage-page-layout.html\" title=\"70.6.\u00a0Database Page Layout\">Section\u00a070.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/14/storage-page-layout.html\" title=\"70.6.\u00a0Database Page Layout\">Section\u00a070.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/14/wal.html\" title=\"Chapter\u00a030.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/14/generic-wal.html\" title=\"Chapter\u00a063.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a new type of WAL records can be implemented. Generic WAL Records are easy, but imply higher WAL volume. Implementation of a new type of WAL record currently requires modifications to core code (specifically, <code class=\"filename\">src/include/access/rmgrlist.h</code>).</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/14/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "eee603c9509a489abd6ec6a12129951277b59ad8334e2edc6299d8edd5fa0e38", "runtime_verified": false}, "15": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "44"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=15", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=15", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=15", "label": "Index AM"}], "release": {"ref": "PostgreSQL 15.19 source archive", "label": "15.19", "major": "15", "channel": "stable", "revision": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89", "source_url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/15/tableam.html", "path": "tableam.html", "label": "PostgreSQL 15 English manual", "sha256": "5ee4097a59afae0117b872700e0a36e63b92fdbefd8a1cc59fd2d77dee35dcc3"}, {"url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "line": 2538, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2538", "sha256": "defee509717f844e43f49497885213030e3bbf0c4f94ea9706605db9d74effe4", "archive_sha256": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89"}, {"url": "/docs/15/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 15 English manual", "sha256": "560c3702c5ba7ce54cd9ab5c0b7548859fa73c2bc1e560a5cb12955a34d550b9"}, {"url": "/docs/15/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 15 English manual", "sha256": "dcb246be9d6131c7227ccde6745458865a0c97ac4c8891c2cbea73a30769d6df"}, {"url": "/docs/15/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 15 English manual", "sha256": "ea4f9434e9f615892aec6bdd734639a8f68968e7e5a447a7819ed64936602def"}, {"url": "/docs/15/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 15 English manual", "sha256": "afaeb26977cb9fa6503500d6eff1bc108f5ac76cc80185345bcde2b8e39c9c93"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filenode = heapam_relation_set_new_filenode,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_block = heapam_scan_bitmap_next_block,\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a063.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/15/catalog-pg-am.html\" title=\"53.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/15/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/15/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands. The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope. The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/15/storage-page-layout.html\" title=\"73.6.\u00a0Database Page Layout\">Section\u00a073.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/15/storage-page-layout.html\" title=\"73.6.\u00a0Database Page Layout\">Section\u00a073.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/15/wal.html\" title=\"Chapter\u00a030.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/15/generic-wal.html\" title=\"Chapter\u00a065.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a <a class=\"link\" href=\"/docs/15/custom-rmgr.html\" title=\"Chapter\u00a066.\u00a0Custom WAL Resource Managers\">Custom WAL Resource Manager</a> can be implemented.</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/15/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "relation_set_new_filenode": "heapam_relation_set_new_filenode", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "eee603c9509a489abd6ec6a12129951277b59ad8334e2edc6299d8edd5fa0e38", "runtime_verified": false}, "16": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "44"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=16", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=16", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=16", "label": "Index AM"}], "release": {"ref": "PostgreSQL 16.15 source archive", "label": "16.15", "major": "16", "channel": "stable", "revision": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed", "source_url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/16/tableam.html", "path": "tableam.html", "label": "PostgreSQL 16 English manual", "sha256": "de4f87f56c28dceda7f0cd9d1cd06d4d743e8d40f0e0c678de9a124620fe60e8"}, {"url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "line": 2545, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2545", "sha256": "098e4c2edc2b72869ca506104e38765eb11a5c9f84c018f932acc86a355c0749", "archive_sha256": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed"}, {"url": "/docs/16/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 16 English manual", "sha256": "44ad702b3a2801b752f632abc5637a121f19d3dec107beedd3ae430b47efed70"}, {"url": "/docs/16/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 16 English manual", "sha256": "dde6108abda6f7358eeccc6867eb68f5ca601329ea3f50bc3d5b728c944a65a8"}, {"url": "/docs/16/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 16 English manual", "sha256": "776a9e2655314bbdc3f689ca444ddac910ab2dc352aec54b102481846d1f1777"}, {"url": "/docs/16/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 16 English manual", "sha256": "596022bb02bdc457528b9821745971fc926674d3ee14dd5d91afb387b927844c"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filelocator = heapam_relation_set_new_filelocator,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_block = heapam_scan_bitmap_next_block,\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a063.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/16/catalog-pg-am.html\" title=\"53.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/16/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/16/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands. The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope. The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/16/storage-page-layout.html\" title=\"73.6.\u00a0Database Page Layout\">Section\u00a073.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/16/storage-page-layout.html\" title=\"73.6.\u00a0Database Page Layout\">Section\u00a073.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/16/wal.html\" title=\"Chapter\u00a030.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/16/generic-wal.html\" title=\"Chapter\u00a065.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a <a class=\"link\" href=\"/docs/16/custom-rmgr.html\" title=\"Chapter\u00a066.\u00a0Custom WAL Resource Managers\">Custom WAL Resource Manager</a> can be implemented.</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/16/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "d129057b9afc0cb9f38d3137a9d84fd96a035ed851fab81db9903db8ab10aabd", "runtime_verified": false}, "17": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "44"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=17", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=17", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=17", "label": "Index AM"}], "release": {"ref": "PostgreSQL 17.11 source archive", "label": "17.11", "major": "17", "channel": "stable", "revision": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979", "source_url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/17/tableam.html", "path": "tableam.html", "label": "PostgreSQL 17 English manual", "sha256": "fe8df94617712b5fe74fe0a46f7f72438e671e243b03a4fb68c5925a10c7aefe"}, {"url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "line": 2592, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2592", "sha256": "c2cb15c279b21f71cb491ea1c6abf94479cb6a7166a341827bce308da56bccd4", "archive_sha256": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979"}, {"url": "/docs/17/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 17 English manual", "sha256": "0ccd499b03dc7f8e803e7682cff147929ae032ff893dcf4b36e66a4480ef0b9a"}, {"url": "/docs/17/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 17 English manual", "sha256": "97385c16a0ff155ad89fe616bb074bf0a8328bcb21f5e64a7a6a0a03ddb1f4ef"}, {"url": "/docs/17/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 17 English manual", "sha256": "2f7caa1e26c93613937e7a6f422db31839f7aae55ee5c97f7b8807ff6b544e38"}, {"url": "/docs/17/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 17 English manual", "sha256": "919e02926ce8d5b206bb575cb8a1c5f60b2eee3d06cd375c0891fc779802b798"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filelocator = heapam_relation_set_new_filelocator,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_block = heapam_scan_bitmap_next_block,\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a061.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/17/catalog-pg-am.html\" title=\"51.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/17/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/17/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands. The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope. The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/17/storage-page-layout.html\" title=\"65.6.\u00a0Database Page Layout\">Section\u00a065.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/17/storage-page-layout.html\" title=\"65.6.\u00a0Database Page Layout\">Section\u00a065.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/17/wal.html\" title=\"Chapter\u00a028.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/17/generic-wal.html\" title=\"63.1.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a <a class=\"link\" href=\"/docs/17/custom-rmgr.html\" title=\"63.2.\u00a0Custom WAL Resource Managers\">Custom WAL Resource Manager</a> can be implemented.</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/17/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "relation_estimate_size": "heapam_estimate_rel_size", "scan_bitmap_next_block": "heapam_scan_bitmap_next_block", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "d129057b9afc0cb9f38d3137a9d84fd96a035ed851fab81db9903db8ab10aabd", "runtime_verified": false}, "18": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "43"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=18", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=18", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=18", "label": "Index AM"}], "release": {"ref": "PostgreSQL 18.6 source archive", "label": "18.6", "major": "18", "channel": "stable", "revision": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f", "source_url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/18/tableam.html", "path": "tableam.html", "label": "PostgreSQL 18 English manual", "sha256": "e659dece936c960dfea9e801720deb3d76abf2c3696abb3f58d32ac17d0f22aa"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "line": 2616, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2616", "sha256": "fd60a1f8d5530ce5c33fda6b74123c3c22e8c3b9ca6455a0e5d47aa392797a1e", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "/docs/18/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 18 English manual", "sha256": "456469051ccd15ec2cfa1f2e656901a3bb63414db367003215ff810d638593e1"}, {"url": "/docs/18/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 18 English manual", "sha256": "b4d703391fe1102d0e02bd6769bef928513eb7a5542f38f7448fc77fe69e0d5b"}, {"url": "/docs/18/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 18 English manual", "sha256": "ede8964df385f5bc69ae991369e6eaf99ae58aa2d6210e8bf868f090bb95b002"}, {"url": "/docs/18/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 18 English manual", "sha256": "579364179365a51945e2edb6481df5d198916c2c725e506f166824dedf08994c"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filelocator = heapam_relation_set_new_filelocator,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a062.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/18/catalog-pg-am.html\" title=\"52.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/18/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/18/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.</p>\n<p>Here is how an extension SQL script file might create a table access method handler:</p>\n<pre class=\"programlisting\">CREATE OR REPLACE FUNCTION my_tableam_handler(internal)\n  RETURNS table_am_handler AS 'my_extension', 'my_tableam_handler'\n  LANGUAGE C STRICT;\n\nCREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;\n</pre>\n<p>The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope.</p>\n<p>Here is how a source file with the table access method handler might look like:</p>\n<pre class=\"programlisting\">#include \"postgres.h\"\n\n#include \"access/tableam.h\"\n#include \"fmgr.h\"\n\nPG_MODULE_MAGIC;\n\nstatic const TableAmRoutine my_tableam_methods = {\n    .type = T_TableAmRoutine,\n\n    /* Methods of TableAmRoutine omitted from example, add them here. */\n};\n\nPG_FUNCTION_INFO_V1(my_tableam_handler);\n\nDatum\nmy_tableam_handler(PG_FUNCTION_ARGS)\n{\n    PG_RETURN_POINTER(&amp;my_tableam_methods);\n}\n\n</pre>\n<p>The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/18/wal.html\" title=\"Chapter\u00a028.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/18/generic-wal.html\" title=\"64.1.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a <a class=\"link\" href=\"/docs/18/custom-rmgr.html\" title=\"64.2.\u00a0Custom WAL Resource Managers\">Custom WAL Resource Manager</a> can be implemented.</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/18/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "1238506f6e6c6648382f3362465d376e28e55ca6108f975b44f413d320769112", "runtime_verified": false}, "19": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "43"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=19", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=19", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=19", "label": "Index AM"}], "release": {"ref": "PostgreSQL 19beta4 source archive", "label": "19beta4", "major": "19", "channel": "preview", "revision": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86", "source_url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/19/tableam.html", "path": "tableam.html", "label": "PostgreSQL 19 English manual", "sha256": "0dd4fc5fe12574339fd83f5a157add6d2bfcaa3a356e9b89fd1156c88e9814ce"}, {"url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "line": 2657, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2657", "sha256": "a4090217097bf16b0eedc5b0448092d640aa259a9ea9ab69caf582f910f9e911", "archive_sha256": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86"}, {"url": "/docs/19/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 19 English manual", "sha256": "edcdc2d76d4d3607abb61e52b63d43af97d3141beb5b050b4fed1e2e829846b0"}, {"url": "/docs/19/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 19 English manual", "sha256": "75f290d105bd0e76c798f124b1eed4ad1e871c8a1d36c35f0db9d38fbb7209f8"}, {"url": "/docs/19/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 19 English manual", "sha256": "11c034fb2035ad09a989c38a4bba17efd989a1e6856a234f0e56bd947b1c7372"}, {"url": "/docs/19/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 19 English manual", "sha256": "e3e87f797a302a2761b57510dbf48acc68ec635c8f538047c78ead25c2fba9aa"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filelocator = heapam_relation_set_new_filelocator,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a062.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/19/catalog-pg-am.html\" title=\"52.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/19/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/19/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.</p>\n<p>Here is how an extension SQL script file might create a table access method handler:</p>\n<pre class=\"programlisting\">CREATE OR REPLACE FUNCTION my_tableam_handler(internal)\n  RETURNS table_am_handler AS 'my_extension', 'my_tableam_handler'\n  LANGUAGE C STRICT;\n\nCREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;\n</pre>\n<p>The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope.</p>\n<p>Here is how a source file with the table access method handler might look like:</p>\n<pre class=\"programlisting\">#include \"postgres.h\"\n\n#include \"access/tableam.h\"\n#include \"fmgr.h\"\n\nPG_MODULE_MAGIC;\n\nstatic const TableAmRoutine my_tableam_methods = {\n    .type = T_TableAmRoutine,\n\n    /* Methods of TableAmRoutine omitted from example, add them here. */\n};\n\nPG_FUNCTION_INFO_V1(my_tableam_handler);\n\nDatum\nmy_tableam_handler(PG_FUNCTION_ARGS)\n{\n    PG_RETURN_POINTER(&amp;my_tableam_methods);\n}\n\n</pre>\n<p>The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/19/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/19/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/19/wal.html\" title=\"Chapter\u00a028.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/19/generic-wal.html\" title=\"64.1.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a <a class=\"link\" href=\"/docs/19/custom-rmgr.html\" title=\"64.2.\u00a0Custom WAL Resource Managers\">Custom WAL Resource Manager</a> can be implemented.</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/19/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "1238506f6e6c6648382f3362465d376e28e55ca6108f975b44f413d320769112", "runtime_verified": false}, "20": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "43"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_scan_begin", "implementation": "heapam_index_scan_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "fetch_tid", "implementation": "heapam_fetch_tid"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=20", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=20", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=20", "label": "Index AM"}], "release": {"ref": "PostgreSQL 20devel source archive", "label": "20devel", "major": "20", "channel": "devel", "revision": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41", "source_url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "source_snapshot_utc": "26-Sep-2026 20:22"}, "sources": [{"url": "/docs/devel/tableam.html", "path": "tableam.html", "label": "PostgreSQL 20 English manual", "sha256": "347e2a6c7355ed2e214ad4159c547b6ee2a8b8c226e2679b9ceaba80c2a8ba33"}, {"url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "line": 2652, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2652", "sha256": "7fe580def664c769e01f174552c19a6063594639183f43ce7b71d98f24400bd8", "archive_sha256": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41"}, {"url": "/docs/devel/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 20 English manual", "sha256": "ce5798f9f3a17538e466afba18c99632ee3cf7b56b0d536172934b8a6565fad7"}, {"url": "/docs/devel/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 20 English manual", "sha256": "5241bd673de4e7a8fec7db6fa2a3a50d8368965206170725c4efd15d64c3fbf2"}, {"url": "/docs/devel/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 20 English manual", "sha256": "b4497c9f953dbf5ca1800dc56b36eba0b08e01aa431c54a6e8f6f0c24f96cec8"}, {"url": "/docs/devel/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 20 English manual", "sha256": "8cc12dbe216ff5b905632e071bed2fa385851a1a7938929650cec7b810acda0d"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_scan_begin = heapam_index_scan_begin,\n\t.index_scan_reset = heapam_index_scan_reset,\n\t.index_scan_end = heapam_index_scan_end,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.fetch_tid = heapam_fetch_tid,\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filelocator = heapam_relation_set_new_filelocator,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "fetch_tid": "heapam_fetch_tid", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "index_scan_end": "heapam_index_scan_end", "slot_callbacks": "heapam_slot_callbacks", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "index_scan_begin": "heapam_index_scan_begin", "index_scan_reset": "heapam_index_scan_reset", "scan_getnextslot": "heap_getnextslot", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a062.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/devel/catalog-pg-am.html\" title=\"52.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/devel/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/devel/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.</p>\n<p>Here is how an extension SQL script file might create a table access method handler:</p>\n<pre class=\"programlisting\">CREATE OR REPLACE FUNCTION my_tableam_handler(internal)\n  RETURNS table_am_handler AS 'my_extension', 'my_tableam_handler'\n  LANGUAGE C STRICT;\n\nCREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;\n</pre>\n<p>The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope.</p>\n<p>Here is how a source file with the table access method handler might look like:</p>\n<pre class=\"programlisting\">#include \"postgres.h\"\n\n#include \"access/tableam.h\"\n#include \"fmgr.h\"\n\nPG_MODULE_MAGIC;\n\nstatic const TableAmRoutine my_tableam_methods = {\n    .type = T_TableAmRoutine,\n\n    /* Methods of TableAmRoutine omitted from example, add them here. */\n};\n\nPG_FUNCTION_INFO_V1(my_tableam_handler);\n\nDatum\nmy_tableam_handler(PG_FUNCTION_ARGS)\n{\n    PG_RETURN_POINTER(&amp;my_tableam_methods);\n}\n\n</pre>\n<p>The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/devel/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/devel/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/devel/wal.html\" title=\"Chapter\u00a028.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/devel/generic-wal.html\" title=\"64.1.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a <a class=\"link\" href=\"/docs/devel/custom-rmgr.html\" title=\"64.2.\u00a0Custom WAL Resource Managers\">Custom WAL Resource Manager</a> can be implemented.</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/devel/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "fetch_tid": "heapam_fetch_tid", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "index_scan_end": "heapam_index_scan_end", "slot_callbacks": "heapam_slot_callbacks", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "index_scan_begin": "heapam_index_scan_begin", "index_scan_reset": "heapam_index_scan_reset", "scan_getnextslot": "heap_getnextslot", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "6d11ecc470cf242732e93216296530e2737359721fd9832ecfc769e7062f62d7", "runtime_verified": false, "collection_tables": [{"key": "tableam-catalogue", "rows": [{"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "14.2.0", "postgres": "16, 17, 18", "extension": {"url": "/e/citus_columnar/", "text": "citus_columnar"}, "description": "Citus columnar storage engine"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "1.1.2", "postgres": "14, 15, 16", "extension": {"url": "/e/columnar/", "text": "columnar"}, "description": "Hydra Columnar extension"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.2.0", "postgres": "14, 15, 16, 17, 18", "extension": {"url": "/e/pg_mooncake/", "text": "pg_mooncake"}, "description": "Columnstore Table in Postgres"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "2.4.0", "postgres": "15, 16, 17, 18", "extension": {"url": "/e/storage_engine/", "text": "storage_engine"}, "description": "colcompress and rowcompress Table Access Methods with vectorized execution"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.1", "postgres": "12, 13, 14, 15, 16, 17, 18", "extension": {"url": "/e/pg_cryogen/", "text": "pg_cryogen"}, "description": "Experimental append-only compressed table access method for PostgreSQL 12 and later."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.1", "postgres": "Unknown", "extension": {"url": "/e/undam/", "text": "undam"}, "description": "UNDO storage table access method with in-place updates"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "1.0", "postgres": "12, 13", "extension": {"url": "/e/tcle/", "text": "tcle"}, "description": "Experimental table access method for transparent AES-256-CBC encryption of selected column types."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "1.0", "postgres": "Unknown", "extension": {"url": "/e/append_only_heap/", "text": "append_only_heap"}, "description": "PostgreSQL table access method that avoids fragmentation of variable-length append-only data."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.0.0", "postgres": "11, 12, 13, 14, 15, 16", "extension": {"url": "/e/redis_backed_storage/", "text": "redis_backed_storage"}, "description": "Experimental PostgreSQL table access method backed by Redis storage."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.1.0", "postgres": "15, 16", "extension": {"url": "/e/pgrand/", "text": "pgrand"}, "description": "Generates random test data through a PostgreSQL FDW, with an experimental table access method."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.0.0", "postgres": "16, 17", "extension": {"url": "/e/pg_elephantduck/", "text": "pg_elephantduck"}, "description": "Columnar PostgreSQL table access method powered by DuckDB and Parquet storage."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.0.1", "postgres": "Unknown", "extension": {"url": "/e/csv_tam/", "text": "csv_tam"}, "description": "CSV table access method for PostgreSQL that stores table tuples in CSV-formatted relation files."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.0.1", "postgres": "Unknown", "extension": {"url": "/e/pgtam/", "text": "pgtam"}, "description": "Experimental in-memory PostgreSQL table access method implemented as a C extension."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.0.1", "postgres": "Unknown", "extension": {"url": "/e/gfs/", "text": "gfs"}, "description": "GFS copy-on-read storage: a Table Access Method whose missing rows are fetched from the source on read and written through locally"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.1.0", "postgres": "Unknown", "extension": {"url": "/e/pg_delta_am/", "text": "pg_delta_am"}, "description": "Delta table access method skeleton"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "0.1", "postgres": "Unknown", "extension": {"url": "/e/traceam/", "text": "traceam"}, "description": "Simple table access method that just prints out what functions in the access methods and related functions that are called."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "1.0", "postgres": "Unknown", "extension": {"url": "/e/treedb_pgext/", "text": "treedb_pgext"}, "description": "TreeDB table access method (Phase 0 prototype)"}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-30", "version": "2.4.0", "postgres": "16, 17, 18", "extension": {"url": "/e/open_pg_tde/", "text": "open_pg_tde"}, "description": "Transparent data encryption for upstream PostgreSQL using the tde_heap access method, including tables, indexes, TOAST, WAL, and temporary files."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-31", "version": "1.7.0", "postgres": "Unknown", "extension": {"url": "/e/autocluster/", "text": "autocluster"}, "description": "EDB table access method that preserves clustering locality during inserts."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-31", "version": "1.7.0", "postgres": "15, 16, 17, 18", "extension": {"url": "/e/bluefin/", "text": "bluefin"}, "description": "Append-only compressed table access method for time-series workloads."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-31", "version": "1.0", "postgres": "17", "extension": {"url": "/e/optimized_row_format/", "text": "optimized_row_format"}, "description": "Experimental table access method for compact, cache-friendly row storage."}, {"scope": "Primary documentation reviewed separately below", "checked": "2026-09-19", "version": "1.0-alpha4", "postgres": "15, 16, 17, 18, 19", "extension": {"url": "/e/pgcolumnar/", "text": "pgcolumnar"}, "description": "Native column-oriented table access method with compression, vectorized scans, and Parquet workflows."}, {"scope": "Catalogue candidate; interface unverified", "checked": "2026-08-31", "version": "1.7.0", "postgres": "Unknown", "extension": {"url": "/e/refdata/", "text": "refdata"}, "description": "EDB table access method for frequently read, rarely changed reference data."}], "title": "Table AM candidates", "caption": "Current catalogue observation 2026-09-29 from pgext.universe. Extension versions, source metadata dates and declared PostgreSQL compatibility are independent of the selected core version. Catalogue classification does not establish capabilities or maintenance support.", "columns": [{"key": "extension", "label": "Existing extension"}, {"key": "version", "label": "Catalogued version"}, {"key": "postgres", "label": "Declared PG majors"}, {"key": "checked", "label": "Metadata checked"}, {"key": "scope", "label": "Evidence scope"}, {"key": "description", "label": "Catalogued purpose"}]}, {"key": "tableam-reviewed-capabilities", "rows": [{"state": "Verified in documentation", "detail": "Native columnar Table AM. This reviewed version is an alpha release.", "version": "1.0-alpha4", "evidence": {"url": "https://github.com/commandprompt/pgcolumnar/blob/0d3100dd4fa76d1b915826be742e9286f621bc29/README.md", "text": "2026-09-29 \u00b7 0d3100dd4fa7 \u00b7 README.md"}, "extension": {"url": "/e/pgcolumnar/", "text": "pgcolumnar"}, "capability": "Table AM identity"}, {"state": "Conditional", "detail": "The planner can create parallel columnar scans; cost and worker settings determine plan selection.", "version": "1.0-alpha4", "evidence": {"url": "https://github.com/commandprompt/pgcolumnar/blob/0d3100dd4fa76d1b915826be742e9286f621bc29/docs/limitations.md", "text": "2026-09-29 \u00b7 0d3100dd4fa7 \u00b7 docs/limitations.md"}, "extension": {"url": "/e/pgcolumnar/", "text": "pgcolumnar"}, "capability": "Parallel scans"}, {"state": "Conditional", "detail": "Its own vacuum performs no parallel work. CLUSTER, VACUUM FULL and REPACK are rejected; extension compaction functions provide alternatives.", "version": "1.0-alpha4", "evidence": {"url": "https://github.com/commandprompt/pgcolumnar/blob/0d3100dd4fa76d1b915826be742e9286f621bc29/docs/limitations.md", "text": "2026-09-29 \u00b7 0d3100dd4fa7 \u00b7 docs/limitations.md"}, "extension": {"url": "/e/pgcolumnar/", "text": "pgcolumnar"}, "capability": "Maintenance"}, {"state": "Verified limitation", "detail": "Sampling a columnar table raises an unsupported-operation error.", "version": "1.0-alpha4", "evidence": {"url": "https://github.com/commandprompt/pgcolumnar/blob/0d3100dd4fa76d1b915826be742e9286f621bc29/docs/limitations.md", "text": "2026-09-29 \u00b7 0d3100dd4fa7 \u00b7 docs/limitations.md"}, "extension": {"url": "/e/pgcolumnar/", "text": "pgcolumnar"}, "capability": "TABLESAMPLE"}, {"state": "Unknown", "detail": "No distributed transaction guarantee was established by this review.", "version": "1.0-alpha4", "evidence": {"url": "https://github.com/commandprompt/pgcolumnar/blob/0d3100dd4fa76d1b915826be742e9286f621bc29/README.md", "text": "2026-09-29 \u00b7 0d3100dd4fa7 \u00b7 README.md"}, "extension": {"url": "/e/pgcolumnar/", "text": "pgcolumnar"}, "capability": "Distributed transaction guarantees"}], "title": "Primary-source capability observations", "caption": "Each statement applies to its named extension version and immutable source revision. Unlisted capabilities remain unknown. These are documentation observations, not runtime tests or current maintenance guarantees.", "columns": [{"key": "extension", "label": "Extension"}, {"key": "version", "label": "Reviewed version"}, {"key": "capability", "label": "Capability"}, {"key": "state", "label": "Evidence state"}, {"key": "detail", "label": "Conditions"}, {"key": "evidence", "label": "Evidence date and source"}]}], "extension_reviews": [{"kind": "tableam", "name": "pgcolumnar", "claims": [{"text": "Native columnar Table AM. This reviewed version is an alpha release.", "label": "Table AM identity", "state": "Verified in documentation"}, {"text": "The planner can create parallel columnar scans; cost and worker settings determine plan selection.", "label": "Parallel scans", "state": "Conditional", "source": 1}, {"text": "Its own vacuum performs no parallel work. CLUSTER, VACUUM FULL and REPACK are rejected; extension compaction functions provide alternatives.", "label": "Maintenance", "state": "Conditional", "source": 1}, {"text": "Sampling a columnar table raises an unsupported-operation error.", "label": "TABLESAMPLE", "state": "Verified limitation", "source": 1}, {"text": "No distributed transaction guarantee was established by this review.", "label": "Distributed transaction guarantees", "state": "Unknown"}], "sources": [{"url": "https://github.com/commandprompt/pgcolumnar/blob/0d3100dd4fa76d1b915826be742e9286f621bc29/README.md", "path": "README.md", "sha256": "dd3196db0ded36ff24d23bf5feb4e2163af784f3b7c0adc9cfc478497a1d5594", "local_name": "pgcolumnar-readme.txt"}, {"url": "https://github.com/commandprompt/pgcolumnar/blob/0d3100dd4fa76d1b915826be742e9286f621bc29/docs/limitations.md", "path": "docs/limitations.md", "sha256": "0133a61c17deba51ffd8e935785614c8e456bb52afe78de465d76f9524c6f521", "local_name": "pgcolumnar-limitations.txt"}], "version": "1.0-alpha4", "revision": "0d3100dd4fa76d1b915826be742e9286f621bc29", "checked_at": "2026-09-29"}], "catalog_observation": {"sha256": "a8f35f83709025575037ce50331f20fc27727e478464e35b48bb501e687cc121", "source": "data.pgext.universe", "identities": [{"id": 2401, "name": "citus_columnar"}, {"id": 2410, "name": "columnar"}, {"id": 2440, "name": "pg_mooncake"}, {"id": 2450, "name": "storage_engine"}, {"id": 100054, "name": "pg_cryogen"}, {"id": 100158, "name": "undam"}, {"id": 100199, "name": "tcle"}, {"id": 100517, "name": "append_only_heap"}, {"id": 100860, "name": "redis_backed_storage"}, {"id": 100918, "name": "pgrand"}, {"id": 100934, "name": "pg_elephantduck"}, {"id": 100973, "name": "csv_tam"}, {"id": 101123, "name": "pgtam"}, {"id": 101375, "name": "gfs"}, {"id": 101534, "name": "pg_delta_am"}, {"id": 101816, "name": "traceam"}, {"id": 101817, "name": "treedb_pgext"}, {"id": 101845, "name": "open_pg_tde"}, {"id": 101866, "name": "autocluster"}, {"id": 101868, "name": "bluefin"}, {"id": 101896, "name": "optimized_row_format"}, {"id": 101942, "name": "pgcolumnar"}, {"id": 101954, "name": "refdata"}], "observed_at": "2026-09-29T15:02:21.407129+00:00", "catalogue_rows": 2452, "candidate_count": 23}}}}, "snapshot": {"facts": [{"label": "Interface family", "value": "Table access method"}, {"label": "Handler or routine", "value": "heapam_methods"}, {"label": "Recorded callbacks", "value": "43"}], "tables": [{"key": "callbacks", "rows": [{"state": "Handler registered; conditions apply", "feature": "Tuple slot", "callback": "slot_callbacks", "implementation": "heapam_slot_callbacks"}, {"state": "Handler registered; conditions apply", "feature": "Begin scan", "callback": "scan_begin", "implementation": "heap_beginscan"}, {"state": "Handler registered; conditions apply", "feature": "Parallel scan initialization", "callback": "parallelscan_initialize", "implementation": "table_block_parallelscan_initialize"}, {"state": "Handler registered; conditions apply", "feature": "Begin index lookup", "callback": "index_fetch_begin", "implementation": "heapam_index_fetch_begin"}, {"state": "Handler registered; conditions apply", "feature": "Fetch identified tuple", "callback": "index_fetch_tuple", "implementation": "heapam_index_fetch_tuple"}, {"state": "Handler registered; conditions apply", "feature": "Insert tuple", "callback": "tuple_insert", "implementation": "heapam_tuple_insert"}, {"state": "Handler registered; conditions apply", "feature": "Update tuple", "callback": "tuple_update", "implementation": "heapam_tuple_update"}, {"state": "Handler registered; conditions apply", "feature": "Delete tuple", "callback": "tuple_delete", "implementation": "heapam_tuple_delete"}, {"state": "Handler registered; conditions apply", "feature": "Vacuum relation", "callback": "relation_vacuum", "implementation": "heap_vacuum_rel"}, {"state": "Handler registered; conditions apply", "feature": "Analyze block", "callback": "scan_analyze_next_block", "implementation": "heapam_scan_analyze_next_block"}, {"state": "Handler registered; conditions apply", "feature": "TOAST decision", "callback": "relation_needs_toast_table", "implementation": "heapam_relation_needs_toast_table"}], "title": "Registered interface handlers", "columns": [{"key": "feature", "label": "Interface operation"}, {"key": "state", "label": "Source observation"}, {"key": "callback", "label": "Callback"}, {"key": "implementation", "label": "Implementation"}]}], "related": [{"url": "/wiki/catalog/pg_am/?v=18", "label": "System catalog pg_am"}, {"url": "/wiki/guc/default_table_access_method/?v=18", "label": "default_table_access_method"}, {"url": "/wiki/indexam/?v=18", "label": "Index AM"}], "release": {"ref": "PostgreSQL 18.6 source archive", "label": "18.6", "major": "18", "channel": "stable", "revision": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f", "source_url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "/docs/18/tableam.html", "path": "tableam.html", "label": "PostgreSQL 18 English manual", "sha256": "e659dece936c960dfea9e801720deb3d76abf2c3696abb3f58d32ac17d0f22aa"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "line": 2616, "path": "src/backend/access/heap/heapam_handler.c", "label": "src/backend/access/heap/heapam_handler.c:2616", "sha256": "fd60a1f8d5530ce5c33fda6b74123c3c22e8c3b9ca6455a0e5d47aa392797a1e", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "/docs/18/mvcc-intro.html", "path": "mvcc-intro.html", "label": "PostgreSQL 18 English manual", "sha256": "456469051ccd15ec2cfa1f2e656901a3bb63414db367003215ff810d638593e1"}, {"url": "/docs/18/sql-createtable.html", "path": "sql-createtable.html", "label": "PostgreSQL 18 English manual", "sha256": "b4d703391fe1102d0e02bd6769bef928513eb7a5542f38f7448fc77fe69e0d5b"}, {"url": "/docs/18/routine-vacuuming.html", "path": "routine-vacuuming.html", "label": "PostgreSQL 18 English manual", "sha256": "ede8964df385f5bc69ae991369e6eaf99ae58aa2d6210e8bf868f090bb95b002"}, {"url": "/docs/18/catalog-pg-am.html", "path": "catalog-pg-am.html", "label": "PostgreSQL 18 English manual", "sha256": "579364179365a51945e2edb6481df5d198916c2c725e506f166824dedf08994c"}], "sections": [{"title": "Interface and capability boundaries", "paragraphs": ["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."]}, {"title": "Heap storage, visibility and WAL", "paragraphs": ["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."]}, {"code": "{\n\t.type = T_TableAmRoutine,\n\n\t.slot_callbacks = heapam_slot_callbacks,\n\n\t.scan_begin = heap_beginscan,\n\t.scan_end = heap_endscan,\n\t.scan_rescan = heap_rescan,\n\t.scan_getnextslot = heap_getnextslot,\n\n\t.scan_set_tidrange = heap_set_tidrange,\n\t.scan_getnextslot_tidrange = heap_getnextslot_tidrange,\n\n\t.parallelscan_estimate = table_block_parallelscan_estimate,\n\t.parallelscan_initialize = table_block_parallelscan_initialize,\n\t.parallelscan_reinitialize = table_block_parallelscan_reinitialize,\n\n\t.index_fetch_begin = heapam_index_fetch_begin,\n\t.index_fetch_reset = heapam_index_fetch_reset,\n\t.index_fetch_end = heapam_index_fetch_end,\n\t.index_fetch_tuple = heapam_index_fetch_tuple,\n\n\t.tuple_insert = heapam_tuple_insert,\n\t.tuple_insert_speculative = heapam_tuple_insert_speculative,\n\t.tuple_complete_speculative = heapam_tuple_complete_speculative,\n\t.multi_insert = heap_multi_insert,\n\t.tuple_delete = heapam_tuple_delete,\n\t.tuple_update = heapam_tuple_update,\n\t.tuple_lock = heapam_tuple_lock,\n\n\t.tuple_fetch_row_version = heapam_fetch_row_version,\n\t.tuple_get_latest_tid = heap_get_latest_tid,\n\t.tuple_tid_valid = heapam_tuple_tid_valid,\n\t.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,\n\t.index_delete_tuples = heap_index_delete_tuples,\n\n\t.relation_set_new_filelocator = heapam_relation_set_new_filelocator,\n\t.relation_nontransactional_truncate = heapam_relation_nontransactional_truncate,\n\t.relation_copy_data = heapam_relation_copy_data,\n\t.relation_copy_for_cluster = heapam_relation_copy_for_cluster,\n\t.relation_vacuum = heap_vacuum_rel,\n\t.scan_analyze_next_block = heapam_scan_analyze_next_block,\n\t.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,\n\t.index_build_range_scan = heapam_index_build_range_scan,\n\t.index_validate_scan = heapam_index_validate_scan,\n\n\t.relation_size = table_block_relation_size,\n\t.relation_needs_toast_table = heapam_relation_needs_toast_table,\n\t.relation_toast_am = heapam_relation_toast_am,\n\t.relation_fetch_toast_slice = heap_fetch_toast_slice,\n\n\t.relation_estimate_size = heapam_estimate_rel_size,\n\n\t.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple,\n\t.scan_sample_next_block = heapam_scan_sample_next_block,\n\t.scan_sample_next_tuple = heapam_scan_sample_next_tuple\n}", "title": "Registered implementation in core source"}], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "description": ["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."], "manual_html": "<div class=\"chapter\" id=\"TABLEAM\">\n<div class=\"titlepage\">\n<div>\n<div>\n<h2 class=\"title\">Chapter\u00a062.\u00a0Table Access Method Interface Definition</h2>\n</div>\n</div>\n</div>\n<p>This chapter explains the interface between the core <span class=\"productname\">PostgreSQL</span> system and <em class=\"firstterm\">table access methods</em>, 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.</p>\n<p>Each table access method is described by a row in the <a class=\"link\" href=\"/docs/18/catalog-pg-am.html\" title=\"52.3.\u00a0pg_am\"><code class=\"structname\">pg_am</code></a> system catalog. The <code class=\"structname\">pg_am</code> entry specifies a name and a <em class=\"firstterm\">handler function</em> for the table access method. These entries can be created and deleted using the <a class=\"xref\" href=\"/docs/18/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"><span class=\"refentrytitle\">CREATE ACCESS METHOD</span></a> and <a class=\"xref\" href=\"/docs/18/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"><span class=\"refentrytitle\">DROP ACCESS METHOD</span></a> SQL commands.</p>\n<p>A table access method handler function must be declared to accept a single argument of type <code class=\"type\">internal</code> and to return the pseudo-type <code class=\"type\">table_am_handler</code>. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.</p>\n<p>Here is how an extension SQL script file might create a table access method handler:</p>\n<pre class=\"programlisting\">CREATE OR REPLACE FUNCTION my_tableam_handler(internal)\n  RETURNS table_am_handler AS 'my_extension', 'my_tableam_handler'\n  LANGUAGE C STRICT;\n\nCREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;\n</pre>\n<p>The result of the function must be a pointer to a struct of type <code class=\"structname\">TableAmRoutine</code>, 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 <code class=\"literal\">static const</code> variable in global scope.</p>\n<p>Here is how a source file with the table access method handler might look like:</p>\n<pre class=\"programlisting\">#include \"postgres.h\"\n\n#include \"access/tableam.h\"\n#include \"fmgr.h\"\n\nPG_MODULE_MAGIC;\n\nstatic const TableAmRoutine my_tableam_methods = {\n    .type = T_TableAmRoutine,\n\n    /* Methods of TableAmRoutine omitted from example, add them here. */\n};\n\nPG_FUNCTION_INFO_V1(my_tableam_handler);\n\nDatum\nmy_tableam_handler(PG_FUNCTION_ARGS)\n{\n    PG_RETURN_POINTER(&amp;my_tableam_methods);\n}\n\n</pre>\n<p>The <code class=\"structname\">TableAmRoutine</code> struct, also called the access method's <em class=\"firstterm\">API struct</em>, 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 <code class=\"structname\">TableAmRoutine</code> 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 <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"><code class=\"filename\">src/include/access/tableam.h</code></a> file.</p>\n<p>To implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see <a class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"><code class=\"filename\">src/include/executor/tuptable.h</code></a>), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.</p>\n<p>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 <span class=\"productname\">PostgreSQL</span>'s standard page layout as described in <a class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>.</p>\n<p>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 <a class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6.\u00a0Database Page Layout\">Section\u00a066.6</a>). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for <code class=\"literal\">heap</code>, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.</p>\n<p>For crash safety, an AM can use postgres' <a class=\"link\" href=\"/docs/18/wal.html\" title=\"Chapter\u00a028.\u00a0Reliability and the Write-Ahead Log\">WAL</a>, or a custom implementation. If WAL is chosen, either <a class=\"link\" href=\"/docs/18/generic-wal.html\" title=\"64.1.\u00a0Generic WAL Records\">Generic WAL Records</a> can be used, or a <a class=\"link\" href=\"/docs/18/custom-rmgr.html\" title=\"64.2.\u00a0Custom WAL Resource Managers\">Custom WAL Resource Manager</a> can be implemented.</p>\n<p>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 <code class=\"filename\">src/backend/access/transam/xlog.c</code>.</p>\n<p>Any developer of a new <code class=\"literal\">table access method</code> can refer to the existing <code class=\"literal\">heap</code> implementation present in <code class=\"filename\">src/backend/access/heap/heapam_handler.c</code> for details of its implementation.</p>\n</div>", "manual_path": "/docs/18/tableam.html", "evidence_kind": "source and documentation", "comparison_data": {"options": [], "callbacks": {"scan_end": "heap_endscan", "scan_begin": "heap_beginscan", "tuple_lock": "heapam_tuple_lock", "scan_rescan": "heap_rescan", "multi_insert": "heap_multi_insert", "tuple_delete": "heapam_tuple_delete", "tuple_insert": "heapam_tuple_insert", "tuple_update": "heapam_tuple_update", "relation_size": "table_block_relation_size", "slot_callbacks": "heapam_slot_callbacks", "index_fetch_end": "heapam_index_fetch_end", "relation_vacuum": "heap_vacuum_rel", "tuple_tid_valid": "heapam_tuple_tid_valid", "scan_getnextslot": "heap_getnextslot", "index_fetch_begin": "heapam_index_fetch_begin", "index_fetch_reset": "heapam_index_fetch_reset", "index_fetch_tuple": "heapam_index_fetch_tuple", "relation_toast_am": "heapam_relation_toast_am", "scan_set_tidrange": "heap_set_tidrange", "relation_copy_data": "heapam_relation_copy_data", "index_delete_tuples": "heap_index_delete_tuples", "index_validate_scan": "heapam_index_validate_scan", "tuple_get_latest_tid": "heap_get_latest_tid", "parallelscan_estimate": "table_block_parallelscan_estimate", "index_build_range_scan": "heapam_index_build_range_scan", "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", "parallelscan_initialize": "table_block_parallelscan_initialize", "scan_analyze_next_block": "heapam_scan_analyze_next_block", "scan_analyze_next_tuple": "heapam_scan_analyze_next_tuple", "tuple_fetch_row_version": "heapam_fetch_row_version", "tuple_insert_speculative": "heapam_tuple_insert_speculative", "tuple_satisfies_snapshot": "heapam_tuple_satisfies_snapshot", "parallelscan_reinitialize": "table_block_parallelscan_reinitialize", "relation_copy_for_cluster": "heapam_relation_copy_for_cluster", "scan_getnextslot_tidrange": "heap_getnextslot_tidrange", "relation_fetch_toast_slice": "heap_fetch_toast_slice", "relation_needs_toast_table": "heapam_relation_needs_toast_table", "tuple_complete_speculative": "heapam_tuple_complete_speculative", "relation_set_new_filelocator": "heapam_relation_set_new_filelocator", "relation_nontransactional_truncate": "heapam_relation_nontransactional_truncate"}, "source_options": [], "protocol_versions": {}}, "comparison_hash": "1238506f6e6c6648382f3362465d376e28e55ca6108f975b44f413d320769112", "runtime_verified": false}, "comparison": {"left": "12", "right": "13", "status": "changed", "diff": "--- PostgreSQL 12\n+++ PostgreSQL 13\n@@ -1,7 +1,6 @@\n {\n   \"callbacks\": {\n     \"compute_xid_horizon_for_tuples\": \"heap_compute_xid_horizon_for_tuples\",\n-    \"finish_bulk_insert\": \"heapam_finish_bulk_insert\",\n     \"index_build_range_scan\": \"heapam_index_build_range_scan\",\n     \"index_fetch_begin\": \"heapam_index_fetch_begin\",\n     \"index_fetch_end\": \"heapam_index_fetch_end\",\n@@ -15,10 +14,12 @@\n     \"relation_copy_data\": \"heapam_relation_copy_data\",\n     \"relation_copy_for_cluster\": \"heapam_relation_copy_for_cluster\",\n     \"relation_estimate_size\": \"heapam_estimate_rel_size\",\n+    \"relation_fetch_toast_slice\": \"heap_fetch_toast_slice\",\n     \"relation_needs_toast_table\": \"heapam_relation_needs_toast_table\",\n     \"relation_nontransactional_truncate\": \"heapam_relation_nontransactional_truncate\",\n     \"relation_set_new_filenode\": \"heapam_relation_set_new_filenode\",\n-    \"relation_size\": \"heapam_relation_size\",\n+    \"relation_size\": \"table_block_relation_size\",\n+    \"relation_toast_am\": \"heapam_relation_toast_am\",\n     \"relation_vacuum\": \"heap_vacuum_rel\",\n     \"scan_analyze_next_block\": \"heapam_scan_analyze_next_block\",\n     \"scan_analyze_next_tuple\": \"heapam_scan_analyze_next_tuple\","}}