aboutsummaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/include')
-rw-r--r--src/include/access/htup.h279
-rw-r--r--src/include/access/tupdesc.h32
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/heap.h3
-rw-r--r--src/include/executor/executor.h4
-rw-r--r--src/include/pg_config.h.in8
-rw-r--r--src/include/storage/bufpage.h60
7 files changed, 199 insertions, 191 deletions
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index f1d9748f5c5..3bede1bfa3a 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: htup.h,v 1.58 2002/08/25 17:20:01 tgl Exp $
+ * $Id: htup.h,v 1.59 2002/09/02 01:05:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,33 +46,69 @@
*/
#define MaxHeapAttributeNumber 1600 /* 8 * 200 */
-/*
+/*----------
* On-disk heap tuple header. Currently this is also used as the header
* format for tuples formed in memory, although in principle they could
- * be different.
+ * 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
*
- * To avoid wasting space, the attributes should be layed out in such a
- * way to reduce structure padding. Note that t_hoff is the offset to
- * the start of the user data, and so must be a multiple of MAXALIGN.
- * Also note that we omit the nulls bitmap if t_infomask shows that there
- * are no nulls in the tuple.
+ * DELETED BY CREATING XACT:
+ * valid valid = XMIN valid invalid
+ *
+ * DELETED BY OTHER XACT:
+ * valid unneeded valid valid invalid
+ *
+ * MOVED BY VACUUM FULL:
+ * valid unneeded maybe-valid unneeded valid
+ *
+ * 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
+ * at t_bits). The bitmap is *not* stored if t_infomask shows that there
+ * 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
+ * the offset shown by t_hoff. Note that t_hoff must be a multiple of
+ * MAXALIGN.
+ *----------
*/
-/*
-** We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac
-** in three physical fields t_xmin, t_cid, t_xmax:
-** CommandId Cmin; insert CID stamp
-** CommandId Cmax; delete CommandId stamp
-** TransactionId Xmin; insert XID stamp
-** TransactionId Xmax; delete XID stamp
-** TransactionId Xvac; used by VACCUUM
-**
-** This assumes, that a CommandId can be stored in a TransactionId.
-*/
typedef struct HeapTupleHeaderData
{
- TransactionId t_xmin; /* Xmin -- 4 bytes each */
- TransactionId t_cid; /* Cmin, Cmax, Xvac */
- TransactionId t_xmax; /* Xmax, Cmax */
+ TransactionId t_xmin; /* inserting xact ID */
+
+ union {
+ CommandId t_cmin; /* inserting command ID */
+ TransactionId t_xmax; /* deleting xact ID */
+ } t_field2;
+
+ union {
+ CommandId t_cmax; /* deleting command ID */
+ TransactionId t_xvac; /* VACUUM FULL xact ID */
+ } t_field3;
ItemPointerData t_ctid; /* current TID of this or newer tuple */
@@ -101,11 +137,12 @@ typedef HeapTupleHeaderData *HeapTupleHeader;
#define HEAP_HASCOMPRESSED 0x0008 /* has compressed stored
* attribute(s) */
#define HEAP_HASEXTENDED 0x000C /* the two above combined */
-
-#define HEAP_XMIN_IS_XMAX 0x0040 /* created and deleted in the */
- /* same transaction */
-#define HEAP_XMAX_UNLOGGED 0x0080 /* to lock tuple for update */
- /* without logging */
+#define HEAP_HASOID 0x0010 /* has an object-id field */
+/* bit 0x0020 is presently unused */
+#define HEAP_XMAX_IS_XMIN 0x0040 /* created and deleted in the
+ * same transaction */
+#define HEAP_XMAX_UNLOGGED 0x0080 /* to lock tuple for update
+ * without logging */
#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 */
@@ -113,143 +150,111 @@ typedef HeapTupleHeaderData *HeapTupleHeader;
#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
- * vacuum */
+ * VACUUM FULL */
#define HEAP_MOVED_IN 0x8000 /* moved from another place by
- * vacuum */
+ * VACUUM FULL */
#define HEAP_MOVED (HEAP_MOVED_OFF | HEAP_MOVED_IN)
-#define HEAP_XACT_MASK 0xFFF0 /* visibility-related bits */
-
-/* paranoid checking */
-
-#ifdef DEBUG_TUPLE_ACCESS
-
-#define HeapTupleHeaderExpectedLen(tup, withoid) \
- MAXALIGN(offsetof(HeapTupleHeaderData, t_bits) + \
- (((tup)->t_infomask & HEAP_HASNULL) \
- ? BITMAPLEN((tup)->t_natts) : 0) + \
- ((withoid) ? sizeof(Oid) : 0) \
- )
-
-#define AssertHeapTupleHeaderHoffIsValid(tup, withoid) \
- AssertMacro((tup)->t_hoff == HeapTupleHeaderExpectedLen(tup, withoid))
-
-#else
-
-#define AssertHeapTupleHeaderHoffIsValid(tup, withoid) ((void)true)
-
-#endif /* DEBUG_TUPLE_ACCESS */
-
+#define HEAP_XACT_MASK 0xFFC0 /* visibility-related bits */
-/* HeapTupleHeader accessor macros */
-#define HeapTupleHeaderGetOid(tup) \
-( \
- AssertHeapTupleHeaderHoffIsValid(tup, true), \
- *((Oid *)((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) \
-)
-
-#define HeapTupleHeaderSetOid(tup, oid) \
-( \
- AssertHeapTupleHeaderHoffIsValid(tup, true), \
- *((Oid *)((char *)(tup) + (tup)->t_hoff - sizeof(Oid))) = (oid) \
-)
-
+/*
+ * HeapTupleHeader accessor macros
+ *
+ * Note: beware of multiple evaluations of "tup" argument. But the Set
+ * macros evaluate their other argument only once.
+ */
#define HeapTupleHeaderGetXmin(tup) \
( \
(tup)->t_xmin \
)
-#define HeapTupleHeaderGetXmax(tup) \
-( \
- ((tup)->t_infomask & HEAP_XMIN_IS_XMAX) ? \
- (tup)->t_xmin \
- : \
- (tup)->t_xmax \
-)
-
-/* no AssertMacro, because this is read as a system-defined attribute */
-#define HeapTupleHeaderGetCmin(tup) \
+#define HeapTupleHeaderSetXmin(tup, xid) \
( \
- ((tup)->t_infomask & HEAP_MOVED) ? \
- FirstCommandId \
- : \
- ( \
- ((tup)->t_infomask & (HEAP_XMIN_IS_XMAX | HEAP_XMAX_INVALID)) ? \
- (CommandId) (tup)->t_cid \
- : \
- FirstCommandId \
- ) \
+ TransactionIdStore((xid), &(tup)->t_xmin) \
)
-#define HeapTupleHeaderGetCmax(tup) \
+#define HeapTupleHeaderGetXmax(tup) \
( \
- ((tup)->t_infomask & HEAP_MOVED) ? \
- FirstCommandId \
+ ((tup)->t_infomask & HEAP_XMAX_IS_XMIN) ? \
+ (tup)->t_xmin \
: \
- ( \
- ((tup)->t_infomask & (HEAP_XMIN_IS_XMAX | HEAP_XMAX_INVALID)) ? \
- (CommandId) (tup)->t_xmax \
- : \
- (CommandId) (tup)->t_cid \
- ) \
-)
-
-#define HeapTupleHeaderGetXvac(tup) \
-( \
- AssertMacro((tup)->t_infomask & HEAP_MOVED), \
- (tup)->t_cid \
-)
-
-
-#define HeapTupleHeaderSetXmin(tup, xid) \
-( \
- TransactionIdStore((xid), &(tup)->t_xmin) \
+ (tup)->t_field2.t_xmax \
)
-#define HeapTupleHeaderSetXminInvalid(tup) \
-do { \
- (tup)->t_infomask &= ~HEAP_XMIN_IS_XMAX; \
- StoreInvalidTransactionId(&(tup)->t_xmin); \
-} while (0)
-
#define HeapTupleHeaderSetXmax(tup, xid) \
do { \
- if (TransactionIdEquals((tup)->t_xmin, (xid))) \
- (tup)->t_infomask |= HEAP_XMIN_IS_XMAX; \
+ TransactionId _newxid = (xid); \
+ if (TransactionIdEquals((tup)->t_xmin, _newxid)) \
+ (tup)->t_infomask |= HEAP_XMAX_IS_XMIN; \
else \
{ \
- (tup)->t_infomask &= ~HEAP_XMIN_IS_XMAX; \
- TransactionIdStore((xid), &(tup)->t_xmax); \
+ (tup)->t_infomask &= ~HEAP_XMAX_IS_XMIN; \
+ TransactionIdStore(_newxid, &(tup)->t_field2.t_xmax); \
} \
} while (0)
-#define HeapTupleHeaderSetXmaxInvalid(tup) \
-do { \
- (tup)->t_infomask &= ~HEAP_XMIN_IS_XMAX; \
- StoreInvalidTransactionId(&(tup)->t_xmax); \
-} while (0)
+/*
+ * 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 \
+)
#define HeapTupleHeaderSetCmin(tup, cid) \
do { \
- Assert(!((tup)->t_infomask & HEAP_MOVED)); \
- TransactionIdStore((TransactionId) (cid), &(tup)->t_cid); \
+ Assert((tup)->t_infomask & HEAP_XMAX_INVALID); \
+ (tup)->t_field2.t_cmin = (cid); \
} while (0)
+/*
+ * 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 \
+)
+
#define HeapTupleHeaderSetCmax(tup, cid) \
do { \
Assert(!((tup)->t_infomask & HEAP_MOVED)); \
- if ((tup)->t_infomask & HEAP_XMIN_IS_XMAX) \
- TransactionIdStore((TransactionId) (cid), &(tup)->t_xmax); \
- else \
- TransactionIdStore((TransactionId) (cid), &(tup)->t_cid); \
+ (tup)->t_field3.t_cmax = (cid); \
} while (0)
+#define HeapTupleHeaderGetXvac(tup) \
+( \
+ ((tup)->t_infomask & HEAP_MOVED) ? \
+ (tup)->t_field3.t_xvac \
+ : \
+ InvalidTransactionId \
+)
+
#define HeapTupleHeaderSetXvac(tup, xid) \
do { \
Assert((tup)->t_infomask & HEAP_MOVED); \
- TransactionIdStore((xid), &(tup)->t_cid); \
+ 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); \
} while (0)
@@ -400,12 +405,10 @@ typedef HeapTupleData *HeapTuple;
#define HEAPTUPLESIZE MAXALIGN(sizeof(HeapTupleData))
-/* ----------------
- * support macros
- * ----------------
+/*
+ * GETSTRUCT - given a HeapTuple pointer, return address of the user data
*/
-#define GETSTRUCT(TUP) (((char *)((HeapTuple)(TUP))->t_data) + \
- ((HeapTuple)(TUP))->t_data->t_hoff)
+#define GETSTRUCT(TUP) ((char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff)
/*
@@ -421,24 +424,24 @@ typedef HeapTupleData *HeapTuple;
#define HeapTupleIsValid(tuple) PointerIsValid(tuple)
#define HeapTupleNoNulls(tuple) \
- (!(((HeapTuple) (tuple))->t_data->t_infomask & HEAP_HASNULL))
+ (!((tuple)->t_data->t_infomask & HEAP_HASNULL))
#define HeapTupleAllFixed(tuple) \
- (!(((HeapTuple) (tuple))->t_data->t_infomask & HEAP_HASVARWIDTH))
+ (!((tuple)->t_data->t_infomask & HEAP_HASVARWIDTH))
#define HeapTupleHasExternal(tuple) \
- ((((HeapTuple)(tuple))->t_data->t_infomask & HEAP_HASEXTERNAL) != 0)
+ (((tuple)->t_data->t_infomask & HEAP_HASEXTERNAL) != 0)
#define HeapTupleHasCompressed(tuple) \
- ((((HeapTuple)(tuple))->t_data->t_infomask & HEAP_HASCOMPRESSED) != 0)
+ (((tuple)->t_data->t_infomask & HEAP_HASCOMPRESSED) != 0)
#define HeapTupleHasExtended(tuple) \
- ((((HeapTuple)(tuple))->t_data->t_infomask & HEAP_HASEXTENDED) != 0)
+ (((tuple)->t_data->t_infomask & HEAP_HASEXTENDED) != 0)
#define HeapTupleGetOid(tuple) \
- HeapTupleHeaderGetOid(((HeapTuple)(tuple))->t_data)
+ HeapTupleHeaderGetOid((tuple)->t_data)
#define HeapTupleSetOid(tuple, oid) \
- HeapTupleHeaderSetOid(((HeapTuple)(tuple))->t_data, (oid))
+ HeapTupleHeaderSetOid((tuple)->t_data, (oid))
#endif /* HTUP_H */
diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h
index c8c9839985e..09512a322e1 100644
--- a/src/include/access/tupdesc.h
+++ b/src/include/access/tupdesc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: tupdesc.h,v 1.37 2002/07/20 05:16:59 momjian Exp $
+ * $Id: tupdesc.h,v 1.38 2002/09/02 01:05:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,14 +41,9 @@ typedef struct tupleConstr
bool has_not_null;
} TupleConstr;
-typedef char hasoid_t;
-#define WITHOID 'C'
-#define WITHOUTOID 'S'
-#define UNDEFOID '?'
-#define BoolToHasOid(b) ((b) ? WITHOID : WITHOUTOID)
/*
* This structure contains all information (i.e. from Classes
- * pg_attribute, pg_attrdef, pg_constraint) for a tuple.
+ * pg_attribute, pg_attrdef, pg_constraint) for the structure of a tuple.
*/
typedef struct tupleDesc
{
@@ -56,29 +51,14 @@ typedef struct tupleDesc
Form_pg_attribute *attrs;
/* attrs[N] is a pointer to the description of Attribute Number N+1. */
TupleConstr *constr;
- hasoid_t tdhasoid; /* Tuple has an oid attribute in its header */
+ bool tdhasoid; /* Tuple has oid attribute in its header */
} *TupleDesc;
-#ifdef DEBUG_TUPLE_ACCESS
-#define AssertTupleDescHasOidIsValid(td) \
- Assert(((td)->tdhasoid == WITHOID) || ((td)->tdhasoid == WITHOUTOID))
-#define AssertTupleDescHasOid(td) \
- Assert((td)->tdhasoid == WITHOID)
-#define AssertTupleDescHasNoOid(td) \
- Assert((td)->tdhasoid == WITHOUTOID)
+extern TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid);
-#else
-
-#define AssertTupleDescHasOidIsValid(td)
-#define AssertTupleDescHasOid(td)
-#define AssertTupleDescHasNoOid(td)
-
-#endif
-
-extern TupleDesc CreateTemplateTupleDesc(int natts, hasoid_t withoid);
-
-extern TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs);
+extern TupleDesc CreateTupleDesc(int natts, bool hasoid,
+ Form_pg_attribute *attrs);
extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc);
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f561dee66b1..652009104fe 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.156 2002/08/31 17:14:28 tgl Exp $
+ * $Id: catversion.h,v 1.157 2002/09/02 01:05:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200208311
+#define CATALOG_VERSION_NO 200209011
#endif
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index f45c61515ad..b1f5dc8600c 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: heap.h,v 1.55 2002/08/02 18:15:09 tgl Exp $
+ * $Id: heap.h,v 1.56 2002/09/02 01:05:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,7 +41,6 @@ extern Oid heap_create_with_catalog(const char *relname,
TupleDesc tupdesc,
char relkind,
bool shared_relation,
- bool relhasoids,
bool allow_system_table_mods);
extern void heap_drop_with_catalog(Oid rid);
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 3fbf63567ac..f2fa81857cd 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: executor.h,v 1.76 2002/08/30 23:59:46 tgl Exp $
+ * $Id: executor.h,v 1.77 2002/09/02 01:05:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -122,7 +122,7 @@ extern void ExecInitScanTupleSlot(EState *estate,
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
TupleDesc tupType);
-extern TupleDesc ExecTypeFromTL(List *targetList, hasoid_t withoid);
+extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
extern void SetChangedParamList(Plan *node, List *newchg);
typedef struct TupOutputState
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index a64be7fcf2a..670c80a4030 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -8,7 +8,7 @@
* or in pg_config.h afterwards. Of course, if you edit pg_config.h, then your
* changes will be overwritten the next time you run configure.
*
- * $Id: pg_config.h.in,v 1.29 2002/08/29 08:03:22 ishii Exp $
+ * $Id: pg_config.h.in,v 1.30 2002/09/02 01:05:06 tgl Exp $
*/
#ifndef PG_CONFIG_H
@@ -298,12 +298,6 @@
/* #define ACLDEBUG */
/* #define RTDEBUG */
/* #define GISTDEBUG */
-/*
- * DEBUG_TUPLE_ACCESS enables paranoid assertions during
- * elimination of oids from the fixed sized part of HeapTupleHeader.
- * This is expected to be undef'd after v7.3 release at the latest.
- */
-#define DEBUG_TUPLE_ACCESS
/*
* defining unsafe floats will make float4 and float8 ops faster
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index a9fc0f7a2a2..7a6080a1bcd 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: bufpage.h,v 1.51 2002/08/06 19:37:10 tgl Exp $
+ * $Id: bufpage.h,v 1.52 2002/09/02 01:05:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -97,12 +97,20 @@ typedef uint16 LocationIndex;
* pd_lower - offset to start of free space.
* pd_upper - offset to end of free space.
* pd_special - offset to start of special space.
- * pd_pagesize - size in bytes.
- * Minimum possible page size is perhaps 64B to fit
- * page header, opaque space and a minimal tuple;
- * of course, in reality you want it much bigger.
- * On the high end, we can only support pages up
- * to 32KB because lp_off/lp_len are 15 bits.
+ * pd_pagesize_version - size in bytes and page layout version number.
+ *
+ * The page version number and page size are packed together into a single
+ * uint16 field. This is for historical reasons: before PostgreSQL 7.3,
+ * there was no concept of a page version number, and doing it this way
+ * lets us pretend that pre-7.3 databases have page version number zero.
+ * We constrain page sizes to be multiples of 256, leaving the low eight
+ * bytes available for a version number.
+ *
+ * Minimum possible page size is perhaps 64B to fit page header, opaque space
+ * and a minimal tuple; of course, in reality you want it much bigger, so
+ * the constraint on pagesize mod 256 is not an important restriction.
+ * On the high end, we can only support pages up to 32KB because lp_off/lp_len
+ * are 15 bits.
*/
typedef struct PageHeaderData
{
@@ -116,12 +124,18 @@ typedef struct PageHeaderData
LocationIndex pd_lower; /* offset to start of free space */
LocationIndex pd_upper; /* offset to end of free space */
LocationIndex pd_special; /* offset to start of special space */
- uint16 pd_pagesize;
+ uint16 pd_pagesize_version;
ItemIdData pd_linp[1]; /* beginning of line pointer array */
} PageHeaderData;
typedef PageHeaderData *PageHeader;
+/*
+ * Page layout version number 0 is for pre-7.3 Postgres releases. The
+ * current version number is 1, denoting a new HeapTupleHeader layout.
+ */
+#define PG_PAGE_LAYOUT_VERSION 1
+
/* ----------------------------------------------------------------
* page support macros
@@ -178,7 +192,7 @@ typedef PageHeaderData *PageHeader;
((char *) (&((PageHeader) (page))->pd_linp[0]))
/* ----------------
- * macros to access opaque space
+ * macros to access page size info
* ----------------
*/
@@ -203,14 +217,32 @@ typedef PageHeaderData *PageHeader;
* however, it can be called on a page for which there is no buffer.
*/
#define PageGetPageSize(page) \
- ((Size) ((PageHeader) (page))->pd_pagesize)
+ ((Size) (((PageHeader) (page))->pd_pagesize_version & (uint16) 0xFF00))
/*
- * PageSetPageSize
- * Sets the page size of a page.
+ * PageGetPageLayoutVersion
+ * Returns the page layout version of a page.
+ *
+ * this can only be called on a formatted page (unlike
+ * BufferGetPageSize, which can be called on an unformatted page).
+ * however, it can be called on a page for which there is no buffer.
*/
-#define PageSetPageSize(page, size) \
- (((PageHeader) (page))->pd_pagesize = (size))
+#define PageGetPageLayoutVersion(page) \
+ (((PageHeader) (page))->pd_pagesize_version & 0x00FF)
+
+/*
+ * PageSetPageSizeAndVersion
+ * Sets the page size and page layout version number of a page.
+ *
+ * We could support setting these two values separately, but there's
+ * no real need for it at the moment.
+ */
+#define PageSetPageSizeAndVersion(page, size, version) \
+( \
+ AssertMacro(((size) & 0xFF00) == (size)), \
+ AssertMacro(((version) & 0x00FF) == (version)), \
+ ((PageHeader) (page))->pd_pagesize_version = (size) | (version) \
+)
/* ----------------
* page special data macros