# 1.1 The Physical Suitcase (The Tuple) ![The Tuple Suitcase](assets/arch_tuple_suitcase.png) In the depot of the Lazy Elephant, a **Tuple** is the absolute smallest unit of luggage. It’s not just a "row" of data; it’s a highly specific, slightly neurotic physical suitcase that carries everything a record needs to survive its journey through the database. It is critical to distinguish between the **Logical Row** and the **Physical Tuple**: - **The Row (Logical)**: This is the "ghost" or the "idea" of a record. When you say `SELECT * FROM animals WHERE id=1`, you are asking for the _concept_ of that animal. - **The Tuple (Physical)**: This is the actual physical suitcase sitting on a conveyor belt. Because of the elephant's refusal to erase things (see [[Chapter 1/1.4 - The Sharpie Ledger (MVCC)|1.4 - The Art of the Sharpie]]), a single logical **Row** might actually be represented by dozens of physical **Tuples**—old versions, newer versions, and deleted versions. --- ## 1. The Header (`HeapTupleHeaderData`) Living in the front pocket of every suitcase is a slightly stressed **Bureaucratic Bird** (the Header). Under the hood, this is literally the C-struct `HeapTupleHeaderData` defined in the Postgres engine. This 23-byte fixed-size structure is the "passport" of the tuple. It tells the system who created it, who deleted it, and whether it’s even legal to look at it without a formal invitation to a tea party. | Field | Size | Metaphor | Technical Description | | :----------- | :------ | :------------------- | :-------------------------------------------------------------------- | | `t_xmin` | 4 bytes | **Creation Stamp** | The Transaction ID (XID) that inserted this tuple. | | `t_xmax` | 4 bytes | **Deletion Stamp** | The Transaction ID that deleted or locked this tuple. | | `t_cid` | 4 bytes | **Command ID** | The specific command within the transaction that acted on it. | | `t_ctid` | 6 bytes | **Location Tag** | The physical address (Page #, Offset) of this tuple or its successor. | | `t_infomask` | 2 bytes | **Visibility Flags** | Bitflags describing the tuple's state (commits, aborts, has nulls). | > [!NOTE] > The `t_ctid` is the physical "GPS coordinate" of the suitcase defined as `(blockNumber, offsetNumber)`. If a row is updated, the old tuple’s `t_ctid` is updated to point to the new physical location of the next version. It’s like a trail of breadcrumbs, but the birds are too busy with paperwork to eat them! ### The Ghost Items (System Columns) Because of the Bird's meticulous record-keeping, every single tuple you create is secretly carrying extra "ghost" items you never asked for. Even if your table only has one column `(name text)`, the elephant quietly packs several **System Columns** into the suitcase. If you ever want to see these hidden passengers, you can explicitly ask the elephant for them in your query. Let's look at a specific animal in our cafe: ```sql -- Asking for the hidden passengers SELECT ctid, xmin, xmax, name FROM animals WHERE name = 'Babu'; ``` The elephant will return something like this: | ctid | xmin | xmax | name | | :---- | :--- | :--- | :--- | | (0,1) | 501 | 0 | Babu | * **`ctid (0,1)`**: This is the literal physical address in the depot: **Page 0, Offset 1**. * **`xmin 501`**: This is the ID of the transaction that "packed" this suitcase (inserted the row). * **`xmax 0`**: Since this is 0, it means nobody has "marked" this suitcase for deletion yet. It is a live, happy row! It’s a glimpse into the matrix! ## 2. The Null Bitmap (The Checklist) If your table has many columns that might be empty (NULL), the elephant doesn't want to waste suitcase space on them. Instead, it maintains a **Checklist** (the Null Bitmap) right after the header. If a bit is set to 0, the elephant knows that specific "item" wasn't packed, and it skips over it entirely when unpacking the suitcase. How very efficient! ## 3. The Padding Socks (Alignment) Postgres prefers to pick up suitcases in 8-byte chunks. If your data (Header + Bitmap + User Data) doesn't end on an 8-byte boundary, the elephant stuffs **Useless Padding Socks** into the corners. This is why a table with `(int, char(1), int)` might actually take up more space than `(int, int, char(1))`. The order of your belongings matters! It’s enough to make one’s hat spin! ## 4. TOAST (Oversized Attribute Storage) How curious! What if a single item is too big for the suitcase (usually > 2KB)? The elephant won't struggle with it. He won't push it, pull it, or try to fold it like a waistcoat. Instead, he ships the large item off to a **Separate Trailer** (the TOAST table) and leaves a tiny "Claim Check" in the suitcase. TOAST stands for **The Oversized-Attribute Storage Technique**, and it is the reason you can store multi-gigabyte "life story" strings without breaking the 8KB [[Structures/Page|Page]] limit. --- [[Chapter 1/1.0 - The Building Blocks of Storage|← 1.0 - The Logical vs. The Physical]] | [[Chapter 1/1.0 - The Building Blocks of Storage|↑ 1.0 - The Logical vs. The Physical]] | [[Chapter 1/1.2 - The Shipping Container (The Page)|1.2 - The Standard Size (8KB) →]]