Skip to content
Snippets Groups Projects
Commit 3212cf94 authored by Tom Lane's avatar Tom Lane
Browse files

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.
parent 3cde0851
No related branches found
No related tags found
No related merge requests found
......@@ -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,
}
}
len = offsetof(HeapTupleHeaderData, t_bits);
if (hasnull)
{
bitmaplen = BITMAPLEN(numberOfAttributes);
len += bitmaplen;
}
len += BITMAPLEN(numberOfAttributes);
hoff = len = MAXALIGN(len); /* be conservative here */
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,
......
......@@ -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);
}
/*
......
......@@ -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))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment