* 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.22 2009/10/02 21:14:04 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)
* 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);
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);
}
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;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.4 2009/09/15 20:31:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.5 2009/10/02 21:14:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/genam.h"
#include "access/gin.h"
-#include "access/tuptoaster.h"
#include "catalog/index.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
*/
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;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.23 2009/07/29 20:56:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.24 2009/10/02 21:14:04 tgl Exp $
*-------------------------------------------------------------------------
*/
{
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)
{
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);
}
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);
* 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.31 2009/10/02 21:14:04 tgl Exp $
*-------------------------------------------------------------------------
*/
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)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.173 2009/08/01 20:59:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.174 2009/10/02 21:14:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
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.")));
* 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.120 2009/10/02 21:14:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
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.")));
*
* 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.35 2009/10/02 21:14:04 tgl Exp $
*--------------------------------------------------------------------------
*/
#ifndef GIN_H
#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)))
/*
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);