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,
        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);
 }
 
 /*
             */
            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)
                {
                    /*
                     * performance, because it's very rarely
                     */
                    v->spl_equiv = NULL;
-                   gistunionsubkey(giststate, itup, v, attno + 1);
+                   gistunionsubkey(giststate, itup, v);
 
                    return false;
                }
                v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
 
        v->spl_equiv = NULL;
-       gistunionsubkey(giststate, itup, v, attno);
+       gistunionsubkey(giststate, itup, v);
    }
    else
    {
 
                v->splitVector = backupSplit;
                /* reunion left and right datums */
-               gistunionsubkey(giststate, itup, v, attno);
+               gistunionsubkey(giststate, itup, v);
            }
        }
    }
 
 #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.
 }
 
 /*
- * 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;
 
    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;
            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;
        {
            if (evec->n == 1)
            {
+               /* unionFn may expect at least two inputs */
                evec->n = 2;
                evec->vector[1] = evec->vector[0];
            }
 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);
 }
 
 /*
                 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)
                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;
 
        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;
        }
    }
    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;
    }
 
 
 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,