From 3212cf94176ff439095104693f45108f3c6d3a6d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 27 May 2002 19:53:33 +0000 Subject: [PATCH] Distinguish between MaxHeapAttributeNumber and MaxTupleAttributeNumber, where the latter is made slightly larger to allow for in-memory tuples containing resjunk attributes. Responds to today's complaint that one cannot UPDATE a table containing the allegedly-legal maximum number of columns. Also, apply Manfred Koizar's recent patch to avoid extra alignment padding when there is a null bitmap. This saves bytes in some cases while not creating any backward-compatibility problem AFAICS. --- src/backend/access/common/heaptuple.c | 24 ++++----- src/backend/access/heap/tuptoaster.c | 32 +++++------- src/include/access/htup.h | 70 ++++++++++++++++----------- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 5b005b3163..daad2bd537 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.74 2001/10/25 05:49:20 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.75 2002/05/27 19:53:33 tgl Exp $ * * NOTES * The old interface functions have been converted to macros @@ -571,18 +571,15 @@ heap_formtuple(TupleDesc tupleDescriptor, { HeapTuple tuple; /* return tuple */ HeapTupleHeader td; /* tuple data */ - int bitmaplen; unsigned long len; int hoff; bool hasnull = false; int i; int numberOfAttributes = tupleDescriptor->natts; - if (numberOfAttributes > MaxHeapAttributeNumber) - elog(ERROR, "heap_formtuple: numberOfAttributes of %d > %d", - numberOfAttributes, MaxHeapAttributeNumber); - - len = offsetof(HeapTupleHeaderData, t_bits); + if (numberOfAttributes > MaxTupleAttributeNumber) + elog(ERROR, "heap_formtuple: numberOfAttributes %d exceeds limit %d", + numberOfAttributes, MaxTupleAttributeNumber); for (i = 0; i < numberOfAttributes; i++) { @@ -593,13 +590,12 @@ heap_formtuple(TupleDesc tupleDescriptor, } } - if (hasnull) - { - bitmaplen = BITMAPLEN(numberOfAttributes); - len += bitmaplen; - } + len = offsetof(HeapTupleHeaderData, t_bits); - hoff = len = MAXALIGN(len); /* be conservative here */ + if (hasnull) + len += BITMAPLEN(numberOfAttributes); + + hoff = len = MAXALIGN(len); /* align user data safely */ len += ComputeDataSize(tupleDescriptor, value, nulls); @@ -615,7 +611,7 @@ heap_formtuple(TupleDesc tupleDescriptor, td->t_natts = numberOfAttributes; td->t_hoff = hoff; - DataFill((char *) td + td->t_hoff, + DataFill((char *) td + hoff, tupleDescriptor, value, nulls, diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index ab5e96f8cc..3c66aed1db 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.31 2002/05/24 18:57:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.32 2002/05/27 19:53:33 tgl Exp $ * * * INTERFACE ROUTINES @@ -715,39 +715,34 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) */ if (need_change) { + HeapTupleHeader olddata = newtup->t_data; char *new_data; int32 new_len; - MemoryContext oldcxt; - HeapTupleHeader olddata; /* - * Calculate the new size of the tuple + * Calculate the new size of the tuple. Header size should not + * change, but data size might. */ new_len = offsetof(HeapTupleHeaderData, t_bits); if (has_nulls) new_len += BITMAPLEN(numAttrs); new_len = MAXALIGN(new_len); + Assert(new_len == olddata->t_hoff); new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls); /* - * Remember the old memory location of the tuple (for below), - * switch to the memory context of the HeapTuple structure and - * allocate the new tuple. + * Allocate new tuple in same context as old one. */ - olddata = newtup->t_data; - oldcxt = MemoryContextSwitchTo(newtup->t_datamcxt); - new_data = palloc(new_len); + new_data = (char *) MemoryContextAlloc(newtup->t_datamcxt, new_len); + newtup->t_data = (HeapTupleHeader) new_data; + newtup->t_len = new_len; /* * Put the tuple header and the changed values into place */ - memcpy(new_data, newtup->t_data, newtup->t_data->t_hoff); - newtup->t_data = (HeapTupleHeader) new_data; - newtup->t_len = new_len; + memcpy(new_data, olddata, olddata->t_hoff); - DataFill((char *) (MAXALIGN((long) new_data + - offsetof(HeapTupleHeaderData, t_bits) + - ((has_nulls) ? BITMAPLEN(numAttrs) : 0))), + DataFill((char *) new_data + olddata->t_hoff, tupleDesc, toast_values, toast_nulls, @@ -760,11 +755,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) */ if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE)) pfree(olddata); - - /* - * Switch back to the old memory context - */ - MemoryContextSwitchTo(oldcxt); } /* diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 08506bbf8f..4860c4ec57 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: htup.h,v 1.51 2001/11/05 17:46:31 momjian Exp $ + * $Id: htup.h,v 1.52 2002/05/27 19:53:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,25 +17,44 @@ #include "storage/bufpage.h" #include "storage/relfilenode.h" -#define MinHeapTupleBitmapSize 32 /* 8 * 4 */ /* - * MaxHeapAttributeNumber limits the number of (user) columns in a table. + * MaxTupleAttributeNumber limits the number of (user) columns in a tuple. * 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 - * machines the absolute upper limit without making t_hoff wider would be - * about 1700. Note, however, that depending on column data types you will - * likely also 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. + * 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. + */ +#define MaxTupleAttributeNumber 1664 /* 8 * 208 */ + +/*---------- + * 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. + *---------- */ #define MaxHeapAttributeNumber 1600 /* 8 * 200 */ /* - * This is the on-disk copy of the tuple. + * 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. * * To avoid wasting space, the attributes should be layed out in such a - * way to reduce structure padding. + * 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. */ typedef struct HeapTupleHeaderData { @@ -51,14 +70,13 @@ typedef struct HeapTupleHeaderData int16 t_natts; /* number of attributes */ - uint16 t_infomask; /* various infos */ + uint16 t_infomask; /* various flag bits, see below */ - uint8 t_hoff; /* sizeof() tuple header */ + uint8 t_hoff; /* sizeof header incl. bitmap, padding */ /* ^ - 31 bytes - ^ */ - bits8 t_bits[MinHeapTupleBitmapSize / 8]; - /* bit map of NULLs */ + bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */ /* MORE DATA FOLLOWS AT END OF STRUCT */ } HeapTupleHeaderData; @@ -183,7 +201,7 @@ typedef struct xl_heap_clean #define FirstLowInvalidHeapAttributeNumber (-8) /* - * This is the in-memory copy of the tuple. + * HeapTupleData is an in-memory data structure that points to a tuple. * * This new HeapTuple for version >= 6.5 and this is why it was changed: * @@ -222,11 +240,9 @@ typedef HeapTupleData *HeapTuple; /* * BITMAPLEN(NATTS) - - * Computes minimum size of bitmap given number of domains. + * Computes size of null bitmap given number of data columns. */ -#define BITMAPLEN(NATTS) \ - ((((((int)(NATTS) - 1) >> 3) + 4 - (MinHeapTupleBitmapSize >> 3)) \ - & ~03) + (MinHeapTupleBitmapSize >> 3)) +#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8) /* * HeapTupleIsValid @@ -240,26 +256,26 @@ typedef HeapTupleData *HeapTuple; #define HEAP_HASNULL 0x0001 /* has null attribute(s) */ #define HEAP_HASVARLENA 0x0002 /* has variable length * attribute(s) */ -#define HEAP_HASEXTERNAL 0x0004 /* has external stored */ - /* attribute(s) */ -#define HEAP_HASCOMPRESSED 0x0008 /* has compressed stored */ - /* attribute(s) */ +#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 */ -#define HEAP_XMAX_UNLOGGED 0x0080 /* to lock tuple for update */ - /* without logging */ +#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 */ #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 /* removed or moved to another - * place by vacuum */ +#define HEAP_MOVED_OFF 0x4000 /* moved to another place by + * vacuum */ #define HEAP_MOVED_IN 0x8000 /* moved from another place by * vacuum */ -#define HEAP_XACT_MASK 0xFFF0 /* */ +#define HEAP_XACT_MASK 0xFFF0 /* visibility-related bits */ #define HeapTupleNoNulls(tuple) \ (!(((HeapTuple) (tuple))->t_data->t_infomask & HEAP_HASNULL))