mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
pgindent run for 8.2.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.142 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.143 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -185,7 +185,7 @@ gistbuildCallback(Relation index,
|
||||
|
||||
/* form an index tuple and point it at the heap tuple */
|
||||
itup = gistFormTuple(&buildstate->giststate, index,
|
||||
values, isnull, true /* size is currently bogus */);
|
||||
values, isnull, true /* size is currently bogus */ );
|
||||
itup->t_tid = htup->t_self;
|
||||
|
||||
/*
|
||||
@ -199,7 +199,7 @@ gistbuildCallback(Relation index,
|
||||
* after initial build do not.
|
||||
*/
|
||||
gistdoinsert(index, itup,
|
||||
RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
|
||||
RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
|
||||
&buildstate->giststate);
|
||||
|
||||
buildstate->indtuples += 1;
|
||||
@ -236,7 +236,7 @@ gistinsert(PG_FUNCTION_ARGS)
|
||||
initGISTstate(&giststate, r);
|
||||
|
||||
itup = gistFormTuple(&giststate, r,
|
||||
values, isnull, true /* size is currently bogus */);
|
||||
values, isnull, true /* size is currently bogus */ );
|
||||
itup->t_tid = *ht_ctid;
|
||||
|
||||
gistdoinsert(r, itup, 0, &giststate);
|
||||
@ -285,18 +285,17 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
||||
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
|
||||
|
||||
/*
|
||||
* if (!is_leaf) remove old key:
|
||||
* This node's key has been modified, either because a child split
|
||||
* occurred or because we needed to adjust our key for an insert in a
|
||||
* child node. Therefore, remove the old version of this node's key.
|
||||
* if (!is_leaf) remove old key: This node's key has been modified, either
|
||||
* because a child split occurred or because we needed to adjust our key
|
||||
* for an insert in a child node. Therefore, remove the old version of
|
||||
* this node's key.
|
||||
*
|
||||
* for WAL replay, in the non-split case we handle this by
|
||||
* setting up a one-element todelete array; in the split case, it's
|
||||
* handled implicitly because the tuple vector passed to gistSplit
|
||||
* won't include this tuple.
|
||||
* for WAL replay, in the non-split case we handle this by setting up a
|
||||
* one-element todelete array; in the split case, it's handled implicitly
|
||||
* because the tuple vector passed to gistSplit won't include this tuple.
|
||||
*
|
||||
* XXX: If we want to change fillfactors between node and leaf,
|
||||
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
|
||||
* XXX: If we want to change fillfactors between node and leaf, fillfactor
|
||||
* = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
|
||||
*/
|
||||
if (gistnospace(state->stack->page, state->itup, state->ituplen,
|
||||
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
|
||||
@ -307,80 +306,88 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
||||
int tlen;
|
||||
SplitedPageLayout *dist = NULL,
|
||||
*ptr;
|
||||
BlockNumber rrlink = InvalidBlockNumber;
|
||||
BlockNumber rrlink = InvalidBlockNumber;
|
||||
GistNSN oldnsn;
|
||||
|
||||
is_splitted = true;
|
||||
|
||||
/*
|
||||
* Form index tuples vector to split:
|
||||
* remove old tuple if t's needed and add new tuples to vector
|
||||
* Form index tuples vector to split: remove old tuple if t's needed
|
||||
* and add new tuples to vector
|
||||
*/
|
||||
itvec = gistextractpage(state->stack->page, &tlen);
|
||||
if ( !is_leaf ) {
|
||||
if (!is_leaf)
|
||||
{
|
||||
/* on inner page we should remove old tuple */
|
||||
int pos = state->stack->childoffnum - FirstOffsetNumber;
|
||||
int pos = state->stack->childoffnum - FirstOffsetNumber;
|
||||
|
||||
tlen--;
|
||||
if ( pos != tlen )
|
||||
memmove( itvec+pos, itvec + pos + 1, sizeof( IndexTuple ) * (tlen-pos) );
|
||||
tlen--;
|
||||
if (pos != tlen)
|
||||
memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
|
||||
}
|
||||
itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
|
||||
dist = gistSplit(state->r, state->stack->page, itvec, tlen, giststate);
|
||||
|
||||
state->itup = (IndexTuple*)palloc( sizeof(IndexTuple) * tlen);
|
||||
state->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * tlen);
|
||||
state->ituplen = 0;
|
||||
|
||||
if (state->stack->blkno != GIST_ROOT_BLKNO) {
|
||||
/* if non-root split then we should not allocate new buffer,
|
||||
but we must create temporary page to operate */
|
||||
if (state->stack->blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
/*
|
||||
* if non-root split then we should not allocate new buffer, but
|
||||
* we must create temporary page to operate
|
||||
*/
|
||||
dist->buffer = state->stack->buffer;
|
||||
dist->page = PageGetTempPage( BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData) );
|
||||
dist->page = PageGetTempPage(BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData));
|
||||
|
||||
/*clean all flags except F_LEAF */
|
||||
/* clean all flags except F_LEAF */
|
||||
GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
|
||||
}
|
||||
|
||||
/* make new pages and fills them */
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
int i;
|
||||
char *data;
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
int i;
|
||||
char *data;
|
||||
|
||||
/* get new page */
|
||||
if ( ptr->buffer == InvalidBuffer ) {
|
||||
ptr->buffer = gistNewBuffer( state->r );
|
||||
GISTInitBuffer( ptr->buffer, (is_leaf) ? F_LEAF : 0 );
|
||||
if (ptr->buffer == InvalidBuffer)
|
||||
{
|
||||
ptr->buffer = gistNewBuffer(state->r);
|
||||
GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
|
||||
ptr->page = BufferGetPage(ptr->buffer);
|
||||
}
|
||||
ptr->block.blkno = BufferGetBlockNumber( ptr->buffer );
|
||||
ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
|
||||
|
||||
/* fill page, we can do it becouse all this pages are new (ie not linked in tree
|
||||
or masked by temp page */
|
||||
data = (char*)(ptr->list);
|
||||
for(i=0;i<ptr->block.num;i++) {
|
||||
if ( PageAddItem(ptr->page, (Item)data, IndexTupleSize((IndexTuple)data), i+FirstOffsetNumber, LP_USED) == InvalidOffsetNumber )
|
||||
/*
|
||||
* fill page, we can do it becouse all this pages are new (ie not
|
||||
* linked in tree or masked by temp page
|
||||
*/
|
||||
data = (char *) (ptr->list);
|
||||
for (i = 0; i < ptr->block.num; i++)
|
||||
{
|
||||
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));
|
||||
data += IndexTupleSize((IndexTuple)data);
|
||||
data += IndexTupleSize((IndexTuple) data);
|
||||
}
|
||||
|
||||
/* set up ItemPointer and remmeber it for parent */
|
||||
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
|
||||
state->itup[ state->ituplen ] = ptr->itup;
|
||||
state->itup[state->ituplen] = ptr->itup;
|
||||
state->ituplen++;
|
||||
}
|
||||
|
||||
/* saves old rightlink */
|
||||
if ( state->stack->blkno != GIST_ROOT_BLKNO )
|
||||
rrlink = GistPageGetOpaque(dist->page)->rightlink;
|
||||
if (state->stack->blkno != GIST_ROOT_BLKNO)
|
||||
rrlink = GistPageGetOpaque(dist->page)->rightlink;
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
/*
|
||||
* must mark buffers dirty before XLogInsert, even though we'll
|
||||
* still be changing their opaque fields below.
|
||||
* set up right links.
|
||||
* must mark buffers dirty before XLogInsert, even though we'll still
|
||||
* be changing their opaque fields below. set up right links.
|
||||
*/
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
MarkBufferDirty(ptr->buffer);
|
||||
GistPageGetOpaque(ptr->page)->rightlink = (ptr->next) ?
|
||||
@ -388,9 +395,10 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
||||
}
|
||||
|
||||
/* restore splitted non-root page */
|
||||
if ( state->stack->blkno != GIST_ROOT_BLKNO ) {
|
||||
PageRestoreTempPage( dist->page, BufferGetPage( dist->buffer ) );
|
||||
dist->page = BufferGetPage( dist->buffer );
|
||||
if (state->stack->blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
|
||||
dist->page = BufferGetPage(dist->buffer);
|
||||
}
|
||||
|
||||
if (!state->r->rd_istemp)
|
||||
@ -419,25 +427,27 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
||||
|
||||
/* set up NSN */
|
||||
oldnsn = GistPageGetOpaque(dist->page)->nsn;
|
||||
if ( state->stack->blkno == GIST_ROOT_BLKNO )
|
||||
if (state->stack->blkno == GIST_ROOT_BLKNO)
|
||||
/* if root split we should put initial value */
|
||||
oldnsn = PageGetLSN(dist->page);
|
||||
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
/* only for last set oldnsn */
|
||||
GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ?
|
||||
PageGetLSN(ptr->page) : oldnsn;
|
||||
}
|
||||
|
||||
/*
|
||||
* release buffers, if it was a root split then
|
||||
* release all buffers because we create all buffers
|
||||
/*
|
||||
* release buffers, if it was a root split then release all buffers
|
||||
* because we create all buffers
|
||||
*/
|
||||
ptr = ( state->stack->blkno == GIST_ROOT_BLKNO ) ? dist : dist->next;
|
||||
for(; ptr; ptr = ptr->next)
|
||||
ptr = (state->stack->blkno == GIST_ROOT_BLKNO) ? dist : dist->next;
|
||||
for (; ptr; ptr = ptr->next)
|
||||
UnlockReleaseBuffer(ptr->buffer);
|
||||
|
||||
if (state->stack->blkno == GIST_ROOT_BLKNO) {
|
||||
if (state->stack->blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));
|
||||
state->needInsertComplete = false;
|
||||
}
|
||||
@ -470,7 +480,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
||||
}
|
||||
|
||||
rdata = formUpdateRdata(state->r->rd_node, state->stack->buffer,
|
||||
offs, noffs,
|
||||
offs, noffs,
|
||||
state->itup, state->ituplen,
|
||||
&(state->key));
|
||||
|
||||
@ -922,16 +932,16 @@ gistSplit(Relation r,
|
||||
GistSplitVector v;
|
||||
GistEntryVector *entryvec;
|
||||
int i;
|
||||
SplitedPageLayout *res = NULL;
|
||||
SplitedPageLayout *res = NULL;
|
||||
|
||||
/* generate the item array */
|
||||
entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));
|
||||
entryvec->n = len + 1;
|
||||
|
||||
memset( v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts );
|
||||
memset( v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts );
|
||||
gistSplitByKey(r, page, itup, len, giststate,
|
||||
&v, entryvec, 0);
|
||||
memset(v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
|
||||
memset(v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
|
||||
gistSplitByKey(r, page, itup, len, giststate,
|
||||
&v, entryvec, 0);
|
||||
|
||||
/* form left and right vector */
|
||||
lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
|
||||
@ -952,19 +962,20 @@ gistSplit(Relation r,
|
||||
{
|
||||
ROTATEDIST(res);
|
||||
res->block.num = v.splitVector.spl_nright;
|
||||
res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &( res->lenlist ) );
|
||||
res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &(res->lenlist));
|
||||
res->itup = (v.spl_rightvalid) ? gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false)
|
||||
: gist_form_invalid_tuple(GIST_ROOT_BLKNO);
|
||||
}
|
||||
|
||||
if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
|
||||
{
|
||||
SplitedPageLayout *resptr, *subres;
|
||||
SplitedPageLayout *resptr,
|
||||
*subres;
|
||||
|
||||
resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
|
||||
|
||||
/* install on list's tail */
|
||||
while( resptr->next )
|
||||
/* install on list's tail */
|
||||
while (resptr->next)
|
||||
resptr = resptr->next;
|
||||
|
||||
resptr->next = res;
|
||||
@ -974,7 +985,7 @@ gistSplit(Relation r,
|
||||
{
|
||||
ROTATEDIST(res);
|
||||
res->block.num = v.splitVector.spl_nleft;
|
||||
res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &( res->lenlist ) );
|
||||
res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &(res->lenlist));
|
||||
res->itup = (v.spl_leftvalid) ? gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false)
|
||||
: gist_form_invalid_tuple(GIST_ROOT_BLKNO);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.60 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.61 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -360,8 +360,7 @@ gistindex_keytest(IndexTuple tuple,
|
||||
IncrIndexProcessed();
|
||||
|
||||
/*
|
||||
* Tuple doesn't restore after crash recovery because of incomplete
|
||||
* insert
|
||||
* Tuple doesn't restore after crash recovery because of incomplete insert
|
||||
*/
|
||||
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple))
|
||||
return true;
|
||||
@ -378,14 +377,18 @@ gistindex_keytest(IndexTuple tuple,
|
||||
giststate->tupdesc,
|
||||
&isNull);
|
||||
|
||||
if ( key->sk_flags & SK_ISNULL ) {
|
||||
/* is the compared-to datum NULL? on non-leaf page it's possible
|
||||
to have nulls in childs :( */
|
||||
if (key->sk_flags & SK_ISNULL)
|
||||
{
|
||||
/*
|
||||
* is the compared-to datum NULL? on non-leaf page it's possible
|
||||
* to have nulls in childs :(
|
||||
*/
|
||||
|
||||
if ( isNull || !GistPageIsLeaf(p) )
|
||||
if (isNull || !GistPageIsLeaf(p))
|
||||
return true;
|
||||
return false;
|
||||
} else if ( isNull )
|
||||
}
|
||||
else if (isNull)
|
||||
return false;
|
||||
|
||||
gistdentryinit(giststate, key->sk_attno - 1, &de,
|
||||
|
@ -10,7 +10,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.8 2006/09/10 00:29:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.9 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -112,7 +112,8 @@ gist_box_consistent(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
static void
|
||||
adjustBox( BOX *b, BOX *addon ) {
|
||||
adjustBox(BOX *b, BOX *addon)
|
||||
{
|
||||
if (b->high.x < addon->high.x)
|
||||
b->high.x = addon->high.x;
|
||||
if (b->low.x > addon->low.x)
|
||||
@ -146,7 +147,7 @@ gist_box_union(PG_FUNCTION_ARGS)
|
||||
for (i = 1; i < numranges; i++)
|
||||
{
|
||||
cur = DatumGetBoxP(entryvec->vector[i].key);
|
||||
adjustBox( pageunion, cur );
|
||||
adjustBox(pageunion, cur);
|
||||
}
|
||||
*sizep = sizeof(BOX);
|
||||
|
||||
@ -210,67 +211,79 @@ compare_KB(const void *a, const void *b)
|
||||
}
|
||||
|
||||
static void
|
||||
chooseLR( GIST_SPLITVEC *v,
|
||||
OffsetNumber *list1, int nlist1, BOX *union1,
|
||||
OffsetNumber *list2, int nlist2, BOX *union2 )
|
||||
chooseLR(GIST_SPLITVEC *v,
|
||||
OffsetNumber *list1, int nlist1, BOX *union1,
|
||||
OffsetNumber *list2, int nlist2, BOX *union2)
|
||||
{
|
||||
bool firstToLeft = true;
|
||||
bool firstToLeft = true;
|
||||
|
||||
if ( v->spl_ldatum_exists || v->spl_rdatum_exists ) {
|
||||
if ( v->spl_ldatum_exists && v->spl_rdatum_exists ) {
|
||||
BOX LRl = *union1, LRr = *union2;
|
||||
BOX RLl = *union2, RLr = *union1;
|
||||
double sizeLR, sizeRL;
|
||||
if (v->spl_ldatum_exists || v->spl_rdatum_exists)
|
||||
{
|
||||
if (v->spl_ldatum_exists && v->spl_rdatum_exists)
|
||||
{
|
||||
BOX LRl = *union1,
|
||||
LRr = *union2;
|
||||
BOX RLl = *union2,
|
||||
RLr = *union1;
|
||||
double sizeLR,
|
||||
sizeRL;
|
||||
|
||||
adjustBox( &LRl, DatumGetBoxP( v->spl_ldatum ) );
|
||||
adjustBox( &LRr, DatumGetBoxP( v->spl_rdatum ) );
|
||||
adjustBox( &RLl, DatumGetBoxP( v->spl_ldatum ) );
|
||||
adjustBox( &RLr, DatumGetBoxP( v->spl_rdatum ) );
|
||||
adjustBox(&LRl, DatumGetBoxP(v->spl_ldatum));
|
||||
adjustBox(&LRr, DatumGetBoxP(v->spl_rdatum));
|
||||
adjustBox(&RLl, DatumGetBoxP(v->spl_ldatum));
|
||||
adjustBox(&RLr, DatumGetBoxP(v->spl_rdatum));
|
||||
|
||||
sizeLR = size_box( DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)) );
|
||||
sizeRL = size_box( DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)) );
|
||||
sizeLR = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)));
|
||||
sizeRL = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)));
|
||||
|
||||
if ( sizeLR > sizeRL )
|
||||
if (sizeLR > sizeRL)
|
||||
firstToLeft = false;
|
||||
|
||||
} else {
|
||||
float p1, p2;
|
||||
GISTENTRY oldUnion, addon;
|
||||
}
|
||||
else
|
||||
{
|
||||
float p1,
|
||||
p2;
|
||||
GISTENTRY oldUnion,
|
||||
addon;
|
||||
|
||||
gistentryinit(oldUnion, ( v->spl_ldatum_exists ) ? v->spl_ldatum : v->spl_rdatum,
|
||||
gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
|
||||
NULL, NULL, InvalidOffsetNumber, FALSE);
|
||||
|
||||
|
||||
gistentryinit(addon, BoxPGetDatum(union1), NULL, NULL, InvalidOffsetNumber, FALSE);
|
||||
DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union1), PointerGetDatum(&p1));
|
||||
DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union1), PointerGetDatum(&p1));
|
||||
gistentryinit(addon, BoxPGetDatum(union2), NULL, NULL, InvalidOffsetNumber, FALSE);
|
||||
DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union2), PointerGetDatum(&p2));
|
||||
|
||||
if ( (v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2) )
|
||||
firstToLeft = false;
|
||||
if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))
|
||||
firstToLeft = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( firstToLeft ) {
|
||||
if (firstToLeft)
|
||||
{
|
||||
v->spl_left = list1;
|
||||
v->spl_right = list2;
|
||||
v->spl_nleft = nlist1;
|
||||
v->spl_nright = nlist2;
|
||||
if ( v->spl_ldatum_exists )
|
||||
adjustBox(union1, DatumGetBoxP( v->spl_ldatum ) );
|
||||
if (v->spl_ldatum_exists)
|
||||
adjustBox(union1, DatumGetBoxP(v->spl_ldatum));
|
||||
v->spl_ldatum = BoxPGetDatum(union1);
|
||||
if ( v->spl_rdatum_exists )
|
||||
adjustBox(union2, DatumGetBoxP( v->spl_rdatum ) );
|
||||
if (v->spl_rdatum_exists)
|
||||
adjustBox(union2, DatumGetBoxP(v->spl_rdatum));
|
||||
v->spl_rdatum = BoxPGetDatum(union2);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
v->spl_left = list2;
|
||||
v->spl_right = list1;
|
||||
v->spl_nleft = nlist2;
|
||||
v->spl_nright = nlist1;
|
||||
if ( v->spl_ldatum_exists )
|
||||
adjustBox(union2, DatumGetBoxP( v->spl_ldatum ) );
|
||||
if (v->spl_ldatum_exists)
|
||||
adjustBox(union2, DatumGetBoxP(v->spl_ldatum));
|
||||
v->spl_ldatum = BoxPGetDatum(union2);
|
||||
if ( v->spl_rdatum_exists )
|
||||
adjustBox(union1, DatumGetBoxP( v->spl_rdatum ) );
|
||||
if (v->spl_rdatum_exists)
|
||||
adjustBox(union1, DatumGetBoxP(v->spl_rdatum));
|
||||
v->spl_rdatum = BoxPGetDatum(union1);
|
||||
}
|
||||
|
||||
@ -326,7 +339,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
))
|
||||
allisequal = false;
|
||||
|
||||
adjustBox( &pageunion, cur );
|
||||
adjustBox(&pageunion, cur);
|
||||
}
|
||||
|
||||
nbytes = (maxoff + 2) * sizeof(OffsetNumber);
|
||||
@ -359,12 +372,12 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
}
|
||||
}
|
||||
|
||||
if ( v->spl_ldatum_exists )
|
||||
adjustBox( unionL, DatumGetBoxP( v->spl_ldatum ) );
|
||||
if (v->spl_ldatum_exists)
|
||||
adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));
|
||||
v->spl_ldatum = BoxPGetDatum(unionL);
|
||||
|
||||
if ( v->spl_rdatum_exists )
|
||||
adjustBox( unionR, DatumGetBoxP( v->spl_rdatum ) );
|
||||
if (v->spl_rdatum_exists)
|
||||
adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));
|
||||
v->spl_rdatum = BoxPGetDatum(unionR);
|
||||
|
||||
v->spl_ldatum_exists = v->spl_rdatum_exists = false;
|
||||
@ -471,13 +484,13 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
if (direction == 'x')
|
||||
chooseLR( v,
|
||||
listL, posL, unionL,
|
||||
listR, posR, unionR );
|
||||
else
|
||||
chooseLR( v,
|
||||
listB, posB, unionB,
|
||||
listT, posT, unionT );
|
||||
chooseLR(v,
|
||||
listL, posL, unionL,
|
||||
listR, posR, unionR);
|
||||
else
|
||||
chooseLR(v,
|
||||
listB, posB, unionB,
|
||||
listT, posT, unionT);
|
||||
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.64 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.65 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -228,12 +228,12 @@ gistendscan(PG_FUNCTION_ARGS)
|
||||
|
||||
static void
|
||||
gistfreestack(GISTSearchStack *s)
|
||||
{
|
||||
{
|
||||
while (s != NULL)
|
||||
{
|
||||
GISTSearchStack *p = s->next;
|
||||
|
||||
pfree(s);
|
||||
s = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.2 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.3 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,12 +16,13 @@
|
||||
|
||||
#include "access/gist_private.h"
|
||||
|
||||
typedef struct {
|
||||
Datum *attr;
|
||||
int len;
|
||||
typedef struct
|
||||
{
|
||||
Datum *attr;
|
||||
int len;
|
||||
OffsetNumber *entries;
|
||||
bool *isnull;
|
||||
bool *equiv;
|
||||
bool *isnull;
|
||||
bool *equiv;
|
||||
} GistSplitUnion;
|
||||
|
||||
|
||||
@ -29,25 +30,28 @@ typedef struct {
|
||||
* Forms unions of subkeys after page split, but
|
||||
* uses only tuples aren't in groups of equalent tuples
|
||||
*/
|
||||
static void
|
||||
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
|
||||
GistSplitUnion *gsvp, int startkey) {
|
||||
IndexTuple *cleanedItVec;
|
||||
int i, cleanedLen=0;
|
||||
static void
|
||||
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
|
||||
GistSplitUnion *gsvp, int startkey)
|
||||
{
|
||||
IndexTuple *cleanedItVec;
|
||||
int i,
|
||||
cleanedLen = 0;
|
||||
|
||||
cleanedItVec = (IndexTuple*)palloc(sizeof(IndexTuple) * gsvp->len);
|
||||
cleanedItVec = (IndexTuple *) palloc(sizeof(IndexTuple) * gsvp->len);
|
||||
|
||||
for(i=0;i<gsvp->len;i++) {
|
||||
if ( gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
|
||||
for (i = 0; i < gsvp->len; i++)
|
||||
{
|
||||
if (gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
|
||||
continue;
|
||||
|
||||
cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1];
|
||||
}
|
||||
|
||||
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
|
||||
gsvp->attr, gsvp->isnull);
|
||||
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
|
||||
gsvp->attr, gsvp->isnull);
|
||||
|
||||
pfree( cleanedItVec );
|
||||
pfree(cleanedItVec);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -56,7 +60,7 @@ gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
|
||||
static void
|
||||
gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, int attno)
|
||||
{
|
||||
GistSplitUnion gsvp;
|
||||
GistSplitUnion gsvp;
|
||||
|
||||
gsvp.equiv = spl->spl_equiv;
|
||||
|
||||
@ -76,34 +80,40 @@ gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, i
|
||||
}
|
||||
|
||||
/*
|
||||
* find group in vector with equivalent value
|
||||
* find group in vector with equivalent value
|
||||
*/
|
||||
static int
|
||||
gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVector *spl, int attno)
|
||||
{
|
||||
int i;
|
||||
GISTENTRY entry;
|
||||
int len=0;
|
||||
int len = 0;
|
||||
|
||||
/*
|
||||
* attno key is always not null (see gistSplitByKey), so we may not check for
|
||||
* nulls
|
||||
* attno key is always not null (see gistSplitByKey), so we may not check
|
||||
* for nulls
|
||||
*/
|
||||
gistentryinit(entry, spl->splitVector.spl_rdatum, r, NULL, (OffsetNumber) 0, FALSE);
|
||||
for (i = 0; i < spl->splitVector.spl_nleft; i++) {
|
||||
float penalty = gistpenalty(giststate, attno, &entry, false,
|
||||
&valvec[spl->splitVector.spl_left[i]], false);
|
||||
if ( penalty == 0.0 ) {
|
||||
for (i = 0; i < spl->splitVector.spl_nleft; i++)
|
||||
{
|
||||
float penalty = gistpenalty(giststate, attno, &entry, false,
|
||||
&valvec[spl->splitVector.spl_left[i]], false);
|
||||
|
||||
if (penalty == 0.0)
|
||||
{
|
||||
spl->spl_equiv[spl->splitVector.spl_left[i]] = true;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
gistentryinit(entry, spl->splitVector.spl_ldatum, r, NULL, (OffsetNumber) 0, FALSE);
|
||||
for (i = 0; i < spl->splitVector.spl_nright; i++) {
|
||||
float penalty = gistpenalty(giststate, attno, &entry, false,
|
||||
&valvec[spl->splitVector.spl_right[i]], false);
|
||||
if ( penalty == 0.0 ) {
|
||||
for (i = 0; i < spl->splitVector.spl_nright; i++)
|
||||
{
|
||||
float penalty = gistpenalty(giststate, attno, &entry, false,
|
||||
&valvec[spl->splitVector.spl_right[i]], false);
|
||||
|
||||
if (penalty == 0.0)
|
||||
{
|
||||
spl->spl_equiv[spl->splitVector.spl_right[i]] = true;
|
||||
len++;
|
||||
}
|
||||
@ -113,24 +123,32 @@ gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVect
|
||||
}
|
||||
|
||||
static void
|
||||
cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
|
||||
int curlen,i;
|
||||
OffsetNumber *curwpos;
|
||||
cleanupOffsets(OffsetNumber *a, int *len, bool *equiv, int *LenEquiv)
|
||||
{
|
||||
int curlen,
|
||||
i;
|
||||
OffsetNumber *curwpos;
|
||||
|
||||
curlen = *len;
|
||||
curwpos = a;
|
||||
for (i = 0; i < *len; i++) {
|
||||
if ( equiv[ a[i] ] == FALSE ) {
|
||||
for (i = 0; i < *len; i++)
|
||||
{
|
||||
if (equiv[a[i]] == FALSE)
|
||||
{
|
||||
*curwpos = a[i];
|
||||
curwpos++;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* corner case: we shouldn't make void array */
|
||||
if ( curlen==1 ) {
|
||||
equiv[ a[i] ] = FALSE; /* mark item as non-equivalent */
|
||||
i--; /* redo the same */
|
||||
if (curlen == 1)
|
||||
{
|
||||
equiv[a[i]] = FALSE; /* mark item as non-equivalent */
|
||||
i--; /* redo the same */
|
||||
*LenEquiv -= 1;
|
||||
continue;
|
||||
} else
|
||||
}
|
||||
else
|
||||
curlen--;
|
||||
}
|
||||
}
|
||||
@ -139,33 +157,37 @@ cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
|
||||
}
|
||||
|
||||
static void
|
||||
placeOne( Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno ) {
|
||||
placeOne(Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno)
|
||||
{
|
||||
GISTENTRY identry[INDEX_MAX_KEYS];
|
||||
bool isnull[INDEX_MAX_KEYS];
|
||||
bool toLeft = true;
|
||||
bool toLeft = true;
|
||||
|
||||
gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, identry, isnull);
|
||||
|
||||
for(;attno<giststate->tupdesc->natts;attno++) {
|
||||
float lpenalty, rpenalty;
|
||||
for (; attno < giststate->tupdesc->natts; attno++)
|
||||
{
|
||||
float lpenalty,
|
||||
rpenalty;
|
||||
GISTENTRY entry;
|
||||
|
||||
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
|
||||
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry+attno, isnull[ attno ]);
|
||||
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
|
||||
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry+attno, isnull[ attno ]);
|
||||
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
|
||||
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry + attno, isnull[attno]);
|
||||
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
|
||||
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry + attno, isnull[attno]);
|
||||
|
||||
if ( lpenalty != rpenalty ) {
|
||||
if ( lpenalty > rpenalty )
|
||||
if (lpenalty != rpenalty)
|
||||
{
|
||||
if (lpenalty > rpenalty)
|
||||
toLeft = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( toLeft )
|
||||
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = off;
|
||||
if (toLeft)
|
||||
v->splitVector.spl_left[v->splitVector.spl_nleft++] = off;
|
||||
else
|
||||
v->splitVector.spl_right[ v->splitVector.spl_nright++ ] = off;
|
||||
v->splitVector.spl_right[v->splitVector.spl_nright++] = off;
|
||||
}
|
||||
|
||||
#define SWAPVAR( s, d, t ) \
|
||||
@ -176,71 +198,83 @@ do { \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* adjust left and right unions according to splits by previous
|
||||
* split by firsts columns. This function is called only in case
|
||||
* adjust left and right unions according to splits by previous
|
||||
* split by firsts columns. This function is called only in case
|
||||
* when pickSplit doesn't support subspplit.
|
||||
*/
|
||||
|
||||
static void
|
||||
supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR ) {
|
||||
bool leaveOnLeft = true, tmpBool;
|
||||
GISTENTRY entryL, entryR, entrySL, entrySR;
|
||||
|
||||
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
|
||||
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE);
|
||||
supportSecondarySplit(Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR)
|
||||
{
|
||||
bool leaveOnLeft = true,
|
||||
tmpBool;
|
||||
GISTENTRY entryL,
|
||||
entryR,
|
||||
entrySL,
|
||||
entrySR;
|
||||
|
||||
if ( sv->spl_ldatum_exists && sv->spl_rdatum_exists ) {
|
||||
float penalty1, penalty2;
|
||||
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
|
||||
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
|
||||
|
||||
if (sv->spl_ldatum_exists && sv->spl_rdatum_exists)
|
||||
{
|
||||
float penalty1,
|
||||
penalty2;
|
||||
|
||||
penalty1 = gistpenalty(giststate, attno, &entryL, false, &entrySL, false) +
|
||||
gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
|
||||
gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
|
||||
penalty2 = gistpenalty(giststate, attno, &entryL, false, &entrySR, false) +
|
||||
gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
|
||||
gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
|
||||
|
||||
if ( penalty1 > penalty2 )
|
||||
if (penalty1 > penalty2)
|
||||
leaveOnLeft = false;
|
||||
|
||||
} else {
|
||||
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
|
||||
float penalty1, penalty2;
|
||||
}
|
||||
else
|
||||
{
|
||||
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
|
||||
float penalty1,
|
||||
penalty2;
|
||||
|
||||
/*
|
||||
* there is only one previously defined union,
|
||||
* so we just choose swap or not by lowest penalty
|
||||
* there is only one previously defined union, so we just choose swap
|
||||
* or not by lowest penalty
|
||||
*/
|
||||
|
||||
penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false);
|
||||
penalty2 = gistpenalty(giststate, attno, entry1, false, &entrySR, false);
|
||||
|
||||
if ( penalty1 < penalty2 )
|
||||
leaveOnLeft = ( sv->spl_ldatum_exists ) ? true : false;
|
||||
if (penalty1 < penalty2)
|
||||
leaveOnLeft = (sv->spl_ldatum_exists) ? true : false;
|
||||
else
|
||||
leaveOnLeft = ( sv->spl_rdatum_exists ) ? true : false;
|
||||
leaveOnLeft = (sv->spl_rdatum_exists) ? true : false;
|
||||
}
|
||||
|
||||
if ( leaveOnLeft == false ) {
|
||||
if (leaveOnLeft == false)
|
||||
{
|
||||
/*
|
||||
* swap left and right
|
||||
* swap left and right
|
||||
*/
|
||||
OffsetNumber *off, noff;
|
||||
Datum datum;
|
||||
OffsetNumber *off,
|
||||
noff;
|
||||
Datum datum;
|
||||
|
||||
SWAPVAR( sv->spl_left, sv->spl_right, off );
|
||||
SWAPVAR( sv->spl_nleft, sv->spl_nright, noff );
|
||||
SWAPVAR( sv->spl_ldatum, sv->spl_rdatum, datum );
|
||||
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE);
|
||||
SWAPVAR(sv->spl_left, sv->spl_right, off);
|
||||
SWAPVAR(sv->spl_nleft, sv->spl_nright, noff);
|
||||
SWAPVAR(sv->spl_ldatum, sv->spl_rdatum, datum);
|
||||
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
|
||||
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
|
||||
}
|
||||
|
||||
if ( sv->spl_ldatum_exists )
|
||||
if (sv->spl_ldatum_exists)
|
||||
gistMakeUnionKey(giststate, attno, &entryL, false, &entrySL, false,
|
||||
&sv->spl_ldatum, &tmpBool);
|
||||
&sv->spl_ldatum, &tmpBool);
|
||||
|
||||
if ( sv->spl_rdatum_exists )
|
||||
if (sv->spl_rdatum_exists)
|
||||
gistMakeUnionKey(giststate, attno, &entryR, false, &entrySR, false,
|
||||
&sv->spl_rdatum, &tmpBool);
|
||||
&sv->spl_rdatum, &tmpBool);
|
||||
|
||||
sv->spl_ldatum_exists = sv->spl_rdatum_exists = false;
|
||||
}
|
||||
@ -251,20 +285,21 @@ supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVE
|
||||
* get better split.
|
||||
* Returns TRUE and v->spl_equiv = NULL if left and right unions of attno columns are the same,
|
||||
* so caller may find better split
|
||||
* Returns TRUE and v->spl_equiv != NULL if there is tuples which may be freely moved
|
||||
* Returns TRUE and v->spl_equiv != NULL if there is tuples which may be freely moved
|
||||
*/
|
||||
static bool
|
||||
gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVector *v,
|
||||
IndexTuple *itup, int len, GISTSTATE *giststate)
|
||||
{
|
||||
GIST_SPLITVEC *sv = &v->splitVector;
|
||||
|
||||
/*
|
||||
* now let the user-defined picksplit function set up the split vector; in
|
||||
* entryvec have no null value!!
|
||||
*/
|
||||
|
||||
sv->spl_ldatum_exists = ( v->spl_lisnull[ attno ] ) ? false : true;
|
||||
sv->spl_rdatum_exists = ( v->spl_risnull[ attno ] ) ? false : true;
|
||||
sv->spl_ldatum_exists = (v->spl_lisnull[attno]) ? false : true;
|
||||
sv->spl_rdatum_exists = (v->spl_risnull[attno]) ? false : true;
|
||||
sv->spl_ldatum = v->spl_lattr[attno];
|
||||
sv->spl_rdatum = v->spl_rattr[attno];
|
||||
|
||||
@ -278,11 +313,12 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
||||
if (sv->spl_right[sv->spl_nright - 1] == InvalidOffsetNumber)
|
||||
sv->spl_right[sv->spl_nright - 1] = (OffsetNumber) (entryvec->n - 1);
|
||||
|
||||
if( sv->spl_ldatum_exists || sv->spl_rdatum_exists ) {
|
||||
elog(LOG,"PickSplit method of %d columns of index '%s' doesn't support secondary split",
|
||||
attno + 1, RelationGetRelationName(r) );
|
||||
if (sv->spl_ldatum_exists || sv->spl_rdatum_exists)
|
||||
{
|
||||
elog(LOG, "PickSplit method of %d columns of index '%s' doesn't support secondary split",
|
||||
attno + 1, RelationGetRelationName(r));
|
||||
|
||||
supportSecondarySplit( r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno] );
|
||||
supportSecondarySplit(r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno]);
|
||||
}
|
||||
|
||||
v->spl_lattr[attno] = sv->spl_ldatum;
|
||||
@ -296,53 +332,64 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
||||
*/
|
||||
v->spl_equiv = NULL;
|
||||
|
||||
if (giststate->tupdesc->natts > 1 && attno+1 != giststate->tupdesc->natts)
|
||||
if (giststate->tupdesc->natts > 1 && attno + 1 != giststate->tupdesc->natts)
|
||||
{
|
||||
if ( gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum) ) {
|
||||
if (gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum))
|
||||
{
|
||||
/*
|
||||
* Left and right key's unions are equial, so
|
||||
* we can get better split by following columns. Note,
|
||||
* unions for attno columns are already done.
|
||||
* Left and right key's unions are equial, so we can get better
|
||||
* split by following columns. Note, unions for attno columns are
|
||||
* already done.
|
||||
*/
|
||||
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
int LenEquiv;
|
||||
|
||||
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n+1));
|
||||
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n + 1));
|
||||
|
||||
LenEquiv = gistfindgroup(r, giststate, entryvec->vector, v, attno);
|
||||
|
||||
/*
|
||||
* if possible, we should distribute equivalent tuples
|
||||
*/
|
||||
if (LenEquiv == 0 ) {
|
||||
* if possible, we should distribute equivalent tuples
|
||||
*/
|
||||
if (LenEquiv == 0)
|
||||
{
|
||||
gistunionsubkey(giststate, itup, v, attno + 1);
|
||||
} else {
|
||||
cleanupOffsets( sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv );
|
||||
cleanupOffsets( sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv );
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanupOffsets(sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv);
|
||||
cleanupOffsets(sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv);
|
||||
|
||||
gistunionsubkey(giststate, itup, v, attno + 1);
|
||||
if (LenEquiv == 1 ) {
|
||||
if (LenEquiv == 1)
|
||||
{
|
||||
/*
|
||||
* In case with one tuple we just choose left-right
|
||||
* by penalty. It's simplify user-defined pickSplit
|
||||
* In case with one tuple we just choose left-right by
|
||||
* penalty. It's simplify user-defined pickSplit
|
||||
*/
|
||||
OffsetNumber toMove = InvalidOffsetNumber;
|
||||
|
||||
for(toMove=FirstOffsetNumber;toMove<entryvec->n;toMove++)
|
||||
if ( v->spl_equiv[ toMove ] )
|
||||
for (toMove = FirstOffsetNumber; toMove < entryvec->n; toMove++)
|
||||
if (v->spl_equiv[toMove])
|
||||
break;
|
||||
Assert( toMove < entryvec->n );
|
||||
|
||||
placeOne( r, giststate, v, itup[ toMove-1 ], toMove, attno+1 );
|
||||
/* redo gistunionsubkey(): it will not degradate performance,
|
||||
* because it's very rarely */
|
||||
Assert(toMove < entryvec->n);
|
||||
|
||||
placeOne(r, giststate, v, itup[toMove - 1], toMove, attno + 1);
|
||||
|
||||
/*
|
||||
* redo gistunionsubkey(): it will not degradate
|
||||
* performance, because it's very rarely
|
||||
*/
|
||||
v->spl_equiv = NULL;
|
||||
gistunionsubkey(giststate, itup, v, attno + 1);
|
||||
|
||||
return false;
|
||||
} else if ( LenEquiv > 1 )
|
||||
}
|
||||
else if (LenEquiv > 1)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -352,60 +399,65 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
|
||||
}
|
||||
|
||||
/*
|
||||
* simple split page
|
||||
* simple split page
|
||||
*/
|
||||
static void
|
||||
gistSplitHalf(GIST_SPLITVEC *v, int len) {
|
||||
int i;
|
||||
gistSplitHalf(GIST_SPLITVEC *v, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
v->spl_nright = v->spl_nleft = 0;
|
||||
v->spl_nright = v->spl_nleft = 0;
|
||||
v->spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
|
||||
v->spl_right= (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
|
||||
for(i = 1; i <= len; i++)
|
||||
if ( i<len/2 )
|
||||
v->spl_right[ v->spl_nright++ ] = i;
|
||||
v->spl_right = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
|
||||
for (i = 1; i <= len; i++)
|
||||
if (i < len / 2)
|
||||
v->spl_right[v->spl_nright++] = i;
|
||||
else
|
||||
v->spl_left[ v->spl_nleft++ ] = i;
|
||||
v->spl_left[v->spl_nleft++] = i;
|
||||
}
|
||||
|
||||
/*
|
||||
* if it was invalid tuple then we need special processing.
|
||||
* We move all invalid tuples on right page.
|
||||
* We move all invalid tuples on right page.
|
||||
*
|
||||
* if there is no place on left page, gistSplit will be called one more
|
||||
* if there is no place on left page, gistSplit will be called one more
|
||||
* time for left page.
|
||||
*
|
||||
* Normally, we never exec this code, but after crash replay it's possible
|
||||
* to get 'invalid' tuples (probability is low enough)
|
||||
*/
|
||||
static void
|
||||
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len) {
|
||||
int i;
|
||||
static OffsetNumber offInvTuples[ MaxOffsetNumber ];
|
||||
int nOffInvTuples = 0;
|
||||
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len)
|
||||
{
|
||||
int i;
|
||||
static OffsetNumber offInvTuples[MaxOffsetNumber];
|
||||
int nOffInvTuples = 0;
|
||||
|
||||
for (i = 1; i <= len; i++)
|
||||
if ( GistTupleIsInvalid(itup[i - 1]) )
|
||||
offInvTuples[ nOffInvTuples++ ] = i;
|
||||
if (GistTupleIsInvalid(itup[i - 1]))
|
||||
offInvTuples[nOffInvTuples++] = i;
|
||||
|
||||
if ( nOffInvTuples == len ) {
|
||||
if (nOffInvTuples == len)
|
||||
{
|
||||
/* corner case, all tuples are invalid */
|
||||
v->spl_rightvalid= v->spl_leftvalid = false;
|
||||
gistSplitHalf( &v->splitVector, len );
|
||||
} else {
|
||||
GistSplitUnion gsvp;
|
||||
|
||||
v->spl_rightvalid = v->spl_leftvalid = false;
|
||||
gistSplitHalf(&v->splitVector, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
GistSplitUnion gsvp;
|
||||
|
||||
v->splitVector.spl_right = offInvTuples;
|
||||
v->splitVector.spl_nright = nOffInvTuples;
|
||||
v->spl_rightvalid = false;
|
||||
|
||||
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
|
||||
v->splitVector.spl_nleft = 0;
|
||||
for(i = 1; i <= len; i++)
|
||||
if ( !GistTupleIsInvalid(itup[i - 1]) )
|
||||
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i;
|
||||
for (i = 1; i <= len; i++)
|
||||
if (!GistTupleIsInvalid(itup[i - 1]))
|
||||
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
|
||||
v->spl_leftvalid = true;
|
||||
|
||||
|
||||
gsvp.equiv = NULL;
|
||||
gsvp.attr = v->spl_lattr;
|
||||
gsvp.len = v->splitVector.spl_nleft;
|
||||
@ -418,52 +470,58 @@ gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, i
|
||||
|
||||
/*
|
||||
* trys to split page by attno key, in a case of null
|
||||
* values move its to separate page.
|
||||
* values move its to separate page.
|
||||
*/
|
||||
void
|
||||
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
|
||||
GistSplitVector *v, GistEntryVector *entryvec, int attno) {
|
||||
int i;
|
||||
static OffsetNumber offNullTuples[ MaxOffsetNumber ];
|
||||
int nOffNullTuples = 0;
|
||||
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
|
||||
GistSplitVector *v, GistEntryVector *entryvec, int attno)
|
||||
{
|
||||
int i;
|
||||
static OffsetNumber offNullTuples[MaxOffsetNumber];
|
||||
int nOffNullTuples = 0;
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
Datum datum;
|
||||
bool IsNull;
|
||||
for (i = 1; i <= len; i++)
|
||||
{
|
||||
Datum datum;
|
||||
bool IsNull;
|
||||
|
||||
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1])) {
|
||||
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1]))
|
||||
{
|
||||
gistSplitByInvalid(giststate, v, itup, len);
|
||||
return;
|
||||
}
|
||||
|
||||
datum = index_getattr(itup[i - 1], attno+1, giststate->tupdesc, &IsNull);
|
||||
datum = index_getattr(itup[i - 1], attno + 1, giststate->tupdesc, &IsNull);
|
||||
gistdentryinit(giststate, attno, &(entryvec->vector[i]),
|
||||
datum, r, page, i,
|
||||
FALSE, IsNull);
|
||||
if ( IsNull )
|
||||
offNullTuples[ nOffNullTuples++ ] = i;
|
||||
if (IsNull)
|
||||
offNullTuples[nOffNullTuples++] = i;
|
||||
}
|
||||
|
||||
v->spl_leftvalid = v->spl_rightvalid = true;
|
||||
|
||||
if ( nOffNullTuples == len ) {
|
||||
/*
|
||||
if (nOffNullTuples == len)
|
||||
{
|
||||
/*
|
||||
* Corner case: All keys in attno column are null, we should try to
|
||||
* split by keys in next column. It all keys in all columns
|
||||
* are NULL just split page half by half
|
||||
* split by keys in next column. It all keys in all columns are NULL
|
||||
* just split page half by half
|
||||
*/
|
||||
v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE;
|
||||
|
||||
if ( attno+1 == r->rd_att->natts )
|
||||
gistSplitHalf( &v->splitVector, len );
|
||||
else
|
||||
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno+1);
|
||||
} else if ( nOffNullTuples > 0 ) {
|
||||
int j=0;
|
||||
|
||||
/*
|
||||
* We don't want to mix NULLs and not-NULLs keys
|
||||
* on one page, so move nulls to right page
|
||||
if (attno + 1 == r->rd_att->natts)
|
||||
gistSplitHalf(&v->splitVector, len);
|
||||
else
|
||||
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
|
||||
}
|
||||
else if (nOffNullTuples > 0)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
/*
|
||||
* We don't want to mix NULLs and not-NULLs keys on one page, so move
|
||||
* nulls to right page
|
||||
*/
|
||||
v->splitVector.spl_right = offNullTuples;
|
||||
v->splitVector.spl_nright = nOffNullTuples;
|
||||
@ -471,61 +529,71 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
|
||||
|
||||
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
|
||||
v->splitVector.spl_nleft = 0;
|
||||
for(i = 1; i <= len; i++)
|
||||
if ( j<v->splitVector.spl_nright && offNullTuples[j] == i )
|
||||
for (i = 1; i <= len; i++)
|
||||
if (j < v->splitVector.spl_nright && offNullTuples[j] == i)
|
||||
j++;
|
||||
else
|
||||
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i;
|
||||
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
|
||||
|
||||
v->spl_equiv = NULL;
|
||||
gistunionsubkey(giststate, itup, v, attno);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* all keys are not-null
|
||||
*/
|
||||
entryvec->n = len+1;
|
||||
entryvec->n = len + 1;
|
||||
|
||||
if ( gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate) && attno+1 != r->rd_att->natts ) {
|
||||
if (gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate) && attno + 1 != r->rd_att->natts)
|
||||
{
|
||||
/*
|
||||
* Splitting on attno column is not optimized: there is a tuples which can be freely
|
||||
* left or right page, we will try to split page by
|
||||
* following columns
|
||||
* Splitting on attno column is not optimized: there is a tuples
|
||||
* which can be freely left or right page, we will try to split
|
||||
* page by following columns
|
||||
*/
|
||||
if ( v->spl_equiv == NULL ) {
|
||||
/* simple case: left and right keys for attno column are equial */
|
||||
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno+1);
|
||||
} else {
|
||||
if (v->spl_equiv == NULL)
|
||||
{
|
||||
/*
|
||||
* simple case: left and right keys for attno column are
|
||||
* equial
|
||||
*/
|
||||
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we should clean up vector from already distributed tuples */
|
||||
IndexTuple *newitup = (IndexTuple*)palloc((len + 1) * sizeof(IndexTuple));
|
||||
OffsetNumber *map = (OffsetNumber*)palloc((len + 1) * sizeof(IndexTuple));
|
||||
int newlen = 0;
|
||||
IndexTuple *newitup = (IndexTuple *) palloc((len + 1) * sizeof(IndexTuple));
|
||||
OffsetNumber *map = (OffsetNumber *) palloc((len + 1) * sizeof(IndexTuple));
|
||||
int newlen = 0;
|
||||
GIST_SPLITVEC backupSplit = v->splitVector;
|
||||
|
||||
for(i=0; i<len; i++)
|
||||
if ( v->spl_equiv[i+1] ) {
|
||||
map[ newlen ] = i+1;
|
||||
newitup[ newlen++ ] = itup[i];
|
||||
for (i = 0; i < len; i++)
|
||||
if (v->spl_equiv[i + 1])
|
||||
{
|
||||
map[newlen] = i + 1;
|
||||
newitup[newlen++] = itup[i];
|
||||
}
|
||||
|
||||
Assert( newlen>0 );
|
||||
Assert(newlen > 0);
|
||||
|
||||
backupSplit.spl_left = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len);
|
||||
memcpy( backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber)*v->splitVector.spl_nleft);
|
||||
backupSplit.spl_right = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len);
|
||||
memcpy( backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber)*v->splitVector.spl_nright);
|
||||
backupSplit.spl_left = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
|
||||
memcpy(backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber) * v->splitVector.spl_nleft);
|
||||
backupSplit.spl_right = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
|
||||
memcpy(backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber) * v->splitVector.spl_nright);
|
||||
|
||||
gistSplitByKey(r, page, newitup, newlen, giststate, v, entryvec, attno+1);
|
||||
gistSplitByKey(r, page, newitup, newlen, giststate, v, entryvec, attno + 1);
|
||||
|
||||
/* merge result of subsplit */
|
||||
for(i=0;i<v->splitVector.spl_nleft;i++)
|
||||
backupSplit.spl_left[ backupSplit.spl_nleft++ ] = map[ v->splitVector.spl_left[i]-1 ];
|
||||
for(i=0;i<v->splitVector.spl_nright;i++)
|
||||
backupSplit.spl_right[ backupSplit.spl_nright++ ] = map[ v->splitVector.spl_right[i]-1 ];
|
||||
for (i = 0; i < v->splitVector.spl_nleft; i++)
|
||||
backupSplit.spl_left[backupSplit.spl_nleft++] = map[v->splitVector.spl_left[i] - 1];
|
||||
for (i = 0; i < v->splitVector.spl_nright; i++)
|
||||
backupSplit.spl_right[backupSplit.spl_nright++] = map[v->splitVector.spl_right[i] - 1];
|
||||
|
||||
v->splitVector = backupSplit;
|
||||
/* reunion left and right datums */
|
||||
gistunionsubkey(giststate, itup, v, attno);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.19 2006/07/14 14:52:16 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.20 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
@ -22,8 +22,8 @@
|
||||
* static *S used for temrorary storage (saves stack and palloc() call)
|
||||
*/
|
||||
|
||||
static Datum attrS[INDEX_MAX_KEYS];
|
||||
static bool isnullS[INDEX_MAX_KEYS];
|
||||
static Datum attrS[INDEX_MAX_KEYS];
|
||||
static bool isnullS[INDEX_MAX_KEYS];
|
||||
|
||||
/*
|
||||
* Write itup vector to page, has no control of free space
|
||||
@ -57,14 +57,17 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
|
||||
bool
|
||||
gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
|
||||
{
|
||||
unsigned int size = freespace, deleted = 0;
|
||||
unsigned int size = freespace,
|
||||
deleted = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
|
||||
|
||||
if ( todelete != InvalidOffsetNumber ) {
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
|
||||
if (todelete != InvalidOffsetNumber)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
|
||||
|
||||
deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
|
||||
}
|
||||
|
||||
@ -72,11 +75,12 @@ gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size f
|
||||
}
|
||||
|
||||
bool
|
||||
gistfitpage(IndexTuple *itvec, int len) {
|
||||
int i;
|
||||
Size size=0;
|
||||
gistfitpage(IndexTuple *itvec, int len)
|
||||
{
|
||||
int i;
|
||||
Size size = 0;
|
||||
|
||||
for(i=0;i<len;i++)
|
||||
for (i = 0; i < len; i++)
|
||||
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
|
||||
|
||||
/* TODO: Consider fillfactor */
|
||||
@ -119,56 +123,64 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
|
||||
*/
|
||||
|
||||
IndexTupleData *
|
||||
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) {
|
||||
char *ptr, *ret;
|
||||
int i;
|
||||
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
|
||||
{
|
||||
char *ptr,
|
||||
*ret;
|
||||
int i;
|
||||
|
||||
*memlen = 0;
|
||||
|
||||
*memlen=0;
|
||||
|
||||
for (i = 0; i < veclen; i++)
|
||||
*memlen += IndexTupleSize(vec[i]);
|
||||
|
||||
ptr = ret = palloc(*memlen);
|
||||
|
||||
for (i = 0; i < veclen; i++) {
|
||||
for (i = 0; i < veclen; i++)
|
||||
{
|
||||
memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
|
||||
ptr += IndexTupleSize(vec[i]);
|
||||
}
|
||||
|
||||
return (IndexTupleData*)ret;
|
||||
return (IndexTupleData *) ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make unions of keys in IndexTuple vector, return FALSE if itvec contains
|
||||
* Make unions of keys in IndexTuple vector, return FALSE if itvec contains
|
||||
* invalid tuple. Resulting Datums aren't compressed.
|
||||
*/
|
||||
|
||||
bool
|
||||
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
|
||||
Datum *attr, bool *isnull ) {
|
||||
bool
|
||||
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
|
||||
Datum *attr, bool *isnull)
|
||||
{
|
||||
int i;
|
||||
GistEntryVector *evec;
|
||||
int attrsize;
|
||||
int attrsize;
|
||||
|
||||
evec = (GistEntryVector *) palloc( ( len + 2 ) * sizeof(GISTENTRY) + GEVHDRSZ);
|
||||
evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
|
||||
|
||||
for (i = startkey; i < giststate->tupdesc->natts; i++) {
|
||||
int j;
|
||||
for (i = startkey; i < giststate->tupdesc->natts; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
evec->n = 0;
|
||||
if ( !isnull[i] ) {
|
||||
gistentryinit( evec->vector[evec->n], attr[i],
|
||||
NULL, NULL, (OffsetNumber) 0,
|
||||
FALSE);
|
||||
if (!isnull[i])
|
||||
{
|
||||
gistentryinit(evec->vector[evec->n], attr[i],
|
||||
NULL, NULL, (OffsetNumber) 0,
|
||||
FALSE);
|
||||
evec->n++;
|
||||
}
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
Datum datum;
|
||||
bool IsNull;
|
||||
for (j = 0; j < len; j++)
|
||||
{
|
||||
Datum datum;
|
||||
bool IsNull;
|
||||
|
||||
if (GistTupleIsInvalid(itvec[j]))
|
||||
return FALSE; /* signals that union with invalid tuple => result is invalid */
|
||||
if (GistTupleIsInvalid(itvec[j]))
|
||||
return FALSE; /* signals that union with invalid tuple =>
|
||||
* result is invalid */
|
||||
|
||||
datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
|
||||
if (IsNull)
|
||||
@ -183,19 +195,23 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startke
|
||||
}
|
||||
|
||||
/* If this tuple vector was all NULLs, the union is NULL */
|
||||
if ( evec->n == 0 ) {
|
||||
if (evec->n == 0)
|
||||
{
|
||||
attr[i] = (Datum) 0;
|
||||
isnull[i] = TRUE;
|
||||
} else {
|
||||
if (evec->n == 1) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (evec->n == 1)
|
||||
{
|
||||
evec->n = 2;
|
||||
evec->vector[1] = evec->vector[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* Make union and store in attr array */
|
||||
attr[i] = FunctionCall2(&giststate->unionFn[i],
|
||||
PointerGetDatum(evec),
|
||||
PointerGetDatum(&attrsize));
|
||||
PointerGetDatum(evec),
|
||||
PointerGetDatum(&attrsize));
|
||||
|
||||
isnull[i] = FALSE;
|
||||
}
|
||||
@ -213,57 +229,67 @@ gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
|
||||
{
|
||||
memset(isnullS, TRUE, sizeof(bool) * giststate->tupdesc->natts);
|
||||
|
||||
if ( !gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS ) )
|
||||
return gist_form_invalid_tuple(InvalidBlockNumber);
|
||||
if (!gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS))
|
||||
return gist_form_invalid_tuple(InvalidBlockNumber);
|
||||
|
||||
return gistFormTuple(giststate, r, attrS, isnullS, false);
|
||||
return gistFormTuple(giststate, r, attrS, isnullS, false);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* makes union of two key
|
||||
*/
|
||||
void
|
||||
gistMakeUnionKey( GISTSTATE *giststate, int attno,
|
||||
GISTENTRY *entry1, bool isnull1,
|
||||
GISTENTRY *entry2, bool isnull2,
|
||||
Datum *dst, bool *dstisnull ) {
|
||||
gistMakeUnionKey(GISTSTATE *giststate, int attno,
|
||||
GISTENTRY *entry1, bool isnull1,
|
||||
GISTENTRY *entry2, bool isnull2,
|
||||
Datum *dst, bool *dstisnull)
|
||||
{
|
||||
|
||||
int dstsize;
|
||||
int dstsize;
|
||||
|
||||
static char storage[ 2 * sizeof(GISTENTRY) + GEVHDRSZ ];
|
||||
GistEntryVector *evec = (GistEntryVector*)storage;
|
||||
static char storage[2 * sizeof(GISTENTRY) + GEVHDRSZ];
|
||||
GistEntryVector *evec = (GistEntryVector *) storage;
|
||||
|
||||
evec->n = 2;
|
||||
|
||||
if ( isnull1 && isnull2 ) {
|
||||
if (isnull1 && isnull2)
|
||||
{
|
||||
*dstisnull = TRUE;
|
||||
*dst = (Datum)0;
|
||||
} else {
|
||||
if ( isnull1 == FALSE && isnull2 == FALSE ) {
|
||||
*dst = (Datum) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isnull1 == FALSE && isnull2 == FALSE)
|
||||
{
|
||||
evec->vector[0] = *entry1;
|
||||
evec->vector[1] = *entry2;
|
||||
} else if ( isnull1 == FALSE ) {
|
||||
}
|
||||
else if (isnull1 == FALSE)
|
||||
{
|
||||
evec->vector[0] = *entry1;
|
||||
evec->vector[1] = *entry1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
evec->vector[0] = *entry2;
|
||||
evec->vector[1] = *entry2;
|
||||
}
|
||||
|
||||
*dstisnull = FALSE;
|
||||
*dst = FunctionCall2(&giststate->unionFn[attno],
|
||||
PointerGetDatum(evec),
|
||||
PointerGetDatum(&dstsize));
|
||||
PointerGetDatum(evec),
|
||||
PointerGetDatum(&dstsize));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b) {
|
||||
bool result;
|
||||
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
|
||||
{
|
||||
bool result;
|
||||
|
||||
FunctionCall3(&giststate->equalFn[attno],
|
||||
a, b,
|
||||
PointerGetDatum(&result));
|
||||
a, b,
|
||||
PointerGetDatum(&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -309,22 +335,24 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis
|
||||
gistDeCompressAtt(giststate, r, addtup, NULL,
|
||||
(OffsetNumber) 0, addentries, addisnull);
|
||||
|
||||
for(i = 0; i < r->rd_att->natts; i++) {
|
||||
gistMakeUnionKey( giststate, i,
|
||||
oldentries + i, oldisnull[i],
|
||||
addentries + i, addisnull[i],
|
||||
attrS + i, isnullS + i );
|
||||
for (i = 0; i < r->rd_att->natts; i++)
|
||||
{
|
||||
gistMakeUnionKey(giststate, i,
|
||||
oldentries + i, oldisnull[i],
|
||||
addentries + i, addisnull[i],
|
||||
attrS + i, isnullS + i);
|
||||
|
||||
if ( neednew )
|
||||
if (neednew)
|
||||
/* we already need new key, so we can skip check */
|
||||
continue;
|
||||
|
||||
if ( isnullS[i] )
|
||||
if (isnullS[i])
|
||||
/* union of key may be NULL if and only if both keys are NULL */
|
||||
continue;
|
||||
|
||||
if ( !addisnull[i] ) {
|
||||
if ( oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i])==false )
|
||||
if (!addisnull[i])
|
||||
{
|
||||
if (oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i]) == false)
|
||||
neednew = true;
|
||||
}
|
||||
}
|
||||
@ -363,8 +391,8 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
|
||||
it, NULL, (OffsetNumber) 0,
|
||||
identry, isnull);
|
||||
|
||||
Assert( maxoff >= FirstOffsetNumber );
|
||||
Assert( !GistPageIsLeaf(p) );
|
||||
Assert(maxoff >= FirstOffsetNumber);
|
||||
Assert(!GistPageIsLeaf(p));
|
||||
|
||||
for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
|
||||
{
|
||||
@ -484,7 +512,7 @@ gistFormTuple(GISTSTATE *giststate, Relation r,
|
||||
{
|
||||
gistcentryinit(giststate, i, ¢ry[i], attdata[i],
|
||||
r, NULL, (OffsetNumber) 0,
|
||||
newValues,
|
||||
newValues,
|
||||
FALSE);
|
||||
compatt[i] = centry[i].key;
|
||||
}
|
||||
@ -500,18 +528,19 @@ gistpenalty(GISTSTATE *giststate, int attno,
|
||||
GISTENTRY *orig, bool isNullOrig,
|
||||
GISTENTRY *add, bool isNullAdd)
|
||||
{
|
||||
float penalty = 0.0;
|
||||
float penalty = 0.0;
|
||||
|
||||
if ( giststate->penaltyFn[attno].fn_strict==FALSE || ( isNullOrig == FALSE && isNullAdd == FALSE ) )
|
||||
if (giststate->penaltyFn[attno].fn_strict == FALSE || (isNullOrig == FALSE && isNullAdd == FALSE))
|
||||
FunctionCall3(&giststate->penaltyFn[attno],
|
||||
PointerGetDatum(orig),
|
||||
PointerGetDatum(add),
|
||||
PointerGetDatum(&penalty));
|
||||
else if ( isNullOrig && isNullAdd )
|
||||
else if (isNullOrig && isNullAdd)
|
||||
penalty = 0.0;
|
||||
else
|
||||
penalty = 1e10; /* try to prevent to mix null and non-null value */
|
||||
|
||||
penalty = 1e10; /* try to prevent to mix null and non-null
|
||||
* value */
|
||||
|
||||
return penalty;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.27 2006/09/21 20:31:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.28 2006/10/04 00:29:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -45,19 +45,24 @@ typedef struct
|
||||
} ArrayTuple;
|
||||
|
||||
/*
|
||||
* Make union of keys on page
|
||||
* Make union of keys on page
|
||||
*/
|
||||
static IndexTuple
|
||||
PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
|
||||
Page page = BufferGetPage( buffer );
|
||||
PageMakeUnionKey(GistVacuum *gv, Buffer buffer)
|
||||
{
|
||||
Page page = BufferGetPage(buffer);
|
||||
IndexTuple *vec,
|
||||
tmp, res;
|
||||
tmp,
|
||||
res;
|
||||
int veclen = 0;
|
||||
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
||||
|
||||
vec = gistextractpage(page, &veclen);
|
||||
/* we call gistunion() in temprorary context because user-defined functions called in gistunion()
|
||||
may do not free all memory */
|
||||
|
||||
/*
|
||||
* we call gistunion() in temprorary context because user-defined
|
||||
* functions called in gistunion() may do not free all memory
|
||||
*/
|
||||
tmp = gistunion(gv->index, vec, veclen, &(gv->giststate));
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
|
||||
@ -73,21 +78,25 @@ PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
|
||||
}
|
||||
|
||||
static void
|
||||
gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
|
||||
{
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
|
||||
buffer = ReadBuffer(gv->index, blkno);
|
||||
LockBuffer(buffer, GIST_EXCLUSIVE);
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
if ( !GistPageIsLeaf(page) ) {
|
||||
int i;
|
||||
if (!GistPageIsLeaf(page))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i)) {
|
||||
ItemId iid = PageGetItemId(page, i);
|
||||
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
|
||||
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
|
||||
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i))
|
||||
{
|
||||
ItemId iid = PageGetItemId(page, i);
|
||||
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
|
||||
|
||||
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +112,7 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
|
||||
{
|
||||
XLogRecData rdata[2];
|
||||
XLogRecPtr recptr;
|
||||
gistxlogPageDelete xlrec;
|
||||
gistxlogPageDelete xlrec;
|
||||
|
||||
xlrec.node = gv->index->rd_node;
|
||||
xlrec.blkno = blkno;
|
||||
@ -125,31 +134,34 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
|
||||
}
|
||||
else
|
||||
PageSetLSN(page, XLogRecPtrForTemp);
|
||||
|
||||
|
||||
END_CRIT_SECTION();
|
||||
|
||||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
static Page
|
||||
GistPageGetCopyPage( Page page ) {
|
||||
Size pageSize = PageGetPageSize( page );
|
||||
Page tmppage;
|
||||
static Page
|
||||
GistPageGetCopyPage(Page page)
|
||||
{
|
||||
Size pageSize = PageGetPageSize(page);
|
||||
Page tmppage;
|
||||
|
||||
tmppage=(Page)palloc( pageSize );
|
||||
memcpy( tmppage, page, pageSize );
|
||||
tmppage = (Page) palloc(pageSize);
|
||||
memcpy(tmppage, page, pageSize);
|
||||
|
||||
return tmppage;
|
||||
}
|
||||
|
||||
static ArrayTuple
|
||||
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon) {
|
||||
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon)
|
||||
{
|
||||
ArrayTuple res = {NULL, 0, false};
|
||||
IndexTuple *vec;
|
||||
SplitedPageLayout *dist = NULL,
|
||||
*ptr;
|
||||
int i, veclen=0;
|
||||
BlockNumber blkno = BufferGetBlockNumber(buffer);
|
||||
*ptr;
|
||||
int i,
|
||||
veclen = 0;
|
||||
BlockNumber blkno = BufferGetBlockNumber(buffer);
|
||||
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
||||
|
||||
vec = gistextractpage(tempPage, &veclen);
|
||||
@ -158,67 +170,73 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
|
||||
|
||||
MemoryContextSwitchTo(oldCtx);
|
||||
|
||||
if (blkno != GIST_ROOT_BLKNO) {
|
||||
if (blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
/* if non-root split then we should not allocate new buffer */
|
||||
dist->buffer = buffer;
|
||||
dist->page = tempPage;
|
||||
/* during vacuum we never split leaf page */
|
||||
GistPageGetOpaque(dist->page)->flags = 0;
|
||||
} else
|
||||
}
|
||||
else
|
||||
pfree(tempPage);
|
||||
|
||||
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple) * veclen);
|
||||
res.ituplen = 0;
|
||||
|
||||
/* make new pages and fills them */
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
char *data;
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
char *data;
|
||||
|
||||
if ( ptr->buffer == InvalidBuffer ) {
|
||||
ptr->buffer = gistNewBuffer( gv->index );
|
||||
GISTInitBuffer( ptr->buffer, 0 );
|
||||
if (ptr->buffer == InvalidBuffer)
|
||||
{
|
||||
ptr->buffer = gistNewBuffer(gv->index);
|
||||
GISTInitBuffer(ptr->buffer, 0);
|
||||
ptr->page = BufferGetPage(ptr->buffer);
|
||||
}
|
||||
ptr->block.blkno = BufferGetBlockNumber( ptr->buffer );
|
||||
ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
|
||||
|
||||
data = (char*)(ptr->list);
|
||||
for(i=0;i<ptr->block.num;i++) {
|
||||
if ( PageAddItem(ptr->page, (Item)data, IndexTupleSize((IndexTuple)data), i+FirstOffsetNumber, LP_USED) == InvalidOffsetNumber )
|
||||
data = (char *) (ptr->list);
|
||||
for (i = 0; i < ptr->block.num; i++)
|
||||
{
|
||||
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(gv->index));
|
||||
data += IndexTupleSize((IndexTuple)data);
|
||||
data += IndexTupleSize((IndexTuple) data);
|
||||
}
|
||||
|
||||
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
|
||||
res.itup[ res.ituplen ] = (IndexTuple)palloc(IndexTupleSize(ptr->itup));
|
||||
memcpy( res.itup[ res.ituplen ], ptr->itup, IndexTupleSize(ptr->itup) );
|
||||
res.itup[res.ituplen] = (IndexTuple) palloc(IndexTupleSize(ptr->itup));
|
||||
memcpy(res.itup[res.ituplen], ptr->itup, IndexTupleSize(ptr->itup));
|
||||
res.ituplen++;
|
||||
}
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
for (ptr = dist; ptr; ptr = ptr->next) {
|
||||
for (ptr = dist; ptr; ptr = ptr->next)
|
||||
{
|
||||
MarkBufferDirty(ptr->buffer);
|
||||
GistPageGetOpaque(ptr->page)->rightlink = InvalidBlockNumber;
|
||||
}
|
||||
|
||||
/* restore splitted non-root page */
|
||||
if (blkno != GIST_ROOT_BLKNO) {
|
||||
PageRestoreTempPage( dist->page, BufferGetPage( dist->buffer ) );
|
||||
dist->page = BufferGetPage( dist->buffer );
|
||||
if (blkno != GIST_ROOT_BLKNO)
|
||||
{
|
||||
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
|
||||
dist->page = BufferGetPage(dist->buffer);
|
||||
}
|
||||
|
||||
if (!gv->index->rd_istemp)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData *rdata;
|
||||
ItemPointerData key; /* set key for incomplete
|
||||
* insert */
|
||||
ItemPointerData key; /* set key for incomplete insert */
|
||||
char *xlinfo;
|
||||
|
||||
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
|
||||
|
||||
rdata = formSplitRdata(gv->index->rd_node, blkno,
|
||||
false, &key, dist);
|
||||
false, &key, dist);
|
||||
xlinfo = rdata->data;
|
||||
|
||||
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
|
||||
@ -241,13 +259,12 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
|
||||
{
|
||||
/* we must keep the buffer pin on the head page */
|
||||
if (BufferGetBlockNumber(ptr->buffer) != blkno)
|
||||
UnlockReleaseBuffer( ptr->buffer );
|
||||
UnlockReleaseBuffer(ptr->buffer);
|
||||
}
|
||||
|
||||
if (blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
ItemPointerData key; /* set key for incomplete
|
||||
* insert */
|
||||
ItemPointerData key; /* set key for incomplete insert */
|
||||
|
||||
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
|
||||
|
||||
@ -266,7 +283,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
{
|
||||
ArrayTuple res = {NULL, 0, false};
|
||||
Buffer buffer;
|
||||
Page page, tempPage = NULL;
|
||||
Page page,
|
||||
tempPage = NULL;
|
||||
OffsetNumber i,
|
||||
maxoff;
|
||||
ItemId iid;
|
||||
@ -278,7 +296,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
*addon = NULL;
|
||||
bool needwrite = false;
|
||||
OffsetNumber offToDelete[MaxOffsetNumber];
|
||||
BlockNumber blkToDelete[MaxOffsetNumber];
|
||||
BlockNumber blkToDelete[MaxOffsetNumber];
|
||||
ItemPointerData *completed = NULL;
|
||||
int ncompleted = 0,
|
||||
lencompleted = 16;
|
||||
@ -322,7 +340,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
if (chldtuple.ituplen || chldtuple.emptypage)
|
||||
{
|
||||
/* update tuple or/and inserts new */
|
||||
if ( chldtuple.emptypage )
|
||||
if (chldtuple.emptypage)
|
||||
blkToDelete[nBlkToDelete++] = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
|
||||
offToDelete[nOffToDelete++] = i;
|
||||
PageIndexTupleDelete(tempPage, i);
|
||||
@ -333,7 +351,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
if (chldtuple.ituplen)
|
||||
{
|
||||
|
||||
Assert( chldtuple.emptypage == false );
|
||||
Assert(chldtuple.emptypage == false);
|
||||
while (curlenaddon + chldtuple.ituplen >= lenaddon)
|
||||
{
|
||||
lenaddon *= 2;
|
||||
@ -367,56 +385,63 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert( maxoff == PageGetMaxOffsetNumber(tempPage) );
|
||||
|
||||
Assert(maxoff == PageGetMaxOffsetNumber(tempPage));
|
||||
|
||||
if (curlenaddon)
|
||||
{
|
||||
/* insert updated tuples */
|
||||
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0)) {
|
||||
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
|
||||
{
|
||||
/* there is no space on page to insert tuples */
|
||||
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
|
||||
tempPage=NULL; /* vacuumSplitPage() free tempPage */
|
||||
needwrite = needunion = false; /* gistSplit already forms unions and writes pages */
|
||||
} else
|
||||
tempPage = NULL; /* vacuumSplitPage() free tempPage */
|
||||
needwrite = needunion = false; /* gistSplit already forms
|
||||
* unions and writes pages */
|
||||
}
|
||||
else
|
||||
/* enough free space */
|
||||
gistfillbuffer(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If page is empty, we should remove pointer to it before
|
||||
* deleting page (except root)
|
||||
/*
|
||||
* If page is empty, we should remove pointer to it before deleting page
|
||||
* (except root)
|
||||
*/
|
||||
|
||||
if ( blkno != GIST_ROOT_BLKNO && ( PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage)) ) ) {
|
||||
if (blkno != GIST_ROOT_BLKNO && (PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage))))
|
||||
{
|
||||
/*
|
||||
* New version of page is empty, so leave it unchanged,
|
||||
* upper call will mark our page as deleted.
|
||||
* In case of page split we never will be here...
|
||||
* New version of page is empty, so leave it unchanged, upper call
|
||||
* will mark our page as deleted. In case of page split we never will
|
||||
* be here...
|
||||
*
|
||||
* If page was empty it can't become non-empty during processing
|
||||
* If page was empty it can't become non-empty during processing
|
||||
*/
|
||||
res.emptypage = true;
|
||||
UnlockReleaseBuffer(buffer);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write page and remove its childs if it need */
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
if ( tempPage && needwrite ) {
|
||||
if (tempPage && needwrite)
|
||||
{
|
||||
PageRestoreTempPage(tempPage, page);
|
||||
tempPage = NULL;
|
||||
}
|
||||
|
||||
/* Empty index */
|
||||
if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO )
|
||||
/* Empty index */
|
||||
if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
needwrite = true;
|
||||
GistPageSetLeaf(page);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (needwrite)
|
||||
{
|
||||
MarkBufferDirty(buffer);
|
||||
@ -446,7 +471,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
|
||||
END_CRIT_SECTION();
|
||||
|
||||
if ( needunion && !PageIsEmpty(page) )
|
||||
if (needunion && !PageIsEmpty(page))
|
||||
{
|
||||
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple));
|
||||
res.ituplen = 1;
|
||||
@ -456,7 +481,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||
UnlockReleaseBuffer(buffer);
|
||||
|
||||
/* delete empty children, now we havn't any links to pointed subtrees */
|
||||
for(i=0;i<nBlkToDelete;i++)
|
||||
for (i = 0; i < nBlkToDelete; i++)
|
||||
gistDeleteSubtree(gv, blkToDelete[i]);
|
||||
|
||||
if (ncompleted && !gv->index->rd_istemp)
|
||||
@ -506,9 +531,10 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
|
||||
/* use heap's tuple count */
|
||||
Assert(info->num_heap_tuples >= 0);
|
||||
stats->std.num_index_tuples = info->num_heap_tuples;
|
||||
|
||||
/*
|
||||
* XXX the above is wrong if index is partial. Would it be OK to
|
||||
* just return NULL, or is there work we must do below?
|
||||
* XXX the above is wrong if index is partial. Would it be OK to just
|
||||
* return NULL, or is there work we must do below?
|
||||
*/
|
||||
}
|
||||
|
||||
@ -545,8 +571,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
|
||||
RelationGetRelationName(rel))));
|
||||
|
||||
/*
|
||||
* If vacuum full, we already have exclusive lock on the index.
|
||||
* Otherwise, need lock unless it's local to this backend.
|
||||
* If vacuum full, we already have exclusive lock on the index. Otherwise,
|
||||
* need lock unless it's local to this backend.
|
||||
*/
|
||||
if (info->vacuum_full)
|
||||
needLock = false;
|
||||
@ -725,7 +751,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
|
||||
|
||||
if (callback(&(idxtuple->t_tid), callback_state))
|
||||
{
|
||||
todelete[ntodelete] = i-ntodelete;
|
||||
todelete[ntodelete] = i - ntodelete;
|
||||
ntodelete++;
|
||||
stats->std.tuples_removed += 1;
|
||||
}
|
||||
@ -739,7 +765,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
|
||||
|
||||
MarkBufferDirty(buffer);
|
||||
|
||||
for(i=0;i<ntodelete;i++)
|
||||
for (i = 0; i < ntodelete; i++)
|
||||
PageIndexTupleDelete(page, todelete[i]);
|
||||
GistMarkTuplesDeleted(page);
|
||||
|
||||
@ -750,7 +776,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
|
||||
gistxlogPageUpdate *xlinfo;
|
||||
|
||||
rdata = formUpdateRdata(rel->rd_node, buffer,
|
||||
todelete, ntodelete,
|
||||
todelete, ntodelete,
|
||||
NULL, 0,
|
||||
NULL);
|
||||
xlinfo = (gistxlogPageUpdate *) rdata->next->data;
|
||||
|
@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.23 2006/08/07 16:57:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.24 2006/10/04 00:29:48 momjian Exp $
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
@ -55,11 +55,11 @@ typedef struct gistIncompleteInsert
|
||||
|
||||
|
||||
static MemoryContext opCtx; /* working memory for operations */
|
||||
static MemoryContext insertCtx; /* holds incomplete_inserts list */
|
||||
static MemoryContext insertCtx; /* holds incomplete_inserts list */
|
||||
static List *incomplete_inserts;
|
||||
|
||||
|
||||
#define ItemPointerEQ(a, b) \
|
||||
#define ItemPointerEQ(a, b) \
|
||||
( ItemPointerGetOffsetNumber(a) == ItemPointerGetOffsetNumber(b) && \
|
||||
ItemPointerGetBlockNumber (a) == ItemPointerGetBlockNumber(b) )
|
||||
|
||||
@ -72,8 +72,9 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
||||
MemoryContext oldCxt;
|
||||
gistIncompleteInsert *ninsert;
|
||||
|
||||
if ( !ItemPointerIsValid(&key) )
|
||||
/*
|
||||
if (!ItemPointerIsValid(&key))
|
||||
|
||||
/*
|
||||
* if key is null then we should not store insertion as incomplete,
|
||||
* because it's a vacuum operation..
|
||||
*/
|
||||
@ -108,8 +109,8 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
||||
|
||||
/*
|
||||
* Stick the new incomplete insert onto the front of the list, not the
|
||||
* back. This is so that gist_xlog_cleanup will process incompletions
|
||||
* in last-in-first-out order.
|
||||
* back. This is so that gist_xlog_cleanup will process incompletions in
|
||||
* last-in-first-out order.
|
||||
*/
|
||||
incomplete_inserts = lcons(ninsert, incomplete_inserts);
|
||||
|
||||
@ -121,10 +122,10 @@ forgetIncompleteInsert(RelFileNode node, ItemPointerData key)
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
if ( !ItemPointerIsValid(&key) )
|
||||
if (!ItemPointerIsValid(&key))
|
||||
return;
|
||||
|
||||
if (incomplete_inserts==NIL)
|
||||
if (incomplete_inserts == NIL)
|
||||
return;
|
||||
|
||||
foreach(l, incomplete_inserts)
|
||||
@ -241,9 +242,12 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
|
||||
if (GistPageIsLeaf(page) && xlrec.len == 0 && xlrec.data->ntodelete == 0)
|
||||
GistClearTuplesDeleted(page);
|
||||
|
||||
if ( !GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO )
|
||||
/* all links on non-leaf root page was deleted by vacuum full,
|
||||
so root page becomes a leaf */
|
||||
if (!GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO)
|
||||
|
||||
/*
|
||||
* all links on non-leaf root page was deleted by vacuum full, so root
|
||||
* page becomes a leaf
|
||||
*/
|
||||
GistPageSetLeaf(page);
|
||||
|
||||
GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
|
||||
@ -432,11 +436,11 @@ static void
|
||||
out_target(StringInfo buf, RelFileNode node, ItemPointerData key)
|
||||
{
|
||||
appendStringInfo(buf, "rel %u/%u/%u",
|
||||
node.spcNode, node.dbNode, node.relNode);
|
||||
if ( ItemPointerIsValid( &key ) )
|
||||
node.spcNode, node.dbNode, node.relNode);
|
||||
if (ItemPointerIsValid(&key))
|
||||
appendStringInfo(buf, "; tid %u/%u",
|
||||
ItemPointerGetBlockNumber(&key),
|
||||
ItemPointerGetOffsetNumber(&key));
|
||||
ItemPointerGetBlockNumber(&key),
|
||||
ItemPointerGetOffsetNumber(&key));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -450,8 +454,8 @@ static void
|
||||
out_gistxlogPageDelete(StringInfo buf, gistxlogPageDelete *xlrec)
|
||||
{
|
||||
appendStringInfo(buf, "page_delete: rel %u/%u/%u; blkno %u",
|
||||
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
|
||||
xlrec->blkno);
|
||||
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
|
||||
xlrec->blkno);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -460,7 +464,7 @@ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
|
||||
appendStringInfo(buf, "page_split: ");
|
||||
out_target(buf, xlrec->node, xlrec->key);
|
||||
appendStringInfo(buf, "; block number %u splits to %d pages",
|
||||
xlrec->origblkno, xlrec->npage);
|
||||
xlrec->origblkno, xlrec->npage);
|
||||
}
|
||||
|
||||
void
|
||||
@ -486,15 +490,15 @@ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
|
||||
break;
|
||||
case XLOG_GIST_CREATE_INDEX:
|
||||
appendStringInfo(buf, "create_index: rel %u/%u/%u",
|
||||
((RelFileNode *) rec)->spcNode,
|
||||
((RelFileNode *) rec)->dbNode,
|
||||
((RelFileNode *) rec)->relNode);
|
||||
((RelFileNode *) rec)->spcNode,
|
||||
((RelFileNode *) rec)->dbNode,
|
||||
((RelFileNode *) rec)->relNode);
|
||||
break;
|
||||
case XLOG_GIST_INSERT_COMPLETE:
|
||||
appendStringInfo(buf, "complete_insert: rel %u/%u/%u",
|
||||
((gistxlogInsertComplete *) rec)->node.spcNode,
|
||||
((gistxlogInsertComplete *) rec)->node.dbNode,
|
||||
((gistxlogInsertComplete *) rec)->node.relNode);
|
||||
((gistxlogInsertComplete *) rec)->node.spcNode,
|
||||
((gistxlogInsertComplete *) rec)->node.dbNode,
|
||||
((gistxlogInsertComplete *) rec)->node.relNode);
|
||||
break;
|
||||
default:
|
||||
appendStringInfo(buf, "unknown gist op code %u", info);
|
||||
@ -547,22 +551,25 @@ gistxlogFindPath(Relation index, gistIncompleteInsert *insert)
|
||||
elog(ERROR, "lost parent for block %u", insert->origblkno);
|
||||
}
|
||||
|
||||
static SplitedPageLayout*
|
||||
gistMakePageLayout(Buffer *buffers, int nbuffers) {
|
||||
SplitedPageLayout *res=NULL, *resptr;
|
||||
static SplitedPageLayout *
|
||||
gistMakePageLayout(Buffer *buffers, int nbuffers)
|
||||
{
|
||||
SplitedPageLayout *res = NULL,
|
||||
*resptr;
|
||||
|
||||
while( nbuffers-- > 0 ) {
|
||||
Page page = BufferGetPage( buffers[ nbuffers ] );
|
||||
IndexTuple* vec;
|
||||
int veclen;
|
||||
while (nbuffers-- > 0)
|
||||
{
|
||||
Page page = BufferGetPage(buffers[nbuffers]);
|
||||
IndexTuple *vec;
|
||||
int veclen;
|
||||
|
||||
resptr = (SplitedPageLayout*)palloc0( sizeof(SplitedPageLayout) );
|
||||
resptr = (SplitedPageLayout *) palloc0(sizeof(SplitedPageLayout));
|
||||
|
||||
resptr->block.blkno = BufferGetBlockNumber( buffers[ nbuffers ] );
|
||||
resptr->block.num = PageGetMaxOffsetNumber( page );
|
||||
resptr->block.blkno = BufferGetBlockNumber(buffers[nbuffers]);
|
||||
resptr->block.num = PageGetMaxOffsetNumber(page);
|
||||
|
||||
vec = gistextractpage( page, &veclen );
|
||||
resptr->list = gistfillitupvec( vec, veclen, &(resptr->lenlist) );
|
||||
vec = gistextractpage(page, &veclen);
|
||||
resptr->list = gistfillitupvec(vec, veclen, &(resptr->lenlist));
|
||||
|
||||
resptr->next = res;
|
||||
res = resptr;
|
||||
@ -580,7 +587,7 @@ gistMakePageLayout(Buffer *buffers, int nbuffers) {
|
||||
* Note that we assume the index is now in a valid state, except for the
|
||||
* unfinished insertion. In particular it's safe to invoke gistFindPath();
|
||||
* there shouldn't be any garbage pages for it to run into.
|
||||
*
|
||||
*
|
||||
* To complete insert we can't use basic insertion algorithm because
|
||||
* during insertion we can't call user-defined support functions of opclass.
|
||||
* So, we insert 'invalid' tuples without real key and do it by separate algorithm.
|
||||
@ -607,7 +614,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
itup[i] = gist_form_invalid_tuple(insert->blkno[i]);
|
||||
|
||||
/*
|
||||
* any insertion of itup[] should make LOG message about
|
||||
* any insertion of itup[] should make LOG message about
|
||||
*/
|
||||
|
||||
if (insert->origblkno == GIST_ROOT_BLKNO)
|
||||
@ -626,7 +633,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
Buffer *buffers;
|
||||
Page *pages;
|
||||
int numbuffer;
|
||||
OffsetNumber *todelete;
|
||||
OffsetNumber *todelete;
|
||||
|
||||
/* construct path */
|
||||
gistxlogFindPath(index, insert);
|
||||
@ -642,21 +649,22 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
int j,
|
||||
k,
|
||||
pituplen = 0;
|
||||
XLogRecData *rdata;
|
||||
XLogRecPtr recptr;
|
||||
Buffer tempbuffer = InvalidBuffer;
|
||||
int ntodelete = 0;
|
||||
XLogRecData *rdata;
|
||||
XLogRecPtr recptr;
|
||||
Buffer tempbuffer = InvalidBuffer;
|
||||
int ntodelete = 0;
|
||||
|
||||
numbuffer = 1;
|
||||
buffers[0] = ReadBuffer(index, insert->path[i]);
|
||||
LockBuffer(buffers[0], GIST_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* we check buffer, because we restored page earlier
|
||||
*/
|
||||
gistcheckpage(index, buffers[0]);
|
||||
|
||||
pages[0] = BufferGetPage(buffers[0]);
|
||||
Assert( !GistPageIsLeaf(pages[0]) );
|
||||
Assert(!GistPageIsLeaf(pages[0]));
|
||||
|
||||
pituplen = PageGetMaxOffsetNumber(pages[0]);
|
||||
|
||||
@ -678,12 +686,12 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
}
|
||||
}
|
||||
|
||||
if ( ntodelete == 0 )
|
||||
elog(PANIC,"gistContinueInsert: can't find pointer to page(s)");
|
||||
if (ntodelete == 0)
|
||||
elog(PANIC, "gistContinueInsert: can't find pointer to page(s)");
|
||||
|
||||
/*
|
||||
* we check space with subtraction only first tuple to delete, hope,
|
||||
* that wiil be enough space....
|
||||
* we check space with subtraction only first tuple to delete,
|
||||
* hope, that wiil be enough space....
|
||||
*/
|
||||
|
||||
if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
|
||||
@ -699,7 +707,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
|
||||
if (BufferGetBlockNumber(buffers[0]) == GIST_ROOT_BLKNO)
|
||||
{
|
||||
Buffer tmp;
|
||||
Buffer tmp;
|
||||
|
||||
/*
|
||||
* we split root, just copy content from root to new page
|
||||
@ -713,44 +721,48 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
/* fill new page, root will be changed later */
|
||||
tempbuffer = ReadBuffer(index, P_NEW);
|
||||
LockBuffer(tempbuffer, GIST_EXCLUSIVE);
|
||||
memcpy( BufferGetPage(tempbuffer), pages[0], BufferGetPageSize(tempbuffer) );
|
||||
memcpy(BufferGetPage(tempbuffer), pages[0], BufferGetPageSize(tempbuffer));
|
||||
|
||||
/* swap buffers[0] (was root) and temp buffer */
|
||||
tmp = buffers[0];
|
||||
buffers[0] = tempbuffer;
|
||||
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO, it is still unchanged */
|
||||
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO,
|
||||
* it is still unchanged */
|
||||
|
||||
pages[0] = BufferGetPage(buffers[0]);
|
||||
}
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
for(j=0;j<ntodelete;j++)
|
||||
for (j = 0; j < ntodelete; j++)
|
||||
PageIndexTupleDelete(pages[0], todelete[j]);
|
||||
|
||||
rdata = formSplitRdata(index->rd_node, insert->path[i],
|
||||
false, &(insert->key),
|
||||
gistMakePageLayout( buffers, numbuffer ) );
|
||||
false, &(insert->key),
|
||||
gistMakePageLayout(buffers, numbuffer));
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
START_CRIT_SECTION();
|
||||
|
||||
for(j=0;j<ntodelete;j++)
|
||||
for (j = 0; j < ntodelete; j++)
|
||||
PageIndexTupleDelete(pages[0], todelete[j]);
|
||||
gistfillbuffer(index, pages[0], itup, lenitup, InvalidOffsetNumber);
|
||||
|
||||
rdata = formUpdateRdata(index->rd_node, buffers[0],
|
||||
todelete, ntodelete,
|
||||
itup, lenitup, &(insert->key));
|
||||
rdata = formUpdateRdata(index->rd_node, buffers[0],
|
||||
todelete, ntodelete,
|
||||
itup, lenitup, &(insert->key));
|
||||
}
|
||||
|
||||
/*
|
||||
* use insert->key as mark for completion of insert (form*Rdata() above)
|
||||
* for following possible replays
|
||||
/*
|
||||
* use insert->key as mark for completion of insert (form*Rdata()
|
||||
* above) for following possible replays
|
||||
*/
|
||||
|
||||
/* write pages, we should mark it dirty befor XLogInsert() */
|
||||
for (j = 0; j < numbuffer; j++) {
|
||||
for (j = 0; j < numbuffer; j++)
|
||||
{
|
||||
GistPageGetOpaque(pages[j])->rightlink = InvalidBlockNumber;
|
||||
MarkBufferDirty(buffers[j]);
|
||||
}
|
||||
@ -764,12 +776,14 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
END_CRIT_SECTION();
|
||||
|
||||
lenitup = numbuffer;
|
||||
for (j = 0; j < numbuffer; j++) {
|
||||
for (j = 0; j < numbuffer; j++)
|
||||
{
|
||||
itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
|
||||
UnlockReleaseBuffer(buffers[j]);
|
||||
}
|
||||
|
||||
if ( tempbuffer != InvalidBuffer ) {
|
||||
if (tempbuffer != InvalidBuffer)
|
||||
{
|
||||
/*
|
||||
* it was a root split, so fill it by new values
|
||||
*/
|
||||
@ -780,9 +794,9 @@ gistContinueInsert(gistIncompleteInsert *insert)
|
||||
}
|
||||
|
||||
ereport(LOG,
|
||||
(errmsg("index %u/%u/%u needs VACUUM FULL or REINDEX to finish crash recovery",
|
||||
(errmsg("index %u/%u/%u needs VACUUM FULL or REINDEX to finish crash recovery",
|
||||
insert->node.spcNode, insert->node.dbNode, insert->node.relNode),
|
||||
errdetail("Incomplete insertion detected during crash replay.")));
|
||||
errdetail("Incomplete insertion detected during crash replay.")));
|
||||
}
|
||||
|
||||
void
|
||||
|
Reference in New Issue
Block a user