{"Entry":{"collection":"storage","key":"tuple-layout","name":"Table row layout","aliases":[],"metadata":{"aliases":[],"category":"Physical structures","content_hash":"d5a72f482bf43cb255bd9db27433f977d58f113d28d0d3a7d6a571464b14dda2","derived_content_hash":"3b769756e7a231d80e0bf532cbb983286fdc05418fa274db3442aa62a22b3705","imported_at":"2026-09-30T00:40:47.109034+08:00","name":"Table row layout","name_zh":"","slug":"tuple-layout","summary":"Physical row headers, null bitmap, alignment and column data."}},"Definition":{"Collection":"storage","Key":"tuple-layout","SourceDatabase":"center","Version":"18","SourceTable":"storage_structure","SourceKey":"tuple-layout","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","Facts":{"comparison_data":{"layouts":[{"columns":[{"key":"c0","label":"Field"},{"key":"c1","label":"Type"},{"key":"c2","label":"Length"},{"key":"c3","label":"Description"}],"key":"layout-2","rows":[{"c0":"t_xmin","c1":"TransactionId","c2":"4 bytes","c3":"insert XID stamp"},{"c0":"t_xmax","c1":"TransactionId","c2":"4 bytes","c3":"delete XID stamp"},{"c0":"t_cid","c1":"CommandId","c2":"4 bytes","c3":"insert and/or delete CID stamp (overlays with t_xvac)"},{"c0":"t_xvac","c1":"TransactionId","c2":"4 bytes","c3":"XID for VACUUM operation moving a row version"},{"c0":"t_ctid","c1":"ItemPointerData","c2":"6 bytes","c3":"current TID of this or newer row version"},{"c0":"t_infomask2","c1":"uint16","c2":"2 bytes","c3":"number of attributes, plus various flag bits"},{"c0":"t_infomask","c1":"uint16","c2":"2 bytes","c3":"various flag bits"},{"c0":"t_hoff","c1":"uint8","c2":"1 byte","c3":"offset to user data"}],"title":"HeapTupleHeaderData Layout"}]},"comparison_hash":"7f6e968716966dae8869d6c14f0a6aa229d745d4d4bde899b61eeec58c8d7ea0","description":["Physical row headers, null bitmap, alignment and column data."],"description_zh":"所有表行的结构都相同。它们都有一个固定大小的头部（在大多数机器上占 23 字节），后面跟着可选的空值位图、可选的对象 ID 字段以及用户数据。头部的详细格式见 表 66.4 。实际用户数据（行的各列）从 t_hoff 指示的偏移位置开始，它必须始终是该平台 MAXALIGN 对齐单位的整数倍。只有当 HEAP_HASNULL 位在 t_infomask 中被置位时，空值位图才存在。若存在，它紧随固定头部之后，并占用足够多的字节，以便为每个数据列提供一位（也就是说，其位数等于 t_infomask2 中的属性个数）。在这个位图中，1 表示非空，0 表示空值。当位图不存在时，假定所有列都非空。只有当 HEAP_HASOID_OLD 位在 t_infomask 中被置位时，对象 ID 才存在。若存在，它位于 t_hoff 边界之前。为了让 t_hoff 成为 MAXALIGN 的整数倍所需的任何填充，都会出现在空值位图与对象 ID 之间。（这又反过来保证了对象 ID 的对齐是合适的。） 所有细节都可以在 src/include/access/htup_details.h 中找到。 要解释实际数据，必须借助从其他表中获得的信息，其中大部分来自 pg_attribute 。识别字段位置所需的关键值是 attlen 和 attalign 。除非所有字段都是定宽且没有空值，否则没有办法直接取得某个特定属性。所有这些技巧都封装在 heap_getattr 、 fastgetattr 和 heap_getsysattr 这些函数中。 读取数据时，需要依次检查每个属性。首先根据空值位图判断该字段是否为 NULL。如果是，就继续下一个。然后确认对齐是否正确。如果字段是定宽字段，那么它的所有字节都是直接摆放的；如果它是变长字段（attlen = -1），情况就会稍复杂一些。所有变长数据类型都共享一个通用头部结构体 struct varlena ，其中包含已存储值的总长度以及一些标志位。根据这些标志，数据可能是行内存储的，也可能位于 TOAST 表中；它也可能是经过压缩的（见 第 66.2 节 ","description_zh_html":"\u003cp\u003e存储结构 tuple-layout。\u003c/p\u003e\u003ch3\u003e同版本中文手册节选\u003c/h3\u003e\u003cp\u003e\n\n  所有表行的结构都相同。它们都有一个固定大小的头部（在大多数机器上占 23 字节），后面跟着可选的空值位图、可选的对象 ID 字段以及用户数据。头部的详细格式见\u003ca class=\"xref\" href=\"/zh/docs/18/storage-page-layout.html#HEAPTUPLEHEADERDATA-TABLE\"\u003e表 66.4\u003c/a\u003e。实际用户数据（行的各列）从\n  \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e 指示的偏移位置开始，它必须始终是该平台\n  MAXALIGN 对齐单位的整数倍。只有当 \u003cem class=\"firstterm\"\u003eHEAP_HASNULL\u003c/em\u003e 位在\n  \u003ccode class=\"structfield\"\u003et_infomask\u003c/code\u003e 中被置位时，空值位图才存在。若存在，它紧随固定头部之后，并占用足够多的字节，以便为每个数据列提供一位（也就是说，其位数等于 \u003ccode class=\"structfield\"\u003et_infomask2\u003c/code\u003e 中的属性个数）。在这个位图中，1 表示非空，0 表示空值。当位图不存在时，假定所有列都非空。只有当 \u003cem class=\"firstterm\"\u003eHEAP_HASOID_OLD\u003c/em\u003e 位在\n  \u003ccode class=\"structfield\"\u003et_infomask\u003c/code\u003e 中被置位时，对象 ID 才存在。若存在，它位于\n  \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e 边界之前。为了让 \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e\n  成为 MAXALIGN 的整数倍所需的任何填充，都会出现在空值位图与对象 ID 之间。（这又反过来保证了对象 ID 的对齐是合适的。）\n\n \u003c/p\u003e\u003cp\u003e\n   所有细节都可以在\n   \u003ccode class=\"filename\"\u003esrc/include/access/htup_details.h\u003c/code\u003e 中找到。\n \u003c/p\u003e\u003cp\u003e\n\n  要解释实际数据，必须借助从其他表中获得的信息，其中大部分来自\n  \u003ccode class=\"structname\"\u003epg_attribute\u003c/code\u003e。识别字段位置所需的关键值是\n  \u003ccode class=\"structfield\"\u003eattlen\u003c/code\u003e 和 \u003ccode class=\"structfield\"\u003eattalign\u003c/code\u003e。除非所有字段都是定宽且没有空值，否则没有办法直接取得某个特定属性。所有这些技巧都封装在 \u003cem class=\"firstterm\"\u003eheap_getattr\u003c/em\u003e、\u003cem class=\"firstterm\"\u003efastgetattr\u003c/em\u003e 和 \u003cem class=\"firstterm\"\u003eheap_getsysattr\u003c/em\u003e\n  这些函数中。\n\n \u003c/p\u003e\u003cp\u003e\n\n  读取数据时，需要依次检查每个属性。首先根据空值位图判断该字段是否为 NULL。如果是，就继续下一个。然后确认对齐是否正确。如果字段是定宽字段，那么它的所有字节都是直接摆放的；如果它是变长字段（attlen = -1），情况就会稍复杂一些。所有变长数据类型都共享一个通用头部结构体 \u003ccode class=\"type\"\u003estruct varlena\u003c/code\u003e，其中包含已存储值的总长度以及一些标志位。根据这些标志，数据可能是行内存储的，也可能位于\n  \u003cacronym class=\"acronym\"\u003eTOAST\u003c/acronym\u003e 表中；它也可能是经过压缩的（见\u003ca class=\"xref\" href=\"/zh/docs/18/storage-toast.html\"\u003e第 66.2 节\u003c/a\u003e）。\n\n \u003c/p\u003e\u003cp\u003e\u003ca href=\"/zh/docs/18/storage-page-layout.html#STORAGE-TUPLE-LAYOUT\"\u003e查看完整中文手册与上下文\u003c/a\u003e。\u003c/p\u003e","facts":[],"facts_zh":[],"manual_html":"\u003cdiv class=\"sect2\"\u003e\n\u003cdiv class=\"titlepage\"\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003ch3 class=\"title\"\u003e66.6.1. Table Row Layout \u003c/h3\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003eAll table rows are structured in the same way. There is a fixed-size header (occupying 23 bytes on most machines), followed by an optional null bitmap, an optional object ID field, and the user data. The header is detailed in \u003ca class=\"xref\" href=\"/docs/18/storage-page-layout.html#HEAPTUPLEHEADERDATA-TABLE\" title=\"Table 66.4. HeapTupleHeaderData Layout\"\u003eTable 66.4\u003c/a\u003e. The actual user data (columns of the row) begins at the offset indicated by \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e, which must always be a multiple of the MAXALIGN distance for the platform. The null bitmap is only present if the \u003cem class=\"firstterm\"\u003eHEAP_HASNULL\u003c/em\u003e bit is set in \u003ccode class=\"structfield\"\u003et_infomask\u003c/code\u003e. If it is present it begins just after the fixed header and occupies enough bytes to have one bit per data column (that is, the number of bits that equals the attribute count in \u003ccode class=\"structfield\"\u003et_infomask2\u003c/code\u003e). In this list of bits, a 1 bit indicates not-null, a 0 bit is a null. When the bitmap is not present, all columns are assumed not-null. The object ID is only present if the \u003cem class=\"firstterm\"\u003eHEAP_HASOID_OLD\u003c/em\u003e bit is set in \u003ccode class=\"structfield\"\u003et_infomask\u003c/code\u003e. If present, it appears just before the \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e boundary. Any padding needed to make \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e a MAXALIGN multiple will appear between the null bitmap and the object ID. (This in turn ensures that the object ID is suitably aligned.)\u003c/p\u003e\n\u003cdiv class=\"table\"\u003e\n\u003cp class=\"title\"\u003e\u003cstrong\u003eTable 66.4. HeapTupleHeaderData Layout\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"table-contents\"\u003e\n\u003ctable class=\"table\"\u003e\n\n\n\n\n\n\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eField\u003c/th\u003e\n\u003cth\u003eType\u003c/th\u003e\n\u003cth\u003eLength\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xmin\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003einsert XID stamp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xmax\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003edelete XID stamp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_cid\u003c/td\u003e\n\u003ctd\u003eCommandId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003einsert and/or delete CID stamp (overlays with t_xvac)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xvac\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003eXID for VACUUM operation moving a row version\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_ctid\u003c/td\u003e\n\u003ctd\u003eItemPointerData\u003c/td\u003e\n\u003ctd\u003e6 bytes\u003c/td\u003e\n\u003ctd\u003ecurrent TID of this or newer row version\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_infomask2\u003c/td\u003e\n\u003ctd\u003euint16\u003c/td\u003e\n\u003ctd\u003e2 bytes\u003c/td\u003e\n\u003ctd\u003enumber of attributes, plus various flag bits\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_infomask\u003c/td\u003e\n\u003ctd\u003euint16\u003c/td\u003e\n\u003ctd\u003e2 bytes\u003c/td\u003e\n\u003ctd\u003evarious flag bits\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_hoff\u003c/td\u003e\n\u003ctd\u003euint8\u003c/td\u003e\n\u003ctd\u003e1 byte\u003c/td\u003e\n\u003ctd\u003eoffset to user data\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cbr class=\"table-break\"\u003e\n\u003cp\u003eAll the details can be found in \u003ccode class=\"filename\"\u003esrc/include/access/htup_details.h\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eInterpreting the actual data can only be done with information obtained from other tables, mostly \u003ccode class=\"structname\"\u003epg_attribute\u003c/code\u003e. The key values needed to identify field locations are \u003ccode class=\"structfield\"\u003eattlen\u003c/code\u003e and \u003ccode class=\"structfield\"\u003eattalign\u003c/code\u003e. There is no way to directly get a particular attribute, except when there are only fixed width fields and no null values. All this trickery is wrapped up in the functions \u003cem class=\"firstterm\"\u003eheap_getattr\u003c/em\u003e, \u003cem class=\"firstterm\"\u003efastgetattr\u003c/em\u003e and \u003cem class=\"firstterm\"\u003eheap_getsysattr\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eTo read the data you need to examine each attribute in turn. First check whether the field is NULL according to the null bitmap. If it is, go to the next. Then make sure you have the right alignment. If the field is a fixed width field, then all the bytes are simply placed. If it's a variable length field (attlen = -1) then it's a bit more complicated. All variable-length data types share the common header structure \u003ccode class=\"type\"\u003estruct varlena\u003c/code\u003e, which includes the total length of the stored value and some flag bits. Depending on the flags, the data can be either inline or in a TOAST table; it might be compressed, too (see \u003ca class=\"xref\" href=\"/docs/18/storage-toast.html\" title=\"66.2. TOAST\"\u003eSection 66.2\u003c/a\u003e).\u003c/p\u003e\n\u003c/div\u003e","manual_path":"/docs/18/storage-page-layout.html","related":[],"release":{"channel":"stable","label":"18.6","major":"18","ref":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"},"sections":[],"sections_zh":[],"signature":"","sources":[{"label":"PostgreSQL 18 English manual","path":"storage-page-layout.html","sha256":"0d9f99e4cef5ea0a6741a74cab87052b929f7001730853c85d5e60d72179d355","url":"/docs/18/storage-page-layout.html#STORAGE-TUPLE-LAYOUT"}],"tables":[{"columns":[{"key":"c0","label":"Field"},{"key":"c1","label":"Type"},{"key":"c2","label":"Length"},{"key":"c3","label":"Description"}],"key":"layout-2","rows":[{"c0":"t_xmin","c1":"TransactionId","c2":"4 bytes","c3":"insert XID stamp"},{"c0":"t_xmax","c1":"TransactionId","c2":"4 bytes","c3":"delete XID stamp"},{"c0":"t_cid","c1":"CommandId","c2":"4 bytes","c3":"insert and/or delete CID stamp (overlays with t_xvac)"},{"c0":"t_xvac","c1":"TransactionId","c2":"4 bytes","c3":"XID for VACUUM operation moving a row version"},{"c0":"t_ctid","c1":"ItemPointerData","c2":"6 bytes","c3":"current TID of this or newer row version"},{"c0":"t_infomask2","c1":"uint16","c2":"2 bytes","c3":"number of attributes, plus various flag bits"},{"c0":"t_infomask","c1":"uint16","c2":"2 bytes","c3":"various flag bits"},{"c0":"t_hoff","c1":"uint8","c2":"1 byte","c3":"offset to user data"}],"title":"HeapTupleHeaderData Layout"}],"tables_zh":[{"columns":[{"key":"c0","label":"字段"},{"key":"c1","label":"类型"},{"key":"c2","label":"长度"},{"key":"c3","label":"说明"}],"key":"layout-2","rows":[{"c0":"t_xmin","c1":"TransactionId","c2":"4 字节","c3":"插入事务的 XID"},{"c0":"t_xmax","c1":"TransactionId","c2":"4 字节","c3":"删除事务的 XID"},{"c0":"t_cid","c1":"CommandId","c2":"4 字节","c3":"插入和／或删除命令的 CID，与 t_xvac 共用存储位置"},{"c0":"t_xvac","c1":"TransactionId","c2":"4 字节","c3":"VACUUM 操作移动行版本时使用的 XID"},{"c0":"t_ctid","c1":"ItemPointerData","c2":"6 字节","c3":"本行版本或较新行版本的当前 TID"},{"c0":"t_infomask2","c1":"uint16","c2":"2 字节","c3":"属性数量及各种标志位"},{"c0":"t_infomask","c1":"uint16","c2":"2 字节","c3":"各种标志位"},{"c0":"t_hoff","c1":"uint8","c2":"1 字节","c3":"用户数据的偏移量"}],"title":"HeapTupleHeaderData 布局"}],"zh_from":{"authored_translation":"source-derived-identity","body_sha256":"67dcd3c43a99523896736f539ec9da214a78606b0e56fda9bc28648357331d0c","kind":"same-version-chinese-manual-with-source-derived-identity","manual":{"anchor":"STORAGE-TUPLE-LAYOUT","build_id":107,"extraction":"concept-introduction","fragment_sha256":"dee1db58a987e1f5ffbc6afe554287351b32d7b3694112aa379057599b1b44f1","locale":"zh-Hans","page_key":"storage-page-layout.html","source_hash":"07870df29bfc52d49b5aa3018212c94da48a0d9edea8d214a87d8aca0b5d55f2","source_revision":"unknown:rendered-translation-baseline","translated_from_revision":null,"translation_revision":"git:b1b500221dbe5437cfca004d6b04d3f6e422765d;html-sha256:08e987a66af27b98444a8057c256314eafa13611a3fb9e888214fc436824244b","url":"/zh/docs/18/storage-page-layout.html#STORAGE-TUPLE-LAYOUT","version":"18"},"runtime_rerun":false,"source_facts_revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}},"ManualEvidence":{"manual_path":"/docs/18/storage-page-layout.html","release":{"channel":"stable","label":"18.6","major":"18","ref":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"},"sources":[{"label":"PostgreSQL 18 English manual","path":"storage-page-layout.html","sha256":"0d9f99e4cef5ea0a6741a74cab87052b929f7001730853c85d5e60d72179d355","url":"/docs/18/storage-page-layout.html#STORAGE-TUPLE-LAYOUT"}]},"MeasuredEvidence":{}},"Text":{"Collection":"storage","Key":"tuple-layout","SourceDatabase":"center","Version":"18","Locale":"en","Title":"Table row layout","Summary":"Physical row headers, null bitmap, alignment and column data.","BodyHTML":"\u003cdiv\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003ch3\u003e66.6.1. Table Row Layout \u003c/h3\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003eAll table rows are structured in the same way. There is a fixed-size header (occupying 23 bytes on most machines), followed by an optional null bitmap, an optional object ID field, and the user data. The header is detailed in \u003ca href=\"/docs/18/storage-page-layout.html#HEAPTUPLEHEADERDATA-TABLE\" rel=\"nofollow\"\u003eTable 66.4\u003c/a\u003e. The actual user data (columns of the row) begins at the offset indicated by \u003ccode\u003et_hoff\u003c/code\u003e, which must always be a multiple of the MAXALIGN distance for the platform. The null bitmap is only present if the \u003cem\u003eHEAP_HASNULL\u003c/em\u003e bit is set in \u003ccode\u003et_infomask\u003c/code\u003e. If it is present it begins just after the fixed header and occupies enough bytes to have one bit per data column (that is, the number of bits that equals the attribute count in \u003ccode\u003et_infomask2\u003c/code\u003e). In this list of bits, a 1 bit indicates not-null, a 0 bit is a null. When the bitmap is not present, all columns are assumed not-null. The object ID is only present if the \u003cem\u003eHEAP_HASOID_OLD\u003c/em\u003e bit is set in \u003ccode\u003et_infomask\u003c/code\u003e. If present, it appears just before the \u003ccode\u003et_hoff\u003c/code\u003e boundary. Any padding needed to make \u003ccode\u003et_hoff\u003c/code\u003e a MAXALIGN multiple will appear between the null bitmap and the object ID. (This in turn ensures that the object ID is suitably aligned.)\u003c/p\u003e\n\u003cdiv\u003e\n\u003cp\u003e\u003cstrong\u003eTable 66.4. HeapTupleHeaderData Layout\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv\u003e\n\u003ctable\u003e\n\n\n\n\n\n\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eField\u003c/th\u003e\n\u003cth\u003eType\u003c/th\u003e\n\u003cth\u003eLength\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xmin\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003einsert XID stamp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xmax\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003edelete XID stamp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_cid\u003c/td\u003e\n\u003ctd\u003eCommandId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003einsert and/or delete CID stamp (overlays with t_xvac)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xvac\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003eXID for VACUUM operation moving a row version\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_ctid\u003c/td\u003e\n\u003ctd\u003eItemPointerData\u003c/td\u003e\n\u003ctd\u003e6 bytes\u003c/td\u003e\n\u003ctd\u003ecurrent TID of this or newer row version\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_infomask2\u003c/td\u003e\n\u003ctd\u003euint16\u003c/td\u003e\n\u003ctd\u003e2 bytes\u003c/td\u003e\n\u003ctd\u003enumber of attributes, plus various flag bits\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_infomask\u003c/td\u003e\n\u003ctd\u003euint16\u003c/td\u003e\n\u003ctd\u003e2 bytes\u003c/td\u003e\n\u003ctd\u003evarious flag bits\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_hoff\u003c/td\u003e\n\u003ctd\u003euint8\u003c/td\u003e\n\u003ctd\u003e1 byte\u003c/td\u003e\n\u003ctd\u003eoffset to user data\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cbr\u003e\n\u003cp\u003eAll the details can be found in \u003ccode\u003esrc/include/access/htup_details.h\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eInterpreting the actual data can only be done with information obtained from other tables, mostly \u003ccode\u003epg_attribute\u003c/code\u003e. The key values needed to identify field locations are \u003ccode\u003eattlen\u003c/code\u003e and \u003ccode\u003eattalign\u003c/code\u003e. There is no way to directly get a particular attribute, except when there are only fixed width fields and no null values. All this trickery is wrapped up in the functions \u003cem\u003eheap_getattr\u003c/em\u003e, \u003cem\u003efastgetattr\u003c/em\u003e and \u003cem\u003eheap_getsysattr\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eTo read the data you need to examine each attribute in turn. First check whether the field is NULL according to the null bitmap. If it is, go to the next. Then make sure you have the right alignment. If the field is a fixed width field, then all the bytes are simply placed. If it\u0026#39;s a variable length field (attlen = -1) then it\u0026#39;s a bit more complicated. All variable-length data types share the common header structure \u003ccode\u003estruct varlena\u003c/code\u003e, which includes the total length of the stored value and some flag bits. Depending on the flags, the data can be either inline or in a TOAST table; it might be compressed, too (see \u003ca href=\"/docs/18/storage-toast.html\" rel=\"nofollow\"\u003eSection 66.2\u003c/a\u003e).\u003c/p\u003e\n\u003c/div\u003e","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","ContentHash":"787d08d6acad13fa22e89999147bdc3f14fcc04438cd4ee835834e1bebc9a236","Payload":{"description":["Physical row headers, null bitmap, alignment and column data."],"manual_html":"\u003cdiv class=\"sect2\"\u003e\n\u003cdiv class=\"titlepage\"\u003e\n\u003cdiv\u003e\n\u003cdiv\u003e\n\u003ch3 class=\"title\"\u003e66.6.1. Table Row Layout \u003c/h3\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003eAll table rows are structured in the same way. There is a fixed-size header (occupying 23 bytes on most machines), followed by an optional null bitmap, an optional object ID field, and the user data. The header is detailed in \u003ca class=\"xref\" href=\"/docs/18/storage-page-layout.html#HEAPTUPLEHEADERDATA-TABLE\" title=\"Table 66.4. HeapTupleHeaderData Layout\"\u003eTable 66.4\u003c/a\u003e. The actual user data (columns of the row) begins at the offset indicated by \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e, which must always be a multiple of the MAXALIGN distance for the platform. The null bitmap is only present if the \u003cem class=\"firstterm\"\u003eHEAP_HASNULL\u003c/em\u003e bit is set in \u003ccode class=\"structfield\"\u003et_infomask\u003c/code\u003e. If it is present it begins just after the fixed header and occupies enough bytes to have one bit per data column (that is, the number of bits that equals the attribute count in \u003ccode class=\"structfield\"\u003et_infomask2\u003c/code\u003e). In this list of bits, a 1 bit indicates not-null, a 0 bit is a null. When the bitmap is not present, all columns are assumed not-null. The object ID is only present if the \u003cem class=\"firstterm\"\u003eHEAP_HASOID_OLD\u003c/em\u003e bit is set in \u003ccode class=\"structfield\"\u003et_infomask\u003c/code\u003e. If present, it appears just before the \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e boundary. Any padding needed to make \u003ccode class=\"structfield\"\u003et_hoff\u003c/code\u003e a MAXALIGN multiple will appear between the null bitmap and the object ID. (This in turn ensures that the object ID is suitably aligned.)\u003c/p\u003e\n\u003cdiv class=\"table\"\u003e\n\u003cp class=\"title\"\u003e\u003cstrong\u003eTable 66.4. HeapTupleHeaderData Layout\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"table-contents\"\u003e\n\u003ctable class=\"table\"\u003e\n\n\n\n\n\n\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eField\u003c/th\u003e\n\u003cth\u003eType\u003c/th\u003e\n\u003cth\u003eLength\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xmin\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003einsert XID stamp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xmax\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003edelete XID stamp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_cid\u003c/td\u003e\n\u003ctd\u003eCommandId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003einsert and/or delete CID stamp (overlays with t_xvac)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_xvac\u003c/td\u003e\n\u003ctd\u003eTransactionId\u003c/td\u003e\n\u003ctd\u003e4 bytes\u003c/td\u003e\n\u003ctd\u003eXID for VACUUM operation moving a row version\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_ctid\u003c/td\u003e\n\u003ctd\u003eItemPointerData\u003c/td\u003e\n\u003ctd\u003e6 bytes\u003c/td\u003e\n\u003ctd\u003ecurrent TID of this or newer row version\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_infomask2\u003c/td\u003e\n\u003ctd\u003euint16\u003c/td\u003e\n\u003ctd\u003e2 bytes\u003c/td\u003e\n\u003ctd\u003enumber of attributes, plus various flag bits\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_infomask\u003c/td\u003e\n\u003ctd\u003euint16\u003c/td\u003e\n\u003ctd\u003e2 bytes\u003c/td\u003e\n\u003ctd\u003evarious flag bits\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003et_hoff\u003c/td\u003e\n\u003ctd\u003euint8\u003c/td\u003e\n\u003ctd\u003e1 byte\u003c/td\u003e\n\u003ctd\u003eoffset to user data\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cbr class=\"table-break\"\u003e\n\u003cp\u003eAll the details can be found in \u003ccode class=\"filename\"\u003esrc/include/access/htup_details.h\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eInterpreting the actual data can only be done with information obtained from other tables, mostly \u003ccode class=\"structname\"\u003epg_attribute\u003c/code\u003e. The key values needed to identify field locations are \u003ccode class=\"structfield\"\u003eattlen\u003c/code\u003e and \u003ccode class=\"structfield\"\u003eattalign\u003c/code\u003e. There is no way to directly get a particular attribute, except when there are only fixed width fields and no null values. All this trickery is wrapped up in the functions \u003cem class=\"firstterm\"\u003eheap_getattr\u003c/em\u003e, \u003cem class=\"firstterm\"\u003efastgetattr\u003c/em\u003e and \u003cem class=\"firstterm\"\u003eheap_getsysattr\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eTo read the data you need to examine each attribute in turn. First check whether the field is NULL according to the null bitmap. If it is, go to the next. Then make sure you have the right alignment. If the field is a fixed width field, then all the bytes are simply placed. If it's a variable length field (attlen = -1) then it's a bit more complicated. All variable-length data types share the common header structure \u003ccode class=\"type\"\u003estruct varlena\u003c/code\u003e, which includes the total length of the stored value and some flag bits. Depending on the flags, the data can be either inline or in a TOAST table; it might be compressed, too (see \u003ca class=\"xref\" href=\"/docs/18/storage-toast.html\" title=\"66.2. TOAST\"\u003eSection 66.2\u003c/a\u003e).\u003c/p\u003e\n\u003c/div\u003e","related":[],"sections":[],"tables":[{"columns":[{"key":"c0","label":"Field"},{"key":"c1","label":"Type"},{"key":"c2","label":"Length"},{"key":"c3","label":"Description"}],"key":"layout-2","rows":[{"c0":"t_xmin","c1":"TransactionId","c2":"4 bytes","c3":"insert XID stamp"},{"c0":"t_xmax","c1":"TransactionId","c2":"4 bytes","c3":"delete XID stamp"},{"c0":"t_cid","c1":"CommandId","c2":"4 bytes","c3":"insert and/or delete CID stamp (overlays with t_xvac)"},{"c0":"t_xvac","c1":"TransactionId","c2":"4 bytes","c3":"XID for VACUUM operation moving a row version"},{"c0":"t_ctid","c1":"ItemPointerData","c2":"6 bytes","c3":"current TID of this or newer row version"},{"c0":"t_infomask2","c1":"uint16","c2":"2 bytes","c3":"number of attributes, plus various flag bits"},{"c0":"t_infomask","c1":"uint16","c2":"2 bytes","c3":"various flag bits"},{"c0":"t_hoff","c1":"uint8","c2":"1 byte","c3":"offset to user data"}],"title":"HeapTupleHeaderData Layout"}]}},"RequestedLocale":"en","Fallback":false,"Versions":["11","12","13","14","15","16","17","18","19","20"],"Locales":["en","zh-Hans"],"Signatures":null,"Spellings":null,"SQLState":null,"Evidence":null}
