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.
This commit is contained in:
parent
3cde085158
commit
3212cf9417
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* The old interface functions have been converted to macros
|
* The old interface functions have been converted to macros
|
||||||
|
@ -571,18 +571,15 @@ heap_formtuple(TupleDesc tupleDescriptor,
|
||||||
{
|
{
|
||||||
HeapTuple tuple; /* return tuple */
|
HeapTuple tuple; /* return tuple */
|
||||||
HeapTupleHeader td; /* tuple data */
|
HeapTupleHeader td; /* tuple data */
|
||||||
int bitmaplen;
|
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
int hoff;
|
int hoff;
|
||||||
bool hasnull = false;
|
bool hasnull = false;
|
||||||
int i;
|
int i;
|
||||||
int numberOfAttributes = tupleDescriptor->natts;
|
int numberOfAttributes = tupleDescriptor->natts;
|
||||||
|
|
||||||
if (numberOfAttributes > MaxHeapAttributeNumber)
|
if (numberOfAttributes > MaxTupleAttributeNumber)
|
||||||
elog(ERROR, "heap_formtuple: numberOfAttributes of %d > %d",
|
elog(ERROR, "heap_formtuple: numberOfAttributes %d exceeds limit %d",
|
||||||
numberOfAttributes, MaxHeapAttributeNumber);
|
numberOfAttributes, MaxTupleAttributeNumber);
|
||||||
|
|
||||||
len = offsetof(HeapTupleHeaderData, t_bits);
|
|
||||||
|
|
||||||
for (i = 0; i < numberOfAttributes; i++)
|
for (i = 0; i < numberOfAttributes; i++)
|
||||||
{
|
{
|
||||||
|
@ -593,13 +590,12 @@ heap_formtuple(TupleDesc tupleDescriptor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasnull)
|
len = offsetof(HeapTupleHeaderData, t_bits);
|
||||||
{
|
|
||||||
bitmaplen = BITMAPLEN(numberOfAttributes);
|
|
||||||
len += bitmaplen;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
len += ComputeDataSize(tupleDescriptor, value, nulls);
|
||||||
|
|
||||||
|
@ -615,7 +611,7 @@ heap_formtuple(TupleDesc tupleDescriptor,
|
||||||
td->t_natts = numberOfAttributes;
|
td->t_natts = numberOfAttributes;
|
||||||
td->t_hoff = hoff;
|
td->t_hoff = hoff;
|
||||||
|
|
||||||
DataFill((char *) td + td->t_hoff,
|
DataFill((char *) td + hoff,
|
||||||
tupleDescriptor,
|
tupleDescriptor,
|
||||||
value,
|
value,
|
||||||
nulls,
|
nulls,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* INTERFACE ROUTINES
|
||||||
|
@ -715,39 +715,34 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||||
*/
|
*/
|
||||||
if (need_change)
|
if (need_change)
|
||||||
{
|
{
|
||||||
|
HeapTupleHeader olddata = newtup->t_data;
|
||||||
char *new_data;
|
char *new_data;
|
||||||
int32 new_len;
|
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);
|
new_len = offsetof(HeapTupleHeaderData, t_bits);
|
||||||
if (has_nulls)
|
if (has_nulls)
|
||||||
new_len += BITMAPLEN(numAttrs);
|
new_len += BITMAPLEN(numAttrs);
|
||||||
new_len = MAXALIGN(new_len);
|
new_len = MAXALIGN(new_len);
|
||||||
|
Assert(new_len == olddata->t_hoff);
|
||||||
new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);
|
new_len += ComputeDataSize(tupleDesc, toast_values, toast_nulls);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remember the old memory location of the tuple (for below),
|
* Allocate new tuple in same context as old one.
|
||||||
* switch to the memory context of the HeapTuple structure and
|
|
||||||
* allocate the new tuple.
|
|
||||||
*/
|
*/
|
||||||
olddata = newtup->t_data;
|
new_data = (char *) MemoryContextAlloc(newtup->t_datamcxt, new_len);
|
||||||
oldcxt = MemoryContextSwitchTo(newtup->t_datamcxt);
|
newtup->t_data = (HeapTupleHeader) new_data;
|
||||||
new_data = palloc(new_len);
|
newtup->t_len = new_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put the tuple header and the changed values into place
|
* Put the tuple header and the changed values into place
|
||||||
*/
|
*/
|
||||||
memcpy(new_data, newtup->t_data, newtup->t_data->t_hoff);
|
memcpy(new_data, olddata, olddata->t_hoff);
|
||||||
newtup->t_data = (HeapTupleHeader) new_data;
|
|
||||||
newtup->t_len = new_len;
|
|
||||||
|
|
||||||
DataFill((char *) (MAXALIGN((long) new_data +
|
DataFill((char *) new_data + olddata->t_hoff,
|
||||||
offsetof(HeapTupleHeaderData, t_bits) +
|
|
||||||
((has_nulls) ? BITMAPLEN(numAttrs) : 0))),
|
|
||||||
tupleDesc,
|
tupleDesc,
|
||||||
toast_values,
|
toast_values,
|
||||||
toast_nulls,
|
toast_nulls,
|
||||||
|
@ -760,11 +755,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||||
*/
|
*/
|
||||||
if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))
|
if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))
|
||||||
pfree(olddata);
|
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) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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/bufpage.h"
|
||||||
#include "storage/relfilenode.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
|
* 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),
|
* 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
|
* 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
|
* machines the upper limit without making t_hoff wider would be a little
|
||||||
* about 1700. Note, however, that depending on column data types you will
|
* over 1700. We use round numbers here and for MaxHeapAttributeNumber
|
||||||
* likely also be running into the disk-block-based limit on overall tuple
|
* so that alterations in HeapTupleHeaderData layout won't change the
|
||||||
* size if you have more than a thousand or so columns. TOAST won't help.
|
* 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 */
|
#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
|
* 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
|
typedef struct HeapTupleHeaderData
|
||||||
{
|
{
|
||||||
|
@ -51,14 +70,13 @@ typedef struct HeapTupleHeaderData
|
||||||
|
|
||||||
int16 t_natts; /* number of attributes */
|
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 - ^ */
|
/* ^ - 31 bytes - ^ */
|
||||||
|
|
||||||
bits8 t_bits[MinHeapTupleBitmapSize / 8];
|
bits8 t_bits[1]; /* bitmap of NULLs -- VARIABLE LENGTH */
|
||||||
/* bit map of NULLs */
|
|
||||||
|
|
||||||
/* MORE DATA FOLLOWS AT END OF STRUCT */
|
/* MORE DATA FOLLOWS AT END OF STRUCT */
|
||||||
} HeapTupleHeaderData;
|
} HeapTupleHeaderData;
|
||||||
|
@ -183,7 +201,7 @@ typedef struct xl_heap_clean
|
||||||
#define FirstLowInvalidHeapAttributeNumber (-8)
|
#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:
|
* This new HeapTuple for version >= 6.5 and this is why it was changed:
|
||||||
*
|
*
|
||||||
|
@ -222,11 +240,9 @@ typedef HeapTupleData *HeapTuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BITMAPLEN(NATTS) -
|
* BITMAPLEN(NATTS) -
|
||||||
* Computes minimum size of bitmap given number of domains.
|
* Computes size of null bitmap given number of data columns.
|
||||||
*/
|
*/
|
||||||
#define BITMAPLEN(NATTS) \
|
#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
|
||||||
((((((int)(NATTS) - 1) >> 3) + 4 - (MinHeapTupleBitmapSize >> 3)) \
|
|
||||||
& ~03) + (MinHeapTupleBitmapSize >> 3))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HeapTupleIsValid
|
* HeapTupleIsValid
|
||||||
|
@ -240,26 +256,26 @@ typedef HeapTupleData *HeapTuple;
|
||||||
#define HEAP_HASNULL 0x0001 /* has null attribute(s) */
|
#define HEAP_HASNULL 0x0001 /* has null attribute(s) */
|
||||||
#define HEAP_HASVARLENA 0x0002 /* has variable length
|
#define HEAP_HASVARLENA 0x0002 /* has variable length
|
||||||
* attribute(s) */
|
* attribute(s) */
|
||||||
#define HEAP_HASEXTERNAL 0x0004 /* has external stored */
|
#define HEAP_HASEXTERNAL 0x0004 /* has external stored
|
||||||
/* attribute(s) */
|
* attribute(s) */
|
||||||
#define HEAP_HASCOMPRESSED 0x0008 /* has compressed stored */
|
#define HEAP_HASCOMPRESSED 0x0008 /* has compressed stored
|
||||||
/* attribute(s) */
|
* attribute(s) */
|
||||||
#define HEAP_HASEXTENDED 0x000C /* the two above combined */
|
#define HEAP_HASEXTENDED 0x000C /* the two above combined */
|
||||||
|
|
||||||
#define HEAP_XMAX_UNLOGGED 0x0080 /* to lock tuple for update */
|
#define HEAP_XMAX_UNLOGGED 0x0080 /* to lock tuple for update
|
||||||
/* without logging */
|
* without logging */
|
||||||
#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */
|
#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */
|
||||||
#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */
|
#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */
|
||||||
#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */
|
#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */
|
||||||
#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */
|
#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */
|
||||||
#define HEAP_MARKED_FOR_UPDATE 0x1000 /* marked for UPDATE */
|
#define HEAP_MARKED_FOR_UPDATE 0x1000 /* marked for UPDATE */
|
||||||
#define HEAP_UPDATED 0x2000 /* this is UPDATEd version of row */
|
#define HEAP_UPDATED 0x2000 /* this is UPDATEd version of row */
|
||||||
#define HEAP_MOVED_OFF 0x4000 /* removed or moved to another
|
#define HEAP_MOVED_OFF 0x4000 /* moved to another place by
|
||||||
* place by vacuum */
|
* vacuum */
|
||||||
#define HEAP_MOVED_IN 0x8000 /* moved from another place by
|
#define HEAP_MOVED_IN 0x8000 /* moved from another place by
|
||||||
* vacuum */
|
* vacuum */
|
||||||
|
|
||||||
#define HEAP_XACT_MASK 0xFFF0 /* */
|
#define HEAP_XACT_MASK 0xFFF0 /* visibility-related bits */
|
||||||
|
|
||||||
#define HeapTupleNoNulls(tuple) \
|
#define HeapTupleNoNulls(tuple) \
|
||||||
(!(((HeapTuple) (tuple))->t_data->t_infomask & HEAP_HASNULL))
|
(!(((HeapTuple) (tuple))->t_data->t_infomask & HEAP_HASNULL))
|
||||||
|
|
Loading…
Reference in New Issue