{"Entry":{"collection":"tableam","key":"heap","name":"heap","aliases":[],"metadata":{"aliases":[],"category":"Core table AM","content_hash":"1612ad33787d9f68db16cce2bce26afa690606249036105dea14c90c64b68b36","derived_content_hash":"f75b72cec1c68853b17c139973045e32469027ab83cb5f6999c0b4de9b9829fc","imported_at":"2026-09-30T00:40:47.142241+08:00","name":"heap","name_zh":"Core table AM","slug":"heap","summary":"The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."}},"Definition":{"Collection":"tableam","Key":"heap","SourceDatabase":"center","Version":"18","SourceTable":"table_am","SourceKey":"heap","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","Facts":{"callbacks":{"index_build_range_scan":"heapam_index_build_range_scan","index_delete_tuples":"heap_index_delete_tuples","index_fetch_begin":"heapam_index_fetch_begin","index_fetch_end":"heapam_index_fetch_end","index_fetch_reset":"heapam_index_fetch_reset","index_fetch_tuple":"heapam_index_fetch_tuple","index_validate_scan":"heapam_index_validate_scan","multi_insert":"heap_multi_insert","parallelscan_estimate":"table_block_parallelscan_estimate","parallelscan_initialize":"table_block_parallelscan_initialize","parallelscan_reinitialize":"table_block_parallelscan_reinitialize","relation_copy_data":"heapam_relation_copy_data","relation_copy_for_cluster":"heapam_relation_copy_for_cluster","relation_estimate_size":"heapam_estimate_rel_size","relation_fetch_toast_slice":"heap_fetch_toast_slice","relation_needs_toast_table":"heapam_relation_needs_toast_table","relation_nontransactional_truncate":"heapam_relation_nontransactional_truncate","relation_set_new_filelocator":"heapam_relation_set_new_filelocator","relation_size":"table_block_relation_size","relation_toast_am":"heapam_relation_toast_am","relation_vacuum":"heap_vacuum_rel","scan_analyze_next_block":"heapam_scan_analyze_next_block","scan_analyze_next_tuple":"heapam_scan_analyze_next_tuple","scan_begin":"heap_beginscan","scan_bitmap_next_tuple":"heapam_scan_bitmap_next_tuple","scan_end":"heap_endscan","scan_getnextslot":"heap_getnextslot","scan_getnextslot_tidrange":"heap_getnextslot_tidrange","scan_rescan":"heap_rescan","scan_sample_next_block":"heapam_scan_sample_next_block","scan_sample_next_tuple":"heapam_scan_sample_next_tuple","scan_set_tidrange":"heap_set_tidrange","slot_callbacks":"heapam_slot_callbacks","tuple_complete_speculative":"heapam_tuple_complete_speculative","tuple_delete":"heapam_tuple_delete","tuple_fetch_row_version":"heapam_fetch_row_version","tuple_get_latest_tid":"heap_get_latest_tid","tuple_insert":"heapam_tuple_insert","tuple_insert_speculative":"heapam_tuple_insert_speculative","tuple_lock":"heapam_tuple_lock","tuple_satisfies_snapshot":"heapam_tuple_satisfies_snapshot","tuple_tid_valid":"heapam_tuple_tid_valid","tuple_update":"heapam_tuple_update"},"comparison_data":{"callbacks":{"index_build_range_scan":"heapam_index_build_range_scan","index_delete_tuples":"heap_index_delete_tuples","index_fetch_begin":"heapam_index_fetch_begin","index_fetch_end":"heapam_index_fetch_end","index_fetch_reset":"heapam_index_fetch_reset","index_fetch_tuple":"heapam_index_fetch_tuple","index_validate_scan":"heapam_index_validate_scan","multi_insert":"heap_multi_insert","parallelscan_estimate":"table_block_parallelscan_estimate","parallelscan_initialize":"table_block_parallelscan_initialize","parallelscan_reinitialize":"table_block_parallelscan_reinitialize","relation_copy_data":"heapam_relation_copy_data","relation_copy_for_cluster":"heapam_relation_copy_for_cluster","relation_estimate_size":"heapam_estimate_rel_size","relation_fetch_toast_slice":"heap_fetch_toast_slice","relation_needs_toast_table":"heapam_relation_needs_toast_table","relation_nontransactional_truncate":"heapam_relation_nontransactional_truncate","relation_set_new_filelocator":"heapam_relation_set_new_filelocator","relation_size":"table_block_relation_size","relation_toast_am":"heapam_relation_toast_am","relation_vacuum":"heap_vacuum_rel","scan_analyze_next_block":"heapam_scan_analyze_next_block","scan_analyze_next_tuple":"heapam_scan_analyze_next_tuple","scan_begin":"heap_beginscan","scan_bitmap_next_tuple":"heapam_scan_bitmap_next_tuple","scan_end":"heap_endscan","scan_getnextslot":"heap_getnextslot","scan_getnextslot_tidrange":"heap_getnextslot_tidrange","scan_rescan":"heap_rescan","scan_sample_next_block":"heapam_scan_sample_next_block","scan_sample_next_tuple":"heapam_scan_sample_next_tuple","scan_set_tidrange":"heap_set_tidrange","slot_callbacks":"heapam_slot_callbacks","tuple_complete_speculative":"heapam_tuple_complete_speculative","tuple_delete":"heapam_tuple_delete","tuple_fetch_row_version":"heapam_fetch_row_version","tuple_get_latest_tid":"heap_get_latest_tid","tuple_insert":"heapam_tuple_insert","tuple_insert_speculative":"heapam_tuple_insert_speculative","tuple_lock":"heapam_tuple_lock","tuple_satisfies_snapshot":"heapam_tuple_satisfies_snapshot","tuple_tid_valid":"heapam_tuple_tid_valid","tuple_update":"heapam_tuple_update"},"options":[],"protocol_versions":{},"source_options":[]},"comparison_hash":"1238506f6e6c6648382f3362465d376e28e55ca6108f975b44f413d320769112","description":["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."],"description_zh":"本章说明 PostgreSQL 核心系统与管理表存储的 表访问方法 之间的接口。除这里规定的内容之外，核心系统对这些访问方法知之甚少，因此可以通过编写附加代码来开发全新的访问方法类型。 每个表访问方法都由系统目录 pg_am 中的一行描述。 pg_am 条目指定了该表访问方法的名称以及一个 处理器函数 。这些条目可以通过 CREATE ACCESS METHOD 和 DROP ACCESS METHOD SQL 命令创建和删除。 表访问方法的处理器函数必须声明为接受一个 internal 类型的参数，并返回伪类型 table_am_handler 。这个参数只是一个占位值，用来防止处理器函数被 SQL 命令直接调用。 下面展示扩展 SQL 脚本文件如何创建表访问方法处理器：","description_zh_html":"\u003cp\u003e表访问方法 heap。\u003c/p\u003e\u003ch3\u003e同版本中文手册节选\u003c/h3\u003e\u003cp\u003e\n  本章说明 \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e 核心系统与管理表存储的\u003cem class=\"firstterm\"\u003e表访问方法\u003c/em\u003e之间的接口。除这里规定的内容之外，核心系统对这些访问方法知之甚少，因此可以通过编写附加代码来开发全新的访问方法类型。\n \u003c/p\u003e\u003cp\u003e\n  每个表访问方法都由系统目录 \u003ca class=\"link\" href=\"/zh/docs/18/catalog-pg-am.html\"\u003e\u003ccode class=\"structname\"\u003epg_am\u003c/code\u003e\u003c/a\u003e 中的一行描述。\u003ccode class=\"structname\"\u003epg_am\u003c/code\u003e 条目指定了该表访问方法的名称以及一个\u003cem class=\"firstterm\"\u003e处理器函数\u003c/em\u003e。这些条目可以通过 \u003ca class=\"xref\" href=\"/zh/docs/18/sql-create-access-method.html\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE ACCESS METHOD\u003c/span\u003e\u003c/a\u003e 和 \u003ca class=\"xref\" href=\"/zh/docs/18/sql-drop-access-method.html\"\u003e\u003cspan class=\"refentrytitle\"\u003eDROP ACCESS METHOD\u003c/span\u003e\u003c/a\u003e SQL 命令创建和删除。\n \u003c/p\u003e\u003cp\u003e\n  表访问方法的处理器函数必须声明为接受一个 \u003ccode class=\"type\"\u003einternal\u003c/code\u003e 类型的参数，并返回伪类型\n  \u003ccode class=\"type\"\u003etable_am_handler\u003c/code\u003e。这个参数只是一个占位值，用来防止处理器函数被 SQL 命令直接调用。\n \u003c/p\u003e\u003cp\u003e\n  下面展示扩展 SQL 脚本文件如何创建表访问方法处理器：\n \u003c/p\u003e\u003cp\u003e\u003ca href=\"/zh/docs/18/tableam.html\"\u003e查看完整中文手册与上下文\u003c/a\u003e。\u003c/p\u003e","evidence_kind":"source and documentation","facts":[{"label":"Interface family","value":"Table access method"},{"label":"Handler or routine","value":"heapam_methods"},{"label":"Recorded callbacks","value":"43"}],"facts_zh":[{"label":"接口类别","value":"表访问方法"},{"label":"处理函数或例程","value":"heapam_methods"},{"label":"记录的回调","value":"43"}],"manual_html":"\u003cdiv class=\"chapter\" id=\"TABLEAM\"\u003e\n\u003cdiv class=\"titlepage\"\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003ch2 class=\"title\"\u003eChapter 62. Table Access Method Interface Definition\u003c/h2\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003eThis chapter explains the interface between the core \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e system and \u003cem class=\"firstterm\"\u003etable access methods\u003c/em\u003e, 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.\u003c/p\u003e\n\u003cp\u003eEach table access method is described by a row in the \u003ca class=\"link\" href=\"/docs/18/catalog-pg-am.html\" title=\"52.3. pg_am\"\u003e\u003ccode class=\"structname\"\u003epg_am\u003c/code\u003e\u003c/a\u003e system catalog. The \u003ccode class=\"structname\"\u003epg_am\u003c/code\u003e entry specifies a name and a \u003cem class=\"firstterm\"\u003ehandler function\u003c/em\u003e for the table access method. These entries can be created and deleted using the \u003ca class=\"xref\" href=\"/docs/18/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE ACCESS METHOD\u003c/span\u003e\u003c/a\u003e and \u003ca class=\"xref\" href=\"/docs/18/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"\u003e\u003cspan class=\"refentrytitle\"\u003eDROP ACCESS METHOD\u003c/span\u003e\u003c/a\u003e SQL commands.\u003c/p\u003e\n\u003cp\u003eA table access method handler function must be declared to accept a single argument of type \u003ccode class=\"type\"\u003einternal\u003c/code\u003e and to return the pseudo-type \u003ccode class=\"type\"\u003etable_am_handler\u003c/code\u003e. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.\u003c/p\u003e\n\u003cp\u003eHere is how an extension SQL script file might create a table access method handler:\u003c/p\u003e\n\u003cpre class=\"programlisting\"\u003eCREATE 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\u003c/pre\u003e\n\u003cp\u003eThe result of the function must be a pointer to a struct of type \u003ccode class=\"structname\"\u003eTableAmRoutine\u003c/code\u003e, 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 \u003ccode class=\"literal\"\u003estatic const\u003c/code\u003e variable in global scope.\u003c/p\u003e\n\u003cp\u003eHere is how a source file with the table access method handler might look like:\u003c/p\u003e\n\u003cpre class=\"programlisting\"\u003e#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(\u0026amp;my_tableam_methods);\n}\n\n\u003c/pre\u003e\n\u003cp\u003eThe \u003ccode class=\"structname\"\u003eTableAmRoutine\u003c/code\u003e struct, also called the access method's \u003cem class=\"firstterm\"\u003eAPI struct\u003c/em\u003e, 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 \u003ccode class=\"structname\"\u003eTableAmRoutine\u003c/code\u003e 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 \u003ca class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"\u003e\u003ccode class=\"filename\"\u003esrc/include/access/tableam.h\u003c/code\u003e\u003c/a\u003e file.\u003c/p\u003e\n\u003cp\u003eTo implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see \u003ca class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"\u003e\u003ccode class=\"filename\"\u003esrc/include/executor/tuptable.h\u003c/code\u003e\u003c/a\u003e), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.\u003c/p\u003e\n\u003cp\u003eCurrently, 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 \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e's standard page layout as described in \u003ca class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6. Database Page Layout\"\u003eSection 66.6\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eOne 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 \u003ca class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6. Database Page Layout\"\u003eSection 66.6\u003c/a\u003e). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for \u003ccode class=\"literal\"\u003eheap\u003c/code\u003e, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.\u003c/p\u003e\n\u003cp\u003eFor crash safety, an AM can use postgres' \u003ca class=\"link\" href=\"/docs/18/wal.html\" title=\"Chapter 28. Reliability and the Write-Ahead Log\"\u003eWAL\u003c/a\u003e, or a custom implementation. If WAL is chosen, either \u003ca class=\"link\" href=\"/docs/18/generic-wal.html\" title=\"64.1. Generic WAL Records\"\u003eGeneric WAL Records\u003c/a\u003e can be used, or a \u003ca class=\"link\" href=\"/docs/18/custom-rmgr.html\" title=\"64.2. Custom WAL Resource Managers\"\u003eCustom WAL Resource Manager\u003c/a\u003e can be implemented.\u003c/p\u003e\n\u003cp\u003eTo 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 \u003ccode class=\"filename\"\u003esrc/backend/access/transam/xlog.c\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eAny developer of a new \u003ccode class=\"literal\"\u003etable access method\u003c/code\u003e can refer to the existing \u003ccode class=\"literal\"\u003eheap\u003c/code\u003e implementation present in \u003ccode class=\"filename\"\u003esrc/backend/access/heap/heapam_handler.c\u003c/code\u003e for details of its implementation.\u003c/p\u003e\n\u003c/div\u003e","manual_path":"/docs/18/tableam.html","related":[{"label":"System catalog pg_am","url":"/wiki/catalog/pg_am/?v=18"},{"label":"default_table_access_method","url":"/wiki/guc/default_table_access_method/?v=18"},{"label":"Index AM","url":"/wiki/indexam/?v=18"}],"release":{"channel":"stable","label":"18.6","major":"18","ref":"PostgreSQL 18.6 source archive","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","source_snapshot_utc":"","source_url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},"runtime_verified":false,"sections":[{"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":"Interface and capability boundaries"},{"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."],"title":"Heap storage, visibility and WAL"},{"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"}],"sections_zh":[{"paragraphs":["矩阵记录此源码构建实际注册的回调。注册表明实现了相应接口钩子；操作是否允许还取决于选项、查询形式、权限和提供方规则。","下方保留同版本完整手册，包括配置、约束和示例。不声称已进行运行时能力测试。"],"title":"接口与能力边界"},{"paragraphs":["此清单从 PostgreSQL 12 引入的 Table AM 接口开始。不会将更早版本的 PostgreSQL 堆存储重新标为 Table AM 实现。","堆可见性遵循 PostgreSQL 快照。WAL 和崩溃恢复行为取决于关系的持久性；临时表、无日志表与永久表不同。索引访问方法与表存储接口分开。"],"title":"堆存储、可见性与 WAL"},{"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":"核心源码中注册的实现"}],"sources":[{"label":"PostgreSQL 18 English manual","path":"tableam.html","sha256":"e659dece936c960dfea9e801720deb3d76abf2c3696abb3f58d32ac17d0f22aa","url":"/docs/18/tableam.html"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/access/heap/heapam_handler.c:2616","line":2616,"path":"src/backend/access/heap/heapam_handler.c","sha256":"fd60a1f8d5530ce5c33fda6b74123c3c22e8c3b9ca6455a0e5d47aa392797a1e","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"label":"PostgreSQL 18 English manual","path":"mvcc-intro.html","sha256":"456469051ccd15ec2cfa1f2e656901a3bb63414db367003215ff810d638593e1","url":"/docs/18/mvcc-intro.html"},{"label":"PostgreSQL 18 English manual","path":"sql-createtable.html","sha256":"b4d703391fe1102d0e02bd6769bef928513eb7a5542f38f7448fc77fe69e0d5b","url":"/docs/18/sql-createtable.html"},{"label":"PostgreSQL 18 English manual","path":"routine-vacuuming.html","sha256":"ede8964df385f5bc69ae991369e6eaf99ae58aa2d6210e8bf868f090bb95b002","url":"/docs/18/routine-vacuuming.html"},{"label":"PostgreSQL 18 English manual","path":"catalog-pg-am.html","sha256":"579364179365a51945e2edb6481df5d198916c2c725e506f166824dedf08994c","url":"/docs/18/catalog-pg-am.html"}],"tables":[{"columns":[{"key":"feature","label":"Interface operation"},{"key":"state","label":"Source observation"},{"key":"callback","label":"Callback"},{"key":"implementation","label":"Implementation"}],"key":"callbacks","rows":[{"callback":"slot_callbacks","feature":"Tuple slot","implementation":"heapam_slot_callbacks","state":"Handler registered; conditions apply"},{"callback":"scan_begin","feature":"Begin scan","implementation":"heap_beginscan","state":"Handler registered; conditions apply"},{"callback":"parallelscan_initialize","feature":"Parallel scan initialization","implementation":"table_block_parallelscan_initialize","state":"Handler registered; conditions apply"},{"callback":"index_fetch_begin","feature":"Begin index lookup","implementation":"heapam_index_fetch_begin","state":"Handler registered; conditions apply"},{"callback":"index_fetch_tuple","feature":"Fetch identified tuple","implementation":"heapam_index_fetch_tuple","state":"Handler registered; conditions apply"},{"callback":"tuple_insert","feature":"Insert tuple","implementation":"heapam_tuple_insert","state":"Handler registered; conditions apply"},{"callback":"tuple_update","feature":"Update tuple","implementation":"heapam_tuple_update","state":"Handler registered; conditions apply"},{"callback":"tuple_delete","feature":"Delete tuple","implementation":"heapam_tuple_delete","state":"Handler registered; conditions apply"},{"callback":"relation_vacuum","feature":"Vacuum relation","implementation":"heap_vacuum_rel","state":"Handler registered; conditions apply"},{"callback":"scan_analyze_next_block","feature":"Analyze block","implementation":"heapam_scan_analyze_next_block","state":"Handler registered; conditions apply"},{"callback":"relation_needs_toast_table","feature":"TOAST decision","implementation":"heapam_relation_needs_toast_table","state":"Handler registered; conditions apply"}],"title":"Registered interface handlers"}],"tables_zh":[{"columns":[{"key":"feature","label":"接口操作"},{"key":"state","label":"源码观察"},{"key":"callback","label":"回调"},{"key":"implementation","label":"实现"}],"key":"callbacks","rows":[{"callback":"slot_callbacks","feature":"元组槽","implementation":"heapam_slot_callbacks","state":"已注册处理函数；适用条件限制"},{"callback":"scan_begin","feature":"开始扫描","implementation":"heap_beginscan","state":"已注册处理函数；适用条件限制"},{"callback":"parallelscan_initialize","feature":"初始化并行扫描","implementation":"table_block_parallelscan_initialize","state":"已注册处理函数；适用条件限制"},{"callback":"index_fetch_begin","feature":"开始索引查找","implementation":"heapam_index_fetch_begin","state":"已注册处理函数；适用条件限制"},{"callback":"index_fetch_tuple","feature":"获取指定元组","implementation":"heapam_index_fetch_tuple","state":"已注册处理函数；适用条件限制"},{"callback":"tuple_insert","feature":"插入元组","implementation":"heapam_tuple_insert","state":"已注册处理函数；适用条件限制"},{"callback":"tuple_update","feature":"更新元组","implementation":"heapam_tuple_update","state":"已注册处理函数；适用条件限制"},{"callback":"tuple_delete","feature":"删除元组","implementation":"heapam_tuple_delete","state":"已注册处理函数；适用条件限制"},{"callback":"relation_vacuum","feature":"对关系执行 VACUUM","implementation":"heap_vacuum_rel","state":"已注册处理函数；适用条件限制"},{"callback":"scan_analyze_next_block","feature":"分析数据块","implementation":"heapam_scan_analyze_next_block","state":"已注册处理函数；适用条件限制"},{"callback":"relation_needs_toast_table","feature":"TOAST 判定","implementation":"heapam_relation_needs_toast_table","state":"已注册处理函数；适用条件限制"}],"title":"注册的接口处理函数"}],"zh_from":{"authored_translation":"source-derived-identity","body_sha256":"85bdb6a1963e89d1415d778bb87d4525566b555ea0b69c0788315776ab9c102b","kind":"same-version-chinese-manual-with-source-derived-identity","manual":{"anchor":"","build_id":107,"extraction":"concept-introduction","fragment_sha256":"96873a2e8ad1f66e093c9294861e7feb00600a79f0d545d60715e7ad0b856019","locale":"zh-Hans","page_key":"tableam.html","source_hash":"5513798c8f4d2e9c76bf0d8caf92f332339bdbeb19e1bb906d44cc1e087d5e02","source_revision":"unknown:rendered-translation-baseline","translated_from_revision":null,"translation_revision":"git:b1b500221dbe5437cfca004d6b04d3f6e422765d;html-sha256:08e987a66af27b98444a8057c256314eafa13611a3fb9e888214fc436824244b","url":"/zh/docs/18/tableam.html","version":"18"},"runtime_rerun":false,"source_facts_revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}},"ManualEvidence":{"manual_path":"/docs/18/tableam.html","release":{"channel":"stable","label":"18.6","major":"18","ref":"PostgreSQL 18.6 source archive","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","source_snapshot_utc":"","source_url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},"sources":[{"label":"PostgreSQL 18 English manual","path":"tableam.html","sha256":"e659dece936c960dfea9e801720deb3d76abf2c3696abb3f58d32ac17d0f22aa","url":"/docs/18/tableam.html"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/access/heap/heapam_handler.c:2616","line":2616,"path":"src/backend/access/heap/heapam_handler.c","sha256":"fd60a1f8d5530ce5c33fda6b74123c3c22e8c3b9ca6455a0e5d47aa392797a1e","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"label":"PostgreSQL 18 English manual","path":"mvcc-intro.html","sha256":"456469051ccd15ec2cfa1f2e656901a3bb63414db367003215ff810d638593e1","url":"/docs/18/mvcc-intro.html"},{"label":"PostgreSQL 18 English manual","path":"sql-createtable.html","sha256":"b4d703391fe1102d0e02bd6769bef928513eb7a5542f38f7448fc77fe69e0d5b","url":"/docs/18/sql-createtable.html"},{"label":"PostgreSQL 18 English manual","path":"routine-vacuuming.html","sha256":"ede8964df385f5bc69ae991369e6eaf99ae58aa2d6210e8bf868f090bb95b002","url":"/docs/18/routine-vacuuming.html"},{"label":"PostgreSQL 18 English manual","path":"catalog-pg-am.html","sha256":"579364179365a51945e2edb6481df5d198916c2c725e506f166824dedf08994c","url":"/docs/18/catalog-pg-am.html"}]},"MeasuredEvidence":{"runtime_verified":false}},"Text":{"Collection":"tableam","Key":"heap","SourceDatabase":"center","Version":"18","Locale":"en","Title":"heap","Summary":"The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL.","BodyHTML":"\u003cdiv id=\"TABLEAM\"\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003ch2\u003eChapter 62. Table Access Method Interface Definition\u003c/h2\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003eThis chapter explains the interface between the core \u003cspan\u003ePostgreSQL\u003c/span\u003e system and \u003cem\u003etable access methods\u003c/em\u003e, 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.\u003c/p\u003e\n\u003cp\u003eEach table access method is described by a row in the \u003ca href=\"/docs/18/catalog-pg-am.html\" rel=\"nofollow\"\u003e\u003ccode\u003epg_am\u003c/code\u003e\u003c/a\u003e system catalog. The \u003ccode\u003epg_am\u003c/code\u003e entry specifies a name and a \u003cem\u003ehandler function\u003c/em\u003e for the table access method. These entries can be created and deleted using the \u003ca href=\"/docs/18/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\" rel=\"nofollow\"\u003e\u003cspan\u003eCREATE ACCESS METHOD\u003c/span\u003e\u003c/a\u003e and \u003ca href=\"/docs/18/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\" rel=\"nofollow\"\u003e\u003cspan\u003eDROP ACCESS METHOD\u003c/span\u003e\u003c/a\u003e SQL commands.\u003c/p\u003e\n\u003cp\u003eA table access method handler function must be declared to accept a single argument of type \u003ccode\u003einternal\u003c/code\u003e and to return the pseudo-type \u003ccode\u003etable_am_handler\u003c/code\u003e. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.\u003c/p\u003e\n\u003cp\u003eHere is how an extension SQL script file might create a table access method handler:\u003c/p\u003e\n\u003cpre\u003eCREATE OR REPLACE FUNCTION my_tableam_handler(internal)\n  RETURNS table_am_handler AS \u0026#39;my_extension\u0026#39;, \u0026#39;my_tableam_handler\u0026#39;\n  LANGUAGE C STRICT;\n\nCREATE ACCESS METHOD myam TYPE TABLE HANDLER my_tableam_handler;\n\u003c/pre\u003e\n\u003cp\u003eThe result of the function must be a pointer to a struct of type \u003ccode\u003eTableAmRoutine\u003c/code\u003e, 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 \u003ccode\u003estatic const\u003c/code\u003e variable in global scope.\u003c/p\u003e\n\u003cp\u003eHere is how a source file with the table access method handler might look like:\u003c/p\u003e\n\u003cpre\u003e#include \u0026#34;postgres.h\u0026#34;\n\n#include \u0026#34;access/tableam.h\u0026#34;\n#include \u0026#34;fmgr.h\u0026#34;\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(\u0026amp;my_tableam_methods);\n}\n\n\u003c/pre\u003e\n\u003cp\u003eThe \u003ccode\u003eTableAmRoutine\u003c/code\u003e struct, also called the access method\u0026#39;s \u003cem\u003eAPI struct\u003c/em\u003e, 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 \u003ccode\u003eTableAmRoutine\u003c/code\u003e 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 \u003ca href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\" rel=\"nofollow\"\u003e\u003ccode\u003esrc/include/access/tableam.h\u003c/code\u003e\u003c/a\u003e file.\u003c/p\u003e\n\u003cp\u003eTo implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see \u003ca href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\" rel=\"nofollow\"\u003e\u003ccode\u003esrc/include/executor/tuptable.h\u003c/code\u003e\u003c/a\u003e), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.\u003c/p\u003e\n\u003cp\u003eCurrently, the way an AM actually stores data is fairly unconstrained. For example, it\u0026#39;s possible, but not required, to use postgres\u0026#39; shared buffer cache. In case it is used, it likely makes sense to use \u003cspan\u003ePostgreSQL\u003c/span\u003e\u0026#39;s standard page layout as described in \u003ca href=\"/docs/18/storage-page-layout.html\" rel=\"nofollow\"\u003eSection 66.6\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eOne 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 \u003ca href=\"/docs/18/storage-page-layout.html\" rel=\"nofollow\"\u003eSection 66.6\u003c/a\u003e). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for \u003ccode\u003eheap\u003c/code\u003e, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.\u003c/p\u003e\n\u003cp\u003eFor crash safety, an AM can use postgres\u0026#39; \u003ca href=\"/docs/18/wal.html\" rel=\"nofollow\"\u003eWAL\u003c/a\u003e, or a custom implementation. If WAL is chosen, either \u003ca href=\"/docs/18/generic-wal.html\" rel=\"nofollow\"\u003eGeneric WAL Records\u003c/a\u003e can be used, or a \u003ca href=\"/docs/18/custom-rmgr.html\" rel=\"nofollow\"\u003eCustom WAL Resource Manager\u003c/a\u003e can be implemented.\u003c/p\u003e\n\u003cp\u003eTo 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 \u003ccode\u003esrc/backend/access/transam/xlog.c\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eAny developer of a new \u003ccode\u003etable access method\u003c/code\u003e can refer to the existing \u003ccode\u003eheap\u003c/code\u003e implementation present in \u003ccode\u003esrc/backend/access/heap/heapam_handler.c\u003c/code\u003e for details of its implementation.\u003c/p\u003e\n\u003c/div\u003e","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","ContentHash":"2b2229cefdc73e95b72d3fd7c31b30de3a9507cb20a5d0553b399e0ad65fccfe","Payload":{"description":["The built-in heap table access method integrates tuple storage, visibility, scans, index fetches and maintenance with PostgreSQL."],"manual_html":"\u003cdiv class=\"chapter\" id=\"TABLEAM\"\u003e\n\u003cdiv class=\"titlepage\"\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003ch2 class=\"title\"\u003eChapter 62. Table Access Method Interface Definition\u003c/h2\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003eThis chapter explains the interface between the core \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e system and \u003cem class=\"firstterm\"\u003etable access methods\u003c/em\u003e, 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.\u003c/p\u003e\n\u003cp\u003eEach table access method is described by a row in the \u003ca class=\"link\" href=\"/docs/18/catalog-pg-am.html\" title=\"52.3. pg_am\"\u003e\u003ccode class=\"structname\"\u003epg_am\u003c/code\u003e\u003c/a\u003e system catalog. The \u003ccode class=\"structname\"\u003epg_am\u003c/code\u003e entry specifies a name and a \u003cem class=\"firstterm\"\u003ehandler function\u003c/em\u003e for the table access method. These entries can be created and deleted using the \u003ca class=\"xref\" href=\"/docs/18/sql-create-access-method.html\" title=\"CREATE ACCESS METHOD\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE ACCESS METHOD\u003c/span\u003e\u003c/a\u003e and \u003ca class=\"xref\" href=\"/docs/18/sql-drop-access-method.html\" title=\"DROP ACCESS METHOD\"\u003e\u003cspan class=\"refentrytitle\"\u003eDROP ACCESS METHOD\u003c/span\u003e\u003c/a\u003e SQL commands.\u003c/p\u003e\n\u003cp\u003eA table access method handler function must be declared to accept a single argument of type \u003ccode class=\"type\"\u003einternal\u003c/code\u003e and to return the pseudo-type \u003ccode class=\"type\"\u003etable_am_handler\u003c/code\u003e. The argument is a dummy value that simply serves to prevent handler functions from being called directly from SQL commands.\u003c/p\u003e\n\u003cp\u003eHere is how an extension SQL script file might create a table access method handler:\u003c/p\u003e\n\u003cpre class=\"programlisting\"\u003eCREATE 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\u003c/pre\u003e\n\u003cp\u003eThe result of the function must be a pointer to a struct of type \u003ccode class=\"structname\"\u003eTableAmRoutine\u003c/code\u003e, 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 \u003ccode class=\"literal\"\u003estatic const\u003c/code\u003e variable in global scope.\u003c/p\u003e\n\u003cp\u003eHere is how a source file with the table access method handler might look like:\u003c/p\u003e\n\u003cpre class=\"programlisting\"\u003e#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(\u0026amp;my_tableam_methods);\n}\n\n\u003c/pre\u003e\n\u003cp\u003eThe \u003ccode class=\"structname\"\u003eTableAmRoutine\u003c/code\u003e struct, also called the access method's \u003cem class=\"firstterm\"\u003eAPI struct\u003c/em\u003e, 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 \u003ccode class=\"structname\"\u003eTableAmRoutine\u003c/code\u003e 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 \u003ca class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/access/tableam.h;hb=HEAD\"\u003e\u003ccode class=\"filename\"\u003esrc/include/access/tableam.h\u003c/code\u003e\u003c/a\u003e file.\u003c/p\u003e\n\u003cp\u003eTo implement an access method, an implementor will typically need to implement an AM-specific type of tuple table slot (see \u003ca class=\"ulink\" href=\"https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/include/executor/tuptable.h;hb=HEAD\"\u003e\u003ccode class=\"filename\"\u003esrc/include/executor/tuptable.h\u003c/code\u003e\u003c/a\u003e), which allows code outside the access method to hold references to tuples of the AM, and to access the columns of the tuple.\u003c/p\u003e\n\u003cp\u003eCurrently, 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 \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e's standard page layout as described in \u003ca class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6. Database Page Layout\"\u003eSection 66.6\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eOne 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 \u003ca class=\"xref\" href=\"/docs/18/storage-page-layout.html\" title=\"66.6. Database Page Layout\"\u003eSection 66.6\u003c/a\u003e). It is not strictly necessary that the sub-parts of TIDs have the same meaning they e.g., have for \u003ccode class=\"literal\"\u003eheap\u003c/code\u003e, but if bitmap scan support is desired (it is optional), the block number needs to provide locality.\u003c/p\u003e\n\u003cp\u003eFor crash safety, an AM can use postgres' \u003ca class=\"link\" href=\"/docs/18/wal.html\" title=\"Chapter 28. Reliability and the Write-Ahead Log\"\u003eWAL\u003c/a\u003e, or a custom implementation. If WAL is chosen, either \u003ca class=\"link\" href=\"/docs/18/generic-wal.html\" title=\"64.1. Generic WAL Records\"\u003eGeneric WAL Records\u003c/a\u003e can be used, or a \u003ca class=\"link\" href=\"/docs/18/custom-rmgr.html\" title=\"64.2. Custom WAL Resource Managers\"\u003eCustom WAL Resource Manager\u003c/a\u003e can be implemented.\u003c/p\u003e\n\u003cp\u003eTo 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 \u003ccode class=\"filename\"\u003esrc/backend/access/transam/xlog.c\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eAny developer of a new \u003ccode class=\"literal\"\u003etable access method\u003c/code\u003e can refer to the existing \u003ccode class=\"literal\"\u003eheap\u003c/code\u003e implementation present in \u003ccode class=\"filename\"\u003esrc/backend/access/heap/heapam_handler.c\u003c/code\u003e for details of its implementation.\u003c/p\u003e\n\u003c/div\u003e","related":[{"label":"System catalog pg_am","url":"/wiki/catalog/pg_am/?v=18"},{"label":"default_table_access_method","url":"/wiki/guc/default_table_access_method/?v=18"},{"label":"Index AM","url":"/wiki/indexam/?v=18"}],"sections":[{"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":"Interface and capability boundaries"},{"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."],"title":"Heap storage, visibility and WAL"},{"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"}],"tables":[{"columns":[{"key":"feature","label":"Interface operation"},{"key":"state","label":"Source observation"},{"key":"callback","label":"Callback"},{"key":"implementation","label":"Implementation"}],"key":"callbacks","rows":[{"callback":"slot_callbacks","feature":"Tuple slot","implementation":"heapam_slot_callbacks","state":"Handler registered; conditions apply"},{"callback":"scan_begin","feature":"Begin scan","implementation":"heap_beginscan","state":"Handler registered; conditions apply"},{"callback":"parallelscan_initialize","feature":"Parallel scan initialization","implementation":"table_block_parallelscan_initialize","state":"Handler registered; conditions apply"},{"callback":"index_fetch_begin","feature":"Begin index lookup","implementation":"heapam_index_fetch_begin","state":"Handler registered; conditions apply"},{"callback":"index_fetch_tuple","feature":"Fetch identified tuple","implementation":"heapam_index_fetch_tuple","state":"Handler registered; conditions apply"},{"callback":"tuple_insert","feature":"Insert tuple","implementation":"heapam_tuple_insert","state":"Handler registered; conditions apply"},{"callback":"tuple_update","feature":"Update tuple","implementation":"heapam_tuple_update","state":"Handler registered; conditions apply"},{"callback":"tuple_delete","feature":"Delete tuple","implementation":"heapam_tuple_delete","state":"Handler registered; conditions apply"},{"callback":"relation_vacuum","feature":"Vacuum relation","implementation":"heap_vacuum_rel","state":"Handler registered; conditions apply"},{"callback":"scan_analyze_next_block","feature":"Analyze block","implementation":"heapam_scan_analyze_next_block","state":"Handler registered; conditions apply"},{"callback":"relation_needs_toast_table","feature":"TOAST decision","implementation":"heapam_relation_needs_toast_table","state":"Handler registered; conditions apply"}],"title":"Registered interface handlers"}]}},"RequestedLocale":"en","Fallback":false,"Versions":["12","13","14","15","16","17","18","19","20"],"Locales":["en","zh-Hans"],"Signatures":null,"Spellings":null,"SQLState":null,"Evidence":null}
