Make sure that GIN fast-insert and regular code paths enforce the same
tuple size limit. Improve the error message for index-tuple-too-large so that it includes the actual size, the limit, and the index name. Sync with the btree occurrences of the same error. Back-patch to 8.4 because it appears that the out-of-sync problem is occurring in the field. Teodor and Tom
This commit is contained in:
parent
ac317a8474
commit
c3110e49b1
@ -8,20 +8,22 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.21 2009/06/11 14:48:53 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.21.2.1 2009/10/02 21:14:11 tgl Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/gin.h"
|
||||
#include "access/tuptoaster.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "utils/rel.h"
|
||||
|
||||
/*
|
||||
* Form a tuple for entry tree.
|
||||
*
|
||||
* If the tuple would be too big to be stored, function throws a suitable
|
||||
* error if errorTooBig is TRUE, or returns NULL if errorTooBig is FALSE.
|
||||
*
|
||||
* On leaf pages, Index tuple has non-traditional layout. Tuple may contain
|
||||
* posting list or root blocknumber of posting tree.
|
||||
* Macros: GinIsPostingTree(itup) / GinSetPostingTree(itup, blkno)
|
||||
@ -49,10 +51,13 @@
|
||||
* and value.
|
||||
*/
|
||||
IndexTuple
|
||||
GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, ItemPointerData *ipd, uint32 nipd)
|
||||
GinFormTuple(Relation index, GinState *ginstate,
|
||||
OffsetNumber attnum, Datum key,
|
||||
ItemPointerData *ipd, uint32 nipd, bool errorTooBig)
|
||||
{
|
||||
bool isnull[2] = {FALSE, FALSE};
|
||||
IndexTuple itup;
|
||||
uint32 newsize;
|
||||
|
||||
if (ginstate->oneCol)
|
||||
itup = index_form_tuple(ginstate->origTupdesc, &key, isnull);
|
||||
@ -69,13 +74,19 @@ GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, ItemPointerData
|
||||
|
||||
if (nipd > 0)
|
||||
{
|
||||
uint32 newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData) * nipd);
|
||||
|
||||
if (newsize >= INDEX_SIZE_MASK)
|
||||
return NULL;
|
||||
|
||||
if (newsize > TOAST_INDEX_TARGET && nipd > 1)
|
||||
newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData) * nipd);
|
||||
if (newsize > Min(INDEX_SIZE_MASK, GinMaxItemSize))
|
||||
{
|
||||
if (errorTooBig)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
|
||||
(unsigned long) newsize,
|
||||
(unsigned long) Min(INDEX_SIZE_MASK,
|
||||
GinMaxItemSize),
|
||||
RelationGetRelationName(index))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
itup = repalloc(itup, newsize);
|
||||
|
||||
@ -89,6 +100,29 @@ GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, ItemPointerData
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Gin tuple without any ItemPointers should be large enough to keep
|
||||
* one ItemPointer, to prevent inconsistency between
|
||||
* ginHeapTupleFastCollect and ginEntryInsert called by
|
||||
* ginHeapTupleInsert. ginHeapTupleFastCollect forms tuple without
|
||||
* extra pointer to heap, but ginEntryInsert (called for pending list
|
||||
* cleanup during vacuum) will form the same tuple with one
|
||||
* ItemPointer.
|
||||
*/
|
||||
newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData));
|
||||
if (newsize > Min(INDEX_SIZE_MASK, GinMaxItemSize))
|
||||
{
|
||||
if (errorTooBig)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
|
||||
(unsigned long) newsize,
|
||||
(unsigned long) Min(INDEX_SIZE_MASK,
|
||||
GinMaxItemSize),
|
||||
RelationGetRelationName(index))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GinSetNPosting(itup, 0);
|
||||
}
|
||||
return itup;
|
||||
|
@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.3.2.1 2009/09/15 20:31:35 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.3.2.2 2009/10/02 21:14:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -20,7 +20,6 @@
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/gin.h"
|
||||
#include "access/tuptoaster.h"
|
||||
#include "catalog/index.h"
|
||||
#include "commands/vacuum.h"
|
||||
#include "miscadmin.h"
|
||||
@ -465,16 +464,10 @@ ginHeapTupleFastCollect(Relation index, GinState *ginstate,
|
||||
*/
|
||||
for (i = 0; i < nentries; i++)
|
||||
{
|
||||
int32 tupsize;
|
||||
|
||||
collector->tuples[collector->ntuples + i] = GinFormTuple(ginstate, attnum, entries[i], NULL, 0);
|
||||
collector->tuples[collector->ntuples + i] =
|
||||
GinFormTuple(index, ginstate, attnum, entries[i], NULL, 0, true);
|
||||
collector->tuples[collector->ntuples + i]->t_tid = *item;
|
||||
tupsize = IndexTupleSize(collector->tuples[collector->ntuples + i]);
|
||||
|
||||
if (tupsize > TOAST_INDEX_TARGET || tupsize >= GinMaxItemSize)
|
||||
elog(ERROR, "huge tuple");
|
||||
|
||||
collector->sumsize += tupsize;
|
||||
collector->sumsize += IndexTupleSize(collector->tuples[collector->ntuples + i]);
|
||||
}
|
||||
|
||||
collector->ntuples += nentries;
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.22 2009/06/11 14:48:53 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.22.2.1 2009/10/02 21:14:11 tgl Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -102,8 +102,9 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
|
||||
{
|
||||
Datum key = gin_index_getattr(ginstate, old);
|
||||
OffsetNumber attnum = gintuple_get_attrnum(ginstate, old);
|
||||
IndexTuple res = GinFormTuple(ginstate, attnum, key,
|
||||
NULL, nitem + GinGetNPosting(old));
|
||||
IndexTuple res = GinFormTuple(index, ginstate, attnum, key,
|
||||
NULL, nitem + GinGetNPosting(old),
|
||||
false);
|
||||
|
||||
if (res)
|
||||
{
|
||||
@ -122,7 +123,7 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
|
||||
GinPostingTreeScan *gdi;
|
||||
|
||||
/* posting list becomes big, so we need to make posting's tree */
|
||||
res = GinFormTuple(ginstate, attnum, key, NULL, 0);
|
||||
res = GinFormTuple(index, ginstate, attnum, key, NULL, 0, true);
|
||||
postingRoot = createPostingTree(index, GinGetPosting(old), GinGetNPosting(old));
|
||||
GinSetPostingTree(res, postingRoot);
|
||||
|
||||
@ -185,13 +186,12 @@ ginEntryInsert(Relation index, GinState *ginstate,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We suppose, that tuple can store at list one itempointer */
|
||||
itup = GinFormTuple(ginstate, attnum, value, items, 1);
|
||||
if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize)
|
||||
elog(ERROR, "huge tuple");
|
||||
/* We suppose that tuple can store at least one itempointer */
|
||||
itup = GinFormTuple(index, ginstate, attnum, value, items, 1, true);
|
||||
|
||||
if (nitem > 1)
|
||||
{
|
||||
/* Add the rest, making a posting tree if necessary */
|
||||
IndexTuple previtup = itup;
|
||||
|
||||
itup = addItemPointersToTuple(index, ginstate, stack, previtup, items + 1, nitem - 1, isBuild);
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.30 2009/06/11 14:48:53 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.30.2.1 2009/10/02 21:14:11 tgl Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -564,7 +564,8 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
|
||||
|
||||
value = gin_index_getattr(&gvs->ginstate, itup);
|
||||
attnum = gintuple_get_attrnum(&gvs->ginstate, itup);
|
||||
itup = GinFormTuple(&gvs->ginstate, attnum, value, GinGetPosting(itup), newN);
|
||||
itup = GinFormTuple(gvs->index, &gvs->ginstate, attnum, value,
|
||||
GinGetPosting(itup), newN, true);
|
||||
PageIndexTupleDelete(tmppage, i);
|
||||
|
||||
if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, false, false) != i)
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.170 2009/06/11 14:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.170.2.1 2009/10/02 21:14:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -418,9 +418,10 @@ _bt_findinsertloc(Relation rel,
|
||||
if (itemsz > BTMaxItemSize(page))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("index row size %lu exceeds btree maximum, %lu",
|
||||
errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
|
||||
(unsigned long) itemsz,
|
||||
(unsigned long) BTMaxItemSize(page)),
|
||||
(unsigned long) BTMaxItemSize(page),
|
||||
RelationGetRelationName(rel)),
|
||||
errhint("Values larger than 1/3 of a buffer page cannot be indexed.\n"
|
||||
"Consider a function index of an MD5 hash of the value, "
|
||||
"or use full text indexing.")));
|
||||
|
@ -59,7 +59,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.119 2009/01/01 17:23:36 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.119.2.1 2009/10/02 21:14:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -480,9 +480,10 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup)
|
||||
if (itupsz > BTMaxItemSize(npage))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("index row size %lu exceeds btree maximum, %lu",
|
||||
errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
|
||||
(unsigned long) itupsz,
|
||||
(unsigned long) BTMaxItemSize(npage)),
|
||||
(unsigned long) BTMaxItemSize(npage),
|
||||
RelationGetRelationName(wstate->index)),
|
||||
errhint("Values larger than 1/3 of a buffer page cannot be indexed.\n"
|
||||
"Consider a function index of an MD5 hash of the value, "
|
||||
"or use full text indexing.")));
|
||||
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (c) 2006-2009, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.34 2009/06/11 14:49:08 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.34.2.1 2009/10/02 21:14:11 tgl Exp $
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef GIN_H
|
||||
@ -165,8 +165,8 @@ typedef struct
|
||||
#define GinGetPosting(itup) ( (ItemPointer)(( ((char*)(itup)) + SHORTALIGN(GinGetOrigSizePosting(itup)) )) )
|
||||
|
||||
#define GinMaxItemSize \
|
||||
((BLCKSZ - SizeOfPageHeaderData - \
|
||||
MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData))
|
||||
MAXALIGN_DOWN(((BLCKSZ - SizeOfPageHeaderData - \
|
||||
MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData)))
|
||||
|
||||
|
||||
/*
|
||||
@ -434,8 +434,9 @@ extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack);
|
||||
extern void findParents(GinBtree btree, GinBtreeStack *stack, BlockNumber rootBlkno);
|
||||
|
||||
/* ginentrypage.c */
|
||||
extern IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key,
|
||||
ItemPointerData *ipd, uint32 nipd);
|
||||
extern IndexTuple GinFormTuple(Relation index, GinState *ginstate,
|
||||
OffsetNumber attnum, Datum key,
|
||||
ItemPointerData *ipd, uint32 nipd, bool errorTooBig);
|
||||
extern void GinShortenTuple(IndexTuple itup, uint32 nipd);
|
||||
extern void prepareEntryScan(GinBtree btree, Relation index, OffsetNumber attnum,
|
||||
Datum value, GinState *ginstate);
|
||||
|
Loading…
Reference in New Issue
Block a user