diff --git a/src/backend/access/gist/gistsplit.c b/src/backend/access/gist/gistsplit.c index a96b881cf1..fd35dd2e52 100644 --- a/src/backend/access/gist/gistsplit.c +++ b/src/backend/access/gist/gistsplit.c @@ -19,21 +19,21 @@ typedef struct { - Datum *attr; - int len; OffsetNumber *entries; + int len; + Datum *attr; bool *isnull; bool *equiv; } GistSplitUnion; /* - * Forms unions of subkeys after page split, but - * uses only tuples that aren't in groups of equivalent tuples + * Form unions of subkeys after a page split, ignoring any tuples + * that are marked in gsvp->equiv[] */ static void gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec, - GistSplitUnion *gsvp, int startkey) + GistSplitUnion *gsvp) { IndexTuple *cleanedItVec; int i, @@ -49,35 +49,36 @@ gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec, cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1]; } - gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey, + gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, gsvp->attr, gsvp->isnull); pfree(cleanedItVec); } /* - * unions subkeys for after user picksplit over attno-1 column + * Recompute unions of subkeys after a page split, ignoring any tuples + * that are marked in spl->spl_equiv[] */ static void -gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, int attno) +gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl) { GistSplitUnion gsvp; gsvp.equiv = spl->spl_equiv; - gsvp.attr = spl->spl_lattr; - gsvp.len = spl->splitVector.spl_nleft; gsvp.entries = spl->splitVector.spl_left; + gsvp.len = spl->splitVector.spl_nleft; + gsvp.attr = spl->spl_lattr; gsvp.isnull = spl->spl_lisnull; - gistunionsubkeyvec(giststate, itvec, &gsvp, attno); + gistunionsubkeyvec(giststate, itvec, &gsvp); - gsvp.attr = spl->spl_rattr; - gsvp.len = spl->splitVector.spl_nright; gsvp.entries = spl->splitVector.spl_right; + gsvp.len = spl->splitVector.spl_nright; + gsvp.attr = spl->spl_rattr; gsvp.isnull = spl->spl_risnull; - gistunionsubkeyvec(giststate, itvec, &gsvp, attno); + gistunionsubkeyvec(giststate, itvec, &gsvp); } /* @@ -443,14 +444,14 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec */ if (LenEquiv == 0) { - gistunionsubkey(giststate, itup, v, attno + 1); + gistunionsubkey(giststate, itup, v); } 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); + gistunionsubkey(giststate, itup, v); if (LenEquiv == 1) { /* @@ -471,7 +472,7 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec * performance, because it's very rarely */ v->spl_equiv = NULL; - gistunionsubkey(giststate, itup, v, attno + 1); + gistunionsubkey(giststate, itup, v); return false; } @@ -562,7 +563,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist v->splitVector.spl_left[v->splitVector.spl_nleft++] = i; v->spl_equiv = NULL; - gistunionsubkey(giststate, itup, v, attno); + gistunionsubkey(giststate, itup, v); } else { @@ -617,7 +618,7 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist v->splitVector = backupSplit; /* reunion left and right datums */ - gistunionsubkey(giststate, itup, v, attno); + gistunionsubkey(giststate, itup, v); } } } diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index a127627334..e5c3d69fca 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -21,12 +21,6 @@ #include "storage/lmgr.h" #include "utils/builtins.h" -/* - * static *S used for temporary storage (saves stack and palloc() call) - */ - -static Datum attrS[INDEX_MAX_KEYS]; -static bool isnullS[INDEX_MAX_KEYS]; /* * Write itup vector to page, has no control of free space. @@ -148,12 +142,12 @@ gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) } /* - * Make unions of keys in IndexTuple vector. + * Make unions of keys in IndexTuple vector (one union datum per index column). + * Union Datums are returned into the attr/isnull arrays. * Resulting Datums aren't compressed. */ - void -gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey, +gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull) { int i; @@ -162,19 +156,12 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startke evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ); - for (i = startkey; i < giststate->tupdesc->natts; i++) + for (i = 0; i < giststate->tupdesc->natts; i++) { int j; + /* Collect non-null datums for this column */ evec->n = 0; - 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; @@ -192,7 +179,7 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startke evec->n++; } - /* If this tuple vector was all NULLs, the union is NULL */ + /* If this column was all NULLs, the union is NULL */ if (evec->n == 0) { attr[i] = (Datum) 0; @@ -202,6 +189,7 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startke { if (evec->n == 1) { + /* unionFn may expect at least two inputs */ evec->n = 2; evec->vector[1] = evec->vector[0]; } @@ -224,11 +212,12 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startke IndexTuple gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate) { - memset(isnullS, TRUE, sizeof(bool) * giststate->tupdesc->natts); + Datum attr[INDEX_MAX_KEYS]; + bool isnull[INDEX_MAX_KEYS]; - gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS); + gistMakeUnionItVec(giststate, itvec, len, attr, isnull); - return gistFormTuple(giststate, r, attrS, isnullS, false); + return gistFormTuple(giststate, r, attr, isnull, false); } /* @@ -240,12 +229,15 @@ gistMakeUnionKey(GISTSTATE *giststate, int attno, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull) { - + /* we need a GistEntryVector with room for exactly 2 elements */ + union + { + GistEntryVector gev; + char padding[2 * sizeof(GISTENTRY) + GEVHDRSZ]; + } storage; + GistEntryVector *evec = &storage.gev; int dstsize; - static char storage[2 * sizeof(GISTENTRY) + GEVHDRSZ]; - GistEntryVector *evec = (GistEntryVector *) storage; - evec->n = 2; if (isnull1 && isnull2) @@ -321,6 +313,8 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis addentries[INDEX_MAX_KEYS]; bool oldisnull[INDEX_MAX_KEYS], addisnull[INDEX_MAX_KEYS]; + Datum attr[INDEX_MAX_KEYS]; + bool isnull[INDEX_MAX_KEYS]; IndexTuple newtup = NULL; int i; @@ -335,19 +329,20 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis gistMakeUnionKey(giststate, i, oldentries + i, oldisnull[i], addentries + i, addisnull[i], - attrS + i, isnullS + i); + attr + i, isnull + i); if (neednew) /* we already need new key, so we can skip check */ continue; - if (isnullS[i]) + if (isnull[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 (oldisnull[i] || + !gistKeyIsEQ(giststate, i, oldentries[i].key, attr[i])) neednew = true; } } @@ -355,7 +350,7 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis if (neednew) { /* need to update key */ - newtup = gistFormTuple(giststate, r, attrS, isnullS, false); + newtup = gistFormTuple(giststate, r, attr, isnull, false); newtup->t_tid = oldtup->t_tid; } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 357b8c9d43..b35268508a 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -500,7 +500,7 @@ extern void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, extern float gistpenalty(GISTSTATE *giststate, int attno, GISTENTRY *key1, bool isNull1, GISTENTRY *key2, bool isNull2); -extern void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey, +extern void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull); extern bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b); extern void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,