Commit 0ad7db4b authored by Marc G. Fournier's avatar Marc G. Fournier

New feature:
   1. Support of variable size keys - new algorithm of insertion to tree
      (GLI - gist layrered insertion). Previous algorithm was implemented
      as described in paper by Joseph M. Hellerstein et.al
      "Generalized Search Trees for Database Systems".  This (old)
      algorithm was not suitable for variable size keys and could be
      not effective ( walking up-down ) in case of multiple levels split
Bug fixed:
   1. fixed bug in gistPageAddItem - key values were written to disk
      uncompressed. This caused failure if decompression function
      does real job.
   2. NULLs handling - we keep NULLs in tree. Right way is to remove them,
      but we don't know how to inform vacuum about index statistics. This is
      just cosmetic warning message (like in case with R-Tree),
      but I'm not sure how to recognize real problem if we remove NULLs
      and suppress this warning as Tom suggested.
   3. various memory leaks

This work was done by Teodor Sigaev (teodor@stack.net) and
Oleg Bartunov (oleg@sai.msu.su).
parent 7cd97118
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.67 2000/11/30 08:46:20 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.68 2001/01/12 00:12:58 scrappy Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -25,37 +25,61 @@ ...@@ -25,37 +25,61 @@
#include "access/xlogutils.h" #include "access/xlogutils.h"
/* result's status */
#define INSERTED 0x01
#define SPLITED 0x02
/* non-export function prototypes */ /* non-export function prototypes */
static InsertIndexResult gistdoinsert(Relation r, IndexTuple itup, static void gistdoinsert(Relation r,
IndexTuple itup,
InsertIndexResult *res,
GISTSTATE *GISTstate); GISTSTATE *GISTstate);
static InsertIndexResult gistentryinsert(Relation r, GISTSTACK *stk, static int gistlayerinsert( Relation r, BlockNumber blkno,
IndexTuple tup, IndexTuple **itup,
GISTSTATE *giststate); int *len,
static void gistentryinserttwo(Relation r, GISTSTACK *stk, IndexTuple ltup, InsertIndexResult *res,
IndexTuple rtup, GISTSTATE *giststate); GISTSTATE *giststate );
static void gistAdjustKeys(Relation r, GISTSTACK *stk, BlockNumber blk, static OffsetNumber gistwritebuffer( Relation r,
char *datum, int att_size, GISTSTATE *giststate); Page page,
static void gistintinsert(Relation r, GISTSTACK *stk, IndexTuple ltup, IndexTuple *itup,
IndexTuple rtup, GISTSTATE *giststate); int len,
static InsertIndexResult gistSplit(Relation r, Buffer buffer, OffsetNumber off,
GISTSTACK *stack, IndexTuple itup, GISTSTATE *giststate );
GISTSTATE *giststate); static int gistnospace( Page page,
static void gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt, IndexTuple *itvec, int len );
IndexTuple rt); static IndexTuple * gistreadbuffer( Relation r,
static void GISTInitBuffer(Buffer b, uint32 f); Buffer buffer, int *len );
static BlockNumber gistChooseSubtree(Relation r, IndexTuple itup, int level, static IndexTuple * gistjoinvector(
IndexTuple *itvec, int *len,
IndexTuple *additvec, int addlen );
static IndexTuple gistunion( Relation r, IndexTuple *itvec,
int len, GISTSTATE *giststate );
static IndexTuple gistgetadjusted( Relation r,
IndexTuple oldtup,
IndexTuple addtup,
GISTSTATE *giststate );
static IndexTuple * gistSplit(Relation r,
Buffer buffer,
IndexTuple *itup,
int *len,
GISTSTATE *giststate, GISTSTATE *giststate,
GISTSTACK **retstack, Buffer *leafbuf); InsertIndexResult *res);
static OffsetNumber gistchoose(Relation r, Page p, IndexTuple it, static void gistnewroot(GISTSTATE *giststate, Relation r,
IndexTuple *itup, int len);
static void GISTInitBuffer(Buffer b, uint32 f);
static OffsetNumber gistchoose(Relation r, Page p,
IndexTuple it,
GISTSTATE *giststate); GISTSTATE *giststate);
static int gistnospace(Page p, IndexTuple it); static IndexTuple gist_tuple_replacekey(Relation r,
static IndexTuple gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t); GISTENTRY entry, IndexTuple t);
static void gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, static void gistcentryinit(GISTSTATE *giststate,
Relation r, Page pg, OffsetNumber o, int b, bool l); GISTENTRY *e, char *pr,
Relation r, Page pg,
OffsetNumber o, int b, bool l);
#undef GISTDEBUG
#ifdef GISTDEBUG #ifdef GISTDEBUG
static char *int_range_out(INTRANGE *r); static void gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff);
#endif #endif
/* /*
...@@ -86,7 +110,6 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -86,7 +110,6 @@ gistbuild(PG_FUNCTION_ARGS)
TupleTableSlot *slot; TupleTableSlot *slot;
#endif #endif
ExprContext *econtext; ExprContext *econtext;
InsertIndexResult res = NULL;
GISTSTATE giststate; GISTSTATE giststate;
GISTENTRY tmpcentry; GISTENTRY tmpcentry;
Buffer buffer = InvalidBuffer; Buffer buffer = InvalidBuffer;
...@@ -223,14 +246,13 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -223,14 +246,13 @@ gistbuild(PG_FUNCTION_ARGS)
* not when you're initializing the whole index at once. * not when you're initializing the whole index at once.
*/ */
res = gistdoinsert(index, itup, &giststate); gistdoinsert(index, itup, NULL, &giststate);
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
if (compvec[i]) if (compvec[i])
pfree(DatumGetPointer(attdata[i])); pfree(DatumGetPointer(attdata[i]));
pfree(itup); pfree(itup);
pfree(res);
} }
/* okay, all heap tuples are indexed */ /* okay, all heap tuples are indexed */
...@@ -274,6 +296,10 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -274,6 +296,10 @@ gistbuild(PG_FUNCTION_ARGS)
} }
} }
#ifdef GISTDEBUG
gist_dumptree(index, 0, GISTP_ROOT, 0);
#endif
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
...@@ -324,7 +350,8 @@ gistinsert(PG_FUNCTION_ARGS) ...@@ -324,7 +350,8 @@ gistinsert(PG_FUNCTION_ARGS)
* RelationSetLockForWrite(r); * RelationSetLockForWrite(r);
*/ */
res = gistdoinsert(r, itup, &giststate); res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
gistdoinsert(r, itup, &res, &giststate);
for (i = 0; i < r->rd_att->natts; i++) for (i = 0; i < r->rd_att->natts; i++)
if (compvec[i] == TRUE) if (compvec[i] == TRUE)
pfree((char *) datum[i]); pfree((char *) datum[i]);
...@@ -353,6 +380,7 @@ gistPageAddItem(GISTSTATE *giststate, ...@@ -353,6 +380,7 @@ gistPageAddItem(GISTSTATE *giststate,
{ {
GISTENTRY tmpcentry; GISTENTRY tmpcentry;
IndexTuple itup = (IndexTuple) item; IndexTuple itup = (IndexTuple) item;
OffsetNumber retval;
/* /*
* recompress the item given that we now know the exact page and * recompress the item given that we now know the exact page and
...@@ -364,295 +392,353 @@ gistPageAddItem(GISTSTATE *giststate, ...@@ -364,295 +392,353 @@ gistPageAddItem(GISTSTATE *giststate,
IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE); IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE);
gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page, gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page,
offsetNumber, dentry->bytes, FALSE); offsetNumber, dentry->bytes, FALSE);
*newtup = gist_tuple_replacekey(r, *dentry, itup); *newtup = gist_tuple_replacekey(r, tmpcentry, itup);
retval = PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup),
offsetNumber, flags);
/* be tidy */ /* be tidy */
if (tmpcentry.pred != dentry->pred if (tmpcentry.pred && tmpcentry.pred != dentry->pred
&& tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData))) && tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
pfree(tmpcentry.pred); pfree(tmpcentry.pred);
return (retval);
return (PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup),
offsetNumber, flags));
} }
static void
gistdoinsert( Relation r,
IndexTuple itup,
InsertIndexResult *res,
GISTSTATE *giststate ) {
IndexTuple *instup;
int i,ret,len = 1;
instup = ( IndexTuple* ) palloc( sizeof(IndexTuple) );
instup[0] = ( IndexTuple ) palloc( IndexTupleSize( itup ) );
memcpy( instup[0], itup, IndexTupleSize( itup ) );
ret = gistlayerinsert(r, GISTP_ROOT, &instup, &len, res, giststate);
if ( ret & SPLITED )
gistnewroot( giststate, r, instup, len );
for(i=0;i<len;i++)
pfree( instup[i] );
pfree( instup );
}
static InsertIndexResult static int
gistdoinsert(Relation r, gistlayerinsert( Relation r, BlockNumber blkno,
IndexTuple itup, /* itup contains compressed entry */ IndexTuple **itup, /* in - out, has compressed entry */
GISTSTATE *giststate) int *len , /* in - out */
{ InsertIndexResult *res, /* out */
GISTENTRY tmpdentry; GISTSTATE *giststate ) {
InsertIndexResult res;
OffsetNumber l;
GISTSTACK *stack;
Buffer buffer; Buffer buffer;
BlockNumber blk;
Page page; Page page;
OffsetNumber off; OffsetNumber child;
IndexTuple newtup; int ret;
GISTPageOpaque opaque;
/* 3rd arg is ignored for now */ buffer = ReadBuffer(r, blkno);
blk = gistChooseSubtree(r, itup, 0, giststate, &stack, &buffer);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
if (gistnospace(page, itup)) if (!(opaque->flags & F_LEAF)) {
{ /* internal page, so we must walk on tree */
/* need to do a split */ /* len IS equial 1 */
res = gistSplit(r, buffer, stack, itup, giststate); ItemId iid;
gistfreestack(stack); BlockNumber nblkno;
WriteBuffer(buffer); /* don't forget to release buffer! */ ItemPointerData oldtid;
return res; IndexTuple oldtup;
child = gistchoose( r, page, *(*itup), giststate );
iid = PageGetItemId(page, child);
oldtup = (IndexTuple) PageGetItem(page, iid);
nblkno = ItemPointerGetBlockNumber(&(oldtup->t_tid));
/*
* After this call:
* 1. if child page was splited, then itup contains
* keys for each page
* 2. if child page wasn't splited, then itup contains
* additional for adjustement of current key
*/
ret = gistlayerinsert( r, nblkno, itup, len, res, giststate );
/* nothing inserted in child */
if ( ! (ret & INSERTED) ) {
ReleaseBuffer(buffer);
return 0x00;
} }
if (PageIsEmpty(page)) /* child does not splited */
off = FirstOffsetNumber; if ( ! (ret & SPLITED) ) {
else IndexTuple newtup = gistgetadjusted( r, oldtup, (*itup)[0], giststate );
off = OffsetNumberNext(PageGetMaxOffsetNumber(page)); if ( ! newtup ) {
/* not need to update key */
ReleaseBuffer(buffer);
return 0x00;
}
/* add the item and write the buffer */ pfree( (*itup)[0] ); /* !!! */
l = gistPageAddItem(giststate, r, page, (Item) itup, IndexTupleSize(itup), (*itup)[0] = newtup;
off, LP_USED, &tmpdentry, &newtup); }
/* key is modified, so old version must be deleted */
ItemPointerSet(&oldtid, blkno, child);
DirectFunctionCall2(gistdelete,
PointerGetDatum(r),
PointerGetDatum(&oldtid));
}
ret = INSERTED;
if ( gistnospace(page, (*itup), *len) ) {
/* no space for insertion */
IndexTuple *itvec;
int tlen;
ret |= SPLITED;
itvec = gistreadbuffer( r, buffer, &tlen );
itvec = gistjoinvector( itvec, &tlen, (*itup), *len );
pfree( (*itup) );
(*itup) = gistSplit( r, buffer, itvec, &tlen, giststate,
(opaque->flags & F_LEAF) ? res : NULL ); /*res only for inserting in leaf*/
ReleaseBuffer( buffer );
pfree( itvec );
*len = tlen; /* now tlen >= 2 */
} else {
/* enogth space */
OffsetNumber off, l;
off = ( PageIsEmpty(page) ) ?
FirstOffsetNumber
:
OffsetNumberNext(PageGetMaxOffsetNumber(page));
l = gistwritebuffer( r, page, (*itup), *len, off, giststate );
WriteBuffer(buffer); WriteBuffer(buffer);
/* now expand the page boundary in the parent to include the new child */ /* set res if insert into leaf page, in
gistAdjustKeys(r, stack, blk, tmpdentry.pred, tmpdentry.bytes, giststate); this case, len = 1 always */
gistfreestack(stack); if ( res && (opaque->flags & F_LEAF) )
ItemPointerSet(&((*res)->pointerData), blkno, l);
/* be tidy */ if ( *len > 1 ) { /* previos insert ret & SPLITED != 0 */
if (itup != newtup) int i;
pfree(newtup); /* child was splited, so we must form union
if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData))) * for insertion in parent */
pfree(tmpdentry.pred); IndexTuple newtup = gistunion(r, (*itup), *len, giststate);
for(i=0; i<*len; i++)
pfree( (*itup)[i] );
(*itup)[0] = newtup;
*len = 1;
}
}
/* build and return an InsertIndexResult for this insertion */ return ret;
res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); }
ItemPointerSet(&(res->pointerData), blk, l);
return res; /*
* Write itup vector to page, has no control of free space
*/
static OffsetNumber
gistwritebuffer( Relation r, Page page, IndexTuple *itup,
int len, OffsetNumber off, GISTSTATE *giststate) {
OffsetNumber l = InvalidOffsetNumber;
int i;
GISTENTRY tmpdentry;
IndexTuple newtup;
for(i=0; i<len; i++) {
l = gistPageAddItem(giststate, r, page,
(Item) itup[i], IndexTupleSize(itup[i]),
off, LP_USED, &tmpdentry, &newtup);
off = OffsetNumberNext( off );
if (tmpdentry.pred != (((char *) itup[i]) + sizeof(IndexTupleData)) && tmpdentry.pred)
pfree(tmpdentry.pred);
if (itup[i] != newtup)
pfree(newtup);
}
return l;
} }
/*
* Check space for itup vector on page
*/
static int
gistnospace( Page page, IndexTuple *itvec, int len ) {
int size = 0;
int i;
for(i=0; i<len; i++)
size += IndexTupleSize( itvec[i] )+4; /* ??? */
static BlockNumber return (PageGetFreeSpace(page) < size);
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; * Read buffer into itup vector
stack = (GISTSTACK *) NULL; */
static IndexTuple *
gistreadbuffer( Relation r, Buffer buffer, int *len /*out*/) {
OffsetNumber i, maxoff;
IndexTuple *itvec;
Page p = (Page) BufferGetPage(buffer);
do *len=0;
{ maxoff = PageGetMaxOffsetNumber(p);
/* let go of current buffer before getting next */ itvec = palloc( sizeof(IndexTuple) * maxoff );
if (buffer != InvalidBuffer) for(i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
ReleaseBuffer(buffer); itvec[ (*len)++ ] = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
/* get next buffer */ return itvec;
buffer = ReadBuffer(r, blk); }
page = (Page) BufferGetPage(buffer);
opaque = (GISTPageOpaque) PageGetSpecialPointer(page); /*
if (!(opaque->flags & F_LEAF)) * join two vectors into one
{ */
GISTSTACK *n; static IndexTuple *
ItemId iid; gistjoinvector( IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen ) {
itvec = (IndexTuple*) repalloc( (void*)itvec, sizeof(IndexTuple) * ( (*len) + addlen ) );
memmove( &itvec[*len], additvec, sizeof(IndexTuple) * addlen );
*len += addlen;
return itvec;
}
n = (GISTSTACK *) palloc(sizeof(GISTSTACK)); /*
n->gs_parent = stack; * return union of itup vector
n->gs_blk = blk; */
n->gs_child = gistchoose(r, page, itup, giststate); static IndexTuple
stack = n; gistunion( Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate ) {
bytea *evec;
char *datum;
int datumsize, i;
GISTENTRY centry;
char isnull;
IndexTuple newtup;
iid = PageGetItemId(page, n->gs_child); evec = (bytea *) palloc(len * sizeof(GISTENTRY) + VARHDRSZ);
which = (IndexTuple) PageGetItem(page, iid); VARATT_SIZEP(evec) = len * sizeof(GISTENTRY) + VARHDRSZ;
blk = ItemPointerGetBlockNumber(&(which->t_tid));
}
} while (!(opaque->flags & F_LEAF));
*retstack = stack; for ( i = 0 ; i< len ; i++ )
*leafbuf = buffer; gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[i],
(char*) itvec[i] + sizeof(IndexTupleData),
(Relation)NULL, (Page)NULL, (OffsetNumber)NULL,
IndexTupleSize((IndexTuple)itvec[i]) - sizeof(IndexTupleData), FALSE);
return blk; datum = (char *)
} DatumGetPointer(FunctionCall2(&giststate->unionFn,
PointerGetDatum(evec),
PointerGetDatum(&datumsize)));
for ( i = 0 ; i< len ; i++ )
if ( ((GISTENTRY *) VARDATA(evec))[i].pred &&
((GISTENTRY *) VARDATA(evec))[i].pred !=
((char*)( itvec[i] )+ sizeof(IndexTupleData)) )
pfree( ((GISTENTRY *) VARDATA(evec))[i].pred );
static void pfree( evec );
gistAdjustKeys(Relation r,
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) gistcentryinit(giststate, &centry, datum,
return; (Relation)NULL, (Page)NULL, (OffsetNumber)NULL,
datumsize, FALSE);
b = ReadBuffer(r, stk->gs_blk); isnull = (centry.pred) ? ' ' : 'n';
p = BufferGetPage(b); newtup = (IndexTuple) index_formtuple( r->rd_att, (Datum *) &centry.pred, &isnull );
if (centry.pred != datum)
pfree( datum );
oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->gs_child)); return newtup;
tid = (IndexTuple) oldud; }
size = IndexTupleSize((IndexTuple) oldud) - sizeof(IndexTupleData);
oldud += sizeof(IndexTupleData); /*
* Forms union of oldtup and addtup, if union == oldtup then return NULL
*/
static IndexTuple
gistgetadjusted( Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate ) {
bytea *evec;
char *datum;
int datumsize;
bool result;
char isnull;
GISTENTRY centry, *ev0p, *ev1p;
IndexTuple newtup = NULL;
evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ); evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ);
VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ; VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
/* insert decompressed oldud into entry vector */
gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[0], gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[0],
oldud, r, p, stk->gs_child, (char*) oldtup + sizeof(IndexTupleData), (Relation) NULL,
size, FALSE); (Page) NULL, (OffsetNumber) 0,
IndexTupleSize((IndexTuple)oldtup) - sizeof(IndexTupleData), FALSE);
ev0p = &((GISTENTRY *) VARDATA(evec))[0]; ev0p = &((GISTENTRY *) VARDATA(evec))[0];
/* insert datum entry into entry vector */ gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[1],
gistentryinit(((GISTENTRY *) VARDATA(evec))[1], datum, (char*) addtup + sizeof(IndexTupleData), (Relation) NULL,
(Relation) NULL, (Page) NULL, (OffsetNumber) 0, att_size, FALSE); (Page) NULL, (OffsetNumber) 0,
IndexTupleSize((IndexTuple)addtup) - sizeof(IndexTupleData), FALSE);
ev1p = &((GISTENTRY *) VARDATA(evec))[1]; ev1p = &((GISTENTRY *) VARDATA(evec))[1];
/* form union of decompressed entries */
datum = (char *) datum = (char *)
DatumGetPointer(FunctionCall2(&giststate->unionFn, DatumGetPointer(FunctionCall2(&giststate->unionFn,
PointerGetDatum(evec), PointerGetDatum(evec),
PointerGetDatum(&datumsize))); PointerGetDatum(&datumsize)));
/* did union leave decompressed version of oldud unchanged? */ if ( ! ( ev0p->pred && ev1p->pred ) ) {
result = ( ev0p->pred == NULL && ev1p->pred == NULL );
} else {
FunctionCall3(&giststate->equalFn, FunctionCall3(&giststate->equalFn,
PointerGetDatum(ev0p->pred), PointerGetDatum(ev0p->pred),
PointerGetDatum(datum), PointerGetDatum(datum),
PointerGetDatum(&result)); PointerGetDatum(&result));
if (!result) }
{
TupleDesc td = RelationGetDescr(r);
/* compress datum for storage on page */ if ( result ) {
/* not need to update key */
pfree( datum );
} else {
gistcentryinit(giststate, &centry, datum, ev0p->rel, ev0p->page, gistcentryinit(giststate, &centry, datum, ev0p->rel, ev0p->page,
ev0p->offset, datumsize, FALSE); 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);
DirectFunctionCall2(gistdelete,
PointerGetDatum(r),
PointerGetDatum(&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);
isnull = (centry.pred) ? ' ' : 'n';
newtup = (IndexTuple) index_formtuple( r->rd_att, (Datum *) &centry.pred, &isnull );
newtup->t_tid = oldtup->t_tid;
if (centry.pred != datum) if (centry.pred != datum)
pfree(datum); pfree( datum );
} }
else
ReleaseBuffer(b); if ( ev0p->pred &&
pfree(evec); ev0p->pred != (char*) oldtup + sizeof(IndexTupleData) )
pfree( ev0p->pred );
if ( ev1p->pred &&
ev1p->pred != (char*) addtup + sizeof(IndexTupleData) )
pfree( ev1p->pred );
pfree( evec );
return newtup;
} }
/* /*
* gistSplit -- split a page in the tree. * gistSplit -- split a page in the tree.
*
*/ */
static InsertIndexResult static IndexTuple *
gistSplit(Relation r, gistSplit(Relation r,
Buffer buffer, Buffer buffer,
GISTSTACK *stack, IndexTuple *itup, /* contains compressed entry */
IndexTuple itup, /* contains compressed entry */ int *len,
GISTSTATE *giststate) GISTSTATE *giststate,
InsertIndexResult *res)
{ {
Page p; Page p;
Buffer leftbuf, Buffer leftbuf, rightbuf;
rightbuf; Page left, right;
Page left, OffsetNumber *spl_left, *spl_right;
right; IndexTuple *lvectup, *rvectup, *newtup;
ItemId itemid; int leftoff, rightoff;
IndexTuple item; BlockNumber lbknum, rbknum;
IndexTuple ltup,
rtup,
newtup;
OffsetNumber maxoff;
OffsetNumber i;
OffsetNumber leftoff,
rightoff;
BlockNumber lbknum,
rbknum;
BlockNumber bufblock;
GISTPageOpaque opaque; GISTPageOpaque opaque;
int blank; char isnull;
InsertIndexResult res;
char *isnull;
GIST_SPLITVEC v; GIST_SPLITVEC v;
TupleDesc tupDesc;
bytea *entryvec; bytea *entryvec;
bool *decompvec; bool *decompvec;
IndexTuple item_1; GISTENTRY tmpentry;
GISTENTRY tmpdentry, int i, nlen;
tmpentry;
isnull = (char *) palloc(r->rd_rel->relnatts);
for (blank = 0; blank < r->rd_rel->relnatts; blank++)
isnull[blank] = ' ';
p = (Page) BufferGetPage(buffer); p = (Page) BufferGetPage(buffer);
opaque = (GISTPageOpaque) PageGetSpecialPointer(p); opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
...@@ -684,313 +770,138 @@ gistSplit(Relation r, ...@@ -684,313 +770,138 @@ gistSplit(Relation r,
right = (Page) BufferGetPage(rightbuf); right = (Page) BufferGetPage(rightbuf);
/* generate the item array */ /* generate the item array */
maxoff = PageGetMaxOffsetNumber(p); entryvec = (bytea *) palloc(VARHDRSZ + (*len+1) * sizeof(GISTENTRY));
entryvec = (bytea *) palloc(VARHDRSZ + (maxoff + 2) * sizeof(GISTENTRY)); decompvec = (bool *) palloc(VARHDRSZ + (*len+1) * sizeof(bool));
decompvec = (bool *) palloc(VARHDRSZ + (maxoff + 2) * sizeof(bool)); VARATT_SIZEP(entryvec) = (*len+1) * sizeof(GISTENTRY) + VARHDRSZ;
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) for (i = 1; i <= *len; i++)
{ {
item_1 = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
gistdentryinit(giststate, &((GISTENTRY *) VARDATA(entryvec))[i], gistdentryinit(giststate, &((GISTENTRY *) VARDATA(entryvec))[i],
(((char *) item_1) + sizeof(IndexTupleData)), (((char *) itup[i-1]) + sizeof(IndexTupleData)),
r, p, i, r, p, i,
IndexTupleSize(item_1) - sizeof(IndexTupleData), FALSE); IndexTupleSize(itup[i-1]) - sizeof(IndexTupleData), FALSE);
if ((char *) (((GISTENTRY *) VARDATA(entryvec))[i].pred) if ((char *) (((GISTENTRY *) VARDATA(entryvec))[i].pred)
== (((char *) item_1) + sizeof(IndexTupleData))) == (((char *) itup[i-1]) + sizeof(IndexTupleData)))
decompvec[i] = FALSE; decompvec[i] = FALSE;
else else
decompvec[i] = TRUE; 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;
VARATT_SIZEP(entryvec) = (maxoff + 2) * sizeof(GISTENTRY) + VARHDRSZ;
/* now let the user-defined picksplit function set up the split vector */ /* now let the user-defined picksplit function set up the split vector */
FunctionCall2(&giststate->picksplitFn, FunctionCall2(&giststate->picksplitFn,
PointerGetDatum(entryvec), PointerGetDatum(entryvec),
PointerGetDatum(&v)); PointerGetDatum(&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 */ /* clean up the entry vector: its preds need to be deleted, too */
for (i = FirstOffsetNumber; i <= maxoff + 1; i = OffsetNumberNext(i)) for (i = 1; i <= *len; i++)
if (decompvec[i]) if (decompvec[i] && ((GISTENTRY *) VARDATA(entryvec))[i].pred)
pfree(((GISTENTRY *) VARDATA(entryvec))[i].pred); pfree(((GISTENTRY *) VARDATA(entryvec))[i].pred);
pfree(entryvec); pfree(entryvec);
pfree(decompvec); pfree(decompvec);
leftoff = rightoff = FirstOffsetNumber; spl_left = v.spl_left; spl_right = v.spl_right;
maxoff = PageGetMaxOffsetNumber(p);
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) /* form left and right vector */
{ lvectup = (IndexTuple*) palloc( sizeof( IndexTuple )*v.spl_nleft );
itemid = PageGetItemId(p, i); rvectup = (IndexTuple*) palloc( sizeof( IndexTuple )*v.spl_nright );
item = (IndexTuple) PageGetItem(p, itemid); leftoff = rightoff = 0;
for( i=1; i <= *len; i++ ) {
if (i == *(v.spl_left)) if (i == *(spl_left) || ( i==*len && *(spl_left) != FirstOffsetNumber ) ) {
{ lvectup[ leftoff++ ] = itup[ i-1 ];
gistPageAddItem(giststate, r, left, (Item) item, spl_left++;
IndexTupleSize(item), } else {
leftoff, LP_USED, &tmpdentry, &newtup); rvectup[ rightoff++ ] = itup[ i-1 ];
leftoff = OffsetNumberNext(leftoff); spl_right++;
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 */ /* write on disk (may be need another split) */
res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData)); if ( gistnospace(right, rvectup, v.spl_nright) ) {
nlen = v.spl_nright;
/* now insert the new index tuple */ newtup = gistSplit(r, rightbuf, rvectup, &nlen, giststate,
if (*(v.spl_left) != FirstOffsetNumber) ( res && rvectup[ nlen-1 ] == itup[ *len - 1 ] ) ? res : NULL );
{ ReleaseBuffer( rightbuf );
gistPageAddItem(giststate, r, left, (Item) itup, } else {
IndexTupleSize(itup), OffsetNumber l;
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) l = gistwritebuffer( r, right, rvectup, v.spl_nright, FirstOffsetNumber, giststate );
PageRestoreTempPage(left, p);
WriteBuffer(leftbuf);
WriteBuffer(rightbuf); WriteBuffer(rightbuf);
/* if ( res )
* Okay, the page is split. We have three things left to do: ItemPointerSet(&((*res)->pointerData), rbknum, l);
* gistcentryinit(giststate, &tmpentry, v.spl_rdatum, (Relation) NULL,
* 1) Adjust any active scans on this index to cope with changes we (Page) NULL, (OffsetNumber) 0,
* introduced in its structure by splitting this page. -1, FALSE);
* if (v.spl_rdatum != tmpentry.pred)
* 2) "Tighten" the bounding box of the pointer to the left page in the pfree(v.spl_rdatum);
* parent node in the tree, if any. Since we moved a bunch of stuff v.spl_rdatum = tmpentry.pred;
* 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); nlen = 1;
pfree(rtup); newtup = (IndexTuple*) palloc( sizeof(IndexTuple) * 1);
isnull = ( v.spl_rdatum ) ? ' ' : 'n';
newtup[0] = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &(v.spl_rdatum), &isnull);
ItemPointerSet(&(newtup[0]->t_tid), rbknum, 1);
}
return res; if ( gistnospace(left, lvectup, v.spl_nleft) ) {
} int llen = v.spl_nleft;
IndexTuple *lntup;
/* lntup = gistSplit(r, leftbuf, lvectup, &llen, giststate,
** After a split, we need to overwrite the old entry's key in the parent, ( res && lvectup[ llen-1 ] == itup[ *len - 1 ] ) ? res : NULL );
** and install install an entry for the new key into the parent. ReleaseBuffer( leftbuf );
*/
static void
gistintinsert(Relation r,
GISTSTACK *stk,
IndexTuple ltup, /* new version of entry for old page */
IndexTuple rtup, /* entry for new page */
GISTSTATE *giststate)
{
ItemPointerData ltid;
if (stk == (GISTSTACK *) NULL) newtup = gistjoinvector( newtup, &nlen, lntup, llen );
{ pfree( lntup );
gistnewroot(giststate, r, ltup, rtup); } else {
return; OffsetNumber l;
}
/* remove old left pointer, insert the 2 new entries */
ItemPointerSet(&ltid, stk->gs_blk, stk->gs_child);
DirectFunctionCall2(gistdelete,
PointerGetDatum(r),
PointerGetDatum(&ltid));
gistentryinserttwo(r, stk, ltup, rtup, giststate);
}
l = gistwritebuffer( r, left, lvectup, v.spl_nleft, FirstOffsetNumber, giststate );
if ( BufferGetBlockNumber(buffer) != GISTP_ROOT)
PageRestoreTempPage(left, p);
/* WriteBuffer(leftbuf);
** 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)
{
Buffer b;
Page p;
InsertIndexResult res;
GISTENTRY tmpentry;
IndexTuple newtup;
b = ReadBuffer(r, stk->gs_blk); if ( res )
p = BufferGetPage(b); ItemPointerSet(&((*res)->pointerData), lbknum, l);
gistcentryinit(giststate, &tmpentry, v.spl_ldatum, (Relation) NULL,
(Page) NULL, (OffsetNumber) 0,
-1, FALSE);
if (v.spl_ldatum != tmpentry.pred)
pfree(v.spl_ldatum);
v.spl_ldatum = tmpentry.pred;
if (gistnospace(p, ltup)) nlen += 1;
{ newtup = (IndexTuple*) repalloc( (void*)newtup, sizeof(IndexTuple) * nlen);
res = gistSplit(r, b, stk->gs_parent, ltup, giststate); isnull = ( v.spl_ldatum ) ? ' ' : 'n';
WriteBuffer(b); /* don't forget to release buffer! - newtup[nlen-1] = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &(v.spl_ldatum), &isnull);
* 01/31/94 */ ItemPointerSet(&(newtup[nlen-1]->t_tid), lbknum, 1);
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);
} }
}
/* /* adjust active scans */
** Insert an entry onto a page gistadjscans(r, GISTOP_SPLIT, BufferGetBlockNumber(buffer), FirstOffsetNumber);
*/
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); /* !!! pfree */
p = BufferGetPage(b); pfree( rvectup );
pfree( lvectup );
pfree( v.spl_left );
pfree( v.spl_right );
if (gistnospace(p, tup)) *len = nlen;
{ return newtup;
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 static void
gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt, IndexTuple rt) gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple *itup, int len)
{ {
Buffer b; Buffer b;
Page p; Page p;
GISTENTRY tmpentry;
IndexTuple newtup;
b = ReadBuffer(r, GISTP_ROOT); b = ReadBuffer(r, GISTP_ROOT);
GISTInitBuffer(b, 0); GISTInitBuffer(b, 0);
p = BufferGetPage(b); p = BufferGetPage(b);
gistPageAddItem(giststate, r, p, (Item) lt, IndexTupleSize(lt),
FirstOffsetNumber, gistwritebuffer( r, p, itup, len, FirstOffsetNumber, giststate );
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); WriteBuffer(b);
} }
...@@ -1057,21 +968,15 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */ ...@@ -1057,21 +968,15 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
if (which_grow == 0) if (which_grow == 0)
break; break;
} }
if (entry.pred != datum) if (entry.pred && entry.pred != datum)
pfree(entry.pred); pfree(entry.pred);
} }
if (identry.pred != id) if (identry.pred && identry.pred != id)
pfree(identry.pred); pfree(identry.pred);
return which; return which;
} }
static int
gistnospace(Page p, IndexTuple it)
{
return PageGetFreeSpace(p) < IndexTupleSize(it);
}
void void
gistfreestack(GISTSTACK *s) gistfreestack(GISTSTACK *s)
{ {
...@@ -1193,7 +1098,7 @@ gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t) ...@@ -1193,7 +1098,7 @@ gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
char *datum = (((char *) t) + sizeof(IndexTupleData)); char *datum = (((char *) t) + sizeof(IndexTupleData));
/* if new entry fits in index tuple, copy it in */ /* if new entry fits in index tuple, copy it in */
if ((Size) entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData)) if ((Size) entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData) || (Size) entry.bytes == 0 )
{ {
memcpy(datum, entry.pred, entry.bytes); memcpy(datum, entry.pred, entry.bytes);
/* clear out old size */ /* clear out old size */
...@@ -1208,17 +1113,13 @@ gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t) ...@@ -1208,17 +1113,13 @@ gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
/* generate a new index tuple for the compressed entry */ /* generate a new index tuple for the compressed entry */
TupleDesc tupDesc = r->rd_att; TupleDesc tupDesc = r->rd_att;
IndexTuple newtup; IndexTuple newtup;
char *isnull; char isnull;
int blank;
isnull = (char *) palloc(r->rd_rel->relnatts); isnull = ( entry.pred ) ? ' ' : 'n';
for (blank = 0; blank < r->rd_rel->relnatts; blank++)
isnull[blank] = ' ';
newtup = (IndexTuple) index_formtuple(tupDesc, newtup = (IndexTuple) index_formtuple(tupDesc,
(Datum *) &(entry.pred), (Datum *) &(entry.pred),
isnull); &isnull);
newtup->t_tid = t->t_tid; newtup->t_tid = t->t_tid;
pfree(isnull);
return newtup; return newtup;
} }
} }
...@@ -1269,81 +1170,46 @@ gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, ...@@ -1269,81 +1170,46 @@ gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r,
} }
} }
#ifdef GISTDEBUG #ifdef GISTDEBUG
static void
/* gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
** sloppy debugging support routine, requires recompilation with appropriate
** "out" method for the index keys. Could be fixed to find that info
** in the catalogs...
*/
void
_gistdump(Relation r)
{ {
Buffer buf; Buffer buffer;
Page page; Page page;
OffsetNumber offnum, GISTPageOpaque opaque;
maxoff; IndexTuple which;
BlockNumber blkno; ItemId iid;
BlockNumber nblocks; OffsetNumber i,maxoff;
GISTPageOpaque po; BlockNumber cblk;
IndexTuple itup; char *pred;
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)) pred = (char*) palloc( sizeof(char)*level+1 );
{ MemSet(pred, '\t', level);
ReleaseBuffer(buf); pred[level]='\0';
continue;
}
for (offnum = FirstOffsetNumber; buffer = ReadBuffer(r, blk);
offnum <= maxoff; page = (Page) BufferGetPage(buffer);
offnum = OffsetNumberNext(offnum)) opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
{
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); maxoff = PageGetMaxOffsetNumber( page );
}
}
static char * elog(NOTICE,"%sPage: %d %s blk: %d maxoff: %d free: %d", pred, coff, ( opaque->flags & F_LEAF ) ? "LEAF" : "INTE", (int)blk, (int)maxoff, PageGetFreeSpace(page));
int_range_out(INTRANGE *r)
{
char *result;
if (r == NULL) for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
return NULL; iid = PageGetItemId(page, i);
result = (char *) palloc(80); which = (IndexTuple) PageGetItem(page, iid);
snprintf(result, 80, "[%d,%d): %d", r->lower, r->upper, r->flag); cblk = ItemPointerGetBlockNumber(&(which->t_tid));
#ifdef PRINTTUPLE
elog(NOTICE,"%s Tuple. blk: %d size: %d", pred, (int)cblk, IndexTupleSize( which ) );
#endif
return result; if ( ! ( opaque->flags & F_LEAF ) ) {
gist_dumptree( r, level+1, cblk, i );
}
}
ReleaseBuffer(buffer);
pfree(pred);
} }
#endif /* defined GISTDEBUG */ #endif /* defined GISTDEBUG */
void void
...@@ -1362,3 +1228,4 @@ void ...@@ -1362,3 +1228,4 @@ void
gist_desc(char *buf, uint8 xl_info, char* rec) gist_desc(char *buf, uint8 xl_info, char* rec)
{ {
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment