mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
Multi-column GIN indexes. Teodor Sigaev
This commit is contained in:
@ -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.13 2008/05/16 01:27:06 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.14 2008/07/11 21:06:29 tgl Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -99,9 +99,9 @@ static IndexTuple
|
||||
addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
|
||||
IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild)
|
||||
{
|
||||
bool isnull;
|
||||
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
|
||||
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
|
||||
Datum key = gin_index_getattr(ginstate, old);
|
||||
OffsetNumber attnum = gintuple_get_attrnum(ginstate, old);
|
||||
IndexTuple res = GinFormTuple(ginstate, attnum, key, NULL, nitem + GinGetNPosting(old));
|
||||
|
||||
if (res)
|
||||
{
|
||||
@ -119,7 +119,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, key, NULL, 0);
|
||||
res = GinFormTuple(ginstate, attnum, key, NULL, 0);
|
||||
postingRoot = createPostingTree(index, GinGetPosting(old), GinGetNPosting(old));
|
||||
GinSetPostingTree(res, postingRoot);
|
||||
|
||||
@ -138,14 +138,15 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
|
||||
* Inserts only one entry to the index, but it can add more than 1 ItemPointer.
|
||||
*/
|
||||
static void
|
||||
ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild)
|
||||
ginEntryInsert(Relation index, GinState *ginstate, OffsetNumber attnum, Datum value,
|
||||
ItemPointerData *items, uint32 nitem, bool isBuild)
|
||||
{
|
||||
GinBtreeData btree;
|
||||
GinBtreeStack *stack;
|
||||
IndexTuple itup;
|
||||
Page page;
|
||||
|
||||
prepareEntryScan(&btree, index, value, ginstate);
|
||||
prepareEntryScan(&btree, index, attnum, value, ginstate);
|
||||
|
||||
stack = ginFindLeafPage(&btree, NULL);
|
||||
page = BufferGetPage(stack->buffer);
|
||||
@ -180,7 +181,7 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
|
||||
else
|
||||
{
|
||||
/* We suppose, that tuple can store at list one itempointer */
|
||||
itup = GinFormTuple(ginstate, value, items, 1);
|
||||
itup = GinFormTuple(ginstate, attnum, value, items, 1);
|
||||
if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize)
|
||||
elog(ERROR, "huge tuple");
|
||||
|
||||
@ -203,21 +204,21 @@ ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData
|
||||
* Function isn't used during normal insert
|
||||
*/
|
||||
static uint32
|
||||
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr)
|
||||
ginHeapTupleBulkInsert(GinBuildState *buildstate, OffsetNumber attnum, Datum value, ItemPointer heapptr)
|
||||
{
|
||||
Datum *entries;
|
||||
int32 nentries;
|
||||
MemoryContext oldCtx;
|
||||
|
||||
oldCtx = MemoryContextSwitchTo(buildstate->funcCtx);
|
||||
entries = extractEntriesSU(buildstate->accum.ginstate, value, &nentries);
|
||||
entries = extractEntriesSU(buildstate->accum.ginstate, attnum, value, &nentries);
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
|
||||
if (nentries == 0)
|
||||
/* nothing to insert */
|
||||
return 0;
|
||||
|
||||
ginInsertRecordBA(&buildstate->accum, heapptr, entries, nentries);
|
||||
ginInsertRecordBA(&buildstate->accum, heapptr, attnum, entries, nentries);
|
||||
|
||||
MemoryContextReset(buildstate->funcCtx);
|
||||
|
||||
@ -230,13 +231,15 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
|
||||
{
|
||||
GinBuildState *buildstate = (GinBuildState *) state;
|
||||
MemoryContext oldCtx;
|
||||
|
||||
if (*isnull)
|
||||
return;
|
||||
int i;
|
||||
|
||||
oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
|
||||
|
||||
buildstate->indtuples += ginHeapTupleBulkInsert(buildstate, *values, &htup->t_self);
|
||||
for(i=0; i<buildstate->ginstate.origTupdesc->natts;i++)
|
||||
if ( !isnull[i] )
|
||||
buildstate->indtuples += ginHeapTupleBulkInsert(buildstate,
|
||||
(OffsetNumber)(i+1), values[i],
|
||||
&htup->t_self);
|
||||
|
||||
/* If we've maxed out our available memory, dump everything to the index */
|
||||
if (buildstate->accum.allocatedMemory >= maintenance_work_mem * 1024L)
|
||||
@ -244,12 +247,13 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
|
||||
ItemPointerData *list;
|
||||
Datum entry;
|
||||
uint32 nlist;
|
||||
OffsetNumber attnum;
|
||||
|
||||
while ((list = ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL)
|
||||
while ((list = ginGetEntry(&buildstate->accum, &attnum, &entry, &nlist)) != NULL)
|
||||
{
|
||||
/* there could be many entries, so be willing to abort here */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
ginEntryInsert(index, &buildstate->ginstate, entry, list, nlist, TRUE);
|
||||
ginEntryInsert(index, &buildstate->ginstate, attnum, entry, list, nlist, TRUE);
|
||||
}
|
||||
|
||||
MemoryContextReset(buildstate->tmpCtx);
|
||||
@ -273,6 +277,7 @@ ginbuild(PG_FUNCTION_ARGS)
|
||||
Datum entry;
|
||||
uint32 nlist;
|
||||
MemoryContext oldCtx;
|
||||
OffsetNumber attnum;
|
||||
|
||||
if (RelationGetNumberOfBlocks(index) != 0)
|
||||
elog(ERROR, "index \"%s\" already contains data",
|
||||
@ -337,11 +342,11 @@ ginbuild(PG_FUNCTION_ARGS)
|
||||
|
||||
/* dump remaining entries to the index */
|
||||
oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
|
||||
while ((list = ginGetEntry(&buildstate.accum, &entry, &nlist)) != NULL)
|
||||
while ((list = ginGetEntry(&buildstate.accum, &attnum, &entry, &nlist)) != NULL)
|
||||
{
|
||||
/* there could be many entries, so be willing to abort here */
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
ginEntryInsert(index, &buildstate.ginstate, entry, list, nlist, TRUE);
|
||||
ginEntryInsert(index, &buildstate.ginstate, attnum, entry, list, nlist, TRUE);
|
||||
}
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
|
||||
@ -362,20 +367,20 @@ ginbuild(PG_FUNCTION_ARGS)
|
||||
* Inserts value during normal insertion
|
||||
*/
|
||||
static uint32
|
||||
ginHeapTupleInsert(Relation index, GinState *ginstate, Datum value, ItemPointer item)
|
||||
ginHeapTupleInsert(Relation index, GinState *ginstate, OffsetNumber attnum, Datum value, ItemPointer item)
|
||||
{
|
||||
Datum *entries;
|
||||
int32 i,
|
||||
nentries;
|
||||
|
||||
entries = extractEntriesSU(ginstate, value, &nentries);
|
||||
entries = extractEntriesSU(ginstate, attnum, value, &nentries);
|
||||
|
||||
if (nentries == 0)
|
||||
/* nothing to insert */
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < nentries; i++)
|
||||
ginEntryInsert(index, ginstate, entries[i], item, 1, FALSE);
|
||||
ginEntryInsert(index, ginstate, attnum, entries[i], item, 1, FALSE);
|
||||
|
||||
return nentries;
|
||||
}
|
||||
@ -395,10 +400,8 @@ gininsert(PG_FUNCTION_ARGS)
|
||||
GinState ginstate;
|
||||
MemoryContext oldCtx;
|
||||
MemoryContext insertCtx;
|
||||
uint32 res;
|
||||
|
||||
if (*isnull)
|
||||
PG_RETURN_BOOL(false);
|
||||
uint32 res = 0;
|
||||
int i;
|
||||
|
||||
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||
"Gin insert temporary context",
|
||||
@ -410,7 +413,9 @@ gininsert(PG_FUNCTION_ARGS)
|
||||
|
||||
initGinState(&ginstate, index);
|
||||
|
||||
res = ginHeapTupleInsert(index, &ginstate, *values, ht_ctid);
|
||||
for(i=0; i<ginstate.origTupdesc->natts;i++)
|
||||
if ( !isnull[i] )
|
||||
res += ginHeapTupleInsert(index, &ginstate, (OffsetNumber)(i+1), values[i], ht_ctid);
|
||||
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
MemoryContextDelete(insertCtx);
|
||||
|
Reference in New Issue
Block a user