htup.h 14.7 KB
Newer Older
1
 /*-------------------------------------------------------------------------
2
 *
3
 * htup.h
4
 *	  POSTGRES heap tuple definitions.
5 6
 *
 *
Bruce Momjian's avatar
Bruce Momjian committed
7
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
8
 * Portions Copyright (c) 1994, Regents of the University of California
9
 *
10
 * $Id: htup.h,v 1.61 2002/09/26 22:46:29 tgl Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14
#ifndef HTUP_H
15 16
#define HTUP_H

17
#include "storage/bufpage.h"
18
#include "storage/relfilenode.h"
19
#include "access/transam.h"
20 21


22
/*
23
 * MaxTupleAttributeNumber limits the number of (user) columns in a tuple.
24 25 26
 * The key limit on this value is that the size of the fixed overhead for
 * a tuple, plus the size of the null-values bitmap (at 1 bit per column),
 * plus MAXALIGN alignment, must fit into t_hoff which is uint8.  On most
27 28 29 30 31
 * machines the upper limit without making t_hoff wider would be a little
 * over 1700.  We use round numbers here and for MaxHeapAttributeNumber
 * so that alterations in HeapTupleHeaderData layout won't change the
 * supported max number of columns.
 */
Bruce Momjian's avatar
Bruce Momjian committed
32
#define MaxTupleAttributeNumber 1664	/* 8 * 208 */
33 34 35 36 37 38 39 40 41 42 43 44 45

/*----------
 * MaxHeapAttributeNumber limits the number of (user) columns in a table.
 * This should be somewhat less than MaxTupleAttributeNumber.  It must be
 * at least one less, else we will fail to do UPDATEs on a maximal-width
 * table (because UPDATE has to form working tuples that include CTID).
 * In practice we want some additional daylight so that we can gracefully
 * support operations that add hidden "resjunk" columns, for example
 * SELECT * FROM wide_table ORDER BY foo, bar, baz.
 * In any case, depending on column data types you will likely be running
 * into the disk-block-based limit on overall tuple size if you have more
 * than a thousand or so columns.  TOAST won't help.
 *----------
46
 */
47
#define MaxHeapAttributeNumber	1600	/* 8 * 200 */
48

49
/*----------
50 51
 * On-disk heap tuple header.  Currently this is also used as the header
 * format for tuples formed in memory, although in principle they could
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
 * be different.  To avoid wasting space, the fields should be layed out
 * in such a way to avoid structure padding.
 *
 * The overall structure of a heap tuple looks like:
 *			fixed fields (HeapTupleHeaderData struct)
 *			nulls bitmap (if HEAP_HASNULL is set in t_infomask)
 *			alignment padding (as needed to make user data MAXALIGN'd)
 *			object ID (if HEAP_HASOID is set in t_infomask)
 *			user data fields
 *
 * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac
 * in just three physical fields.  Xmin is always really stored, but
 * Cmin and Xmax share a field, as do Cmax and Xvac.  This works because
 * we know that there are only a limited number of states that a tuple can
 * be in, and that Cmin and Cmax are only interesting for the lifetime of
 * the inserting and deleting transactions respectively.  We have the
 * following possible states of a tuple:
 *
 *		XMIN		CMIN		XMAX		CMAX		XVAC
 *
 * NEW (never deleted, not moved by vacuum):
 *		valid		valid		invalid		invalid		invalid
74
 *
75 76 77 78 79 80 81
 * DELETED BY CREATING XACT:
 *		valid		valid		= XMIN		valid		invalid
 *
 * DELETED BY OTHER XACT:
 *		valid		unneeded	valid		valid		invalid
 *
 * MOVED BY VACUUM FULL:
Bruce Momjian's avatar
Bruce Momjian committed
82
 *		valid		unneeded	maybe-valid unneeded	valid
83 84 85 86 87 88 89 90 91
 *
 * This assumes that VACUUM FULL never tries to move a tuple whose Cmin or
 * Cmax is still interesting (ie, insert-in-progress or delete-in-progress).
 *
 * This table shows that if we use an infomask bit to handle the case
 * XMAX=XMIN specially, we never need to store Cmin and Xmax at the same
 * time.  Nor do we need to store Cmax and Xvac at the same time.
 *
 * Following the fixed header fields, the nulls bitmap is stored (beginning
Bruce Momjian's avatar
Bruce Momjian committed
92
 * at t_bits).	The bitmap is *not* stored if t_infomask shows that there
93 94
 * are no nulls in the tuple.  If an OID field is present (as indicated by
 * t_infomask), then it is stored just before the user data, which begins at
Bruce Momjian's avatar
Bruce Momjian committed
95
 * the offset shown by t_hoff.	Note that t_hoff must be a multiple of
96 97
 * MAXALIGN.
 *----------
98
 */
99
typedef struct HeapTupleHeaderData
100
{
Bruce Momjian's avatar
Bruce Momjian committed
101
	TransactionId t_xmin;		/* inserting xact ID */
102

Bruce Momjian's avatar
Bruce Momjian committed
103 104
	union
	{
105 106
		CommandId	t_cmin;		/* inserting command ID */
		TransactionId t_xmax;	/* deleting xact ID */
Bruce Momjian's avatar
Bruce Momjian committed
107
	}			t_field2;
108

Bruce Momjian's avatar
Bruce Momjian committed
109 110
	union
	{
111 112
		CommandId	t_cmax;		/* deleting command ID */
		TransactionId t_xvac;	/* VACUUM FULL xact ID */
Bruce Momjian's avatar
Bruce Momjian committed
113
	}			t_field3;
114

115
	ItemPointerData t_ctid;		/* current TID of this or newer tuple */
116

117
	int16		t_natts;		/* number of attributes */
118

119
	uint16		t_infomask;		/* various flag bits, see below */
120

121
	uint8		t_hoff;			/* sizeof header incl. bitmap, padding */
122

123
	/* ^ - 23 bytes - ^ */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
124

125
	bits8		t_bits[1];		/* bitmap of NULLs -- VARIABLE LENGTH */
126

127
	/* MORE DATA FOLLOWS AT END OF STRUCT */
128
} HeapTupleHeaderData;
129

130
typedef HeapTupleHeaderData *HeapTupleHeader;
131

132 133 134 135
/*
 * information stored in t_infomask:
 */
#define HEAP_HASNULL			0x0001	/* has null attribute(s) */
136
#define HEAP_HASVARWIDTH		0x0002	/* has variable-width attribute(s) */
137 138 139 140 141
#define HEAP_HASEXTERNAL		0x0004	/* has external stored
										 * attribute(s) */
#define HEAP_HASCOMPRESSED		0x0008	/* has compressed stored
										 * attribute(s) */
#define HEAP_HASEXTENDED		0x000C	/* the two above combined */
142 143
#define HEAP_HASOID				0x0010	/* has an object-id field */
/* bit 0x0020 is presently unused */
Bruce Momjian's avatar
Bruce Momjian committed
144 145
#define HEAP_XMAX_IS_XMIN		0x0040	/* created and deleted in the same
										 * transaction */
146 147
#define HEAP_XMAX_UNLOGGED		0x0080	/* to lock tuple for update
										 * without logging */
148 149 150 151 152 153 154
#define HEAP_XMIN_COMMITTED		0x0100	/* t_xmin committed */
#define HEAP_XMIN_INVALID		0x0200	/* t_xmin invalid/aborted */
#define HEAP_XMAX_COMMITTED		0x0400	/* t_xmax committed */
#define HEAP_XMAX_INVALID		0x0800	/* t_xmax invalid/aborted */
#define HEAP_MARKED_FOR_UPDATE	0x1000	/* marked for UPDATE */
#define HEAP_UPDATED			0x2000	/* this is UPDATEd version of row */
#define HEAP_MOVED_OFF			0x4000	/* moved to another place by
155
										 * VACUUM FULL */
156
#define HEAP_MOVED_IN			0x8000	/* moved from another place by
157
										 * VACUUM FULL */
158
#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)
159

160
#define HEAP_XACT_MASK			0xFFC0	/* visibility-related bits */
161 162


163 164 165
/*
 * HeapTupleHeader accessor macros
 *
Bruce Momjian's avatar
Bruce Momjian committed
166
 * Note: beware of multiple evaluations of "tup" argument.	But the Set
167 168
 * macros evaluate their other argument only once.
 */
169

170
#define HeapTupleHeaderGetXmin(tup) \
171 172 173
( \
	(tup)->t_xmin \
)
174

175
#define HeapTupleHeaderSetXmin(tup, xid) \
176
( \
177
	TransactionIdStore((xid), &(tup)->t_xmin) \
178 179
)

180
#define HeapTupleHeaderGetXmax(tup) \
181
( \
182 183
	((tup)->t_infomask & HEAP_XMAX_IS_XMIN) ? \
		(tup)->t_xmin \
184
	: \
185
		(tup)->t_field2.t_xmax \
186
)
187 188

#define HeapTupleHeaderSetXmax(tup, xid) \
189
do { \
190 191 192
	TransactionId	_newxid = (xid); \
	if (TransactionIdEquals((tup)->t_xmin, _newxid)) \
		(tup)->t_infomask |= HEAP_XMAX_IS_XMIN; \
193 194
	else \
	{ \
195 196
		(tup)->t_infomask &= ~HEAP_XMAX_IS_XMIN; \
		TransactionIdStore(_newxid, &(tup)->t_field2.t_xmax); \
197 198
	} \
} while (0)
199

200 201 202 203 204 205 206 207 208 209 210 211
/*
 * Note: GetCmin will produce wrong answers after SetXmax has been executed
 * by a transaction other than the inserting one.  We could check
 * HEAP_XMAX_INVALID and return FirstCommandId if it's clear, but since that
 * bit will be set again if the deleting transaction aborts, there'd be no
 * real gain in safety from the extra test.  So, just rely on the caller not
 * to trust the value unless it's meaningful.
 */
#define HeapTupleHeaderGetCmin(tup) \
( \
	(tup)->t_field2.t_cmin \
)
212 213

#define HeapTupleHeaderSetCmin(tup, cid) \
214
do { \
215 216
	Assert((tup)->t_infomask & HEAP_XMAX_INVALID); \
	(tup)->t_field2.t_cmin = (cid); \
217
} while (0)
218

219 220 221 222 223 224 225 226 227
/*
 * As with GetCmin, we can't completely ensure that GetCmax can detect whether
 * a valid command ID is available, and there's little point in a partial test.
 */
#define HeapTupleHeaderGetCmax(tup) \
( \
	(tup)->t_field3.t_cmax \
)

228
#define HeapTupleHeaderSetCmax(tup, cid) \
229 230
do { \
	Assert(!((tup)->t_infomask & HEAP_MOVED)); \
231
	(tup)->t_field3.t_cmax = (cid); \
232
} while (0)
233

234 235 236 237 238 239 240 241
#define HeapTupleHeaderGetXvac(tup) \
( \
	((tup)->t_infomask & HEAP_MOVED) ? \
		(tup)->t_field3.t_xvac \
	: \
		InvalidTransactionId \
)

242
#define HeapTupleHeaderSetXvac(tup, xid) \
243 244
do { \
	Assert((tup)->t_infomask & HEAP_MOVED); \
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
	TransactionIdStore((xid), &(tup)->t_field3.t_xvac); \
} while (0)

#define HeapTupleHeaderGetOid(tup) \
( \
	((tup)->t_infomask & HEAP_HASOID) ? \
		*((Oid *) ((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) \
	: \
		InvalidOid \
)

#define HeapTupleHeaderSetOid(tup, oid) \
do { \
	Assert((tup)->t_infomask & HEAP_HASOID); \
	*((Oid *) ((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) = (oid); \
260
} while (0)
261 262


Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
263
/*
264 265
 * WAL record definitions for heapam.c's WAL operations
 *
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
266 267 268
 * XLOG allows to store some information in high 4 bits of log
 * record xl_info field
 */
269 270 271 272 273
#define XLOG_HEAP_INSERT	0x00
#define XLOG_HEAP_DELETE	0x10
#define XLOG_HEAP_UPDATE	0x20
#define XLOG_HEAP_MOVE		0x30
#define XLOG_HEAP_CLEAN		0x40
274 275 276 277 278
#define XLOG_HEAP_OPMASK	0x70
/*
 * When we insert 1st item on new page in INSERT/UPDATE
 * we can (and we do) restore entire page in redo
 */
279
#define XLOG_HEAP_INIT_PAGE 0x80
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
280 281

/*
282
 * All what we need to find changed tuple (14 bytes)
283 284 285 286 287
 *
 * NB: on most machines, sizeof(xl_heaptid) will include some trailing pad
 * bytes for alignment.  We don't want to store the pad space in the XLOG,
 * so use SizeOfHeapTid for space calculations.  Similar comments apply for
 * the other xl_FOO structs.
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
288 289 290
 */
typedef struct xl_heaptid
{
291 292
	RelFileNode node;
	ItemPointerData tid;		/* changed tuple id */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
293 294
} xl_heaptid;

295 296
#define SizeOfHeapTid		(offsetof(xl_heaptid, tid) + SizeOfIptrData)

297
/* This is what we need to know about delete */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
298 299
typedef struct xl_heap_delete
{
300
	xl_heaptid	target;			/* deleted tuple id */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
301 302
} xl_heap_delete;

303
#define SizeOfHeapDelete	(offsetof(xl_heap_delete, target) + SizeOfHeapTid)
Vadim B. Mikheev's avatar
misc  
Vadim B. Mikheev committed
304

305 306 307 308 309 310 311 312
/*
 * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted
 * or updated tuple in WAL; we can save a few bytes by reconstructing the
 * fields that are available elsewhere in the WAL record, or perhaps just
 * plain needn't be reconstructed.  These are the fields we must store.
 * NOTE: t_hoff could be recomputed, but we may as well store it because
 * it will come for free due to alignment considerations.
 */
313
typedef struct xl_heap_header
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
314
{
315
	int16		t_natts;
316
	uint16		t_infomask;
317
	uint8		t_hoff;
318 319
} xl_heap_header;

320
#define SizeOfHeapHeader	(offsetof(xl_heap_header, t_hoff) + sizeof(uint8))
321 322 323 324

/* This is what we need to know about insert */
typedef struct xl_heap_insert
{
325
	xl_heaptid	target;			/* inserted tuple id */
326
	/* xl_heap_header & TUPLE DATA FOLLOWS AT END OF STRUCT */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
327 328
} xl_heap_insert;

329
#define SizeOfHeapInsert	(offsetof(xl_heap_insert, target) + SizeOfHeapTid)
Vadim B. Mikheev's avatar
misc  
Vadim B. Mikheev committed
330

331
/* This is what we need to know about update|move */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
332 333
typedef struct xl_heap_update
{
334 335
	xl_heaptid	target;			/* deleted tuple id */
	ItemPointerData newtid;		/* new inserted tuple id */
336
	/* NEW TUPLE xl_heap_header (PLUS xmax & xmin IF MOVE OP) */
337
	/* and TUPLE DATA FOLLOWS AT END OF STRUCT */
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
338 339
} xl_heap_update;

340 341 342 343 344
#define SizeOfHeapUpdate	(offsetof(xl_heap_update, newtid) + SizeOfIptrData)

/* This is what we need to know about page cleanup */
typedef struct xl_heap_clean
{
345 346
	RelFileNode node;
	BlockNumber block;
347
	/* UNUSED OFFSET NUMBERS FOLLOW AT THE END */
348 349
} xl_heap_clean;

350
#define SizeOfHeapClean (offsetof(xl_heap_clean, block) + sizeof(BlockNumber))
Vadim B. Mikheev's avatar
misc  
Vadim B. Mikheev committed
351

352 353


354 355
/*
 * MaxTupleSize is the maximum allowed size of a tuple, including header and
356
 * MAXALIGN alignment padding.	Basically it's BLCKSZ minus the other stuff
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
 * that has to be on a disk page.  The "other stuff" includes access-method-
 * dependent "special space", which we assume will be no more than
 * MaxSpecialSpace bytes (currently, on heap pages it's actually zero).
 *
 * NOTE: we do not need to count an ItemId for the tuple because
 * sizeof(PageHeaderData) includes the first ItemId on the page.
 */
#define MaxSpecialSpace  32

#define MaxTupleSize	\
	(BLCKSZ - MAXALIGN(sizeof(PageHeaderData) + MaxSpecialSpace))

/*
 * MaxAttrSize is a somewhat arbitrary upper limit on the declared size of
 * data fields of char(n) and similar types.  It need not have anything
 * directly to do with the *actual* upper limit of varlena values, which
 * is currently 1Gb (see struct varattrib in postgres.h).  I've set it
 * at 10Mb which seems like a reasonable number --- tgl 8/6/00.
 */
#define MaxAttrSize		(10 * 1024 * 1024)
377

378

379 380 381
/*
 * Attribute numbers for the system-defined attributes
 */
382 383 384 385 386 387
#define SelfItemPointerAttributeNumber			(-1)
#define ObjectIdAttributeNumber					(-2)
#define MinTransactionIdAttributeNumber			(-3)
#define MinCommandIdAttributeNumber				(-4)
#define MaxTransactionIdAttributeNumber			(-5)
#define MaxCommandIdAttributeNumber				(-6)
388
#define TableOidAttributeNumber					(-7)
389
#define FirstLowInvalidHeapAttributeNumber		(-8)
390

391
/*
392
 * HeapTupleData is an in-memory data structure that points to a tuple.
Bruce Momjian's avatar
Bruce Momjian committed
393
 *
394 395 396 397
 * This new HeapTuple for version >= 6.5 and this is why it was changed:
 *
 * 1. t_len moved off on-disk tuple data - ItemIdData is used to get len;
 * 2. t_ctid above is not self tuple TID now - it may point to
Bruce Momjian's avatar
Bruce Momjian committed
398 399 400
 *	  updated version of tuple (required by MVCC);
 * 3. someday someone let tuple to cross block boundaries -
 *	  he have to add something below...
401 402
 *
 * Change for 7.0:
403
 *	  Up to now t_data could be NULL, the memory location directly following
Tom Lane's avatar
Tom Lane committed
404
 *	  HeapTupleData, or pointing into a buffer. Now, it could also point to
405
 *	  a separate allocation that was done in the t_datamcxt memory context.
406 407 408
 */
typedef struct HeapTupleData
{
409 410 411 412 413
	uint32		t_len;			/* length of *t_data */
	ItemPointerData t_self;		/* SelfItemPointer */
	Oid			t_tableOid;		/* table the tuple came from */
	MemoryContext t_datamcxt;	/* memory context of allocation */
	HeapTupleHeader t_data;		/* -> tuple header and data */
414
} HeapTupleData;
Bruce Momjian's avatar
Bruce Momjian committed
415

416 417
typedef HeapTupleData *HeapTuple;

418
#define HEAPTUPLESIZE	MAXALIGN(sizeof(HeapTupleData))
Bruce Momjian's avatar
Bruce Momjian committed
419 420


421 422
/*
 * GETSTRUCT - given a HeapTuple pointer, return address of the user data
423
 */
424
#define GETSTRUCT(TUP) ((char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff)
425 426 427


/*
428
 * BITMAPLEN(NATTS) -
429
 *		Computes size of null bitmap given number of data columns.
430
 */
431
#define BITMAPLEN(NATTS)	(((int)(NATTS) + 7) / 8)
432 433 434

/*
 * HeapTupleIsValid
435
 *		True iff the heap tuple is valid.
436
 */
437
#define HeapTupleIsValid(tuple) PointerIsValid(tuple)
438 439

#define HeapTupleNoNulls(tuple) \
440
		(!((tuple)->t_data->t_infomask & HEAP_HASNULL))
441 442

#define HeapTupleAllFixed(tuple) \
443
		(!((tuple)->t_data->t_infomask & HEAP_HASVARWIDTH))
444

445
#define HeapTupleHasExternal(tuple) \
446
		(((tuple)->t_data->t_infomask & HEAP_HASEXTERNAL) != 0)
447 448

#define HeapTupleHasCompressed(tuple) \
449
		(((tuple)->t_data->t_infomask & HEAP_HASCOMPRESSED) != 0)
450 451

#define HeapTupleHasExtended(tuple) \
452
		(((tuple)->t_data->t_infomask & HEAP_HASEXTENDED) != 0)
453

454
#define HeapTupleGetOid(tuple) \
455
		HeapTupleHeaderGetOid((tuple)->t_data)
456 457

#define HeapTupleSetOid(tuple, oid) \
458
		HeapTupleHeaderSetOid((tuple)->t_data, (oid))
459

460
#endif   /* HTUP_H */