diff options
Diffstat (limited to 'src/backend/access/gist/gist.c')
-rw-r--r-- | src/backend/access/gist/gist.c | 2267 |
1 files changed, 1186 insertions, 1081 deletions
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 1d36f340ed..598f9ed8f0 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------- * * gist.c-- - * interface routines for the postgres GiST index access method. + * interface routines for the postgres GiST index access method. * * * @@ -26,308 +26,345 @@ #include <utils/syscache.h> #ifndef HAVE_MEMMOVE -# include <regex/utils.h> +#include <regex/utils.h> #else -# include <string.h> +#include <string.h> #endif /* non-export function prototypes */ -static InsertIndexResult gistdoinsert(Relation r, IndexTuple itup, - GISTSTATE *GISTstate); -static InsertIndexResult gistentryinsert(Relation r, GISTSTACK *stk, - IndexTuple tup, - GISTSTATE *giststate); -static void gistentryinserttwo(Relation r, GISTSTACK *stk, IndexTuple ltup, - IndexTuple rtup, GISTSTATE *giststate); -static void gistAdjustKeys(Relation r, GISTSTACK *stk, BlockNumber blk, - char *datum, int att_size, GISTSTATE *giststate); -static void gistintinsert(Relation r, GISTSTACK *stk, IndexTuple ltup, - IndexTuple rtup, GISTSTATE *giststate); -static InsertIndexResult gistSplit(Relation r, Buffer buffer, - GISTSTACK *stack, IndexTuple itup, - GISTSTATE *giststate); -static void gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt, +static InsertIndexResult +gistdoinsert(Relation r, IndexTuple itup, + GISTSTATE * GISTstate); +static InsertIndexResult +gistentryinsert(Relation r, GISTSTACK * stk, + IndexTuple tup, + GISTSTATE * giststate); +static void +gistentryinserttwo(Relation r, GISTSTACK * stk, IndexTuple ltup, + IndexTuple rtup, GISTSTATE * giststate); +static void +gistAdjustKeys(Relation r, GISTSTACK * stk, BlockNumber blk, + char *datum, int att_size, GISTSTATE * giststate); +static void +gistintinsert(Relation r, GISTSTACK * stk, IndexTuple ltup, + IndexTuple rtup, GISTSTATE * giststate); +static InsertIndexResult +gistSplit(Relation r, Buffer buffer, + GISTSTACK * stack, IndexTuple itup, + GISTSTATE * giststate); +static void +gistnewroot(GISTSTATE * giststate, Relation r, IndexTuple lt, IndexTuple rt); -static void GISTInitBuffer(Buffer b, uint32 f); -static BlockNumber gistChooseSubtree(Relation r, IndexTuple itup, int level, - GISTSTATE *giststate, - GISTSTACK **retstack, Buffer *leafbuf); -static OffsetNumber gistchoose(Relation r, Page p, IndexTuple it, - GISTSTATE *giststate); -static int gistnospace(Page p, IndexTuple it); -void gistdelete(Relation r, ItemPointer tid); +static void GISTInitBuffer(Buffer b, uint32 f); +static BlockNumber +gistChooseSubtree(Relation r, IndexTuple itup, int level, + GISTSTATE * giststate, + GISTSTACK ** retstack, Buffer * leafbuf); +static OffsetNumber +gistchoose(Relation r, Page p, IndexTuple it, + GISTSTATE * giststate); +static int gistnospace(Page p, IndexTuple it); +void gistdelete(Relation r, ItemPointer tid); static IndexTuple gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t); -static void gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, - Relation r, Page pg, OffsetNumber o, int b, bool l) ; -static char *int_range_out(INTRANGE *r); +static void +gistcentryinit(GISTSTATE * giststate, GISTENTRY * e, char *pr, + Relation r, Page pg, OffsetNumber o, int b, bool l); +static char *int_range_out(INTRANGE * r); /* ** routine to build an index. Basically calls insert over and over */ void gistbuild(Relation heap, - Relation index, - int natts, - AttrNumber *attnum, - IndexStrategy istrat, - uint16 pint, - Datum *params, - FuncIndexInfo *finfo, - PredInfo *predInfo) + Relation index, + int natts, + AttrNumber * attnum, + IndexStrategy istrat, + uint16 pint, + Datum * params, + FuncIndexInfo * finfo, + PredInfo * predInfo) { - HeapScanDesc scan; - Buffer buffer; - AttrNumber i; - HeapTuple htup; - IndexTuple itup; - TupleDesc hd, id; - InsertIndexResult res; - Datum *d; - bool *nulls; - int nb, nh, ni; + HeapScanDesc scan; + Buffer buffer; + AttrNumber i; + HeapTuple htup; + IndexTuple itup; + TupleDesc hd, + id; + InsertIndexResult res; + Datum *d; + bool *nulls; + int nb, + nh, + ni; + #ifndef OMIT_PARTIAL_INDEX - ExprContext *econtext; - TupleTable tupleTable; - TupleTableSlot *slot; + ExprContext *econtext; + TupleTable tupleTable; + TupleTableSlot *slot; + #endif - Oid hrelid, irelid; - Node *pred, *oldPred; - GISTSTATE giststate; - GISTENTRY tmpcentry; - bool *compvec; - - /* GiSTs only know how to do stupid locking now */ - RelationSetLockForWrite(index); - - setheapoverride(TRUE); /* so we can see the new pg_index tuple */ - initGISTstate(&giststate, index); - setheapoverride(FALSE); - - pred = predInfo->pred; - oldPred = predInfo->oldPred; - - /* - * We expect to be called exactly once for any index relation. - * If that's not the case, big trouble's what we have. - */ - - if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0) - elog(WARN, "%.16s already contains data", &(index->rd_rel->relname.data[0])); - - /* initialize the root page (if this is a new index) */ - if (oldPred == NULL) { - buffer = ReadBuffer(index, P_NEW); - GISTInitBuffer(buffer, F_LEAF); - WriteBuffer(buffer); - } - - /* init the tuple descriptors and get set for a heap scan */ - hd = RelationGetTupleDescriptor(heap); - id = RelationGetTupleDescriptor(index); - d = (Datum *)palloc(natts * sizeof (*d)); - nulls = (bool *)palloc(natts * sizeof (*nulls)); - - /* - * If this is a predicate (partial) index, we will need to evaluate the - * predicate using ExecQual, which requires the current tuple to be in a - * slot of a TupleTable. In addition, ExecQual must have an ExprContext - * referring to that slot. Here, we initialize dummy TupleTable and - * ExprContext objects for this purpose. --Nels, Feb '92 - */ + Oid hrelid, + irelid; + Node *pred, + *oldPred; + GISTSTATE giststate; + GISTENTRY tmpcentry; + bool *compvec; + + /* GiSTs only know how to do stupid locking now */ + RelationSetLockForWrite(index); + + setheapoverride(TRUE); /* so we can see the new pg_index tuple */ + initGISTstate(&giststate, index); + setheapoverride(FALSE); + + pred = predInfo->pred; + oldPred = predInfo->oldPred; + + /* + * We expect to be called exactly once for any index relation. If + * that's not the case, big trouble's what we have. + */ + + if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0) + elog(WARN, "%.16s already contains data", &(index->rd_rel->relname.data[0])); + + /* initialize the root page (if this is a new index) */ + if (oldPred == NULL) + { + buffer = ReadBuffer(index, P_NEW); + GISTInitBuffer(buffer, F_LEAF); + WriteBuffer(buffer); + } + + /* init the tuple descriptors and get set for a heap scan */ + hd = RelationGetTupleDescriptor(heap); + id = RelationGetTupleDescriptor(index); + d = (Datum *) palloc(natts * sizeof(*d)); + nulls = (bool *) palloc(natts * sizeof(*nulls)); + + /* + * If this is a predicate (partial) index, we will need to evaluate + * the predicate using ExecQual, which requires the current tuple to + * be in a slot of a TupleTable. In addition, ExecQual must have an + * ExprContext referring to that slot. Here, we initialize dummy + * TupleTable and ExprContext objects for this purpose. --Nels, Feb + * '92 + */ #ifndef OMIT_PARTIAL_INDEX - if (pred != NULL || oldPred != NULL) { - tupleTable = ExecCreateTupleTable(1); - slot = ExecAllocTableSlot(tupleTable); - econtext = makeNode(ExprContext); - FillDummyExprContext(econtext, slot, hd, buffer); - } - else /* shut the compiler up */ + if (pred != NULL || oldPred != NULL) + { + tupleTable = ExecCreateTupleTable(1); + slot = ExecAllocTableSlot(tupleTable); + econtext = makeNode(ExprContext); + FillDummyExprContext(econtext, slot, hd, buffer); + } + else +/* shut the compiler up */ { tupleTable = NULL; slot = NULL; econtext = NULL; } -#endif /* OMIT_PARTIAL_INDEX */ - scan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL); - htup = heap_getnext(scan, 0, &buffer); - - /* int the tuples as we insert them */ - nh = ni = 0; - - for (; HeapTupleIsValid(htup); htup = heap_getnext(scan, 0, &buffer)) { - - nh++; - - /* - * If oldPred != NULL, this is an EXTEND INDEX command, so skip - * this tuple if it was already in the existing partial index - */ - if (oldPred != NULL) { +#endif /* OMIT_PARTIAL_INDEX */ + scan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL); + htup = heap_getnext(scan, 0, &buffer); + + /* int the tuples as we insert them */ + nh = ni = 0; + + for (; HeapTupleIsValid(htup); htup = heap_getnext(scan, 0, &buffer)) + { + + nh++; + + /* + * If oldPred != NULL, this is an EXTEND INDEX command, so skip + * this tuple if it was already in the existing partial index + */ + if (oldPred != NULL) + { #ifndef OMIT_PARTIAL_INDEX - /*SetSlotContents(slot, htup); */ - slot->val = htup; - if (ExecQual((List*)oldPred, econtext) == true) { + /* SetSlotContents(slot, htup); */ + slot->val = htup; + if (ExecQual((List *) oldPred, econtext) == true) + { + ni++; + continue; + } +#endif /* OMIT_PARTIAL_INDEX */ + } + + /* + * Skip this tuple if it doesn't satisfy the partial-index + * predicate + */ + if (pred != NULL) + { +#ifndef OMIT_PARTIAL_INDEX + /* SetSlotContents(slot, htup); */ + slot->val = htup; + if (ExecQual((List *) pred, econtext) == false) + continue; +#endif /* OMIT_PARTIAL_INDEX */ + } + ni++; - continue; - } -#endif /* OMIT_PARTIAL_INDEX */ + + /* + * For the current heap tuple, extract all the attributes we use + * in this index, and note which are null. + */ + + for (i = 1; i <= natts; i++) + { + int attoff; + bool attnull; + + /* + * Offsets are from the start of the tuple, and are + * zero-based; indices are one-based. The next call returns i + * - 1. That's data hiding for you. + */ + + attoff = AttrNumberGetAttrOffset(i); + + /* + * d[attoff] = HeapTupleGetAttributeValue(htup, buffer, + */ + d[attoff] = GetIndexValue(htup, + hd, + attoff, + attnum, + finfo, + &attnull, + buffer); + nulls[attoff] = (attnull ? 'n' : ' '); + } + + /* immediately compress keys to normalize */ + compvec = (bool *) palloc(sizeof(bool) * natts); + for (i = 0; i < natts; i++) + { + gistcentryinit(&giststate, &tmpcentry, (char *) d[i], + (Relation) NULL, (Page) NULL, (OffsetNumber) 0, + -1 /* size is currently bogus */ , TRUE); + if (d[i] != (Datum) tmpcentry.pred && !(giststate.keytypbyval)) + compvec[i] = TRUE; + else + compvec[i] = FALSE; + d[i] = (Datum) tmpcentry.pred; + } + + /* form an index tuple and point it at the heap tuple */ + itup = index_formtuple(id, &d[0], nulls); + itup->t_tid = htup->t_ctid; + + /* + * Since we already have the index relation locked, we call + * gistdoinsert directly. Normal access method calls dispatch + * through gistinsert, which locks the relation for write. This + * is the right thing to do if you're inserting single tups, but + * not when you're initializing the whole index at once. + */ + + res = gistdoinsert(index, itup, &giststate); + for (i = 0; i < natts; i++) + if (compvec[i] == TRUE) + pfree((char *) d[i]); + pfree(itup); + pfree(res); + pfree(compvec); } - - /* Skip this tuple if it doesn't satisfy the partial-index predicate */ - if (pred != NULL) { + + /* okay, all heap tuples are indexed */ + heap_endscan(scan); + RelationUnsetLockForWrite(index); + + if (pred != NULL || oldPred != NULL) + { #ifndef OMIT_PARTIAL_INDEX - /*SetSlotContents(slot, htup); */ - slot->val = htup; - if (ExecQual((List*)pred, econtext) == false) - continue; -#endif /* OMIT_PARTIAL_INDEX */ + ExecDestroyTupleTable(tupleTable, true); + pfree(econtext); +#endif /* OMIT_PARTIAL_INDEX */ } - - ni++; - + /* - * For the current heap tuple, extract all the attributes - * we use in this index, and note which are null. + * Since we just inted the tuples in the heap, we update its stats in + * pg_relation to guarantee that the planner takes advantage of the + * index we just created. UpdateStats() does a + * CommandinterIncrement(), which flushes changed entries from the + * system relcache. The act of constructing an index changes these + * heap and index tuples in the system catalogs, so they need to be + * flushed. We close them to guarantee that they will be. */ - - for (i = 1; i <= natts; i++) { - int attoff; - bool attnull; - - /* - * Offsets are from the start of the tuple, and are - * zero-based; indices are one-based. The next call - * returns i - 1. That's data hiding for you. - */ - - attoff = AttrNumberGetAttrOffset(i); - /* - d[attoff] = HeapTupleGetAttributeValue(htup, buffer, - */ - d[attoff] = GetIndexValue(htup, - hd, - attoff, - attnum, - finfo, - &attnull, - buffer); - nulls[attoff] = (attnull ? 'n' : ' '); - } - - /* immediately compress keys to normalize */ - compvec = (bool *)palloc(sizeof(bool) * natts); - for (i = 0; i < natts; i++) { - gistcentryinit(&giststate, &tmpcentry, (char *)d[i], - (Relation) NULL, (Page) NULL, (OffsetNumber) 0, - -1 /* size is currently bogus */, TRUE); - if (d[i] != (Datum)tmpcentry.pred && !(giststate.keytypbyval)) - compvec[i] = TRUE; - else compvec[i] = FALSE; - d[i] = (Datum)tmpcentry.pred; + + hrelid = heap->rd_id; + irelid = index->rd_id; + heap_close(heap); + index_close(index); + + UpdateStats(hrelid, nh, true); + UpdateStats(irelid, ni, false); + + if (oldPred != NULL) + { + if (ni == nh) + pred = NULL; + UpdateIndexPredicate(irelid, oldPred, pred); } - /* form an index tuple and point it at the heap tuple */ - itup = index_formtuple(id, &d[0], nulls); - itup->t_tid = htup->t_ctid; - - /* - * Since we already have the index relation locked, we - * call gistdoinsert directly. Normal access method calls - * dispatch through gistinsert, which locks the relation - * for write. This is the right thing to do if you're - * inserting single tups, but not when you're initializing - * the whole index at once. - */ - - res = gistdoinsert(index, itup, &giststate); - for (i = 0; i < natts; i++) - if (compvec[i] == TRUE) pfree((char *)d[i]); - pfree(itup); - pfree(res); - pfree(compvec); - } - - /* okay, all heap tuples are indexed */ - heap_endscan(scan); - RelationUnsetLockForWrite(index); - - if (pred != NULL || oldPred != NULL) { -#ifndef OMIT_PARTIAL_INDEX - ExecDestroyTupleTable(tupleTable, true); - pfree(econtext); -#endif /* OMIT_PARTIAL_INDEX */ - } - - /* - * Since we just inted the tuples in the heap, we update its - * stats in pg_relation to guarantee that the planner takes - * advantage of the index we just created. UpdateStats() does a - * CommandinterIncrement(), which flushes changed entries from - * the system relcache. The act of constructing an index changes - * these heap and index tuples in the system catalogs, so they - * need to be flushed. We close them to guarantee that they - * will be. - */ - - hrelid = heap->rd_id; - irelid = index->rd_id; - heap_close(heap); - index_close(index); - - UpdateStats(hrelid, nh, true); - UpdateStats(irelid, ni, false); - - if (oldPred != NULL) { - if (ni == nh) pred = NULL; - UpdateIndexPredicate(irelid, oldPred, pred); - } - - /* be tidy */ - pfree(nulls); - pfree(d); + /* be tidy */ + pfree(nulls); + pfree(d); } /* - * gistinsert -- wrapper for GiST tuple insertion. + * gistinsert -- wrapper for GiST tuple insertion. * - * This is the public interface routine for tuple insertion in GiSTs. - * It doesn't do any work; just locks the relation and passes the buck. + * This is the public interface routine for tuple insertion in GiSTs. + * It doesn't do any work; just locks the relation and passes the buck. */ InsertIndexResult -gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation heapRel) +gistinsert(Relation r, Datum * datum, char *nulls, ItemPointer ht_ctid, Relation heapRel) { - InsertIndexResult res; - IndexTuple itup; - GISTSTATE giststate; - GISTENTRY tmpentry; - int i; - bool *compvec; - - initGISTstate(&giststate, r); - - /* immediately compress keys to normalize */ - compvec = (bool *)palloc(sizeof(bool) * r->rd_att->natts); - for (i = 0; i < r->rd_att->natts; i++) { - gistcentryinit(&giststate, &tmpentry, (char *)datum[i], - (Relation) NULL, (Page) NULL, (OffsetNumber) 0, - -1 /* size is currently bogus */, TRUE); - if (datum[i] != (Datum)tmpentry.pred && !(giststate.keytypbyval)) - compvec[i] = TRUE; - else compvec[i] = FALSE; - datum[i] = (Datum)tmpentry.pred; - } - itup = index_formtuple(RelationGetTupleDescriptor(r), datum, nulls); - itup->t_tid = *ht_ctid; - - RelationSetLockForWrite(r); - res = gistdoinsert(r, itup, &giststate); - for (i = 0; i < r->rd_att->natts; i++) - if (compvec[i] == TRUE) pfree((char *)datum[i]); - pfree(itup); - pfree(compvec); - - /* XXX two-phase locking -- don't unlock the relation until EOT */ - return (res); + InsertIndexResult res; + IndexTuple itup; + GISTSTATE giststate; + GISTENTRY tmpentry; + int i; + bool *compvec; + + initGISTstate(&giststate, r); + + /* immediately compress keys to normalize */ + compvec = (bool *) palloc(sizeof(bool) * r->rd_att->natts); + for (i = 0; i < r->rd_att->natts; i++) + { + gistcentryinit(&giststate, &tmpentry, (char *) datum[i], + (Relation) NULL, (Page) NULL, (OffsetNumber) 0, + -1 /* size is currently bogus */ , TRUE); + if (datum[i] != (Datum) tmpentry.pred && !(giststate.keytypbyval)) + compvec[i] = TRUE; + else + compvec[i] = FALSE; + datum[i] = (Datum) tmpentry.pred; + } + itup = index_formtuple(RelationGetTupleDescriptor(r), datum, nulls); + itup->t_tid = *ht_ctid; + + RelationSetLockForWrite(r); + res = gistdoinsert(r, itup, &giststate); + for (i = 0; i < r->rd_att->natts; i++) + if (compvec[i] == TRUE) + pfree((char *) datum[i]); + pfree(itup); + pfree(compvec); + + /* XXX two-phase locking -- don't unlock the relation until EOT */ + return (res); } /* @@ -336,475 +373,509 @@ gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation ** that knowledge (some compression routines may want to fish around ** on the page, for example, or do something special for leaf nodes.) */ -static OffsetNumber -gistPageAddItem(GISTSTATE *giststate, - Relation r, - Page page, - Item item, - Size size, - OffsetNumber offsetNumber, - ItemIdFlags flags, - GISTENTRY *dentry, - IndexTuple *newtup) +static OffsetNumber +gistPageAddItem(GISTSTATE * giststate, + Relation r, + Page page, + Item item, + Size size, + OffsetNumber offsetNumber, + ItemIdFlags flags, + GISTENTRY * dentry, + IndexTuple * newtup) { - GISTENTRY tmpcentry; - IndexTuple itup = (IndexTuple)item; - - /* recompress the item given that we now know the exact page and - offset for insertion */ - gistdentryinit(giststate, dentry, - (((char *) itup) + sizeof(IndexTupleData)), - (Relation)0, (Page)0, (OffsetNumber)InvalidOffsetNumber, - IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE); - gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page, - offsetNumber, dentry->bytes, FALSE); - *newtup = gist_tuple_replacekey(r, *dentry, itup); - /* be tidy */ - if (tmpcentry.pred != dentry->pred - && tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData))) - pfree(tmpcentry.pred); - - return(PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup), - offsetNumber, flags)); + GISTENTRY tmpcentry; + IndexTuple itup = (IndexTuple) item; + + /* + * recompress the item given that we now know the exact page and + * offset for insertion + */ + gistdentryinit(giststate, dentry, + (((char *) itup) + sizeof(IndexTupleData)), + (Relation) 0, (Page) 0, (OffsetNumber) InvalidOffsetNumber, + IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE); + gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page, + offsetNumber, dentry->bytes, FALSE); + *newtup = gist_tuple_replacekey(r, *dentry, itup); + /* be tidy */ + if (tmpcentry.pred != dentry->pred + && tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData))) + pfree(tmpcentry.pred); + + return (PageAddItem(page, (Item) * newtup, IndexTupleSize(*newtup), + offsetNumber, flags)); } -static InsertIndexResult -gistdoinsert(Relation r, - IndexTuple itup, /* itup contains compressed entry */ - GISTSTATE *giststate) +static InsertIndexResult +gistdoinsert(Relation r, + IndexTuple itup, /* itup contains compressed entry */ + GISTSTATE * giststate) { - GISTENTRY tmpdentry; - InsertIndexResult res; - OffsetNumber l; - GISTSTACK *stack; - Buffer buffer; - BlockNumber blk; - Page page; - OffsetNumber off; - IndexTuple newtup; - - /* 3rd arg is ignored for now */ - blk = gistChooseSubtree(r, itup, 0, giststate, &stack, &buffer); - page = (Page) BufferGetPage(buffer); - - if (gistnospace(page, itup)) { - /* need to do a split */ - res = gistSplit(r, buffer, stack, itup, giststate); + GISTENTRY tmpdentry; + InsertIndexResult res; + OffsetNumber l; + GISTSTACK *stack; + Buffer buffer; + BlockNumber blk; + Page page; + OffsetNumber off; + IndexTuple newtup; + + /* 3rd arg is ignored for now */ + blk = gistChooseSubtree(r, itup, 0, giststate, &stack, &buffer); + page = (Page) BufferGetPage(buffer); + + if (gistnospace(page, itup)) + { + /* need to do a split */ + res = gistSplit(r, buffer, stack, itup, giststate); + gistfreestack(stack); + WriteBuffer(buffer); /* don't forget to release buffer! */ + return (res); + } + + if (PageIsEmpty(page)) + off = FirstOffsetNumber; + else + off = OffsetNumberNext(PageGetMaxOffsetNumber(page)); + + /* add the item and write the buffer */ + l = gistPageAddItem(giststate, r, page, (Item) itup, IndexTupleSize(itup), + off, LP_USED, &tmpdentry, &newtup); + WriteBuffer(buffer); + + /* now expand the page boundary in the parent to include the new child */ + gistAdjustKeys(r, stack, blk, tmpdentry.pred, tmpdentry.bytes, giststate); gistfreestack(stack); - WriteBuffer(buffer); /* don't forget to release buffer! */ + + /* be tidy */ + if (itup != newtup) + pfree(newtup); + if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData))) + pfree(tmpdentry.pred); + + /* build and return an InsertIndexResult for this insertion */ + res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); + ItemPointerSet(&(res->pointerData), blk, l); + return (res); - } - - if (PageIsEmpty(page)) - off = FirstOffsetNumber; - else - off = OffsetNumberNext(PageGetMaxOffsetNumber(page)); - - /* add the item and write the buffer */ - l = gistPageAddItem(giststate, r, page, (Item) itup, IndexTupleSize(itup), - off, LP_USED, &tmpdentry, &newtup); - WriteBuffer(buffer); - - /* now expand the page boundary in the parent to include the new child */ - gistAdjustKeys(r, stack, blk, tmpdentry.pred, tmpdentry.bytes, giststate); - gistfreestack(stack); - - /* be tidy */ - if (itup != newtup) - pfree(newtup); - if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData))) - pfree(tmpdentry.pred); - - /* build and return an InsertIndexResult for this insertion */ - res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); - ItemPointerSet(&(res->pointerData), blk, l); - - return (res); } -static BlockNumber -gistChooseSubtree(Relation r, IndexTuple itup, /* itup has compressed entry */ - int level, - GISTSTATE *giststate, - GISTSTACK **retstack /*out*/, - Buffer *leafbuf /*out*/) +static BlockNumber +gistChooseSubtree(Relation r, IndexTuple itup, /* itup has compressed + * entry */ + int level, + GISTSTATE * giststate, + GISTSTACK ** retstack /* out */ , + Buffer * leafbuf /* out */ ) { - Buffer buffer; - BlockNumber blk; - GISTSTACK *stack; - Page page; - GISTPageOpaque opaque; - IndexTuple which; - - blk = GISTP_ROOT; - buffer = InvalidBuffer; - stack = (GISTSTACK *) NULL; - - do { - /* let go of current buffer before getting next */ - if (buffer != InvalidBuffer) - ReleaseBuffer(buffer); - - /* get next buffer */ - buffer = ReadBuffer(r, blk); - page = (Page) BufferGetPage(buffer); - - opaque = (GISTPageOpaque) PageGetSpecialPointer(page); - if (!(opaque->flags & F_LEAF)) { - GISTSTACK *n; - ItemId iid; - - n = (GISTSTACK *) palloc(sizeof(GISTSTACK)); - n->gs_parent = stack; - n->gs_blk = blk; - n->gs_child = gistchoose(r, page, itup, giststate); - stack = n; - - iid = PageGetItemId(page, n->gs_child); - which = (IndexTuple) PageGetItem(page, iid); - blk = ItemPointerGetBlockNumber(&(which->t_tid)); - } - } while (!(opaque->flags & F_LEAF)); - - *retstack = stack; - *leafbuf = buffer; - - return(blk); + Buffer buffer; + BlockNumber blk; + GISTSTACK *stack; + Page page; + GISTPageOpaque opaque; + IndexTuple which; + + blk = GISTP_ROOT; + buffer = InvalidBuffer; + stack = (GISTSTACK *) NULL; + + do + { + /* let go of current buffer before getting next */ + if (buffer != InvalidBuffer) + ReleaseBuffer(buffer); + + /* get next buffer */ + buffer = ReadBuffer(r, blk); + page = (Page) BufferGetPage(buffer); + + opaque = (GISTPageOpaque) PageGetSpecialPointer(page); + if (!(opaque->flags & F_LEAF)) + { + GISTSTACK *n; + ItemId iid; + + n = (GISTSTACK *) palloc(sizeof(GISTSTACK)); + n->gs_parent = stack; + n->gs_blk = blk; + n->gs_child = gistchoose(r, page, itup, giststate); + stack = n; + + iid = PageGetItemId(page, n->gs_child); + which = (IndexTuple) PageGetItem(page, iid); + blk = ItemPointerGetBlockNumber(&(which->t_tid)); + } + } while (!(opaque->flags & F_LEAF)); + + *retstack = stack; + *leafbuf = buffer; + + return (blk); } static void gistAdjustKeys(Relation r, - GISTSTACK *stk, - BlockNumber blk, - char *datum, /* datum is uncompressed */ - int att_size, - GISTSTATE *giststate) + GISTSTACK * stk, + BlockNumber blk, + char *datum, /* datum is uncompressed */ + int att_size, + GISTSTATE * giststate) { - char *oldud; - Page p; - Buffer b; - bool result; - bytea *evec; - GISTENTRY centry, *ev0p, *ev1p; - int size, datumsize; - IndexTuple tid; - - if (stk == (GISTSTACK *) NULL) - return; - - b = ReadBuffer(r, stk->gs_blk); - p = BufferGetPage(b); - - oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->gs_child)); - tid = (IndexTuple) oldud; - size = IndexTupleSize((IndexTuple)oldud) - sizeof(IndexTupleData); - oldud += sizeof(IndexTupleData); - - evec = (bytea *) palloc(2*sizeof(GISTENTRY) + VARHDRSZ); - VARSIZE(evec) = 2*sizeof(GISTENTRY) + VARHDRSZ; - - /* insert decompressed oldud into entry vector */ - gistdentryinit(giststate, &((GISTENTRY *)VARDATA(evec))[0], - oldud, r, p, stk->gs_child, - size, FALSE); - ev0p = &((GISTENTRY *)VARDATA(evec))[0]; - - /* insert datum entry into entry vector */ - gistentryinit(((GISTENTRY *)VARDATA(evec))[1], datum, - (Relation)NULL,(Page)NULL,(OffsetNumber)0, att_size, FALSE); - ev1p = &((GISTENTRY *)VARDATA(evec))[1]; - - /* form union of decompressed entries */ - datum = (char *) (giststate->unionFn)(evec, &datumsize); - - /* did union leave decompressed version of oldud unchanged? */ - (giststate->equalFn)(ev0p->pred, datum, &result); - if (!result) { - TupleDesc td = RelationGetTupleDescriptor(r); - - /* compress datum for storage on page */ - gistcentryinit(giststate, ¢ry, datum, ev0p->rel, ev0p->page, - ev0p->offset, datumsize, FALSE); - if (td->attrs[0]->attlen >= 0) { - memmove(oldud, centry.pred, att_size); - gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size, - giststate); + char *oldud; + Page p; + Buffer b; + bool result; + bytea *evec; + GISTENTRY centry, + *ev0p, + *ev1p; + int size, + datumsize; + IndexTuple tid; + + if (stk == (GISTSTACK *) NULL) + return; + + b = ReadBuffer(r, stk->gs_blk); + p = BufferGetPage(b); + + oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->gs_child)); + tid = (IndexTuple) oldud; + size = IndexTupleSize((IndexTuple) oldud) - sizeof(IndexTupleData); + oldud += sizeof(IndexTupleData); + + evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ); + VARSIZE(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ; + + /* insert decompressed oldud into entry vector */ + gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[0], + oldud, r, p, stk->gs_child, + size, FALSE); + ev0p = &((GISTENTRY *) VARDATA(evec))[0]; + + /* insert datum entry into entry vector */ + gistentryinit(((GISTENTRY *) VARDATA(evec))[1], datum, + (Relation) NULL, (Page) NULL, (OffsetNumber) 0, att_size, FALSE); + ev1p = &((GISTENTRY *) VARDATA(evec))[1]; + + /* form union of decompressed entries */ + datum = (char *) (giststate->unionFn) (evec, &datumsize); + + /* did union leave decompressed version of oldud unchanged? */ + (giststate->equalFn) (ev0p->pred, datum, &result); + if (!result) + { + TupleDesc td = RelationGetTupleDescriptor(r); + + /* compress datum for storage on page */ + gistcentryinit(giststate, ¢ry, datum, ev0p->rel, ev0p->page, + ev0p->offset, datumsize, FALSE); + if (td->attrs[0]->attlen >= 0) + { + memmove(oldud, centry.pred, att_size); + gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size, + giststate); + } + else if (VARSIZE(centry.pred) == VARSIZE(oldud)) + { + memmove(oldud, centry.pred, VARSIZE(centry.pred)); + gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size, + giststate); + } + else + { + + /* + * * new datum is not the same size as the old. * We have to + * delete the old entry and insert the new * one. Note that + * this may cause a split here! + */ + IndexTuple newtup; + ItemPointerData oldtid; + char *isnull; + TupleDesc tupDesc; + InsertIndexResult res; + + /* delete old tuple */ + ItemPointerSet(&oldtid, stk->gs_blk, stk->gs_child); + gistdelete(r, (ItemPointer) & oldtid); + + /* generate and insert new tuple */ + tupDesc = r->rd_att; + isnull = (char *) palloc(r->rd_rel->relnatts); + memset(isnull, ' ', r->rd_rel->relnatts); + newtup = (IndexTuple) index_formtuple(tupDesc, + (Datum *) & centry.pred, isnull); + pfree(isnull); + /* set pointer in new tuple to point to current child */ + ItemPointerSet(&oldtid, blk, 1); + newtup->t_tid = oldtid; + + /* inserting the new entry also adjust keys above */ + res = gistentryinsert(r, stk, newtup, giststate); + + /* in stack, set info to point to new tuple */ + stk->gs_blk = ItemPointerGetBlockNumber(&(res->pointerData)); + stk->gs_child = ItemPointerGetOffsetNumber(&(res->pointerData)); + + pfree(res); + } + WriteBuffer(b); + + if (centry.pred != datum) + pfree(datum); } - else if (VARSIZE(centry.pred) == VARSIZE(oldud)) { - memmove(oldud, centry.pred, VARSIZE(centry.pred)); - gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size, - giststate); + else + { + ReleaseBuffer(b); } - else { - /* - ** new datum is not the same size as the old. - ** We have to delete the old entry and insert the new - ** one. Note that this may cause a split here! - */ - IndexTuple newtup; - ItemPointerData oldtid; - char *isnull; - TupleDesc tupDesc; - InsertIndexResult res; - - /* delete old tuple */ - ItemPointerSet(&oldtid, stk->gs_blk, stk->gs_child); - gistdelete(r, (ItemPointer)&oldtid); - - /* generate and insert new tuple */ - tupDesc = r->rd_att; - isnull = (char *) palloc(r->rd_rel->relnatts); - memset(isnull, ' ', r->rd_rel->relnatts); - newtup = (IndexTuple) index_formtuple(tupDesc, - (Datum *) ¢ry.pred, isnull); - pfree(isnull); - /* set pointer in new tuple to point to current child */ - ItemPointerSet(&oldtid, blk, 1); - newtup->t_tid = oldtid; - - /* inserting the new entry also adjust keys above */ - res = gistentryinsert(r, stk, newtup, giststate); - - /* in stack, set info to point to new tuple */ - stk->gs_blk = ItemPointerGetBlockNumber(&(res->pointerData)); - stk->gs_child = ItemPointerGetOffsetNumber(&(res->pointerData)); - - pfree(res); - } - WriteBuffer(b); - - if (centry.pred != datum) - pfree(datum); - } - else { - ReleaseBuffer(b); - } - pfree(evec); + pfree(evec); } /* - * gistSplit -- split a page in the tree. + * gistSplit -- split a page in the tree. * */ -static InsertIndexResult +static InsertIndexResult gistSplit(Relation r, - Buffer buffer, - GISTSTACK *stack, - IndexTuple itup, /* contains compressed entry */ - GISTSTATE *giststate) + Buffer buffer, + GISTSTACK * stack, + IndexTuple itup, /* contains compressed entry */ + GISTSTATE * giststate) { - Page p; - Buffer leftbuf, rightbuf; - Page left, right; - ItemId itemid; - IndexTuple item; - IndexTuple ltup, rtup, newtup; - OffsetNumber maxoff; - OffsetNumber i; - OffsetNumber leftoff, rightoff; - BlockNumber lbknum, rbknum; - BlockNumber bufblock; - GISTPageOpaque opaque; - int blank; - InsertIndexResult res; - char *isnull; - GIST_SPLITVEC v; - TupleDesc tupDesc; - bytea *entryvec; - bool *decompvec; - IndexTuple item_1; - GISTENTRY tmpdentry, tmpentry; - - isnull = (char *) palloc(r->rd_rel->relnatts); - for (blank = 0; blank < r->rd_rel->relnatts; blank++) - isnull[blank] = ' '; - p = (Page) BufferGetPage(buffer); - opaque = (GISTPageOpaque) PageGetSpecialPointer(p); - - - /* - * The root of the tree is the first block in the relation. If - * we're about to split the root, we need to do some hocus-pocus - * to enforce this guarantee. - */ - - if (BufferGetBlockNumber(buffer) == GISTP_ROOT) { - leftbuf = ReadBuffer(r, P_NEW); - GISTInitBuffer(leftbuf, opaque->flags); - lbknum = BufferGetBlockNumber(leftbuf); - left = (Page) BufferGetPage(leftbuf); - } else { - leftbuf = buffer; - IncrBufferRefCount(buffer); - lbknum = BufferGetBlockNumber(buffer); - left = (Page) PageGetTempPage(p, sizeof(GISTPageOpaqueData)); - } - - rightbuf = ReadBuffer(r, P_NEW); - GISTInitBuffer(rightbuf, opaque->flags); - rbknum = BufferGetBlockNumber(rightbuf); - right = (Page) BufferGetPage(rightbuf); - - /* generate the item array */ - maxoff = PageGetMaxOffsetNumber(p); - entryvec = (bytea *)palloc(VARHDRSZ + (maxoff + 2) * sizeof(GISTENTRY)); - decompvec = (bool *)palloc(VARHDRSZ + (maxoff + 2) * sizeof(bool)); - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { - item_1 = (IndexTuple) PageGetItem(p, PageGetItemId(p, i)); - gistdentryinit(giststate, &((GISTENTRY *)VARDATA(entryvec))[i], - (((char *) item_1) + sizeof(IndexTupleData)), - r, p, i, - IndexTupleSize(item_1) - sizeof(IndexTupleData), FALSE); - if ((char *)(((GISTENTRY *)VARDATA(entryvec))[i].pred) - == (((char *) item_1) + sizeof(IndexTupleData))) - decompvec[i] = FALSE; - else decompvec[i] = TRUE; - } - - /* add the new datum as the last entry */ - gistdentryinit(giststate, &(((GISTENTRY *)VARDATA(entryvec))[maxoff+1]), - (((char *) itup) + sizeof(IndexTupleData)), - (Relation)NULL, (Page)NULL, - (OffsetNumber)0, tmpentry.bytes, FALSE); - if ((char *)(((GISTENTRY *)VARDATA(entryvec))[maxoff+1]).pred != - (((char *) itup) + sizeof(IndexTupleData))) - decompvec[maxoff+1] = TRUE; - else decompvec[maxoff+1] = FALSE; - - VARSIZE(entryvec) = (maxoff + 2) * sizeof(GISTENTRY) + VARHDRSZ; - - /* now let the user-defined picksplit function set up the split vector */ - (giststate->picksplitFn)(entryvec, &v); - - /* compress ldatum and rdatum */ - gistcentryinit(giststate, &tmpentry, v.spl_ldatum, (Relation)NULL, - (Page)NULL, (OffsetNumber)0, - ((GISTENTRY *)VARDATA(entryvec))[i].bytes, FALSE); - if (v.spl_ldatum != tmpentry.pred) - pfree(v.spl_ldatum); - v.spl_ldatum = tmpentry.pred; - - gistcentryinit(giststate, &tmpentry, v.spl_rdatum, (Relation)NULL, - (Page)NULL, (OffsetNumber)0, - ((GISTENTRY *)VARDATA(entryvec))[i].bytes, FALSE); - if (v.spl_rdatum != tmpentry.pred) - pfree(v.spl_rdatum); - v.spl_rdatum = tmpentry.pred; - - /* clean up the entry vector: its preds need to be deleted, too */ - for (i = FirstOffsetNumber; i <= maxoff+1; i = OffsetNumberNext(i)) - if (decompvec[i]) - pfree(((GISTENTRY *)VARDATA(entryvec))[i].pred); - pfree(entryvec); - pfree(decompvec); - - leftoff = rightoff = FirstOffsetNumber; - maxoff = PageGetMaxOffsetNumber(p); - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { - itemid = PageGetItemId(p, i); - item = (IndexTuple) PageGetItem(p, itemid); - - if (i == *(v.spl_left)) { - gistPageAddItem(giststate, r, left, (Item) item, - IndexTupleSize(item), - leftoff, LP_USED, &tmpdentry, &newtup); - leftoff = OffsetNumberNext(leftoff); - v.spl_left++; /* advance in left split vector */ - /* be tidy */ - if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData))) - pfree(tmpdentry.pred); - if ((IndexTuple)item != newtup) - pfree(newtup); - } - else { - gistPageAddItem(giststate, r, right, (Item) item, - IndexTupleSize(item), - rightoff, LP_USED, &tmpdentry, &newtup); - rightoff = OffsetNumberNext(rightoff); - v.spl_right++; /* advance in right split vector */ - /* be tidy */ - if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData))) - pfree(tmpdentry.pred); - if (item != newtup) - pfree(newtup); + Page p; + Buffer leftbuf, + rightbuf; + Page left, + right; + ItemId itemid; + IndexTuple item; + IndexTuple ltup, + rtup, + newtup; + OffsetNumber maxoff; + OffsetNumber i; + OffsetNumber leftoff, + rightoff; + BlockNumber lbknum, + rbknum; + BlockNumber bufblock; + GISTPageOpaque opaque; + int blank; + InsertIndexResult res; + char *isnull; + GIST_SPLITVEC v; + TupleDesc tupDesc; + bytea *entryvec; + bool *decompvec; + IndexTuple item_1; + GISTENTRY tmpdentry, + tmpentry; + + isnull = (char *) palloc(r->rd_rel->relnatts); + for (blank = 0; blank < r->rd_rel->relnatts; blank++) + isnull[blank] = ' '; + p = (Page) BufferGetPage(buffer); + opaque = (GISTPageOpaque) PageGetSpecialPointer(p); + + + /* + * The root of the tree is the first block in the relation. If we're + * about to split the root, we need to do some hocus-pocus to enforce + * this guarantee. + */ + + if (BufferGetBlockNumber(buffer) == GISTP_ROOT) + { + leftbuf = ReadBuffer(r, P_NEW); + GISTInitBuffer(leftbuf, opaque->flags); + lbknum = BufferGetBlockNumber(leftbuf); + left = (Page) BufferGetPage(leftbuf); } - } - - /* build an InsertIndexResult for this insertion */ - res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); - - /* now insert the new index tuple */ - if (*(v.spl_left) != FirstOffsetNumber) { - gistPageAddItem(giststate, r, left, (Item) itup, - IndexTupleSize(itup), - leftoff, LP_USED, &tmpdentry, &newtup); - leftoff = OffsetNumberNext(leftoff); - ItemPointerSet(&(res->pointerData), lbknum, leftoff); - /* be tidy */ - if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData))) - pfree(tmpdentry.pred); - if (itup != newtup) - pfree(newtup); - } else { - gistPageAddItem(giststate, r, right, (Item) itup, - IndexTupleSize(itup), - rightoff, LP_USED, &tmpdentry, &newtup); - rightoff = OffsetNumberNext(rightoff); - ItemPointerSet(&(res->pointerData), rbknum, rightoff); - /* be tidy */ - if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData))) - pfree(tmpdentry.pred); - if (itup != newtup) - pfree(newtup); - } - - if ((bufblock = BufferGetBlockNumber(buffer)) != GISTP_ROOT) { - PageRestoreTempPage(left, p); - } - WriteBuffer(leftbuf); - WriteBuffer(rightbuf); - - /* - * Okay, the page is split. We have three things left to do: - * - * 1) Adjust any active scans on this index to cope with changes - * we introduced in its structure by splitting this page. - * - * 2) "Tighten" the bounding box of the pointer to the left - * page in the parent node in the tree, if any. Since we - * moved a bunch of stuff off the left page, we expect it - * to get smaller. This happens in the internal insertion - * routine. - * - * 3) Insert a pointer to the right page in the parent. This - * may cause the parent to split. If it does, we need to - * repeat steps one and two for each split node in the tree. - */ - - /* adjust active scans */ - gistadjscans(r, GISTOP_SPLIT, bufblock, FirstOffsetNumber); - - tupDesc = r->rd_att; - - ltup = (IndexTuple) index_formtuple(tupDesc, - (Datum *) &(v.spl_ldatum), isnull); - rtup = (IndexTuple) index_formtuple(tupDesc, - (Datum *) &(v.spl_rdatum), isnull); - pfree(isnull); - - /* set pointers to new child pages in the internal index tuples */ - ItemPointerSet(&(ltup->t_tid), lbknum, 1); - ItemPointerSet(&(rtup->t_tid), rbknum, 1); - - gistintinsert(r, stack, ltup, rtup, giststate); - - pfree(ltup); - pfree(rtup); - - return (res); + else + { + leftbuf = buffer; + IncrBufferRefCount(buffer); + lbknum = BufferGetBlockNumber(buffer); + left = (Page) PageGetTempPage(p, sizeof(GISTPageOpaqueData)); + } + + rightbuf = ReadBuffer(r, P_NEW); + GISTInitBuffer(rightbuf, opaque->flags); + rbknum = BufferGetBlockNumber(rightbuf); + right = (Page) BufferGetPage(rightbuf); + + /* generate the item array */ + maxoff = PageGetMaxOffsetNumber(p); + entryvec = (bytea *) palloc(VARHDRSZ + (maxoff + 2) * sizeof(GISTENTRY)); + decompvec = (bool *) palloc(VARHDRSZ + (maxoff + 2) * sizeof(bool)); + for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) + { + item_1 = (IndexTuple) PageGetItem(p, PageGetItemId(p, i)); + gistdentryinit(giststate, &((GISTENTRY *) VARDATA(entryvec))[i], + (((char *) item_1) + sizeof(IndexTupleData)), + r, p, i, + IndexTupleSize(item_1) - sizeof(IndexTupleData), FALSE); + if ((char *) (((GISTENTRY *) VARDATA(entryvec))[i].pred) + == (((char *) item_1) + sizeof(IndexTupleData))) + decompvec[i] = FALSE; + else + decompvec[i] = TRUE; + } + + /* add the new datum as the last entry */ + gistdentryinit(giststate, &(((GISTENTRY *) VARDATA(entryvec))[maxoff + 1]), + (((char *) itup) + sizeof(IndexTupleData)), + (Relation) NULL, (Page) NULL, + (OffsetNumber) 0, tmpentry.bytes, FALSE); + if ((char *) (((GISTENTRY *) VARDATA(entryvec))[maxoff + 1]).pred != + (((char *) itup) + sizeof(IndexTupleData))) + decompvec[maxoff + 1] = TRUE; + else + decompvec[maxoff + 1] = FALSE; + + VARSIZE(entryvec) = (maxoff + 2) * sizeof(GISTENTRY) + VARHDRSZ; + + /* now let the user-defined picksplit function set up the split vector */ + (giststate->picksplitFn) (entryvec, &v); + + /* compress ldatum and rdatum */ + gistcentryinit(giststate, &tmpentry, v.spl_ldatum, (Relation) NULL, + (Page) NULL, (OffsetNumber) 0, + ((GISTENTRY *) VARDATA(entryvec))[i].bytes, FALSE); + if (v.spl_ldatum != tmpentry.pred) + pfree(v.spl_ldatum); + v.spl_ldatum = tmpentry.pred; + + gistcentryinit(giststate, &tmpentry, v.spl_rdatum, (Relation) NULL, + (Page) NULL, (OffsetNumber) 0, + ((GISTENTRY *) VARDATA(entryvec))[i].bytes, FALSE); + if (v.spl_rdatum != tmpentry.pred) + pfree(v.spl_rdatum); + v.spl_rdatum = tmpentry.pred; + + /* clean up the entry vector: its preds need to be deleted, too */ + for (i = FirstOffsetNumber; i <= maxoff + 1; i = OffsetNumberNext(i)) + if (decompvec[i]) + pfree(((GISTENTRY *) VARDATA(entryvec))[i].pred); + pfree(entryvec); + pfree(decompvec); + + leftoff = rightoff = FirstOffsetNumber; + maxoff = PageGetMaxOffsetNumber(p); + for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) + { + itemid = PageGetItemId(p, i); + item = (IndexTuple) PageGetItem(p, itemid); + + if (i == *(v.spl_left)) + { + gistPageAddItem(giststate, r, left, (Item) item, + IndexTupleSize(item), + leftoff, LP_USED, &tmpdentry, &newtup); + leftoff = OffsetNumberNext(leftoff); + v.spl_left++; /* advance in left split vector */ + /* be tidy */ + if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData))) + pfree(tmpdentry.pred); + if ((IndexTuple) item != newtup) + pfree(newtup); + } + else + { + gistPageAddItem(giststate, r, right, (Item) item, + IndexTupleSize(item), + rightoff, LP_USED, &tmpdentry, &newtup); + rightoff = OffsetNumberNext(rightoff); + v.spl_right++; /* advance in right split vector */ + /* be tidy */ + if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData))) + pfree(tmpdentry.pred); + if (item != newtup) + pfree(newtup); + } + } + + /* build an InsertIndexResult for this insertion */ + res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); + + /* now insert the new index tuple */ + if (*(v.spl_left) != FirstOffsetNumber) + { + gistPageAddItem(giststate, r, left, (Item) itup, + IndexTupleSize(itup), + leftoff, LP_USED, &tmpdentry, &newtup); + leftoff = OffsetNumberNext(leftoff); + ItemPointerSet(&(res->pointerData), lbknum, leftoff); + /* be tidy */ + if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData))) + pfree(tmpdentry.pred); + if (itup != newtup) + pfree(newtup); + } + else + { + gistPageAddItem(giststate, r, right, (Item) itup, + IndexTupleSize(itup), + rightoff, LP_USED, &tmpdentry, &newtup); + rightoff = OffsetNumberNext(rightoff); + ItemPointerSet(&(res->pointerData), rbknum, rightoff); + /* be tidy */ + if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData))) + pfree(tmpdentry.pred); + if (itup != newtup) + pfree(newtup); + } + + if ((bufblock = BufferGetBlockNumber(buffer)) != GISTP_ROOT) + { + PageRestoreTempPage(left, p); + } + WriteBuffer(leftbuf); + WriteBuffer(rightbuf); + + /* + * Okay, the page is split. We have three things left to do: + * + * 1) Adjust any active scans on this index to cope with changes we + * introduced in its structure by splitting this page. + * + * 2) "Tighten" the bounding box of the pointer to the left page in the + * parent node in the tree, if any. Since we moved a bunch of stuff + * off the left page, we expect it to get smaller. This happens in + * the internal insertion routine. + * + * 3) Insert a pointer to the right page in the parent. This may cause + * the parent to split. If it does, we need to repeat steps one and + * two for each split node in the tree. + */ + + /* adjust active scans */ + gistadjscans(r, GISTOP_SPLIT, bufblock, FirstOffsetNumber); + + tupDesc = r->rd_att; + + ltup = (IndexTuple) index_formtuple(tupDesc, + (Datum *) & (v.spl_ldatum), isnull); + rtup = (IndexTuple) index_formtuple(tupDesc, + (Datum *) & (v.spl_rdatum), isnull); + pfree(isnull); + + /* set pointers to new child pages in the internal index tuples */ + ItemPointerSet(&(ltup->t_tid), lbknum, 1); + ItemPointerSet(&(rtup->t_tid), rbknum, 1); + + gistintinsert(r, stack, ltup, rtup, giststate); + + pfree(ltup); + pfree(rtup); + + return (res); } /* @@ -813,22 +884,23 @@ gistSplit(Relation r, */ static void gistintinsert(Relation r, - GISTSTACK *stk, - IndexTuple ltup, /* new version of entry for old page */ - IndexTuple rtup, /* entry for new page */ - GISTSTATE *giststate) + GISTSTACK * stk, + IndexTuple ltup, /* new version of entry for old page */ + IndexTuple rtup, /* entry for new page */ + GISTSTATE * giststate) { - ItemPointerData ltid; + ItemPointerData ltid; - if (stk == (GISTSTACK *) NULL) { - gistnewroot(giststate, r, ltup, rtup); - return; - } - - /* remove old left pointer, insert the 2 new entries */ - ItemPointerSet(<id, stk->gs_blk, stk->gs_child); - gistdelete(r, (ItemPointer)<id); - gistentryinserttwo(r, stk, ltup, rtup, giststate); + if (stk == (GISTSTACK *) NULL) + { + gistnewroot(giststate, r, ltup, rtup); + return; + } + + /* remove old left pointer, insert the 2 new entries */ + ItemPointerSet(<id, stk->gs_blk, stk->gs_child); + gistdelete(r, (ItemPointer) & ltid); + gistentryinserttwo(r, stk, ltup, rtup, giststate); } @@ -836,280 +908,299 @@ gistintinsert(Relation r, ** Insert two entries onto one page, handling a split for either one! */ static void -gistentryinserttwo(Relation r, GISTSTACK *stk, IndexTuple ltup, - IndexTuple rtup, GISTSTATE *giststate) +gistentryinserttwo(Relation r, GISTSTACK * stk, IndexTuple ltup, + IndexTuple rtup, GISTSTATE * giststate) { - Buffer b; - Page p; - InsertIndexResult res; - GISTENTRY tmpentry; - IndexTuple newtup; - - b = ReadBuffer(r, stk->gs_blk); - p = BufferGetPage(b); - - if (gistnospace(p, ltup)) { - res = gistSplit(r, b, stk->gs_parent, ltup, giststate); - WriteBuffer(b); /* don't forget to release buffer! - 01/31/94 */ - pfree(res); - gistdoinsert(r, rtup, giststate); - } else { - gistPageAddItem(giststate, r, p, (Item)ltup, - IndexTupleSize(ltup), InvalidOffsetNumber, - LP_USED, &tmpentry, &newtup); - WriteBuffer(b); - gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred, - tmpentry.bytes, giststate); - /* be tidy */ - if (tmpentry.pred != (((char *) ltup) + sizeof(IndexTupleData))) - pfree(tmpentry.pred); - if (ltup != newtup) - pfree(newtup); - gistentryinsert(r, stk, rtup, giststate); - } -} + Buffer b; + Page p; + InsertIndexResult res; + GISTENTRY tmpentry; + IndexTuple newtup; + + b = ReadBuffer(r, stk->gs_blk); + p = BufferGetPage(b); + + if (gistnospace(p, ltup)) + { + res = gistSplit(r, b, stk->gs_parent, ltup, giststate); + WriteBuffer(b); /* don't forget to release buffer! - + * 01/31/94 */ + pfree(res); + gistdoinsert(r, rtup, giststate); + } + else + { + gistPageAddItem(giststate, r, p, (Item) ltup, + IndexTupleSize(ltup), InvalidOffsetNumber, + LP_USED, &tmpentry, &newtup); + WriteBuffer(b); + gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred, + tmpentry.bytes, giststate); + /* be tidy */ + if (tmpentry.pred != (((char *) ltup) + sizeof(IndexTupleData))) + pfree(tmpentry.pred); + if (ltup != newtup) + pfree(newtup); + gistentryinsert(r, stk, rtup, giststate); + } +} /* ** Insert an entry onto a page */ -static InsertIndexResult -gistentryinsert(Relation r, GISTSTACK *stk, IndexTuple tup, - GISTSTATE *giststate) +static InsertIndexResult +gistentryinsert(Relation r, GISTSTACK * stk, IndexTuple tup, + GISTSTATE * giststate) { - Buffer b; - Page p; - InsertIndexResult res; - OffsetNumber off; - GISTENTRY tmpentry; - IndexTuple newtup; - - b = ReadBuffer(r, stk->gs_blk); - p = BufferGetPage(b); - - if (gistnospace(p, tup)) { - res = gistSplit(r, b, stk->gs_parent, tup, giststate); - WriteBuffer(b); /* don't forget to release buffer! - 01/31/94 */ - return(res); - } - else { - res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); - off = gistPageAddItem(giststate, r, p, (Item) tup, IndexTupleSize(tup), - InvalidOffsetNumber, LP_USED, &tmpentry, &newtup); - WriteBuffer(b); - ItemPointerSet(&(res->pointerData), stk->gs_blk, off); - gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred, - tmpentry.bytes, giststate); - /* be tidy */ - if (tmpentry.pred != (((char *) tup) + sizeof(IndexTupleData))) - pfree(tmpentry.pred); - if (tup != newtup) - pfree(newtup); - return(res); - } -} + Buffer b; + Page p; + InsertIndexResult res; + OffsetNumber off; + GISTENTRY tmpentry; + IndexTuple newtup; + + b = ReadBuffer(r, stk->gs_blk); + p = BufferGetPage(b); + + if (gistnospace(p, tup)) + { + res = gistSplit(r, b, stk->gs_parent, tup, giststate); + WriteBuffer(b); /* don't forget to release buffer! - + * 01/31/94 */ + return (res); + } + else + { + res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); + off = gistPageAddItem(giststate, r, p, (Item) tup, IndexTupleSize(tup), + InvalidOffsetNumber, LP_USED, &tmpentry, &newtup); + WriteBuffer(b); + ItemPointerSet(&(res->pointerData), stk->gs_blk, off); + gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred, + tmpentry.bytes, giststate); + /* be tidy */ + if (tmpentry.pred != (((char *) tup) + sizeof(IndexTupleData))) + pfree(tmpentry.pred); + if (tup != newtup) + pfree(newtup); + return (res); + } +} static void -gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt, IndexTuple rt) +gistnewroot(GISTSTATE * giststate, Relation r, IndexTuple lt, IndexTuple rt) { - Buffer b; - Page p; - GISTENTRY tmpentry; - IndexTuple newtup; - - b = ReadBuffer(r, GISTP_ROOT); - GISTInitBuffer(b, 0); - p = BufferGetPage(b); - gistPageAddItem(giststate, r, p, (Item) lt, IndexTupleSize(lt), - FirstOffsetNumber, - LP_USED, &tmpentry, &newtup); - /* be tidy */ - if (tmpentry.pred != (((char *) lt) + sizeof(IndexTupleData))) - pfree(tmpentry.pred); - if (lt != newtup) - pfree(newtup); - gistPageAddItem(giststate, r, p, (Item) rt, IndexTupleSize(rt), - OffsetNumberNext(FirstOffsetNumber), LP_USED, - &tmpentry, &newtup); - /* be tidy */ - if (tmpentry.pred != (((char *) rt) + sizeof(IndexTupleData))) - pfree(tmpentry.pred); - if (rt != newtup) - pfree(newtup); - WriteBuffer(b); + Buffer b; + Page p; + GISTENTRY tmpentry; + IndexTuple newtup; + + b = ReadBuffer(r, GISTP_ROOT); + GISTInitBuffer(b, 0); + p = BufferGetPage(b); + gistPageAddItem(giststate, r, p, (Item) lt, IndexTupleSize(lt), + FirstOffsetNumber, + LP_USED, &tmpentry, &newtup); + /* be tidy */ + if (tmpentry.pred != (((char *) lt) + sizeof(IndexTupleData))) + pfree(tmpentry.pred); + if (lt != newtup) + pfree(newtup); + gistPageAddItem(giststate, r, p, (Item) rt, IndexTupleSize(rt), + OffsetNumberNext(FirstOffsetNumber), LP_USED, + &tmpentry, &newtup); + /* be tidy */ + if (tmpentry.pred != (((char *) rt) + sizeof(IndexTupleData))) + pfree(tmpentry.pred); + if (rt != newtup) + pfree(newtup); + WriteBuffer(b); } static void GISTInitBuffer(Buffer b, uint32 f) { - GISTPageOpaque opaque; - Page page; - Size pageSize; - - pageSize = BufferGetPageSize(b); - - page = BufferGetPage(b); - memset(page, 0, (int) pageSize); - PageInit(page, pageSize, sizeof(GISTPageOpaqueData)); - - opaque = (GISTPageOpaque) PageGetSpecialPointer(page); - opaque->flags = f; + GISTPageOpaque opaque; + Page page; + Size pageSize; + + pageSize = BufferGetPageSize(b); + + page = BufferGetPage(b); + memset(page, 0, (int) pageSize); + PageInit(page, pageSize, sizeof(GISTPageOpaqueData)); + + opaque = (GISTPageOpaque) PageGetSpecialPointer(page); + opaque->flags = f; } /* ** find entry with lowest penalty */ -static OffsetNumber -gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */ - GISTSTATE *giststate) +static OffsetNumber +gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */ + GISTSTATE * giststate) { - OffsetNumber maxoff; - OffsetNumber i; - char *id; - char *datum; - float usize; - OffsetNumber which; - float which_grow; - GISTENTRY entry, identry; - int size, idsize; - - idsize = IndexTupleSize(it) - sizeof(IndexTupleData); - id = ((char *) it) + sizeof(IndexTupleData); - maxoff = PageGetMaxOffsetNumber(p); - which_grow = -1.0; - which = -1; - - gistdentryinit(giststate,&identry,id,(Relation)NULL,(Page)NULL, - (OffsetNumber)0, idsize, FALSE); - - for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { - datum = (char *) PageGetItem(p, PageGetItemId(p, i)); - size = IndexTupleSize(datum) - sizeof(IndexTupleData); - datum += sizeof(IndexTupleData); - gistdentryinit(giststate,&entry,datum,r,p,i,size,FALSE); - (giststate->penaltyFn)(&entry, &identry, &usize); - if (which_grow < 0 || usize < which_grow) { - which = i; - which_grow = usize; - if (which_grow == 0) - break; + OffsetNumber maxoff; + OffsetNumber i; + char *id; + char *datum; + float usize; + OffsetNumber which; + float which_grow; + GISTENTRY entry, + identry; + int size, + idsize; + + idsize = IndexTupleSize(it) - sizeof(IndexTupleData); + id = ((char *) it) + sizeof(IndexTupleData); + maxoff = PageGetMaxOffsetNumber(p); + which_grow = -1.0; + which = -1; + + gistdentryinit(giststate, &identry, id, (Relation) NULL, (Page) NULL, + (OffsetNumber) 0, idsize, FALSE); + + for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) + { + datum = (char *) PageGetItem(p, PageGetItemId(p, i)); + size = IndexTupleSize(datum) - sizeof(IndexTupleData); + datum += sizeof(IndexTupleData); + gistdentryinit(giststate, &entry, datum, r, p, i, size, FALSE); + (giststate->penaltyFn) (&entry, &identry, &usize); + if (which_grow < 0 || usize < which_grow) + { + which = i; + which_grow = usize; + if (which_grow == 0) + break; + } + if (entry.pred != datum) + pfree(entry.pred); } - if (entry.pred != datum) - pfree(entry.pred); - } - if (identry.pred != id) - pfree(identry.pred); - - return (which); + if (identry.pred != id) + pfree(identry.pred); + + return (which); } static int gistnospace(Page p, IndexTuple it) { - return (PageGetFreeSpace(p) < IndexTupleSize(it)); + return (PageGetFreeSpace(p) < IndexTupleSize(it)); } void -gistfreestack(GISTSTACK *s) +gistfreestack(GISTSTACK * s) { - GISTSTACK *p; - - while (s != (GISTSTACK *) NULL) { - p = s->gs_parent; - pfree(s); - s = p; - } + GISTSTACK *p; + + while (s != (GISTSTACK *) NULL) + { + p = s->gs_parent; + pfree(s); + s = p; + } } -/* -** remove an entry from a page +/* +** remove an entry from a page */ void gistdelete(Relation r, ItemPointer tid) { - BlockNumber blkno; - OffsetNumber offnum; - Buffer buf; - Page page; - - /* must write-lock on delete */ - RelationSetLockForWrite(r); - - blkno = ItemPointerGetBlockNumber(tid); - offnum = ItemPointerGetOffsetNumber(tid); - - /* adjust any scans that will be affected by this deletion */ - gistadjscans(r, GISTOP_DEL, blkno, offnum); - - /* delete the index tuple */ - buf = ReadBuffer(r, blkno); - page = BufferGetPage(buf); - - PageIndexTupleDelete(page, offnum); - - WriteBuffer(buf); - - /* XXX -- two-phase locking, don't release the write lock */ + BlockNumber blkno; + OffsetNumber offnum; + Buffer buf; + Page page; + + /* must write-lock on delete */ + RelationSetLockForWrite(r); + + blkno = ItemPointerGetBlockNumber(tid); + offnum = ItemPointerGetOffsetNumber(tid); + + /* adjust any scans that will be affected by this deletion */ + gistadjscans(r, GISTOP_DEL, blkno, offnum); + + /* delete the index tuple */ + buf = ReadBuffer(r, blkno); + page = BufferGetPage(buf); + + PageIndexTupleDelete(page, offnum); + + WriteBuffer(buf); + + /* XXX -- two-phase locking, don't release the write lock */ } -void -initGISTstate(GISTSTATE *giststate, Relation index) +void +initGISTstate(GISTSTATE * giststate, Relation index) { - RegProcedure consistent_proc, union_proc, compress_proc, decompress_proc; - RegProcedure penalty_proc, picksplit_proc, equal_proc; - func_ptr user_fn; - int pronargs; - HeapTuple htup; - IndexTupleForm itupform; - - consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC); - union_proc = index_getprocid(index, 1, GIST_UNION_PROC); - compress_proc = index_getprocid(index, 1, GIST_COMPRESS_PROC); - decompress_proc = index_getprocid(index, 1, GIST_DECOMPRESS_PROC); - penalty_proc = index_getprocid(index, 1, GIST_PENALTY_PROC); - picksplit_proc = index_getprocid(index, 1, GIST_PICKSPLIT_PROC); - equal_proc = index_getprocid(index, 1, GIST_EQUAL_PROC); - fmgr_info(consistent_proc, &user_fn, &pronargs); - giststate->consistentFn = user_fn; - fmgr_info(union_proc, &user_fn, &pronargs); - giststate->unionFn = user_fn; - fmgr_info(compress_proc, &user_fn, &pronargs); - giststate->compressFn = user_fn; - fmgr_info(decompress_proc, &user_fn, &pronargs); - giststate->decompressFn = user_fn; - fmgr_info(penalty_proc, &user_fn, &pronargs); - giststate->penaltyFn = user_fn; - fmgr_info(picksplit_proc, &user_fn, &pronargs); - giststate->picksplitFn = user_fn; - fmgr_info(equal_proc, &user_fn, &pronargs); - giststate->equalFn = user_fn; - - /* see if key type is different from type of attribute being indexed */ - htup = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(index->rd_id), - 0,0,0); - itupform = (IndexTupleForm)GETSTRUCT(htup); - if (!HeapTupleIsValid(htup)) - elog(WARN, "initGISTstate: index %d not found", index->rd_id); - giststate->haskeytype = itupform->indhaskeytype; - if (giststate->haskeytype) { - /* key type is different -- is it byval? */ - htup = SearchSysCacheTuple(ATTNUM, - ObjectIdGetDatum(itupform->indexrelid), - UInt16GetDatum(FirstOffsetNumber), - 0,0); - if (!HeapTupleIsValid(htup)) { - elog(WARN, "initGISTstate: no attribute tuple %d %d", - itupform->indexrelid, FirstOffsetNumber); - return; + RegProcedure consistent_proc, + union_proc, + compress_proc, + decompress_proc; + RegProcedure penalty_proc, + picksplit_proc, + equal_proc; + func_ptr user_fn; + int pronargs; + HeapTuple htup; + IndexTupleForm itupform; + + consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC); + union_proc = index_getprocid(index, 1, GIST_UNION_PROC); + compress_proc = index_getprocid(index, 1, GIST_COMPRESS_PROC); + decompress_proc = index_getprocid(index, 1, GIST_DECOMPRESS_PROC); + penalty_proc = index_getprocid(index, 1, GIST_PENALTY_PROC); + picksplit_proc = index_getprocid(index, 1, GIST_PICKSPLIT_PROC); + equal_proc = index_getprocid(index, 1, GIST_EQUAL_PROC); + fmgr_info(consistent_proc, &user_fn, &pronargs); + giststate->consistentFn = user_fn; + fmgr_info(union_proc, &user_fn, &pronargs); + giststate->unionFn = user_fn; + fmgr_info(compress_proc, &user_fn, &pronargs); + giststate->compressFn = user_fn; + fmgr_info(decompress_proc, &user_fn, &pronargs); + giststate->decompressFn = user_fn; + fmgr_info(penalty_proc, &user_fn, &pronargs); + giststate->penaltyFn = user_fn; + fmgr_info(picksplit_proc, &user_fn, &pronargs); + giststate->picksplitFn = user_fn; + fmgr_info(equal_proc, &user_fn, &pronargs); + giststate->equalFn = user_fn; + + /* see if key type is different from type of attribute being indexed */ + htup = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(index->rd_id), + 0, 0, 0); + itupform = (IndexTupleForm) GETSTRUCT(htup); + if (!HeapTupleIsValid(htup)) + elog(WARN, "initGISTstate: index %d not found", index->rd_id); + giststate->haskeytype = itupform->indhaskeytype; + if (giststate->haskeytype) + { + /* key type is different -- is it byval? */ + htup = SearchSysCacheTuple(ATTNUM, + ObjectIdGetDatum(itupform->indexrelid), + UInt16GetDatum(FirstOffsetNumber), + 0, 0); + if (!HeapTupleIsValid(htup)) + { + elog(WARN, "initGISTstate: no attribute tuple %d %d", + itupform->indexrelid, FirstOffsetNumber); + return; + } + giststate->keytypbyval = (((AttributeTupleForm) htup)->attbyval); } - giststate->keytypbyval = (((AttributeTupleForm)htup)->attbyval); - } - else - giststate->keytypbyval = FALSE; - return; + else + giststate->keytypbyval = FALSE; + return; } @@ -1118,56 +1209,61 @@ initGISTstate(GISTSTATE *giststate, Relation index) ** the key with another key, which may involve generating a new IndexTuple ** if the sizes don't match */ -static IndexTuple +static IndexTuple gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t) { - char * datum = (((char *) t) + sizeof(IndexTupleData)); - - /* if new entry fits in index tuple, copy it in */ - if (entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData)) { - memcpy(datum, entry.pred, entry.bytes); - /* clear out old size */ - t->t_info &= 0xe000; - /* or in new size */ - t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData)); - - return(t); - } - else { - /* generate a new index tuple for the compressed entry */ - TupleDesc tupDesc = r->rd_att; - IndexTuple newtup; - char *isnull; - int blank; - - isnull = (char *) palloc(r->rd_rel->relnatts); - for (blank = 0; blank < r->rd_rel->relnatts; blank++) - isnull[blank] = ' '; - newtup = (IndexTuple) index_formtuple(tupDesc, - (Datum *)&(entry.pred), - isnull); - newtup->t_tid = t->t_tid; - pfree(isnull); - return(newtup); - } + char *datum = (((char *) t) + sizeof(IndexTupleData)); + + /* if new entry fits in index tuple, copy it in */ + if (entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData)) + { + memcpy(datum, entry.pred, entry.bytes); + /* clear out old size */ + t->t_info &= 0xe000; + /* or in new size */ + t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData)); + + return (t); + } + else + { + /* generate a new index tuple for the compressed entry */ + TupleDesc tupDesc = r->rd_att; + IndexTuple newtup; + char *isnull; + int blank; + + isnull = (char *) palloc(r->rd_rel->relnatts); + for (blank = 0; blank < r->rd_rel->relnatts; blank++) + isnull[blank] = ' '; + newtup = (IndexTuple) index_formtuple(tupDesc, + (Datum *) & (entry.pred), + isnull); + newtup->t_tid = t->t_tid; + pfree(isnull); + return (newtup); + } } - + /* ** initialize a GiST entry with a decompressed version of pred */ void -gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, - Page pg, OffsetNumber o, int b, bool l) -{ - GISTENTRY *dep; - gistentryinit(*e, pr, r, pg, o, b, l); - if (giststate->haskeytype) { - dep = (GISTENTRY *)((giststate->decompressFn)(e)); - gistentryinit(*e, dep->pred, dep->rel, dep->page, dep->offset, dep->bytes, - dep->leafkey); - if (dep != e) pfree(dep); - } +gistdentryinit(GISTSTATE * giststate, GISTENTRY * e, char *pr, Relation r, + Page pg, OffsetNumber o, int b, bool l) +{ + GISTENTRY *dep; + + gistentryinit(*e, pr, r, pg, o, b, l); + if (giststate->haskeytype) + { + dep = (GISTENTRY *) ((giststate->decompressFn) (e)); + gistentryinit(*e, dep->pred, dep->rel, dep->page, dep->offset, dep->bytes, + dep->leafkey); + if (dep != e) + pfree(dep); + } } @@ -1175,19 +1271,22 @@ gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, ** initialize a GiST entry with a compressed version of pred */ static void -gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, - Page pg, OffsetNumber o, int b, bool l) -{ - GISTENTRY *cep; - gistentryinit(*e, pr, r, pg, o, b, l); - if (giststate->haskeytype) { - cep = (GISTENTRY *)((giststate->compressFn)(e)); - gistentryinit(*e, cep->pred, cep->rel, cep->page, cep->offset, cep->bytes, - cep->leafkey); - if (cep != e) pfree(cep); - } +gistcentryinit(GISTSTATE * giststate, GISTENTRY * e, char *pr, Relation r, + Page pg, OffsetNumber o, int b, bool l) +{ + GISTENTRY *cep; + + gistentryinit(*e, pr, r, pg, o, b, l); + if (giststate->haskeytype) + { + cep = (GISTENTRY *) ((giststate->compressFn) (e)); + gistentryinit(*e, cep->pred, cep->rel, cep->page, cep->offset, cep->bytes, + cep->leafkey); + if (cep != e) + pfree(cep); + } } - + #ifdef GISTDEBUG @@ -1200,89 +1299,95 @@ gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, void _gistdump(Relation r) { - Buffer buf; - Page page; - OffsetNumber offnum, maxoff; - BlockNumber blkno; - BlockNumber nblocks; - GISTPageOpaque po; - IndexTuple itup; - BlockNumber itblkno; - OffsetNumber itoffno; - char *datum; - char *itkey; - - nblocks = RelationGetNumberOfBlocks(r); - for (blkno = 0; blkno < nblocks; blkno++) { - buf = ReadBuffer(r, blkno); - page = BufferGetPage(buf); - po = (GISTPageOpaque) PageGetSpecialPointer(page); - maxoff = PageGetMaxOffsetNumber(page); - printf("Page %d maxoff %d <%s>\n", blkno, maxoff, - (po->flags & F_LEAF ? "LEAF" : "INTERNAL")); - - if (PageIsEmpty(page)) { - ReleaseBuffer(buf); - continue; - } - - for (offnum = FirstOffsetNumber; - offnum <= maxoff; - offnum = OffsetNumberNext(offnum)) { - itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); - itblkno = ItemPointerGetBlockNumber(&(itup->t_tid)); - itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid)); - datum = ((char *) itup); - datum += sizeof(IndexTupleData); - /* get out function for type of key, and out it! */ - itkey = (char *) int_range_out((INTRANGE *)datum); - /* itkey = " unable to print"; */ - printf("\t[%d] size %d heap <%d,%d> key:%s\n", - offnum, IndexTupleSize(itup), itblkno, itoffno, itkey); - pfree(itkey); + Buffer buf; + Page page; + OffsetNumber offnum, + maxoff; + BlockNumber blkno; + BlockNumber nblocks; + GISTPageOpaque po; + IndexTuple itup; + BlockNumber itblkno; + OffsetNumber itoffno; + char *datum; + char *itkey; + + nblocks = RelationGetNumberOfBlocks(r); + for (blkno = 0; blkno < nblocks; blkno++) + { + buf = ReadBuffer(r, blkno); + page = BufferGetPage(buf); + po = (GISTPageOpaque) PageGetSpecialPointer(page); + maxoff = PageGetMaxOffsetNumber(page); + printf("Page %d maxoff %d <%s>\n", blkno, maxoff, + (po->flags & F_LEAF ? "LEAF" : "INTERNAL")); + + if (PageIsEmpty(page)) + { + ReleaseBuffer(buf); + continue; + } + + for (offnum = FirstOffsetNumber; + offnum <= maxoff; + offnum = OffsetNumberNext(offnum)) + { + itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); + itblkno = ItemPointerGetBlockNumber(&(itup->t_tid)); + itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid)); + datum = ((char *) itup); + datum += sizeof(IndexTupleData); + /* get out function for type of key, and out it! */ + itkey = (char *) int_range_out((INTRANGE *) datum); + /* itkey = " unable to print"; */ + printf("\t[%d] size %d heap <%d,%d> key:%s\n", + offnum, IndexTupleSize(itup), itblkno, itoffno, itkey); + pfree(itkey); + } + + ReleaseBuffer(buf); } - - ReleaseBuffer(buf); - } } #ifdef NOT_USED -static char *text_range_out(TXTRANGE *r) +static char * +text_range_out(TXTRANGE * r) { - char *result; - char *lower, *upper; - - if (r == NULL) - return(NULL); - result = (char *)palloc(16 + VARSIZE(TRLOWER(r)) + VARSIZE(TRUPPER(r)) - - 2*VARHDRSZ); - - lower = (char *)palloc(VARSIZE(TRLOWER(r)) + 1 - VARHDRSZ); - memcpy(lower, VARDATA(TRLOWER(r)), VARSIZE(TRLOWER(r)) - VARHDRSZ); - lower[VARSIZE(TRLOWER(r)) - VARHDRSZ] = '\0'; - upper = (char *)palloc(VARSIZE(TRUPPER(r)) + 1 - VARHDRSZ); - memcpy(upper, VARDATA(TRUPPER(r)), VARSIZE(TRUPPER(r)) - VARHDRSZ); - upper[VARSIZE(TRUPPER(r)) - VARHDRSZ] = '\0'; - - sprintf(result, "[%s,%s): %d", lower, upper, r->flag); - pfree(lower); - pfree(upper); - return(result); + char *result; + char *lower, + *upper; + + if (r == NULL) + return (NULL); + result = (char *) palloc(16 + VARSIZE(TRLOWER(r)) + VARSIZE(TRUPPER(r)) + - 2 * VARHDRSZ); + + lower = (char *) palloc(VARSIZE(TRLOWER(r)) + 1 - VARHDRSZ); + memcpy(lower, VARDATA(TRLOWER(r)), VARSIZE(TRLOWER(r)) - VARHDRSZ); + lower[VARSIZE(TRLOWER(r)) - VARHDRSZ] = '\0'; + upper = (char *) palloc(VARSIZE(TRUPPER(r)) + 1 - VARHDRSZ); + memcpy(upper, VARDATA(TRUPPER(r)), VARSIZE(TRUPPER(r)) - VARHDRSZ); + upper[VARSIZE(TRUPPER(r)) - VARHDRSZ] = '\0'; + + sprintf(result, "[%s,%s): %d", lower, upper, r->flag); + pfree(lower); + pfree(upper); + return (result); } + #endif -static char * -int_range_out(INTRANGE *r) +static char * +int_range_out(INTRANGE * r) { - char *result; - - if (r == NULL) - return(NULL); - result = (char *)palloc(80); - sprintf(result, "[%d,%d): %d",r->lower, r->upper, r->flag); - - return(result); -} + char *result; + + if (r == NULL) + return (NULL); + result = (char *) palloc(80); + sprintf(result, "[%d,%d): %d", r->lower, r->upper, r->flag); -#endif /* defined GISTDEBUG */ + return (result); +} +#endif /* defined GISTDEBUG */ |