]> granicus.if.org Git - postgresql/commitdiff
Updates to make GIST work with multi-key indexes (from Oleg Bartunov
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 31 May 2001 18:16:55 +0000 (18:16 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 31 May 2001 18:16:55 +0000 (18:16 +0000)
and Teodor Sigaev).  Declare key values as Datum where appropriate,
rather than char* (Tom Lane).

contrib/cube/cube.c
contrib/intarray/_int.c
contrib/seg/seg.c
src/backend/access/gist/gist.c
src/backend/access/gist/gistget.c
src/backend/access/gist/gistscan.c
src/backend/access/index/indexam.c
src/backend/commands/indexcmds.c
src/include/access/gist.h

index 4d6169a48020fe9ea42390e4fee2b1ebc123a6f9..72f6e5a0695e840b851ad363b945f8096726bfc7 100644 (file)
@@ -45,7 +45,7 @@ NDBOX    *g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep);
 bool      *g_cube_same(NDBOX * b1, NDBOX * b2, bool *result);
 
 /*
-** R-tree suport functions
+** R-tree support functions
 */
 bool           cube_same(NDBOX * a, NDBOX * b);
 bool           cube_different(NDBOX * a, NDBOX * b);
@@ -168,13 +168,15 @@ g_cube_consistent(GISTENTRY *entry,
 {
 
        /*
-        * * if entry is not leaf, use g_cube_internal_consistent, * else use
+        * if entry is not leaf, use g_cube_internal_consistent, else use
         * g_cube_leaf_consistent
         */
        if (GIST_LEAF(entry))
-               return (g_cube_leaf_consistent((NDBOX *) (entry->pred), query, strategy));
+               return g_cube_leaf_consistent((NDBOX *) DatumGetPointer(entry->key),
+                                                                         query, strategy);
        else
-               return (g_cube_internal_consistent((NDBOX *) (entry->pred), query, strategy));
+               return g_cube_internal_consistent((NDBOX *) DatumGetPointer(entry->key),
+                                                                                 query, strategy);
 }
 
 
@@ -194,7 +196,7 @@ g_cube_union(bytea *entryvec, int *sizep)
         * fprintf(stderr, "union\n");
         */
        numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
-       tmp = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[0]).pred;
+       tmp = (NDBOX *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[0]).key);
 
        /*
         * sizep = sizeof(NDBOX); -- NDBOX has variable size
@@ -204,14 +206,8 @@ g_cube_union(bytea *entryvec, int *sizep)
        for (i = 1; i < numranges; i++)
        {
                out = g_cube_binary_union(tmp, (NDBOX *)
-                                                  (((GISTENTRY *) (VARDATA(entryvec)))[i]).pred,
+                                                                 DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i]).key),
                                                                  sizep);
-
-               /*
-                * fprintf(stderr, "\t%s ^ %s -> %s\n", cube_out(tmp),
-                * cube_out((NDBOX *)(((GISTENTRY
-                * *)(VARDATA(entryvec)))[i]).pred), cube_out(out));
-                */
                if (i > 1)
                        pfree(tmp);
                tmp = out;
@@ -243,15 +239,16 @@ g_cube_decompress(GISTENTRY *entry)
 float *
 g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
 {
-       Datum           ud;
+       NDBOX      *ud;
        float           tmp1,
                                tmp2;
 
-       ud = (Datum) cube_union((NDBOX *) (origentry->pred), (NDBOX *) (newentry->pred));
-       rt_cube_size((NDBOX *) ud, &tmp1);
-       rt_cube_size((NDBOX *) (origentry->pred), &tmp2);
+       ud = cube_union((NDBOX *) DatumGetPointer(origentry->key),
+                                       (NDBOX *) DatumGetPointer(newentry->key));
+       rt_cube_size(ud, &tmp1);
+       rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2);
        *result = tmp1 - tmp2;
-       pfree((char *) ud);
+       pfree(ud);
 
        /*
         * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
@@ -308,16 +305,16 @@ g_cube_picksplit(bytea *entryvec,
 
        for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
        {
-               datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
+               datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[i].key);
                for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
                {
-                       datum_beta = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[j].pred);
+                       datum_beta = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[j].key);
 
                        /* compute the wasted space by unioning these guys */
                        /* size_waste = size_union - size_inter; */
-                       union_d = (NDBOX *) cube_union(datum_alpha, datum_beta);
+                       union_d = cube_union(datum_alpha, datum_beta);
                        rt_cube_size(union_d, &size_union);
-                       inter_d = (NDBOX *) cube_inter(datum_alpha, datum_beta);
+                       inter_d = cube_inter(datum_alpha, datum_beta);
                        rt_cube_size(inter_d, &size_inter);
                        size_waste = size_union - size_inter;
 
@@ -346,12 +343,12 @@ g_cube_picksplit(bytea *entryvec,
        right = v->spl_right;
        v->spl_nright = 0;
 
-       datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_1].pred);
-       datum_l = (NDBOX *) cube_union(datum_alpha, datum_alpha);
-       rt_cube_size((NDBOX *) datum_l, &size_l);
-       datum_beta = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_2].pred);;
-       datum_r = (NDBOX *) cube_union(datum_beta, datum_beta);
-       rt_cube_size((NDBOX *) datum_r, &size_r);
+       datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[seed_1].key);
+       datum_l = cube_union(datum_alpha, datum_alpha);
+       rt_cube_size(datum_l, &size_l);
+       datum_beta = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[seed_2].key);
+       datum_r = cube_union(datum_beta, datum_beta);
+       rt_cube_size(datum_r, &size_r);
 
        /*
         * Now split up the regions between the two seeds.      An important
@@ -389,11 +386,11 @@ g_cube_picksplit(bytea *entryvec,
                }
 
                /* okay, which page needs least enlargement? */
-               datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
-               union_dl = (NDBOX *) cube_union(datum_l, datum_alpha);
-               union_dr = (NDBOX *) cube_union(datum_r, datum_alpha);
-               rt_cube_size((NDBOX *) union_dl, &size_alpha);
-               rt_cube_size((NDBOX *) union_dr, &size_beta);
+               datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[i].key);
+               union_dl = cube_union(datum_l, datum_alpha);
+               union_dr = cube_union(datum_r, datum_alpha);
+               rt_cube_size(union_dl, &size_alpha);
+               rt_cube_size(union_dr, &size_beta);
 
                /* pick which page to add it to */
                if (size_alpha - size_l < size_beta - size_r)
@@ -417,8 +414,8 @@ g_cube_picksplit(bytea *entryvec,
        }
        *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
 
-       v->spl_ldatum = (char *) datum_l;
-       v->spl_rdatum = (char *) datum_r;
+       v->spl_ldatum = PointerGetDatum(datum_l);
+       v->spl_rdatum = PointerGetDatum(datum_r);
 
        return v;
 }
index f15d3ca112dfeaff2db7719fb8d6235fc245d718..dc49355739e66d4a25dab23460be5ba0b6b16979 100644 (file)
 
 /* useful macros for accessing int4 arrays */
 #define ARRPTR(x)  ( (int4 *) ARR_DATA_PTR(x) )
-#ifdef PGSQL71
 #define ARRNELEMS(x)  ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
-#else
-#define ARRNELEMS(x)  getNitems( ARR_NDIM(x), ARR_DIMS(x))
-#endif
 
 #define ARRISNULL(x) ( (x) ? ( ( ARR_NDIM(x) == NDIM ) ? ( ( ARRNELEMS( x ) ) ? 0 : 1 ) : 1  ) : 1 )
 
@@ -228,14 +224,17 @@ g_int_consistent(GISTENTRY *entry,
        switch (strategy)
        {
                case RTOverlapStrategyNumber:
-                       retval = (bool) inner_int_overlap((ArrayType *) (entry->pred), query);
+                       retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key),
+                                                                          query);
                        break;
                case RTSameStrategyNumber:
                case RTContainsStrategyNumber:
-                       retval = (bool) inner_int_contains((ArrayType *) (entry->pred), query);
+                       retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key),
+                                                                               query);
                        break;
                case RTContainedByStrategyNumber:
-                       retval = (bool) inner_int_overlap((ArrayType *) (entry->pred), query);
+                       retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key),
+                                                                          query);
                        break;
                default:
                        retval = FALSE;
@@ -265,14 +264,10 @@ g_int_compress(GISTENTRY *entry)
 
        retval = palloc(sizeof(GISTENTRY));
 
-#ifdef PGSQL71
-       if (entry->pred)
-               r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->pred);
+       if (DatumGetPointer(entry->key) != NULL)
+               r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key);
        else
                r = NULL;
-#else
-       r = copy_intArrayType((ArrayType *) entry->pred);
-#endif
 
        if (ARRISNULL(r))
        {
@@ -280,10 +275,10 @@ g_int_compress(GISTENTRY *entry)
                elog(NOTICE, "COMP IN: NULL");
 #endif
                if (r)
-                       if ((char *) r != (char *) entry->pred)
+                       if (r != (ArrayType *) DatumGetPointer(entry->key))
                                pfree(r);
 
-               gistentryinit(*retval, (char *) NULL, entry->rel, entry->page, entry->offset,
+               gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset,
                                          0, FALSE);
                return (retval);
        }
@@ -322,7 +317,8 @@ g_int_compress(GISTENTRY *entry)
                r = resize_intArrayType(r, len);
        }
 
-       gistentryinit(*retval, (char *) r, entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);
+       gistentryinit(*retval, PointerGetDatum(r),
+                                 entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);
 
        return (retval);
 }
@@ -340,25 +336,19 @@ g_int_decompress(GISTENTRY *entry)
        int                     i,
                                j;
 
-#ifdef PGSQL71
-       if (entry->pred)
-               in = (ArrayType *) PG_DETOAST_DATUM(entry->pred);
+       if (DatumGetPointer(entry->key) != NULL)
+               in = (ArrayType *) PG_DETOAST_DATUM(entry->key);
        else
                in = NULL;
-#else
-       in = (ArrayType *) entry->pred;
-#endif
 
        if (entry->bytes < ARR_OVERHEAD(NDIM) || ARRISNULL(in))
        {
                retval = palloc(sizeof(GISTENTRY));
 
-#ifdef PGSQL71
                if (in)
-                       if ((char *) in != (char *) entry->pred)
+                       if (in != (ArrayType *) DatumGetPointer(entry->key))
                                pfree(in);
-#endif
-               gistentryinit(*retval, (char *) NULL, entry->rel, entry->page, entry->offset, 0, FALSE);
+               gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset, 0, FALSE);
 #ifdef GIST_DEBUG
                elog(NOTICE, "DECOMP IN: NULL");
 #endif
@@ -372,7 +362,7 @@ g_int_decompress(GISTENTRY *entry)
        if (lenin < 2 * MAXNUMRANGE)
        {                                                       /* not comressed value */
                /* sometimes strange bytesize */
-               gistentryinit(*entry, (char *) in, entry->rel, entry->page, entry->offset, VARSIZE(in), FALSE);
+               gistentryinit(*entry, PointerGetDatum(in), entry->rel, entry->page, entry->offset, VARSIZE(in), FALSE);
                return (entry);
        }
 
@@ -390,13 +380,11 @@ g_int_decompress(GISTENTRY *entry)
                        if ((!i) || *(dr - 1) != j)
                                *dr++ = j;
 
-#ifdef PGSQL71
-       if ((char *) in != (char *) entry->pred)
+       if (in != (ArrayType *) DatumGetPointer(entry->key))
                pfree(in);
-#endif
        retval = palloc(sizeof(GISTENTRY));
 
-       gistentryinit(*retval, (char *) r, entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);
+       gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);
 
        return (retval);
 }
@@ -835,9 +823,6 @@ new_intArrayType(int num)
        MemSet(r, 0, nbytes);
        r->size = nbytes;
        r->ndim = NDIM;
-#ifndef PGSQL71
-       SET_LO_FLAG(false, r);
-#endif
        *((int *) ARR_DIMS(r)) = num;
        *((int *) ARR_LBOUND(r)) = 1;
 
@@ -1056,14 +1041,10 @@ g_intbig_compress(GISTENTRY *entry)
        ArrayType  *r,
                           *in;
 
-#ifdef PGSQL71
-       if (entry->pred)
-               in = (ArrayType *) PG_DETOAST_DATUM(entry->pred);
+       if (DatumGetPointer(entry->key) != NULL)
+               in = (ArrayType *) PG_DETOAST_DATUM(entry->key);
        else
                in = NULL;
-#else
-       in = (ArrayType *) entry->pred;
-#endif
 
        if (!entry->leafkey)
                return entry;
@@ -1072,12 +1053,10 @@ g_intbig_compress(GISTENTRY *entry)
 
        if (ARRISNULL(in))
        {
-#ifdef PGSQL71
                if (in)
-                       if ((char *) in != (char *) entry->pred)
+                       if (in != (ArrayType *) DatumGetPointer(entry->key))
                                pfree(in);
-#endif
-               gistentryinit(*retval, (char *) NULL, entry->rel, entry->page, entry->offset, 0, FALSE);
+               gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset, 0, FALSE);
                return (retval);
        }
 
@@ -1086,13 +1065,11 @@ g_intbig_compress(GISTENTRY *entry)
                        ARRPTR(in),
                        ARRNELEMS(in));
 
-       gistentryinit(*retval, (char *) r, entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);
+       gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, entry->offset, VARSIZE(r), FALSE);
 
-#ifdef PGSQL71
        if (in)
-               if ((char *) in != (char *) entry->pred)
+               if (in != (ArrayType *) DatumGetPointer(entry->key))
                        pfree(in);
-#endif
 
        return (retval);
 }
@@ -1100,20 +1077,18 @@ g_intbig_compress(GISTENTRY *entry)
 GISTENTRY  *
 g_intbig_decompress(GISTENTRY *entry)
 {
-#ifdef PGSQL71
        ArrayType  *key;
 
-       key = (ArrayType *) PG_DETOAST_DATUM(entry->pred);
-       if ((char *) key != (char *) entry->pred)
+       key = (ArrayType *) PG_DETOAST_DATUM(entry->key);
+       if (key != (ArrayType *) DatumGetPointer(entry->key))
        {
                GISTENTRY  *retval;
 
                retval = palloc(sizeof(GISTENTRY));
 
-               gistentryinit(*retval, (char *) key, entry->rel, entry->page, entry->offset, VARSIZE(key), FALSE);
+               gistentryinit(*retval, PointerGetDatum(key), entry->rel, entry->page, entry->offset, VARSIZE(key), FALSE);
                return retval;
        }
-#endif
        return entry;
 }
 
@@ -1159,14 +1134,14 @@ g_intbig_consistent(GISTENTRY *entry, ArrayType *query, StrategyNumber strategy)
        switch (strategy)
        {
                case RTOverlapStrategyNumber:
-                       retval = (bool) _intbig_overlap((ArrayType *) (entry->pred), q);
+                       retval = _intbig_overlap((ArrayType *) DatumGetPointer(entry->key), q);
                        break;
                case RTSameStrategyNumber:
                case RTContainsStrategyNumber:
-                       retval = (bool) _intbig_contains((ArrayType *) (entry->pred), q);
+                       retval = _intbig_contains((ArrayType *) DatumGetPointer(entry->key), q);
                        break;
                case RTContainedByStrategyNumber:
-                       retval = (bool) _intbig_overlap((ArrayType *) (entry->pred), q);
+                       retval = _intbig_overlap((ArrayType *) DatumGetPointer(entry->key), q);
                        break;
                default:
                        retval = FALSE;
@@ -1196,12 +1171,12 @@ _int_common_union(bytea *entryvec, int *sizep, formarray unionf)
 #endif
 
        numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
-       tmp = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[0]).pred;
+       tmp = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[0].key);
 
        for (i = 1; i < numranges; i++)
        {
                out = (*unionf) (tmp, (ArrayType *)
-                                                (((GISTENTRY *) (VARDATA(entryvec)))[i]).pred);
+                                                DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key));
                if (i > 1 && tmp)
                        pfree(tmp);
                tmp = out;
@@ -1232,18 +1207,19 @@ _int_common_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result,
                                        formarray unionf,
                                        formfloat sizef)
 {
-       Datum           ud;
+       ArrayType  *ud;
        float           tmp1,
                                tmp2;
 
 #ifdef GIST_DEBUG
        elog(NOTICE, "penalty");
 #endif
-       ud = (Datum) (*unionf) ((ArrayType *) (origentry->pred), (ArrayType *) (newentry->pred));
-       (*sizef) ((ArrayType *) ud, &tmp1);
-       (*sizef) ((ArrayType *) (origentry->pred), &tmp2);
+       ud = (*unionf) ((ArrayType *) DatumGetPointer(origentry->key),
+                                       (ArrayType *) DatumGetPointer(newentry->key));
+       (*sizef) (ud, &tmp1);
+       (*sizef) ((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
        *result = tmp1 - tmp2;
-       pfree((char *) ud);
+       pfree(ud);
 
 #ifdef GIST_DEBUG
        elog(NOTICE, "--penalty\t%g", *result);
@@ -1304,10 +1280,10 @@ _int_common_picksplit(bytea *entryvec,
 
        for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
        {
-               datum_alpha = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
+               datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key);
                for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
                {
-                       datum_beta = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[j].pred);
+                       datum_beta = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[j].key);
 
                        /* compute the wasted space by unioning these guys */
                        /* size_waste = size_union - size_inter; */
@@ -1342,12 +1318,12 @@ _int_common_picksplit(bytea *entryvec,
        right = v->spl_right;
        v->spl_nright = 0;
 
-       datum_alpha = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_1].pred);
+       datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_1].key);
        datum_l = copy_intArrayType(datum_alpha);
-       (*sizef) ((ArrayType *) datum_l, &size_l);
-       datum_beta = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_2].pred);
+       (*sizef) (datum_l, &size_l);
+       datum_beta = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_2].key);
        datum_r = copy_intArrayType(datum_beta);
-       (*sizef) ((ArrayType *) datum_r, &size_r);
+       (*sizef) (datum_r, &size_r);
 
        /*
         * Now split up the regions between the two seeds.      An important
@@ -1386,11 +1362,11 @@ _int_common_picksplit(bytea *entryvec,
                }
 
                /* okay, which page needs least enlargement? */
-               datum_alpha = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
-               union_dl = (ArrayType *) (*unionf) (datum_l, datum_alpha);
-               union_dr = (ArrayType *) (*unionf) (datum_r, datum_alpha);
-               (*sizef) ((ArrayType *) union_dl, &size_alpha);
-               (*sizef) ((ArrayType *) union_dr, &size_beta);
+               datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key);
+               union_dl = (*unionf) (datum_l, datum_alpha);
+               union_dr = (*unionf) (datum_r, datum_alpha);
+               (*sizef) (union_dl, &size_alpha);
+               (*sizef) (union_dr, &size_beta);
 
                /* pick which page to add it to */
                if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, coef))
@@ -1428,8 +1404,8 @@ _int_common_picksplit(bytea *entryvec,
                *(right - 1) = InvalidOffsetNumber;
        }
 
-       v->spl_ldatum = (char *) datum_l;
-       v->spl_rdatum = (char *) datum_r;
+       v->spl_ldatum = PointerGetDatum(datum_l);
+       v->spl_rdatum = PointerGetDatum(datum_r);
 
 #ifdef GIST_DEBUG
        elog(NOTICE, "--------ENDpicksplit %d %d", v->spl_nleft, v->spl_nright);
index 3ed7926389190689ab755e23edbcdee8b9f591b1..124299ab44d97c15a54348f68b1bab0f495eddd4 100644 (file)
@@ -225,9 +225,9 @@ gseg_consistent(GISTENTRY *entry,
         * gseg_leaf_consistent
         */
        if (GIST_LEAF(entry))
-               return (gseg_leaf_consistent((SEG *) (entry->pred), query, strategy));
+               return (gseg_leaf_consistent((SEG *) DatumGetPointer(entry->key), query, strategy));
        else
-               return (gseg_internal_consistent((SEG *) (entry->pred), query, strategy));
+               return (gseg_internal_consistent((SEG *) DatumGetPointer(entry->key), query, strategy));
 }
 
 /*
@@ -247,22 +247,14 @@ gseg_union(bytea *entryvec, int *sizep)
 #endif
 
        numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
-       tmp = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[0]).pred;
+       tmp = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[0].key);
        *sizep = sizeof(SEG);
 
        for (i = 1; i < numranges; i++)
        {
                out = gseg_binary_union(tmp, (SEG *)
-                                                  (((GISTENTRY *) (VARDATA(entryvec)))[i]).pred,
+                                                               DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key),
                                                                sizep);
-#ifdef GIST_DEBUG
-
-               /*
-                * fprintf(stderr, "\t%s ^ %s -> %s\n", seg_out(tmp), seg_out((SEG
-                * *)(((GISTENTRY *)(VARDATA(entryvec)))[i]).pred), seg_out(out));
-                */
-#endif
-
                if (i > 1)
                        pfree(tmp);
                tmp = out;
@@ -294,15 +286,16 @@ gseg_decompress(GISTENTRY *entry)
 float *
 gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
 {
-       Datum           ud;
+       SEG                *ud;
        float           tmp1,
                                tmp2;
 
-       ud = (Datum) seg_union((SEG *) (origentry->pred), (SEG *) (newentry->pred));
-       rt_seg_size((SEG *) ud, &tmp1);
-       rt_seg_size((SEG *) (origentry->pred), &tmp2);
+       ud = seg_union((SEG *) DatumGetPointer(origentry->key),
+                                  (SEG *) DatumGetPointer(newentry->key));
+       rt_seg_size(ud, &tmp1);
+       rt_seg_size((SEG *) DatumGetPointer(origentry->key), &tmp2);
        *result = tmp1 - tmp2;
-       pfree((char *) ud);
+       pfree(ud);
 
 #ifdef GIST_DEBUG
        fprintf(stderr, "penalty\n");
@@ -362,16 +355,16 @@ gseg_picksplit(bytea *entryvec,
 
        for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
        {
-               datum_alpha = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
+               datum_alpha = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key);
                for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
                {
-                       datum_beta = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[j].pred);
+                       datum_beta = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[j].key);
 
                        /* compute the wasted space by unioning these guys */
                        /* size_waste = size_union - size_inter; */
-                       union_d = (SEG *) seg_union(datum_alpha, datum_beta);
+                       union_d = seg_union(datum_alpha, datum_beta);
                        rt_seg_size(union_d, &size_union);
-                       inter_d = (SEG *) seg_inter(datum_alpha, datum_beta);
+                       inter_d = seg_inter(datum_alpha, datum_beta);
                        rt_seg_size(inter_d, &size_inter);
                        size_waste = size_union - size_inter;
 
@@ -400,12 +393,12 @@ gseg_picksplit(bytea *entryvec,
        right = v->spl_right;
        v->spl_nright = 0;
 
-       datum_alpha = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_1].pred);
-       datum_l = (SEG *) seg_union(datum_alpha, datum_alpha);
-       rt_seg_size((SEG *) datum_l, &size_l);
-       datum_beta = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_2].pred);;
-       datum_r = (SEG *) seg_union(datum_beta, datum_beta);
-       rt_seg_size((SEG *) datum_r, &size_r);
+       datum_alpha = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_1].key);
+       datum_l = seg_union(datum_alpha, datum_alpha);
+       rt_seg_size(datum_l, &size_l);
+       datum_beta = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_2].key);
+       datum_r = seg_union(datum_beta, datum_beta);
+       rt_seg_size(datum_r, &size_r);
 
        /*
         * Now split up the regions between the two seeds.      An important
@@ -443,11 +436,11 @@ gseg_picksplit(bytea *entryvec,
                }
 
                /* okay, which page needs least enlargement? */
-               datum_alpha = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred);
-               union_dl = (SEG *) seg_union(datum_l, datum_alpha);
-               union_dr = (SEG *) seg_union(datum_r, datum_alpha);
-               rt_seg_size((SEG *) union_dl, &size_alpha);
-               rt_seg_size((SEG *) union_dr, &size_beta);
+               datum_alpha = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key);
+               union_dl = seg_union(datum_l, datum_alpha);
+               union_dr = seg_union(datum_r, datum_alpha);
+               rt_seg_size(union_dl, &size_alpha);
+               rt_seg_size(union_dr, &size_beta);
 
                /* pick which page to add it to */
                if (size_alpha - size_l < size_beta - size_r)
@@ -471,8 +464,8 @@ gseg_picksplit(bytea *entryvec,
        }
        *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
 
-       v->spl_ldatum = (char *) datum_l;
-       v->spl_rdatum = (char *) datum_r;
+       v->spl_ldatum = PointerGetDatum(datum_l);
+       v->spl_rdatum = PointerGetDatum(datum_r);
 
        return v;
 }
index 8f23d14d79dedfd2026d7365a3524bcdd37dac70..8f0cfbbb499f575b642580d18ae5fb02c4867554 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.77 2001/05/30 19:53:39 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.78 2001/05/31 18:16:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "access/xlogutils.h"
 
 
+#undef GIST_PAGEADDITEM
+
+#define ATTSIZE( datum, Rel, i, isnull ) \
+       ( \
+               ( isnull ) ? 0 : \
+                       att_addlength(0, (Rel)->rd_att->attrs[(i)-1]->attlen, (datum)) \
+       )
+
 /* result's status */
 #define INSERTED       0x01
 #define SPLITED                0x02
 
+/* group flags ( in gistSplit ) */
+#define LEFT_ADDED     0x01
+#define RIGHT_ADDED    0x02
+#define BOTH_ADDED     ( LEFT_ADDED | RIGHT_ADDED )
+
 /* non-export function prototypes */
 static void gistdoinsert(Relation r,
                         IndexTuple itup,
@@ -55,10 +68,15 @@ static IndexTuple *gistjoinvector(
                           IndexTuple *additvec, int addlen);
 static IndexTuple gistunion(Relation r, IndexTuple *itvec,
                  int len, GISTSTATE *giststate);
+
 static IndexTuple gistgetadjusted(Relation r,
                                IndexTuple oldtup,
                                IndexTuple addtup,
                                GISTSTATE *giststate);
+static int gistfindgroup( GISTSTATE *giststate, 
+                       GISTENTRY *valvec, GIST_SPLITVEC * spl );
+static IndexTuple gistFormTuple( GISTSTATE *giststate, 
+                       Relation r, Datum attdata[], int datumsize[] );
 static IndexTuple *gistSplit(Relation r,
                  Buffer buffer,
                  IndexTuple *itup,
@@ -71,13 +89,18 @@ static void GISTInitBuffer(Buffer b, uint32 f);
 static OffsetNumber gistchoose(Relation r, Page p,
                   IndexTuple it,
                   GISTSTATE *giststate);
+#ifdef GIST_PAGEADDITEM
 static IndexTuple gist_tuple_replacekey(Relation r,
                                          GISTENTRY entry, IndexTuple t);
-static void gistcentryinit(GISTSTATE *giststate,
-                          GISTENTRY *e, char *pr,
+#endif
+static void gistcentryinit(GISTSTATE *giststate, int nkey,
+                          GISTENTRY *e, Datum k,
                           Relation r, Page pg,
                           OffsetNumber o, int b, bool l);
-
+static bool gistDeCompressAtt(         GISTSTATE *giststate, Relation r, 
+                               IndexTuple tuple, Page p, OffsetNumber o, 
+                               GISTENTRY attdata[], bool decompvec[] );
+static void gistFreeAtt(  Relation r, GISTENTRY attdata[], bool decompvec[] );
 #undef GISTDEBUG
 
 #ifdef GISTDEBUG
@@ -230,15 +253,15 @@ gistbuild(PG_FUNCTION_ARGS)
                /* immediately compress keys to normalize */
                for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
                {
-                       gistcentryinit(&giststate, &tmpcentry, (char *) attdata[i],
+                       gistcentryinit(&giststate, i, &tmpcentry, attdata[i],
                                                   (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
                                                   -1 /* size is currently bogus */ , TRUE);
-                       if (attdata[i] != (Datum) tmpcentry.pred &&
+                       if (attdata[i] != tmpcentry.key &&
                                !(giststate.keytypbyval))
                                compvec[i] = TRUE;
                        else
                                compvec[i] = FALSE;
-                       attdata[i] = (Datum) tmpcentry.pred;
+                       attdata[i] = tmpcentry.key;
                }
 
                /* form an index tuple and point it at the heap tuple */
@@ -252,7 +275,6 @@ gistbuild(PG_FUNCTION_ARGS)
                 * is the right thing to do if you're inserting single tups, but
                 * not when you're initializing the whole index at once.
                 */
-
                gistdoinsert(index, itup, NULL, &giststate);
 
                for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
@@ -339,14 +361,14 @@ gistinsert(PG_FUNCTION_ARGS)
        compvec = (bool *) palloc(sizeof(bool) * r->rd_att->natts);
        for (i = 0; i < r->rd_att->natts; i++)
        {
-               gistcentryinit(&giststate, &tmpentry, (char *) datum[i],
+               gistcentryinit(&giststate, i,&tmpentry, datum[i],
                                           (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
                                           -1 /* size is currently bogus */ , TRUE);
-               if (datum[i] != (Datum) tmpentry.pred && !(giststate.keytypbyval))
+               if (datum[i] != tmpentry.key && !(giststate.keytypbyval))
                        compvec[i] = TRUE;
                else
                        compvec[i] = FALSE;
-               datum[i] = (Datum) tmpentry.pred;
+               datum[i] = tmpentry.key;
        }
        itup = index_formtuple(RelationGetDescr(r), datum, nulls);
        itup->t_tid = *ht_ctid;
@@ -361,13 +383,14 @@ gistinsert(PG_FUNCTION_ARGS)
        gistdoinsert(r, itup, &res, &giststate);
        for (i = 0; i < r->rd_att->natts; i++)
                if (compvec[i] == TRUE)
-                       pfree((char *) datum[i]);
+                       pfree(DatumGetPointer(datum[i]));
        pfree(itup);
        pfree(compvec);
 
        PG_RETURN_POINTER(res);
 }
 
+#ifdef GIST_PAGEADDITEM
 /*
 ** Take a compressed entry, and install it on a page.  Since we now know
 ** where the entry will live, we decompress it and recompress it using
@@ -388,16 +411,20 @@ gistPageAddItem(GISTSTATE *giststate,
        GISTENTRY       tmpcentry;
        IndexTuple      itup = (IndexTuple) item;
        OffsetNumber retval;
+       Datum           datum;
+       bool            IsNull;
 
        /*
         * recompress the item given that we now know the exact page and
         * offset for insertion
         */
-       gistdentryinit(giststate, dentry,
-                                  (((char *) itup) + sizeof(IndexTupleData)),
-                         (Relation) 0, (Page) 0, (OffsetNumber) InvalidOffsetNumber,
-                                  IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE);
-       gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page,
+       datum = index_getattr(itup, 1, r->rd_att, &IsNull);
+       gistdentryinit(giststate, 0,dentry, datum,
+                                  (Relation) 0, (Page) 0,
+                                  (OffsetNumber) InvalidOffsetNumber,
+                                  ATTSIZE( datum, r, 1, IsNull ),
+                                  FALSE);
+       gistcentryinit(giststate, 0,&tmpcentry, dentry->key, r, page,
                                   offsetNumber, dentry->bytes, FALSE);
        *newtup = gist_tuple_replacekey(r, tmpcentry, itup);
        retval = PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup),
@@ -406,11 +433,13 @@ gistPageAddItem(GISTSTATE *giststate,
                elog(ERROR, "gist: failed to add index item to %s",
                         RelationGetRelationName(r));
        /* be tidy */
-       if (tmpcentry.pred && tmpcentry.pred != dentry->pred
-               && tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
-               pfree(tmpcentry.pred);
+       if (DatumGetPointer(tmpcentry.key) != NULL &&
+               tmpcentry.key != dentry->key &&
+               tmpcentry.key != datum )
+               pfree(DatumGetPointer(tmpcentry.key));
        return (retval);
 }
+#endif
 
 static void
 gistdoinsert(Relation r,
@@ -485,7 +514,6 @@ gistlayerinsert(Relation r, BlockNumber blkno,
                if (!(ret & SPLITED))
                {
                        IndexTuple      newtup = gistgetadjusted(r, oldtup, (*itup)[0], giststate);
-
                        if (!newtup)
                        {
                                /* not need to update key */
@@ -509,18 +537,23 @@ gistlayerinsert(Relation r, BlockNumber blkno,
        if (gistnospace(page, (*itup), *len))
        {
                /* no space for insertion */
-               IndexTuple *itvec;
-               int                     tlen;
+               IndexTuple *itvec, *newitup;
+               int tlen,oldlen;
 
                ret |= SPLITED;
                itvec = gistreadbuffer(r, buffer, &tlen);
                itvec = gistjoinvector(itvec, &tlen, (*itup), *len);
-               pfree((*itup));
-               (*itup) = gistSplit(r, buffer, itvec, &tlen, giststate,
+               oldlen = *len;
+               newitup = gistSplit(r, buffer, itvec, &tlen, giststate,
                                                        (opaque->flags & F_LEAF) ? res : NULL);         /* res only for
                                                                                                                                                 * inserting in leaf */
                ReleaseBuffer(buffer);
+               do  
+                       pfree( (*itup)[ oldlen-1 ] );
+               while ( (--oldlen) > 0 );
+               pfree((*itup));
                pfree(itvec);
+               *itup = newitup;
                *len = tlen;                    /* now tlen >= 2 */
        }
        else
@@ -551,6 +584,7 @@ gistlayerinsert(Relation r, BlockNumber blkno,
                         * parent
                         */
                        IndexTuple      newtup = gistunion(r, (*itup), *len, giststate);
+                       ItemPointerSet(&(newtup->t_tid), blkno, 1); 
 
                        for (i = 0; i < *len; i++)
                                pfree((*itup)[i]);
@@ -571,19 +605,30 @@ gistwritebuffer(Relation r, Page page, IndexTuple *itup,
 {
        OffsetNumber l = InvalidOffsetNumber;
        int                     i;
+#ifdef GIST_PAGEADDITEM
        GISTENTRY       tmpdentry;
        IndexTuple      newtup;
-
+       bool IsNull;    
+#endif
        for (i = 0; i < len; i++)
        {
+#ifdef GIST_PAGEADDITEM
                l = gistPageAddItem(giststate, r, page,
                                                        (Item) itup[i], IndexTupleSize(itup[i]),
                                                        off, LP_USED, &tmpdentry, &newtup);
                off = OffsetNumberNext(off);
-               if (tmpdentry.pred != (((char *) itup[i]) + sizeof(IndexTupleData)) && tmpdentry.pred)
-                       pfree(tmpdentry.pred);
+               if (DatumGetPointer(tmpdentry.key) != NULL &&
+                       tmpdentry.key != index_getattr(itup[i], 1, r->rd_att, &IsNull))
+                       pfree(DatumGetPointer(tmpdentry.key));
                if (itup[i] != newtup)
                        pfree(newtup);
+#else
+               l = PageAddItem(page, (Item) itup[i], IndexTupleSize(itup[i]),
+                       off, LP_USED);
+               if (l == InvalidOffsetNumber)
+                       elog(ERROR, "gist: failed to add index item to %s",
+                                RelationGetRelationName(r));
+#endif
        }
        return l;
 }
@@ -598,7 +643,7 @@ gistnospace(Page page, IndexTuple *itvec, int len)
        int                     i;
 
        for (i = 0; i < len; i++)
-               size += IndexTupleSize(itvec[i]) + 4;   /* ??? */
+               size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
 
        return (PageGetFreeSpace(page) < size);
 }
@@ -614,11 +659,11 @@ gistreadbuffer(Relation r, Buffer buffer, int *len /* out */ )
        IndexTuple *itvec;
        Page            p = (Page) BufferGetPage(buffer);
 
-       *len = 0;
        maxoff = PageGetMaxOffsetNumber(p);
+       *len = maxoff;
        itvec = palloc(sizeof(IndexTuple) * maxoff);
        for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
-               itvec[(*len)++] = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
+               itvec[i-1] = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
 
        return itvec;
 }
@@ -639,46 +684,66 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
  * return union of itup vector
  */
 static IndexTuple
-gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
-{
+gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate) {
+       Datum           attr[INDEX_MAX_KEYS];
+       bool    whatfree[INDEX_MAX_KEYS];
+       char            isnull[INDEX_MAX_KEYS];
        bytea      *evec;
-       char       *datum;
+       Datum           datum;
        int                     datumsize,
-                               i;
-       GISTENTRY       centry;
-       char            isnull;
-       IndexTuple      newtup;
+                               i,j;
+       GISTENTRY       centry[INDEX_MAX_KEYS];
+       bool    *needfree;
+       IndexTuple newtup;
+       bool IsNull;
 
+       needfree = (bool *) palloc(len * sizeof(bool));
        evec = (bytea *) palloc(len * sizeof(GISTENTRY) + VARHDRSZ);
        VARATT_SIZEP(evec) = len * sizeof(GISTENTRY) + VARHDRSZ;
 
-       for (i = 0; i < len; i++)
-               gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[i],
-                                          (char *) itvec[i] + sizeof(IndexTupleData),
-                                          (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
-                                          IndexTupleSize((IndexTuple) itvec[i]) - sizeof(IndexTupleData), FALSE);
-
-       datum = (char *)
-               DatumGetPointer(FunctionCall2(&giststate->unionFn,
-                                                                         PointerGetDatum(evec),
-                                                                         PointerGetDatum(&datumsize)));
+       for (j = 0; j < r->rd_att->natts; j++) { 
+               for (i = 0; i < len; i++) {
+                       datum = index_getattr(itvec[i], j+1, r->rd_att, &IsNull);
+                       gistdentryinit(giststate, j,
+                                                  &((GISTENTRY *) VARDATA(evec))[i],
+                                                  datum,
+                                                  (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
+                                                  ATTSIZE( datum, r, j+1, IsNull ), FALSE);
+                       if ( DatumGetPointer(((GISTENTRY *) VARDATA(evec))[i].key) != NULL
+                                && ((GISTENTRY *) VARDATA(evec))[i].key != datum ) 
+                               needfree[i] = TRUE;
+                       else
+                               needfree[i] = FALSE; 
+               }
 
-       for (i = 0; i < len; i++)
-               if (((GISTENTRY *) VARDATA(evec))[i].pred &&
-                       ((GISTENTRY *) VARDATA(evec))[i].pred !=
-                       ((char *) (itvec[i]) + sizeof(IndexTupleData)))
-                       pfree(((GISTENTRY *) VARDATA(evec))[i].pred);
+               datum = FunctionCall2(&giststate->unionFn[j],
+                                                         PointerGetDatum(evec),
+                                                         PointerGetDatum(&datumsize));
+
+               for (i = 0; i < len; i++)
+                       if ( needfree[i] )
+                               pfree(DatumGetPointer(((GISTENTRY *) VARDATA(evec))[i].key));
+
+               gistcentryinit(giststate, j, &centry[j], datum,
+                       (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
+                       datumsize, FALSE);
+               isnull[j] = DatumGetPointer(centry[j].key) != NULL ? ' ' : 'n';
+               attr[j] =  centry[j].key;
+               if ( DatumGetPointer(centry[j].key) != NULL ) {
+                       whatfree[j] = TRUE;
+                       if ( centry[j].key != datum )
+                               pfree(DatumGetPointer(datum));
+               } else 
+                       whatfree[j] = FALSE;
+       }
 
        pfree(evec);
+       pfree(needfree);
 
-       gistcentryinit(giststate, &centry, datum,
-                                  (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
-                                  datumsize, FALSE);
-
-       isnull = (centry.pred) ? ' ' : 'n';
-       newtup = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &centry.pred, &isnull);
-       if (centry.pred != datum)
-               pfree(datum);
+       newtup = (IndexTuple) index_formtuple(r->rd_att, attr, isnull);
+       for (j = 0; j < r->rd_att->natts; j++)
+               if ( whatfree[j] )
+                       pfree(DatumGetPointer(attr[j]));
 
        return newtup;
 }
@@ -690,71 +755,232 @@ static IndexTuple
 gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
 {
        bytea      *evec;
-       char       *datum;
+       Datum           datum;
        int                     datumsize;
-       bool            result;
-       char            isnull;
-       GISTENTRY       centry,
+       bool            result, neednew = false;
+       char            isnull[INDEX_MAX_KEYS],
+                               whatfree[INDEX_MAX_KEYS];
+       Datum           attr[INDEX_MAX_KEYS];
+       GISTENTRY       centry[INDEX_MAX_KEYS],
+                               oldatt[INDEX_MAX_KEYS],
+                               addatt[INDEX_MAX_KEYS],
                           *ev0p,
                           *ev1p;
+       bool            olddec[INDEX_MAX_KEYS],
+                               adddec[INDEX_MAX_KEYS];
+
        IndexTuple      newtup = NULL;
+       int j;
 
        evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ);
        VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
-
-       gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[0],
-                          (char *) oldtup + sizeof(IndexTupleData), (Relation) NULL,
-                                  (Page) NULL, (OffsetNumber) 0,
-       IndexTupleSize((IndexTuple) oldtup) - sizeof(IndexTupleData), FALSE);
        ev0p = &((GISTENTRY *) VARDATA(evec))[0];
-
-       gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[1],
-                          (char *) addtup + sizeof(IndexTupleData), (Relation) NULL,
-                                  (Page) NULL, (OffsetNumber) 0,
-       IndexTupleSize((IndexTuple) addtup) - sizeof(IndexTupleData), FALSE);
        ev1p = &((GISTENTRY *) VARDATA(evec))[1];
+       
+       gistDeCompressAtt( giststate, r, oldtup, (Page) NULL, 
+               (OffsetNumber) 0, oldatt, olddec);
+
+       gistDeCompressAtt( giststate, r, addtup, (Page) NULL, 
+               (OffsetNumber) 0, addatt, adddec);
+
+               
+       for( j=0; j<r->rd_att->natts; j++ ) {
+               gistentryinit(*ev0p, oldatt[j].key, r, (Page) NULL, 
+                       (OffsetNumber) 0, oldatt[j].bytes, FALSE);
+               gistentryinit(*ev1p, addatt[j].key, r, (Page) NULL, 
+                       (OffsetNumber) 0, addatt[j].bytes, FALSE);
+
+               datum = FunctionCall2(&giststate->unionFn[j],
+                                                         PointerGetDatum(evec),
+                                                         PointerGetDatum(&datumsize));
+
+               if (!(DatumGetPointer(ev0p->key) != NULL &&
+                         DatumGetPointer(ev1p->key) != NULL))
+                       result = (DatumGetPointer(ev0p->key) == NULL &&
+                                         DatumGetPointer(ev1p->key) == NULL);
+               else
+               {
+                       FunctionCall3(&giststate->equalFn[j],
+                                                 ev0p->key,
+                                                 datum,
+                                                 PointerGetDatum(&result));
+               }
+               if ( !result ) 
+                       neednew = true;
+
+               if ( olddec[j] && DatumGetPointer(oldatt[j].key) != NULL )
+                       pfree( DatumGetPointer(oldatt[j].key) );
+               if ( adddec[j] && DatumGetPointer(addatt[j].key) != NULL )
+                       pfree( DatumGetPointer(addatt[j].key) );
+
+               gistcentryinit(giststate, j, &centry[j], datum,
+                       (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
+                       datumsize, FALSE);
+       
+               isnull[j] = DatumGetPointer(centry[j].key) != NULL ? ' ' : 'n';
+               attr[j] =  centry[j].key;
+               if ( DatumGetPointer(centry[j].key) != NULL ) {
+                       whatfree[j] = TRUE;
+                       if ( centry[j].key != datum )
+                               pfree(DatumGetPointer(datum));
+               } else
+                       whatfree[j] = FALSE;
+
+       } 
+       pfree(evec);
 
-       datum = (char *)
-               DatumGetPointer(FunctionCall2(&giststate->unionFn,
-                                                                         PointerGetDatum(evec),
-                                                                         PointerGetDatum(&datumsize)));
-
-       if (!(ev0p->pred && ev1p->pred))
-               result = (ev0p->pred == NULL && ev1p->pred == NULL);
-       else
-       {
-               FunctionCall3(&giststate->equalFn,
-                                         PointerGetDatum(ev0p->pred),
-                                         PointerGetDatum(datum),
-                                         PointerGetDatum(&result));
+       if (neednew) {
+               /* need to update key */
+               newtup = (IndexTuple) index_formtuple(r->rd_att, attr, isnull);
+               newtup->t_tid = oldtup->t_tid;
        }
+       
+       for (j = 0; j < r->rd_att->natts; j++)
+               if ( whatfree[j] )
+                       pfree(DatumGetPointer(attr[j]));
 
-       if (result)
-       {
-               /* not need to update key */
-               pfree(datum);
-       }
-       else
-       {
-               gistcentryinit(giststate, &centry, datum, ev0p->rel, ev0p->page,
-                                          ev0p->offset, datumsize, FALSE);
+       return newtup;
+}
 
-               isnull = (centry.pred) ? ' ' : 'n';
-               newtup = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &centry.pred, &isnull);
-               newtup->t_tid = oldtup->t_tid;
-               if (centry.pred != datum)
-                       pfree(datum);
+static void
+gistunionsubkey( Relation r, GISTSTATE *giststate, IndexTuple *itvec, GIST_SPLITVEC * spl ) {
+       int i,j,lr;
+       Datum      *attr;
+       bool *needfree, IsNull;
+       int len, *attrsize;
+       OffsetNumber    *entries;
+       bytea      *evec;
+       Datum           datum;
+       int datumsize;
+
+       for(lr=0;lr<=1;lr++) {  
+               if ( lr ) {
+                       attrsize = spl->spl_lattrsize;
+                       attr = spl->spl_lattr;
+                       len = spl->spl_nleft;
+                       entries = spl->spl_left;
+               } else {
+                       attrsize = spl->spl_rattrsize;
+                       attr = spl->spl_rattr;
+                       len = spl->spl_nright;
+                       entries = spl->spl_right;
+               }
+
+               needfree =  (bool *) palloc( (( len==1 ) ? 2 : len ) * sizeof(bool));
+               evec     = (bytea *) palloc( (( len==1 ) ? 2 : len ) * sizeof(GISTENTRY) + VARHDRSZ);
+               VARATT_SIZEP(evec) =         (( len==1 ) ? 2 : len ) * sizeof(GISTENTRY) + VARHDRSZ;
+               for (j = 1; j < r->rd_att->natts; j++) {
+                       for (i = 0; i < len; i++) {
+                               if ( spl->spl_idgrp[ entries[i] ] )
+                               {
+                                       datum = (Datum) 0;
+                                       IsNull = true;
+                               } else
+                                       datum = index_getattr(itvec[ entries[i]-1 ], j+1,
+                                                                                 r->rd_att, &IsNull);
+                               gistdentryinit(giststate, j,
+                                                          &((GISTENTRY *) VARDATA(evec))[i],
+                                                          datum,
+                                                          (Relation) NULL, (Page) NULL,
+                                                          (OffsetNumber) NULL,
+                                                          ATTSIZE( datum, r, j+1, IsNull ), FALSE);
+                               if ( DatumGetPointer(((GISTENTRY *) VARDATA(evec))[i].key) != NULL &&
+                                               ((GISTENTRY *) VARDATA(evec))[i].key != datum )
+                                       needfree[i] = TRUE;
+                               else
+                                       needfree[i] = FALSE;
+                       
+                       } 
+                       if ( len == 1 &&
+                                DatumGetPointer(((GISTENTRY *) VARDATA(evec))[0].key) == NULL)
+                       {
+                               datum = (Datum) 0;
+                               datumsize = 0;
+                       } else {
+                               /*
+                                * ((GISTENTRY *) VARDATA(evec))[0].bytes may be not defined,
+                                * so form union with itself
+                                */
+                               if ( len == 1 ) {
+                                       memcpy( (void*) &((GISTENTRY *) VARDATA(evec))[1],
+                                               (void*) &((GISTENTRY *) VARDATA(evec))[0],
+                                               sizeof( GISTENTRY ) );
+                               }
+                               datum = FunctionCall2(&giststate->unionFn[j],
+                                                                         PointerGetDatum(evec),
+                                                                         PointerGetDatum(&datumsize));
+                       } 
+
+                       for (i = 0; i < len; i++)
+                               if ( needfree[i] )
+                                       pfree(DatumGetPointer(((GISTENTRY *) VARDATA(evec))[i].key));
+                       
+                       attr[j] = datum;
+                       attrsize[j] = datumsize;
+               }
+               pfree(evec);
+               pfree(needfree);
        }
+}
 
-       if (ev0p->pred &&
-               ev0p->pred != (char *) oldtup + sizeof(IndexTupleData))
-               pfree(ev0p->pred);
-       if (ev1p->pred &&
-               ev1p->pred != (char *) addtup + sizeof(IndexTupleData))
-               pfree(ev1p->pred);
-       pfree(evec);
+/*
+ * find group in vector with equial value 
+ */
+static int
+gistfindgroup( GISTSTATE *giststate, GISTENTRY *valvec, GIST_SPLITVEC * spl ) {
+       int i,j,len;
+       int curid = 1;
+       bool result;
+
+       for(i=0; i<spl->spl_nleft; i++) {
+               if ( spl->spl_idgrp[ spl->spl_left[i] ]) continue;
+               len = 0;
+               /* find all equal value in right part */
+               for(j=0; j < spl->spl_nright; j++) {
+                       if ( spl->spl_idgrp[ spl->spl_right[j] ]) continue;
+                       if (!(DatumGetPointer(valvec[ spl->spl_left[i] ].key) != NULL &&
+                                 DatumGetPointer(valvec[ spl->spl_right[j]].key) != NULL))
+                               result =
+                                       DatumGetPointer(valvec[ spl->spl_left[i] ].key) == NULL && 
+                                       DatumGetPointer(valvec[ spl->spl_right[j]].key) == NULL;
+                       else
+                               FunctionCall3(&giststate->equalFn[0],
+                                                         valvec[ spl->spl_left[i]  ].key,
+                                                         valvec[ spl->spl_right[j] ].key,
+                                                         PointerGetDatum(&result));
+                       if ( result ) {
+                               spl->spl_idgrp[ spl->spl_right[j] ] = curid;
+                               len++;
+                       }
+               }
+               /* find all other equal value in left part */
+               if ( len ) {
+                       /* add current val to list of equial values*/
+                       spl->spl_idgrp[ spl->spl_left[i] ]=curid;
+                       /* searching .. */
+                       for(j=i+1; j < spl->spl_nleft; j++) {
+                               if ( spl->spl_idgrp[ spl->spl_left[j] ]) continue;
+                               if (!(DatumGetPointer(valvec[ spl->spl_left[i]].key) != NULL &&
+                                         DatumGetPointer(valvec[ spl->spl_left[j]].key) != NULL))
+                                       result =
+                                               DatumGetPointer(valvec[ spl->spl_left[i]].key) == NULL && 
+                                               DatumGetPointer(valvec[ spl->spl_left[j]].key) == NULL;
+                               else
+                                       FunctionCall3(&giststate->equalFn[0],
+                                                                 valvec[ spl->spl_left[i]  ].key,
+                                                                 valvec[ spl->spl_left[j]  ].key,
+                                                                 PointerGetDatum(&result));
+                               if ( result ) {
+                                       spl->spl_idgrp[ spl->spl_left[j] ] = curid;
+                                       len++;
+                               }
+                       }
+                       spl->spl_ngrp[curid] = len+1;
+                       curid++;
+               }
+       }
 
-       return newtup;
+       return curid;
 }
 
 /*
@@ -773,23 +999,20 @@ gistSplit(Relation r,
                                rightbuf;
        Page            left,
                                right;
-       OffsetNumber *spl_left,
-                          *spl_right;
        IndexTuple *lvectup,
                           *rvectup,
                           *newtup;
-       int                     leftoff,
-                               rightoff;
        BlockNumber lbknum,
                                rbknum;
        GISTPageOpaque opaque;
-       char            isnull;
        GIST_SPLITVEC v;
        bytea      *entryvec;
        bool       *decompvec;
-       GISTENTRY       tmpentry;
-       int                     i,
+       int                     i,j,
                                nlen;
+       int MaxGrpId    = 1;
+       Datum           datum;
+       bool IsNull;
 
        p = (Page) BufferGetPage(buffer);
        opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
@@ -827,49 +1050,187 @@ gistSplit(Relation r,
        VARATT_SIZEP(entryvec) = (*len + 1) * sizeof(GISTENTRY) + VARHDRSZ;
        for (i = 1; i <= *len; i++)
        {
-               gistdentryinit(giststate, &((GISTENTRY *) VARDATA(entryvec))[i],
-                                          (((char *) itup[i - 1]) + sizeof(IndexTupleData)),
-                                          r, p, i,
-                       IndexTupleSize(itup[i - 1]) - sizeof(IndexTupleData), FALSE);
-               if ((char *) (((GISTENTRY *) VARDATA(entryvec))[i].pred)
-                       == (((char *) itup[i - 1]) + sizeof(IndexTupleData)))
+               datum = index_getattr(itup[i - 1], 1, r->rd_att, &IsNull);
+               gistdentryinit(giststate, 0,&((GISTENTRY *) VARDATA(entryvec))[i],
+                                       datum, r, p, i,
+                                       ATTSIZE( datum, r, 1, IsNull ), FALSE);
+               if (((GISTENTRY *) VARDATA(entryvec))[i].key == datum ||
+                       DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key) == NULL)
                        decompvec[i] = FALSE;
                else
                        decompvec[i] = TRUE;
        }
 
        /* now let the user-defined picksplit function set up the split vector */
-       FunctionCall2(&giststate->picksplitFn,
+       FunctionCall2(&giststate->picksplitFn[0],
                                  PointerGetDatum(entryvec),
                                  PointerGetDatum(&v));
 
-       /* clean up the entry vector: its preds need to be deleted, too */
+       /* compatibility with old code */       
+       if ( v.spl_left[ v.spl_nleft-1 ] == InvalidOffsetNumber ) 
+               v.spl_left[ v.spl_nleft-1 ] = (OffsetNumber)*len;
+       if ( v.spl_right[ v.spl_nright-1 ] == InvalidOffsetNumber ) 
+               v.spl_right[ v.spl_nright-1 ] = (OffsetNumber)*len;
+       
+       v.spl_lattr[0] = v.spl_ldatum; 
+       v.spl_rattr[0] = v.spl_rdatum;
+
+       /* if index is multikey, then we must to try get smaller
+        * bounding box for subkey(s)
+         */
+       if ( r->rd_att->natts > 1 ) {
+               v.spl_idgrp  = (int*) palloc( sizeof(int) * (*len + 1) );
+               MemSet((void*)v.spl_idgrp, 0, sizeof(int) * (*len + 1) );
+               v.spl_grpflag = (char*) palloc( sizeof(char) * (*len + 1) );
+               MemSet((void*)v.spl_grpflag, 0, sizeof(char) * (*len + 1) );
+               v.spl_ngrp    = (int*) palloc( sizeof(int) * (*len + 1) );
+
+               MaxGrpId = gistfindgroup( giststate, (GISTENTRY *) VARDATA(entryvec), &v );
+
+               /* form union of sub keys for each page (l,p) */
+               gistunionsubkey( r, giststate, itup, &v );
+
+               /* if possible, we insert equivalrnt tuples
+                * with control by penalty for a subkey(s)
+                 */
+               if ( MaxGrpId > 1 ) {
+                       int     curlen;
+                       OffsetNumber    *curwpos;
+                       bool decfree[INDEX_MAX_KEYS];
+                       GISTENTRY entry,identry[INDEX_MAX_KEYS], *ev0p, *ev1p;
+                       float lpenalty, rpenalty;
+                       bytea      *evec;
+                       int     datumsize;
+
+                       /* clear vectors */
+                       curlen = v.spl_nleft;
+                       curwpos = v.spl_left;
+                       for( i=0; i<v.spl_nleft;i++ )
+                               if ( v.spl_idgrp[ v.spl_left[i] ] == 0 ) {
+                                       *curwpos = v.spl_left[i];
+                                       curwpos++;
+                               } else
+                                       curlen--;
+                       v.spl_nleft = curlen;
+
+                       curlen = v.spl_nright;
+                       curwpos = v.spl_right;
+                       for( i=0; i<v.spl_nright;i++ )
+                               if ( v.spl_idgrp[ v.spl_right[i] ] == 0 ) {
+                                       *curwpos = v.spl_right[i];
+                                       curwpos++;
+                               } else
+                                       curlen--;
+                       v.spl_nright = curlen;
+
+                       evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ);
+                       VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
+                       ev0p = &((GISTENTRY *) VARDATA(evec))[0];
+                       ev1p = &((GISTENTRY *) VARDATA(evec))[1];
+
+                       /* add equivalent tuple */
+                       for(i = 0; i< *len; i++) {
+                               if ( v.spl_idgrp[ i+1 ]==0 ) /* already inserted */
+                                       continue;
+                               gistDeCompressAtt( giststate, r, itup[i], (Page) NULL, (OffsetNumber) 0,
+                                       identry, decfree);
+
+                               v.spl_ngrp[ v.spl_idgrp[ i+1 ] ]--;
+                               if ( v.spl_ngrp[ v.spl_idgrp[ i+1 ] ] == 0 && 
+                                       (v.spl_grpflag[ v.spl_idgrp[ i+1 ] ] & BOTH_ADDED) != BOTH_ADDED ) {
+
+                                       /* force last in group */
+                                       rpenalty = 1.0;
+                                       lpenalty = ( v.spl_grpflag[ v.spl_idgrp[ i+1 ] ] & LEFT_ADDED ) ? 2.0 : 0.0;
+                               } else { 
+                                       /*where?*/
+                                       for( j=1; j<r->rd_att->natts; j++ ) {
+                                               gistentryinit(entry,v.spl_lattr[j], r, (Page) NULL,
+                                                       (OffsetNumber) 0, v.spl_lattrsize[j], FALSE);
+                                               FunctionCall3(&giststate->penaltyFn[j],
+                                                       PointerGetDatum(&entry),
+                                                       PointerGetDatum(&identry[j]),
+                                                       PointerGetDatum(&lpenalty));
+       
+                                               gistentryinit(entry,v.spl_rattr[j], r, (Page) NULL,
+                                                       (OffsetNumber) 0, v.spl_rattrsize[j], FALSE);
+                                               FunctionCall3(&giststate->penaltyFn[j],
+                                                       PointerGetDatum(&entry),
+                                                       PointerGetDatum(&identry[j]),
+                                                       PointerGetDatum(&rpenalty));
+       
+                                               if ( lpenalty != rpenalty ) 
+                                                       break;
+                                       }
+                               }
+                               /* add */
+                               if ( lpenalty < rpenalty ) {
+                                       v.spl_grpflag[ v.spl_idgrp[ i+1 ] ] |= LEFT_ADDED;
+                                       v.spl_left[ v.spl_nleft ] = i+1;
+                                       v.spl_nleft++;
+                                       for( j=1; j<r->rd_att->natts; j++ ) {
+                                               gistentryinit(*ev0p, v.spl_lattr[j], r, (Page) NULL, 
+                                                       (OffsetNumber) 0, v.spl_lattrsize[j], FALSE);
+                                               gistentryinit(*ev1p, identry[j].key, r, (Page) NULL, 
+                                                       (OffsetNumber) 0, identry[j].bytes, FALSE);
+
+                                               datum = FunctionCall2(&giststate->unionFn[j],
+                                                                                         PointerGetDatum(evec),
+                                                                                         PointerGetDatum(&datumsize));
+
+                                               if ( DatumGetPointer(v.spl_lattr[j]) != NULL )
+                                                       pfree( DatumGetPointer(v.spl_lattr[j]) );
+
+                                               v.spl_lattr[j] = datum;
+                                               v.spl_lattrsize[j] = datumsize;
+                                       }
+                               } else {
+                                       v.spl_grpflag[ v.spl_idgrp[ i+1 ] ] |= RIGHT_ADDED;
+                                       v.spl_right[ v.spl_nright ] = i+1;
+                                       v.spl_nright++;
+                                       for( j=1; j<r->rd_att->natts; j++ ) {
+                                               gistentryinit(*ev0p, v.spl_rattr[j], r, (Page) NULL, 
+                                                       (OffsetNumber) 0, v.spl_rattrsize[j], FALSE);
+                                               gistentryinit(*ev1p, identry[j].key, r, (Page) NULL, 
+                                                       (OffsetNumber) 0, identry[j].bytes, FALSE);
+
+                                               datum = FunctionCall2(&giststate->unionFn[j],
+                                                                                         PointerGetDatum(evec),
+                                                                                         PointerGetDatum(&datumsize));
+
+                                               if ( DatumGetPointer(v.spl_rattr[j]) != NULL )
+                                                       pfree( DatumGetPointer(v.spl_rattr[j]) );
+
+                                               v.spl_rattr[j] = datum;
+                                               v.spl_rattrsize[j] = datumsize;
+                                       }
+
+                               } 
+                               gistFreeAtt( r, identry, decfree );
+                       }
+                       pfree(evec);
+               }               
+               pfree( v.spl_idgrp );
+               pfree( v.spl_grpflag );
+               pfree( v.spl_ngrp );
+       } 
+
+       /* clean up the entry vector: its keys need to be deleted, too */
        for (i = 1; i <= *len; i++)
-               if (decompvec[i] && ((GISTENTRY *) VARDATA(entryvec))[i].pred)
-                       pfree(((GISTENTRY *) VARDATA(entryvec))[i].pred);
+               if (decompvec[i])
+                       pfree(DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key));
        pfree(entryvec);
        pfree(decompvec);
 
-       spl_left = v.spl_left;
-       spl_right = v.spl_right;
-
        /* form left and right vector */
        lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nleft);
        rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nright);
-       leftoff = rightoff = 0;
-       for (i = 1; i <= *len; i++)
-       {
-               if (i == *(spl_left) || (i == *len && *(spl_left) != FirstOffsetNumber))
-               {
-                       lvectup[leftoff++] = itup[i - 1];
-                       spl_left++;
-               }
-               else
-               {
-                       rvectup[rightoff++] = itup[i - 1];
-                       spl_right++;
-               }
-       }
+
+       for(i=0; i<v.spl_nleft;i++) 
+               lvectup[i] = itup[ v.spl_left[i] - 1 ];
+
+       for(i=0; i<v.spl_nright;i++) 
+               rvectup[i] = itup[ v.spl_right[i] - 1 ];
 
        /* write on disk (may be need another split) */
        if (gistnospace(right, rvectup, v.spl_nright))
@@ -878,6 +1239,9 @@ gistSplit(Relation r,
                newtup = gistSplit(r, rightbuf, rvectup, &nlen, giststate,
                          (res && rvectup[nlen - 1] == itup[*len - 1]) ? res : NULL);
                ReleaseBuffer(rightbuf);
+               for( j=1; j<r->rd_att->natts; j++ ) 
+                       if ( DatumGetPointer(v.spl_rattr[j]) != NULL )
+                               pfree( DatumGetPointer(v.spl_rattr[j]) ); 
        }
        else
        {
@@ -888,20 +1252,14 @@ gistSplit(Relation r,
 
                if (res)
                        ItemPointerSet(&((*res)->pointerData), rbknum, l);
-               gistcentryinit(giststate, &tmpentry, v.spl_rdatum, (Relation) NULL,
-                                          (Page) NULL, (OffsetNumber) 0,
-                                          -1, FALSE);
-               if (v.spl_rdatum != tmpentry.pred)
-                       pfree(v.spl_rdatum);
-               v.spl_rdatum = tmpentry.pred;
 
                nlen = 1;
                newtup = (IndexTuple *) palloc(sizeof(IndexTuple) * 1);
-               isnull = (v.spl_rdatum) ? ' ' : 'n';
-               newtup[0] = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &(v.spl_rdatum), &isnull);
+               newtup[0] = gistFormTuple( giststate, r, v.spl_rattr, v.spl_rattrsize ); 
                ItemPointerSet(&(newtup[0]->t_tid), rbknum, 1);
        }
 
+
        if (gistnospace(left, lvectup, v.spl_nleft))
        {
                int                     llen = v.spl_nleft;
@@ -911,6 +1269,10 @@ gistSplit(Relation r,
                          (res && lvectup[llen - 1] == itup[*len - 1]) ? res : NULL);
                ReleaseBuffer(leftbuf);
 
+               for( j=1; j<r->rd_att->natts; j++ ) 
+                       if ( DatumGetPointer(v.spl_lattr[j]) != NULL )
+                               pfree( DatumGetPointer(v.spl_lattr[j]) ); 
+
                newtup = gistjoinvector(newtup, &nlen, lntup, llen);
                pfree(lntup);
        }
@@ -926,17 +1288,10 @@ gistSplit(Relation r,
 
                if (res)
                        ItemPointerSet(&((*res)->pointerData), lbknum, l);
-               gistcentryinit(giststate, &tmpentry, v.spl_ldatum, (Relation) NULL,
-                                          (Page) NULL, (OffsetNumber) 0,
-                                          -1, FALSE);
-               if (v.spl_ldatum != tmpentry.pred)
-                       pfree(v.spl_ldatum);
-               v.spl_ldatum = tmpentry.pred;
 
                nlen += 1;
                newtup = (IndexTuple *) repalloc((void *) newtup, sizeof(IndexTuple) * nlen);
-               isnull = (v.spl_ldatum) ? ' ' : 'n';
-               newtup[nlen - 1] = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &(v.spl_ldatum), &isnull);
+               newtup[nlen - 1] = gistFormTuple( giststate, r, v.spl_lattr, v.spl_lattrsize );
                ItemPointerSet(&(newtup[nlen - 1]->t_tid), lbknum, 1);
        }
 
@@ -995,48 +1350,52 @@ gistchoose(Relation r, Page p, IndexTuple it,    /* it has compressed entry */
 {
        OffsetNumber maxoff;
        OffsetNumber i;
-       char       *id;
-       char       *datum;
+       Datum           datum;
        float           usize;
        OffsetNumber which;
-       float           which_grow;
+       float           sum_grow, which_grow[INDEX_MAX_KEYS];
        GISTENTRY       entry,
-                               identry;
-       int                     size,
-                               idsize;
+                               identry[INDEX_MAX_KEYS];
+       bool IsNull, decompvec[INDEX_MAX_KEYS];
+       int j;
 
-       idsize = IndexTupleSize(it) - sizeof(IndexTupleData);
-       id = ((char *) it) + sizeof(IndexTupleData);
        maxoff = PageGetMaxOffsetNumber(p);
-       which_grow = -1.0;
+       *which_grow = -1.0;
        which = -1;
+       sum_grow=1;
+       gistDeCompressAtt( giststate, r, 
+                                it, (Page) NULL, (OffsetNumber) 0, 
+                                identry, decompvec );
 
-       gistdentryinit(giststate, &identry, id, (Relation) NULL, (Page) NULL,
-                                  (OffsetNumber) 0, idsize, FALSE);
-
-       for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+       for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
        {
-               datum = (char *) PageGetItem(p, PageGetItemId(p, i));
-               size = IndexTupleSize(datum) - sizeof(IndexTupleData);
-               datum += sizeof(IndexTupleData);
-               gistdentryinit(giststate, &entry, datum, r, p, i, size, FALSE);
-               FunctionCall3(&giststate->penaltyFn,
-                                         PointerGetDatum(&entry),
-                                         PointerGetDatum(&identry),
-                                         PointerGetDatum(&usize));
-               if (which_grow < 0 || usize < which_grow)
-               {
-                       which = i;
-                       which_grow = usize;
-                       if (which_grow == 0)
+               sum_grow=0;
+               for( j=0; j<r->rd_att->natts; j++ ) {
+                       datum = index_getattr( (IndexTuple)PageGetItem(p, PageGetItemId(p, i)), j+1, r->rd_att, &IsNull);
+                       gistdentryinit(giststate, j, &entry, datum, r, p, i, ATTSIZE( datum, r, j+1, IsNull ), FALSE);
+                       FunctionCall3(&giststate->penaltyFn[j],
+                                                 PointerGetDatum(&entry),
+                                                 PointerGetDatum(&identry[j]),
+                                                 PointerGetDatum(&usize));
+
+                       if (DatumGetPointer(entry.key) != NULL && entry.key != datum) 
+                               pfree(DatumGetPointer(entry.key));
+
+                       if ( which_grow[j]<0 || usize < which_grow[j] ) {
+                               which = i;
+                               which_grow[j] = usize;
+                               if ( j<r->rd_att->natts-1 && i==FirstOffsetNumber ) which_grow[j+1]=-1;
+                               sum_grow += which_grow[j]; 
+                       } else if ( which_grow[j] == usize )  {
+                               sum_grow += usize;
+                       } else {
+                               sum_grow=1;
                                break;
+                       }
                }
-               if (entry.pred && entry.pred != datum)
-                       pfree(entry.pred);
        }
-       if (identry.pred && identry.pred != id)
-               pfree(identry.pred);
 
+       gistFreeAtt( r, identry, decompvec );
        return which;
 }
 
@@ -1104,21 +1463,28 @@ initGISTstate(GISTSTATE *giststate, Relation index)
        HeapTuple       htup;
        Form_pg_index itupform;
        Oid                     indexrelid;
-
-       consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC);
-       union_proc = index_getprocid(index, 1, GIST_UNION_PROC);
-       compress_proc = index_getprocid(index, 1, GIST_COMPRESS_PROC);
-       decompress_proc = index_getprocid(index, 1, GIST_DECOMPRESS_PROC);
-       penalty_proc = index_getprocid(index, 1, GIST_PENALTY_PROC);
-       picksplit_proc = index_getprocid(index, 1, GIST_PICKSPLIT_PROC);
-       equal_proc = index_getprocid(index, 1, GIST_EQUAL_PROC);
-       fmgr_info(consistent_proc, &giststate->consistentFn);
-       fmgr_info(union_proc, &giststate->unionFn);
-       fmgr_info(compress_proc, &giststate->compressFn);
-       fmgr_info(decompress_proc, &giststate->decompressFn);
-       fmgr_info(penalty_proc, &giststate->penaltyFn);
-       fmgr_info(picksplit_proc, &giststate->picksplitFn);
-       fmgr_info(equal_proc, &giststate->equalFn);
+       int i;
+
+        if (index->rd_att->natts >= INDEX_MAX_KEYS)
+                elog(ERROR, "initGISTstate: numberOfAttributes %d > %d",
+                         index->rd_att->natts, INDEX_MAX_KEYS);
+
+       for(i=0; i<index->rd_att->natts; i++) {
+               consistent_proc = index_getprocid(index, i+1, GIST_CONSISTENT_PROC      );
+               union_proc      = index_getprocid(index, i+1, GIST_UNION_PROC           );
+               compress_proc   = index_getprocid(index, i+1, GIST_COMPRESS_PROC        );
+               decompress_proc = index_getprocid(index, i+1, GIST_DECOMPRESS_PROC      );
+               penalty_proc    = index_getprocid(index, i+1, GIST_PENALTY_PROC         );
+               picksplit_proc  = index_getprocid(index, i+1, GIST_PICKSPLIT_PROC       );
+               equal_proc      = index_getprocid(index, i+1, GIST_EQUAL_PROC           );
+               fmgr_info(consistent_proc,      &((giststate->consistentFn)[i])         );
+               fmgr_info(union_proc,           &((giststate->unionFn)[i])              );
+               fmgr_info(compress_proc,        &((giststate->compressFn)[i])           );
+               fmgr_info(decompress_proc,      &((giststate->decompressFn)[i])         );
+               fmgr_info(penalty_proc,         &((giststate->penaltyFn)[i])            );
+               fmgr_info(picksplit_proc,       &((giststate->picksplitFn)[i])          );
+               fmgr_info(equal_proc,           &((giststate->equalFn)[i])              );
+       }
 
        /* see if key type is different from type of attribute being indexed */
        htup = SearchSysCache(INDEXRELID,
@@ -1149,21 +1515,31 @@ initGISTstate(GISTSTATE *giststate, Relation index)
                giststate->keytypbyval = FALSE;
 }
 
-
+#ifdef GIST_PAGEADDITEM
 /*
 ** Given an IndexTuple to be inserted on a page, this routine replaces
 ** the key with another key, which may involve generating a new IndexTuple
-** if the sizes don't match
+** if the sizes don't match or if the null status changes.
+**
+** XXX this only works for a single-column index tuple!
 */
 static IndexTuple
 gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
 {
-       char       *datum = (((char *) t) + sizeof(IndexTupleData));
+       bool IsNull;
+       Datum   datum = index_getattr(t, 1, r->rd_att, &IsNull);
 
-       /* if new entry fits in index tuple, copy it in */
-       if ((Size) entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData) || (Size) entry.bytes == 0)
+       /*
+        * If new entry fits in index tuple, copy it in.  To avoid worrying
+        * about null-value bitmask, pass it off to the general index_formtuple
+        * routine if either the previous or new value is NULL.
+        */
+       if (!IsNull && DatumGetPointer(entry.key) != NULL &&
+               (Size) entry.bytes <= ATTSIZE(datum, r, 1, IsNull))
        {
-               memcpy(datum, entry.pred, entry.bytes);
+               memcpy(DatumGetPointer(datum),
+                          DatumGetPointer(entry.key),
+                          entry.bytes);
                /* clear out old size */
                t->t_info &= ~INDEX_SIZE_MASK;
                /* or in new size */
@@ -1178,65 +1554,131 @@ gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
                IndexTuple      newtup;
                char            isnull;
 
-               isnull = (entry.pred) ? ' ' : 'n';
+               isnull = DatumGetPointer(entry.key) != NULL ? ' ' : 'n';
                newtup = (IndexTuple) index_formtuple(tupDesc,
-                                                                                         (Datum *) &(entry.pred),
+                                                                                         &(entry.key),
                                                                                          &isnull);
                newtup->t_tid = t->t_tid;
                return newtup;
        }
 }
-
+#endif
 
 /*
-** initialize a GiST entry with a decompressed version of pred
+** initialize a GiST entry with a decompressed version of key
 */
 void
-gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r,
-                          Page pg, OffsetNumber o, int b, bool l)
+gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
+                          Datum k, Relation r, Page pg, OffsetNumber o,
+                          int b, bool l)
 {
        GISTENTRY  *dep;
 
-       gistentryinit(*e, pr, r, pg, o, b, l);
+       gistentryinit(*e, k, r, pg, o, b, l);
        if (giststate->haskeytype)
        {
                if ( b ) {
                        dep = (GISTENTRY *)
-                               DatumGetPointer(FunctionCall1(&giststate->decompressFn,
+                               DatumGetPointer(FunctionCall1(&giststate->decompressFn[nkey],
                                                                                  PointerGetDatum(e)));
-                       gistentryinit(*e, dep->pred, dep->rel, dep->page, dep->offset, dep->bytes,
+                       gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset, dep->bytes,
                                          dep->leafkey);
                        if (dep != e)
                                pfree(dep);
                } else {
-                       gistentryinit(*e, (char*)NULL, r, pg, o, 0, l);
+                       gistentryinit(*e, (Datum) 0, r, pg, o, 0, l);
                }
        }
 }
 
 
 /*
-** initialize a GiST entry with a compressed version of pred
+** initialize a GiST entry with a compressed version of key
 */
 static void
-gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r,
+gistcentryinit(GISTSTATE *giststate, int nkey,
+                          GISTENTRY *e, Datum k, Relation r,
                           Page pg, OffsetNumber o, int b, bool l)
 {
        GISTENTRY  *cep;
 
-       gistentryinit(*e, pr, r, pg, o, b, l);
+       gistentryinit(*e, k, r, pg, o, b, l);
        if (giststate->haskeytype)
        {
                cep = (GISTENTRY *)
-                       DatumGetPointer(FunctionCall1(&giststate->compressFn,
+                       DatumGetPointer(FunctionCall1(&giststate->compressFn[nkey],
                                                                                  PointerGetDatum(e)));
-               gistentryinit(*e, cep->pred, cep->rel, cep->page, cep->offset, cep->bytes,
-                                         cep->leafkey);
+               gistentryinit(*e, cep->key, cep->rel, cep->page, cep->offset,
+                                         cep->bytes, cep->leafkey);
                if (cep != e)
                        pfree(cep);
        }
 }
 
+static IndexTuple
+gistFormTuple( GISTSTATE *giststate, Relation r,
+                          Datum attdata[], int datumsize[] )
+{
+       IndexTuple      tup;
+       char            isnull[INDEX_MAX_KEYS];
+       bool    whatfree[INDEX_MAX_KEYS];
+       GISTENTRY       centry[INDEX_MAX_KEYS];
+       Datum   compatt[INDEX_MAX_KEYS];
+       int j;
+       
+       for (j = 0; j < r->rd_att->natts; j++) {
+               gistcentryinit(giststate, j, &centry[j], attdata[j],
+                       (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
+                       datumsize[j], FALSE);
+               isnull[j] = DatumGetPointer(centry[j].key) != NULL ? ' ' : 'n';
+               compatt[j] = centry[j].key;
+               if ( DatumGetPointer(centry[j].key) != NULL ) {
+                       whatfree[j] = TRUE;
+                       if ( centry[j].key != attdata[j] )
+                               pfree(DatumGetPointer(attdata[j]));
+               } else
+                       whatfree[j] = FALSE;
+       }
+
+       tup = (IndexTuple) index_formtuple(r->rd_att, compatt, isnull);
+       for (j = 0; j < r->rd_att->natts; j++)
+               if ( whatfree[j] ) pfree(DatumGetPointer(compatt[j]));
+
+       return  tup;
+}  
+
+static bool
+gistDeCompressAtt( GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, 
+                       OffsetNumber o, GISTENTRY attdata[], bool decompvec[] ) {
+       bool allIsNull=true;
+       bool IsNull;
+       int i;
+       Datum   datum;
+
+       for(i=0; i < r->rd_att->natts; i++ ) {
+               datum = index_getattr(tuple, i+1, r->rd_att, &IsNull);
+               if ( ! IsNull ) allIsNull = false;
+               gistdentryinit(giststate, i, &attdata[i],
+                                       datum, r, p, o,
+                                       ATTSIZE( datum, r, i+1, IsNull ), FALSE);
+               if (attdata[i].key == datum ||
+                       DatumGetPointer(attdata[i].key) == NULL )
+                       decompvec[i] = FALSE;
+               else
+                       decompvec[i] = TRUE;
+       }
+
+       return allIsNull;
+} 
+
+static void
+gistFreeAtt(  Relation r, GISTENTRY attdata[], bool decompvec[] ) {
+       int i;
+       for(i=0; i < r->rd_att->natts; i++ )
+               if ( decompvec[i] && DatumGetPointer(attdata[i].key) != NULL )
+                       pfree( DatumGetPointer(attdata[i].key) );
+}
 #ifdef GISTDEBUG
 static void
 gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
@@ -1261,7 +1703,9 @@ gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
 
        maxoff = PageGetMaxOffsetNumber(page);
 
-       elog(NOTICE, "%sPage: %d %s blk: %d maxoff: %d free: %d", pred, coff, (opaque->flags & F_LEAF) ? "LEAF" : "INTE", (int) blk, (int) maxoff, PageGetFreeSpace(page));
+       elog(NOTICE, "%sPage: %d %s blk: %d maxoff: %d free: %d", pred,
+                coff, (opaque->flags & F_LEAF) ? "LEAF" : "INTE", (int) blk,
+                (int) maxoff, PageGetFreeSpace(page));
 
        for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
        {
@@ -1269,7 +1713,8 @@ gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
                which = (IndexTuple) PageGetItem(page, iid);
                cblk = ItemPointerGetBlockNumber(&(which->t_tid));
 #ifdef PRINTTUPLE
-               elog(NOTICE, "%s  Tuple. blk: %d size: %d", pred, (int) cblk, IndexTupleSize(which));
+               elog(NOTICE, "%s  Tuple. blk: %d size: %d", pred, (int) cblk,
+                        IndexTupleSize(which));
 #endif
 
                if (!(opaque->flags & F_LEAF))
index f922da750dd494631dd61bdfe3019975b31846cd..028ff601d9f3278af404df5d1fb40c81a8163633 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/gist/gistget.c,v 1.27 2001/05/30 19:53:40 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/gist/gistget.c,v 1.28 2001/05/31 18:16:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -238,16 +238,21 @@ gistindex_keytest(IndexTuple tuple,
        while (scanKeySize > 0)
        {
                datum = index_getattr(tuple,
-                                                         1,
+                                                         key[0].sk_attno,
                                                          tupdesc,
                                                          &isNull);
-               if (isNull || IndexTupleSize(tuple) == sizeof(IndexTupleData) )
+               if (isNull)
                {
                        /* XXX eventually should check if SK_ISNULL */
                        return false;
                }
 
-               gistdentryinit(giststate, &de, (char *) datum, r, p, offset,
+/* this code from backend/access/common/indexvalid.c. But why and what???
+               if (key[0].sk_flags & SK_ISNULL)
+                       return false;
+*/
+               gistdentryinit(giststate, key[0].sk_attno-1, &de,
+                                          datum, r, p, offset,
                                           IndexTupleSize(tuple) - sizeof(IndexTupleData),
                                           FALSE);
 
@@ -266,16 +271,16 @@ gistindex_keytest(IndexTuple tuple,
                                                                 ObjectIdGetDatum(key[0].sk_procedure));
                }
 
-               if ( (char*)de.pred != (char*)datum )
-                       if ( de.pred ) pfree( de.pred );
+               if ( de.key != datum )
+                       if ( DatumGetPointer(de.key) != NULL )
+                               pfree( DatumGetPointer(de.key) );
 
                if (DatumGetBool(test) == !!(key[0].sk_flags & SK_NEGATE))
                        return false;
 
-               scanKeySize -= 1;
+               scanKeySize--;
                key++;
        }
-
        return true;
 }
 
@@ -284,7 +289,7 @@ static OffsetNumber
 gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
 {
        OffsetNumber maxoff;
-       char       *it;
+       IndexTuple      it;
        GISTPageOpaque po;
        GISTScanOpaque so;
        GISTSTATE  *giststate;
@@ -307,8 +312,8 @@ gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
 
        while (n >= FirstOffsetNumber && n <= maxoff)
        {
-               it = (char *) PageGetItem(p, PageGetItemId(p, n));
-               if (gistindex_keytest((IndexTuple) it,
+               it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+               if (gistindex_keytest(it,
                                                          RelationGetDescr(s->relation),
                                                          s->numberOfKeys, s->keyData, giststate,
                                                          s->relation, p, n))
index bcabd6caf2ec6caf2fe9579e72baf5fe325ad229..9ffbd0389825eb5f4d09206b725540915e13e770 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.34 2001/05/30 19:53:40 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.35 2001/05/31 18:16:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -122,7 +122,7 @@ gistrescan(PG_FUNCTION_ARGS)
                        s->keyData[i].sk_procedure
                                = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
                                                                                  s->keyData[i].sk_procedure);
-                       s->keyData[i].sk_func = p->giststate->consistentFn;
+                       s->keyData[i].sk_func = p->giststate->consistentFn[i];
                }
        }
        else
@@ -153,7 +153,7 @@ gistrescan(PG_FUNCTION_ARGS)
                                s->keyData[i].sk_procedure
                                        = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
                                                                                          s->keyData[i].sk_procedure);
-                               s->keyData[i].sk_func = p->giststate->consistentFn;
+                               s->keyData[i].sk_func = p->giststate->consistentFn[i];
                        }
        }
 
index b48ef923652b4c18566842e0980e31398fa91f4e..3cea6895f318722f79f976f80d6e185975afe832 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.48 2001/03/22 06:16:07 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.49 2001/05/31 18:16:54 tgl Exp $
  *
  * INTERFACE ROUTINES
  *             index_open              - open an index relation by relationId
@@ -410,13 +410,13 @@ index_getprocid(Relation irel,
                                uint16 procnum)
 {
        RegProcedure *loc;
-       int                     natts;
+       int                     nproc;
 
-       natts = irel->rd_rel->relnatts;
+       nproc = irel->rd_am->amsupport;
 
        loc = irel->rd_support;
 
        Assert(loc != NULL);
 
-       return loc[(natts * (procnum - 1)) + (attnum - 1)];
+       return loc[(nproc * (attnum - 1)) + (procnum - 1)];
 }
index 213a3cc3ed08c8320c54e4b3ca45b14fc4ff6118..373a68fbf30e2b02bacc2ca10a1b3ca1ea120001 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.48 2001/05/30 20:52:32 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.49 2001/05/31 18:16:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -120,13 +120,15 @@ DefineIndex(char *heapRelationName,
        /*
         * XXX Hardwired hacks to check for limitations on supported index
         * types. We really ought to be learning this info from entries in the
-        * pg_am table, instead of having it wired in here!
+        * pg_am table, instead of having it wired-in here!
         */
        if (unique && accessMethodId != BTREE_AM_OID)
                elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
 
-       if (numberOfAttributes > 1 && accessMethodId != BTREE_AM_OID)
-               elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
+       if (numberOfAttributes > 1 &&
+               !( accessMethodId == BTREE_AM_OID ||
+                  accessMethodId == GIST_AM_OID))
+               elog(ERROR, "DefineIndex: multi-column indices are only available with the btree or GiST access methods");
 
        /*
         * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
index 694a628c4a41b3cd464decfc026f8c52ac47424a..9e8091a8a09c7b462f79c405623d0ed0b60b7b0a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: gist.h,v 1.27 2001/05/30 19:53:39 tgl Exp $
+ * $Id: gist.h,v 1.28 2001/05/31 18:16:55 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,13 +65,13 @@ typedef struct GISTSTACK
 
 typedef struct GISTSTATE
 {
-       FmgrInfo        consistentFn;
-       FmgrInfo        unionFn;
-       FmgrInfo        compressFn;
-       FmgrInfo        decompressFn;
-       FmgrInfo        penaltyFn;
-       FmgrInfo        picksplitFn;
-       FmgrInfo        equalFn;
+       FmgrInfo        consistentFn[INDEX_MAX_KEYS];
+       FmgrInfo        unionFn[INDEX_MAX_KEYS];
+       FmgrInfo        compressFn[INDEX_MAX_KEYS];
+       FmgrInfo        decompressFn[INDEX_MAX_KEYS];
+       FmgrInfo        penaltyFn[INDEX_MAX_KEYS];
+       FmgrInfo        picksplitFn[INDEX_MAX_KEYS];
+       FmgrInfo        equalFn[INDEX_MAX_KEYS];
        bool            haskeytype;
        bool            keytypbyval;
 } GISTSTATE;
@@ -121,21 +121,30 @@ typedef struct GIST_SPLITVEC
 {
        OffsetNumber *spl_left;         /* array of entries that go left */
        int                     spl_nleft;              /* size of this array */
-       char       *spl_ldatum;         /* Union of keys in spl_left */
+       Datum           spl_ldatum;             /* Union of keys in spl_left */
+       Datum           spl_lattr[INDEX_MAX_KEYS];  /* Union of subkeys in spl_left */
+       int        spl_lattrsize[INDEX_MAX_KEYS];
+
        OffsetNumber *spl_right;        /* array of entries that go right */
        int                     spl_nright;             /* size of the array */
-       char       *spl_rdatum;         /* Union of keys in spl_right */
+       Datum           spl_rdatum;             /* Union of keys in spl_right */
+       Datum           spl_rattr[INDEX_MAX_KEYS];  /* Union of subkeys in spl_right */
+       int        spl_rattrsize[INDEX_MAX_KEYS];
+
+       int     *spl_idgrp;
+       int     *spl_ngrp;                 /* number in each group */
+       char    *spl_grpflag;              /* flags of each group */
 } GIST_SPLITVEC;
 
 /*
- * An entry on a GiST node.  Contains the key (pred), as well as
+ * An entry on a GiST node.  Contains the key, as well as
  * its own location (rel,page,offset) which can supply the matching
- * pointer.  The size of the pred is in bytes, and leafkey is a flag to
+ * pointer.  The size of the key is in bytes, and leafkey is a flag to
  * tell us if the entry is in a leaf node.
  */
 typedef struct GISTENTRY
 {
-       char       *pred;
+       Datum           key;
        Relation        rel;
        Page            page;
        OffsetNumber offset;
@@ -146,43 +155,20 @@ typedef struct GISTENTRY
 /*
  * macro to initialize a GISTENTRY
  */
-#define gistentryinit(e, pr, r, pg, o, b, l)\
-   do {(e).pred = (pr); (e).rel = (r); (e).page = (pg); (e).offset = (o); (e).bytes = (b); (e).leafkey = (l);} while (0)
-
-/* defined in gist.c */
-#define TRLOWER(tr) (((tr)->bytes))
-#define TRUPPER(tr) (&((tr)->bytes[MAXALIGN(VARSIZE(TRLOWER(tr)))]))
-
-typedef struct txtrange
-{
-       int32           vl_len;
-       /*
-        * flag: NINF means that lower is negative infinity; PINF means that *
-        * upper is positive infinity.  0 means that both are numbers.
-        */
-       int32           flag;
-       char            bytes[2];
-} TXTRANGE;
-
-typedef struct intrange
-{
-       int                     lower;
-       int                     upper;
-       /*
-        * flag: NINF means that lower is negative infinity; PINF means that *
-        * upper is positive infinity.  0 means that both are numbers.
-        */
-       int                     flag;
-} INTRANGE;
+#define gistentryinit(e, k, r, pg, o, b, l) \
+       do { (e).key = (k); (e).rel = (r); (e).page = (pg); \
+                (e).offset = (o); (e).bytes = (b); (e).leafkey = (l); } while (0)
 
+/* gist.c */
 extern Datum gistbuild(PG_FUNCTION_ARGS);
 extern Datum gistinsert(PG_FUNCTION_ARGS);
 extern Datum gistdelete(PG_FUNCTION_ARGS);
 extern void _gistdump(Relation r);
 extern void gistfreestack(GISTSTACK *s);
 extern void initGISTstate(GISTSTATE *giststate, Relation index);
-extern void gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr,
-                          Relation r, Page pg, OffsetNumber o, int b, bool l);
+extern void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
+                                                  Datum k, Relation r, Page pg, OffsetNumber o,
+                                                  int b, bool l);
 extern StrategyNumber RelationGetGISTStrategy(Relation, AttrNumber,
                                                                                          RegProcedure);