Commit 3043810d authored by Tom Lane's avatar Tom Lane

Updates to make GIST work with multi-key indexes (from Oleg Bartunov

and Teodor Sigaev).  Declare key values as Datum where appropriate,
rather than char* (Tom Lane).
parent e1107fc2
...@@ -45,7 +45,7 @@ NDBOX *g_cube_binary_union(NDBOX * r1, NDBOX * r2, int *sizep); ...@@ -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); 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_same(NDBOX * a, NDBOX * b);
bool cube_different(NDBOX * a, NDBOX * b); bool cube_different(NDBOX * a, NDBOX * b);
...@@ -168,13 +168,15 @@ g_cube_consistent(GISTENTRY *entry, ...@@ -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 * g_cube_leaf_consistent
*/ */
if (GIST_LEAF(entry)) 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 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) ...@@ -194,7 +196,7 @@ g_cube_union(bytea *entryvec, int *sizep)
* fprintf(stderr, "union\n"); * fprintf(stderr, "union\n");
*/ */
numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); 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 * sizep = sizeof(NDBOX); -- NDBOX has variable size
...@@ -204,14 +206,8 @@ g_cube_union(bytea *entryvec, int *sizep) ...@@ -204,14 +206,8 @@ g_cube_union(bytea *entryvec, int *sizep)
for (i = 1; i < numranges; i++) for (i = 1; i < numranges; i++)
{ {
out = g_cube_binary_union(tmp, (NDBOX *) out = g_cube_binary_union(tmp, (NDBOX *)
(((GISTENTRY *) (VARDATA(entryvec)))[i]).pred, DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i]).key),
sizep); 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) if (i > 1)
pfree(tmp); pfree(tmp);
tmp = out; tmp = out;
...@@ -243,15 +239,16 @@ g_cube_decompress(GISTENTRY *entry) ...@@ -243,15 +239,16 @@ g_cube_decompress(GISTENTRY *entry)
float * float *
g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result) g_cube_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
{ {
Datum ud; NDBOX *ud;
float tmp1, float tmp1,
tmp2; tmp2;
ud = (Datum) cube_union((NDBOX *) (origentry->pred), (NDBOX *) (newentry->pred)); ud = cube_union((NDBOX *) DatumGetPointer(origentry->key),
rt_cube_size((NDBOX *) ud, &tmp1); (NDBOX *) DatumGetPointer(newentry->key));
rt_cube_size((NDBOX *) (origentry->pred), &tmp2); rt_cube_size(ud, &tmp1);
rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &tmp2);
*result = tmp1 - tmp2; *result = tmp1 - tmp2;
pfree((char *) ud); pfree(ud);
/* /*
* fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
...@@ -308,16 +305,16 @@ g_cube_picksplit(bytea *entryvec, ...@@ -308,16 +305,16 @@ g_cube_picksplit(bytea *entryvec,
for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) 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)) 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 */ /* compute the wasted space by unioning these guys */
/* size_waste = size_union - size_inter; */ /* 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); 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); rt_cube_size(inter_d, &size_inter);
size_waste = size_union - size_inter; size_waste = size_union - size_inter;
...@@ -346,12 +343,12 @@ g_cube_picksplit(bytea *entryvec, ...@@ -346,12 +343,12 @@ g_cube_picksplit(bytea *entryvec,
right = v->spl_right; right = v->spl_right;
v->spl_nright = 0; v->spl_nright = 0;
datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_1].pred); datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[seed_1].key);
datum_l = (NDBOX *) cube_union(datum_alpha, datum_alpha); datum_l = cube_union(datum_alpha, datum_alpha);
rt_cube_size((NDBOX *) datum_l, &size_l); rt_cube_size(datum_l, &size_l);
datum_beta = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_2].pred);; datum_beta = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[seed_2].key);
datum_r = (NDBOX *) cube_union(datum_beta, datum_beta); datum_r = cube_union(datum_beta, datum_beta);
rt_cube_size((NDBOX *) datum_r, &size_r); rt_cube_size(datum_r, &size_r);
/* /*
* Now split up the regions between the two seeds. An important * Now split up the regions between the two seeds. An important
...@@ -389,11 +386,11 @@ g_cube_picksplit(bytea *entryvec, ...@@ -389,11 +386,11 @@ g_cube_picksplit(bytea *entryvec,
} }
/* okay, which page needs least enlargement? */ /* okay, which page needs least enlargement? */
datum_alpha = (NDBOX *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred); datum_alpha = (NDBOX *) DatumGetPointer(((GISTENTRY *) (VARDATA(entryvec)))[i].key);
union_dl = (NDBOX *) cube_union(datum_l, datum_alpha); union_dl = cube_union(datum_l, datum_alpha);
union_dr = (NDBOX *) cube_union(datum_r, datum_alpha); union_dr = cube_union(datum_r, datum_alpha);
rt_cube_size((NDBOX *) union_dl, &size_alpha); rt_cube_size(union_dl, &size_alpha);
rt_cube_size((NDBOX *) union_dr, &size_beta); rt_cube_size(union_dr, &size_beta);
/* pick which page to add it to */ /* pick which page to add it to */
if (size_alpha - size_l < size_beta - size_r) if (size_alpha - size_l < size_beta - size_r)
...@@ -417,8 +414,8 @@ g_cube_picksplit(bytea *entryvec, ...@@ -417,8 +414,8 @@ g_cube_picksplit(bytea *entryvec,
} }
*left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
v->spl_ldatum = (char *) datum_l; v->spl_ldatum = PointerGetDatum(datum_l);
v->spl_rdatum = (char *) datum_r; v->spl_rdatum = PointerGetDatum(datum_r);
return v; return v;
} }
......
...@@ -34,11 +34,7 @@ ...@@ -34,11 +34,7 @@
/* useful macros for accessing int4 arrays */ /* useful macros for accessing int4 arrays */
#define ARRPTR(x) ( (int4 *) ARR_DATA_PTR(x) ) #define ARRPTR(x) ( (int4 *) ARR_DATA_PTR(x) )
#ifdef PGSQL71
#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) #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 ) #define ARRISNULL(x) ( (x) ? ( ( ARR_NDIM(x) == NDIM ) ? ( ( ARRNELEMS( x ) ) ? 0 : 1 ) : 1 ) : 1 )
...@@ -228,14 +224,17 @@ g_int_consistent(GISTENTRY *entry, ...@@ -228,14 +224,17 @@ g_int_consistent(GISTENTRY *entry,
switch (strategy) switch (strategy)
{ {
case RTOverlapStrategyNumber: case RTOverlapStrategyNumber:
retval = (bool) inner_int_overlap((ArrayType *) (entry->pred), query); retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key),
query);
break; break;
case RTSameStrategyNumber: case RTSameStrategyNumber:
case RTContainsStrategyNumber: case RTContainsStrategyNumber:
retval = (bool) inner_int_contains((ArrayType *) (entry->pred), query); retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key),
query);
break; break;
case RTContainedByStrategyNumber: case RTContainedByStrategyNumber:
retval = (bool) inner_int_overlap((ArrayType *) (entry->pred), query); retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key),
query);
break; break;
default: default:
retval = FALSE; retval = FALSE;
...@@ -265,14 +264,10 @@ g_int_compress(GISTENTRY *entry) ...@@ -265,14 +264,10 @@ g_int_compress(GISTENTRY *entry)
retval = palloc(sizeof(GISTENTRY)); retval = palloc(sizeof(GISTENTRY));
#ifdef PGSQL71 if (DatumGetPointer(entry->key) != NULL)
if (entry->pred) r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->key);
r = (ArrayType *) PG_DETOAST_DATUM_COPY(entry->pred);
else else
r = NULL; r = NULL;
#else
r = copy_intArrayType((ArrayType *) entry->pred);
#endif
if (ARRISNULL(r)) if (ARRISNULL(r))
{ {
...@@ -280,10 +275,10 @@ g_int_compress(GISTENTRY *entry) ...@@ -280,10 +275,10 @@ g_int_compress(GISTENTRY *entry)
elog(NOTICE, "COMP IN: NULL"); elog(NOTICE, "COMP IN: NULL");
#endif #endif
if (r) if (r)
if ((char *) r != (char *) entry->pred) if (r != (ArrayType *) DatumGetPointer(entry->key))
pfree(r); pfree(r);
gistentryinit(*retval, (char *) NULL, entry->rel, entry->page, entry->offset, gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset,
0, FALSE); 0, FALSE);
return (retval); return (retval);
} }
...@@ -322,7 +317,8 @@ g_int_compress(GISTENTRY *entry) ...@@ -322,7 +317,8 @@ g_int_compress(GISTENTRY *entry)
r = resize_intArrayType(r, len); 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); return (retval);
} }
...@@ -340,25 +336,19 @@ g_int_decompress(GISTENTRY *entry) ...@@ -340,25 +336,19 @@ g_int_decompress(GISTENTRY *entry)
int i, int i,
j; j;
#ifdef PGSQL71 if (DatumGetPointer(entry->key) != NULL)
if (entry->pred) in = (ArrayType *) PG_DETOAST_DATUM(entry->key);
in = (ArrayType *) PG_DETOAST_DATUM(entry->pred);
else else
in = NULL; in = NULL;
#else
in = (ArrayType *) entry->pred;
#endif
if (entry->bytes < ARR_OVERHEAD(NDIM) || ARRISNULL(in)) if (entry->bytes < ARR_OVERHEAD(NDIM) || ARRISNULL(in))
{ {
retval = palloc(sizeof(GISTENTRY)); retval = palloc(sizeof(GISTENTRY));
#ifdef PGSQL71
if (in) if (in)
if ((char *) in != (char *) entry->pred) if (in != (ArrayType *) DatumGetPointer(entry->key))
pfree(in); pfree(in);
#endif gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset, 0, FALSE);
gistentryinit(*retval, (char *) NULL, entry->rel, entry->page, entry->offset, 0, FALSE);
#ifdef GIST_DEBUG #ifdef GIST_DEBUG
elog(NOTICE, "DECOMP IN: NULL"); elog(NOTICE, "DECOMP IN: NULL");
#endif #endif
...@@ -372,7 +362,7 @@ g_int_decompress(GISTENTRY *entry) ...@@ -372,7 +362,7 @@ g_int_decompress(GISTENTRY *entry)
if (lenin < 2 * MAXNUMRANGE) if (lenin < 2 * MAXNUMRANGE)
{ /* not comressed value */ { /* not comressed value */
/* sometimes strange bytesize */ /* 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); return (entry);
} }
...@@ -390,13 +380,11 @@ g_int_decompress(GISTENTRY *entry) ...@@ -390,13 +380,11 @@ g_int_decompress(GISTENTRY *entry)
if ((!i) || *(dr - 1) != j) if ((!i) || *(dr - 1) != j)
*dr++ = j; *dr++ = j;
#ifdef PGSQL71 if (in != (ArrayType *) DatumGetPointer(entry->key))
if ((char *) in != (char *) entry->pred)
pfree(in); pfree(in);
#endif
retval = palloc(sizeof(GISTENTRY)); 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); return (retval);
} }
...@@ -835,9 +823,6 @@ new_intArrayType(int num) ...@@ -835,9 +823,6 @@ new_intArrayType(int num)
MemSet(r, 0, nbytes); MemSet(r, 0, nbytes);
r->size = nbytes; r->size = nbytes;
r->ndim = NDIM; r->ndim = NDIM;
#ifndef PGSQL71
SET_LO_FLAG(false, r);
#endif
*((int *) ARR_DIMS(r)) = num; *((int *) ARR_DIMS(r)) = num;
*((int *) ARR_LBOUND(r)) = 1; *((int *) ARR_LBOUND(r)) = 1;
...@@ -1056,14 +1041,10 @@ g_intbig_compress(GISTENTRY *entry) ...@@ -1056,14 +1041,10 @@ g_intbig_compress(GISTENTRY *entry)
ArrayType *r, ArrayType *r,
*in; *in;
#ifdef PGSQL71 if (DatumGetPointer(entry->key) != NULL)
if (entry->pred) in = (ArrayType *) PG_DETOAST_DATUM(entry->key);
in = (ArrayType *) PG_DETOAST_DATUM(entry->pred);
else else
in = NULL; in = NULL;
#else
in = (ArrayType *) entry->pred;
#endif
if (!entry->leafkey) if (!entry->leafkey)
return entry; return entry;
...@@ -1072,12 +1053,10 @@ g_intbig_compress(GISTENTRY *entry) ...@@ -1072,12 +1053,10 @@ g_intbig_compress(GISTENTRY *entry)
if (ARRISNULL(in)) if (ARRISNULL(in))
{ {
#ifdef PGSQL71
if (in) if (in)
if ((char *) in != (char *) entry->pred) if (in != (ArrayType *) DatumGetPointer(entry->key))
pfree(in); pfree(in);
#endif gistentryinit(*retval, (Datum) 0, entry->rel, entry->page, entry->offset, 0, FALSE);
gistentryinit(*retval, (char *) NULL, entry->rel, entry->page, entry->offset, 0, FALSE);
return (retval); return (retval);
} }
...@@ -1086,13 +1065,11 @@ g_intbig_compress(GISTENTRY *entry) ...@@ -1086,13 +1065,11 @@ g_intbig_compress(GISTENTRY *entry)
ARRPTR(in), ARRPTR(in),
ARRNELEMS(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 (in)
if ((char *) in != (char *) entry->pred) if (in != (ArrayType *) DatumGetPointer(entry->key))
pfree(in); pfree(in);
#endif
return (retval); return (retval);
} }
...@@ -1100,20 +1077,18 @@ g_intbig_compress(GISTENTRY *entry) ...@@ -1100,20 +1077,18 @@ g_intbig_compress(GISTENTRY *entry)
GISTENTRY * GISTENTRY *
g_intbig_decompress(GISTENTRY *entry) g_intbig_decompress(GISTENTRY *entry)
{ {
#ifdef PGSQL71
ArrayType *key; ArrayType *key;
key = (ArrayType *) PG_DETOAST_DATUM(entry->pred); key = (ArrayType *) PG_DETOAST_DATUM(entry->key);
if ((char *) key != (char *) entry->pred) if (key != (ArrayType *) DatumGetPointer(entry->key))
{ {
GISTENTRY *retval; GISTENTRY *retval;
retval = palloc(sizeof(GISTENTRY)); 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; return retval;
} }
#endif
return entry; return entry;
} }
...@@ -1159,14 +1134,14 @@ g_intbig_consistent(GISTENTRY *entry, ArrayType *query, StrategyNumber strategy) ...@@ -1159,14 +1134,14 @@ g_intbig_consistent(GISTENTRY *entry, ArrayType *query, StrategyNumber strategy)
switch (strategy) switch (strategy)
{ {
case RTOverlapStrategyNumber: case RTOverlapStrategyNumber:
retval = (bool) _intbig_overlap((ArrayType *) (entry->pred), q); retval = _intbig_overlap((ArrayType *) DatumGetPointer(entry->key), q);
break; break;
case RTSameStrategyNumber: case RTSameStrategyNumber:
case RTContainsStrategyNumber: case RTContainsStrategyNumber:
retval = (bool) _intbig_contains((ArrayType *) (entry->pred), q); retval = _intbig_contains((ArrayType *) DatumGetPointer(entry->key), q);
break; break;
case RTContainedByStrategyNumber: case RTContainedByStrategyNumber:
retval = (bool) _intbig_overlap((ArrayType *) (entry->pred), q); retval = _intbig_overlap((ArrayType *) DatumGetPointer(entry->key), q);
break; break;
default: default:
retval = FALSE; retval = FALSE;
...@@ -1196,12 +1171,12 @@ _int_common_union(bytea *entryvec, int *sizep, formarray unionf) ...@@ -1196,12 +1171,12 @@ _int_common_union(bytea *entryvec, int *sizep, formarray unionf)
#endif #endif
numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); 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++) for (i = 1; i < numranges; i++)
{ {
out = (*unionf) (tmp, (ArrayType *) out = (*unionf) (tmp, (ArrayType *)
(((GISTENTRY *) (VARDATA(entryvec)))[i]).pred); DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key));
if (i > 1 && tmp) if (i > 1 && tmp)
pfree(tmp); pfree(tmp);
tmp = out; tmp = out;
...@@ -1232,18 +1207,19 @@ _int_common_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result, ...@@ -1232,18 +1207,19 @@ _int_common_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result,
formarray unionf, formarray unionf,
formfloat sizef) formfloat sizef)
{ {
Datum ud; ArrayType *ud;
float tmp1, float tmp1,
tmp2; tmp2;
#ifdef GIST_DEBUG #ifdef GIST_DEBUG
elog(NOTICE, "penalty"); elog(NOTICE, "penalty");
#endif #endif
ud = (Datum) (*unionf) ((ArrayType *) (origentry->pred), (ArrayType *) (newentry->pred)); ud = (*unionf) ((ArrayType *) DatumGetPointer(origentry->key),
(*sizef) ((ArrayType *) ud, &tmp1); (ArrayType *) DatumGetPointer(newentry->key));
(*sizef) ((ArrayType *) (origentry->pred), &tmp2); (*sizef) (ud, &tmp1);
(*sizef) ((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
*result = tmp1 - tmp2; *result = tmp1 - tmp2;
pfree((char *) ud); pfree(ud);
#ifdef GIST_DEBUG #ifdef GIST_DEBUG
elog(NOTICE, "--penalty\t%g", *result); elog(NOTICE, "--penalty\t%g", *result);
...@@ -1304,10 +1280,10 @@ _int_common_picksplit(bytea *entryvec, ...@@ -1304,10 +1280,10 @@ _int_common_picksplit(bytea *entryvec,
for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) 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)) 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 */ /* compute the wasted space by unioning these guys */
/* size_waste = size_union - size_inter; */ /* size_waste = size_union - size_inter; */
...@@ -1342,12 +1318,12 @@ _int_common_picksplit(bytea *entryvec, ...@@ -1342,12 +1318,12 @@ _int_common_picksplit(bytea *entryvec,
right = v->spl_right; right = v->spl_right;
v->spl_nright = 0; 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); datum_l = copy_intArrayType(datum_alpha);
(*sizef) ((ArrayType *) datum_l, &size_l); (*sizef) (datum_l, &size_l);
datum_beta = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_2].pred); datum_beta = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_2].key);
datum_r = copy_intArrayType(datum_beta); 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 * Now split up the regions between the two seeds. An important
...@@ -1386,11 +1362,11 @@ _int_common_picksplit(bytea *entryvec, ...@@ -1386,11 +1362,11 @@ _int_common_picksplit(bytea *entryvec,
} }
/* okay, which page needs least enlargement? */ /* okay, which page needs least enlargement? */
datum_alpha = (ArrayType *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred); datum_alpha = (ArrayType *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key);
union_dl = (ArrayType *) (*unionf) (datum_l, datum_alpha); union_dl = (*unionf) (datum_l, datum_alpha);
union_dr = (ArrayType *) (*unionf) (datum_r, datum_alpha); union_dr = (*unionf) (datum_r, datum_alpha);
(*sizef) ((ArrayType *) union_dl, &size_alpha); (*sizef) (union_dl, &size_alpha);
(*sizef) ((ArrayType *) union_dr, &size_beta); (*sizef) (union_dr, &size_beta);
/* pick which page to add it to */ /* 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)) 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, ...@@ -1428,8 +1404,8 @@ _int_common_picksplit(bytea *entryvec,
*(right - 1) = InvalidOffsetNumber; *(right - 1) = InvalidOffsetNumber;
} }
v->spl_ldatum = (char *) datum_l; v->spl_ldatum = PointerGetDatum(datum_l);
v->spl_rdatum = (char *) datum_r; v->spl_rdatum = PointerGetDatum(datum_r);
#ifdef GIST_DEBUG #ifdef GIST_DEBUG
elog(NOTICE, "--------ENDpicksplit %d %d", v->spl_nleft, v->spl_nright); elog(NOTICE, "--------ENDpicksplit %d %d", v->spl_nleft, v->spl_nright);
......
...@@ -225,9 +225,9 @@ gseg_consistent(GISTENTRY *entry, ...@@ -225,9 +225,9 @@ gseg_consistent(GISTENTRY *entry,
* gseg_leaf_consistent * gseg_leaf_consistent
*/ */
if (GIST_LEAF(entry)) if (GIST_LEAF(entry))
return (gseg_leaf_consistent((SEG *) (entry->pred), query, strategy)); return (gseg_leaf_consistent((SEG *) DatumGetPointer(entry->key), query, strategy));
else 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) ...@@ -247,22 +247,14 @@ gseg_union(bytea *entryvec, int *sizep)
#endif #endif
numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
tmp = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[0]).pred; tmp = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[0].key);
*sizep = sizeof(SEG); *sizep = sizeof(SEG);
for (i = 1; i < numranges; i++) for (i = 1; i < numranges; i++)
{ {
out = gseg_binary_union(tmp, (SEG *) out = gseg_binary_union(tmp, (SEG *)
(((GISTENTRY *) (VARDATA(entryvec)))[i]).pred, DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key),
sizep); 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) if (i > 1)
pfree(tmp); pfree(tmp);
tmp = out; tmp = out;
...@@ -294,15 +286,16 @@ gseg_decompress(GISTENTRY *entry) ...@@ -294,15 +286,16 @@ gseg_decompress(GISTENTRY *entry)
float * float *
gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result) gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
{ {
Datum ud; SEG *ud;
float tmp1, float tmp1,
tmp2; tmp2;
ud = (Datum) seg_union((SEG *) (origentry->pred), (SEG *) (newentry->pred)); ud = seg_union((SEG *) DatumGetPointer(origentry->key),
rt_seg_size((SEG *) ud, &tmp1); (SEG *) DatumGetPointer(newentry->key));
rt_seg_size((SEG *) (origentry->pred), &tmp2); rt_seg_size(ud, &tmp1);
rt_seg_size((SEG *) DatumGetPointer(origentry->key), &tmp2);
*result = tmp1 - tmp2; *result = tmp1 - tmp2;
pfree((char *) ud); pfree(ud);
#ifdef GIST_DEBUG #ifdef GIST_DEBUG
fprintf(stderr, "penalty\n"); fprintf(stderr, "penalty\n");
...@@ -362,16 +355,16 @@ gseg_picksplit(bytea *entryvec, ...@@ -362,16 +355,16 @@ gseg_picksplit(bytea *entryvec,
for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) 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)) 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 */ /* compute the wasted space by unioning these guys */
/* size_waste = size_union - size_inter; */ /* 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); 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); rt_seg_size(inter_d, &size_inter);
size_waste = size_union - size_inter; size_waste = size_union - size_inter;
...@@ -400,12 +393,12 @@ gseg_picksplit(bytea *entryvec, ...@@ -400,12 +393,12 @@ gseg_picksplit(bytea *entryvec,
right = v->spl_right; right = v->spl_right;
v->spl_nright = 0; v->spl_nright = 0;
datum_alpha = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_1].pred); datum_alpha = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_1].key);
datum_l = (SEG *) seg_union(datum_alpha, datum_alpha); datum_l = seg_union(datum_alpha, datum_alpha);
rt_seg_size((SEG *) datum_l, &size_l); rt_seg_size(datum_l, &size_l);
datum_beta = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[seed_2].pred);; datum_beta = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[seed_2].key);
datum_r = (SEG *) seg_union(datum_beta, datum_beta); datum_r = seg_union(datum_beta, datum_beta);
rt_seg_size((SEG *) datum_r, &size_r); rt_seg_size(datum_r, &size_r);
/* /*
* Now split up the regions between the two seeds. An important * Now split up the regions between the two seeds. An important
...@@ -443,11 +436,11 @@ gseg_picksplit(bytea *entryvec, ...@@ -443,11 +436,11 @@ gseg_picksplit(bytea *entryvec,
} }
/* okay, which page needs least enlargement? */ /* okay, which page needs least enlargement? */
datum_alpha = (SEG *) (((GISTENTRY *) (VARDATA(entryvec)))[i].pred); datum_alpha = (SEG *) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key);
union_dl = (SEG *) seg_union(datum_l, datum_alpha); union_dl = seg_union(datum_l, datum_alpha);
union_dr = (SEG *) seg_union(datum_r, datum_alpha); union_dr = seg_union(datum_r, datum_alpha);
rt_seg_size((SEG *) union_dl, &size_alpha); rt_seg_size(union_dl, &size_alpha);
rt_seg_size((SEG *) union_dr, &size_beta); rt_seg_size(union_dr, &size_beta);
/* pick which page to add it to */ /* pick which page to add it to */
if (size_alpha - size_l < size_beta - size_r) if (size_alpha - size_l < size_beta - size_r)
...@@ -471,8 +464,8 @@ gseg_picksplit(bytea *entryvec, ...@@ -471,8 +464,8 @@ gseg_picksplit(bytea *entryvec,
} }
*left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */ *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
v->spl_ldatum = (char *) datum_l; v->spl_ldatum = PointerGetDatum(datum_l);
v->spl_rdatum = (char *) datum_r; v->spl_rdatum = PointerGetDatum(datum_r);
return v; return v;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,10 +26,23 @@ ...@@ -26,10 +26,23 @@
#include "access/xlogutils.h" #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 */ /* result's status */
#define INSERTED 0x01 #define INSERTED 0x01
#define SPLITED 0x02 #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 */ /* non-export function prototypes */
static void gistdoinsert(Relation r, static void gistdoinsert(Relation r,
IndexTuple itup, IndexTuple itup,
...@@ -55,10 +68,15 @@ static IndexTuple *gistjoinvector( ...@@ -55,10 +68,15 @@ static IndexTuple *gistjoinvector(
IndexTuple *additvec, int addlen); IndexTuple *additvec, int addlen);
static IndexTuple gistunion(Relation r, IndexTuple *itvec, static IndexTuple gistunion(Relation r, IndexTuple *itvec,
int len, GISTSTATE *giststate); int len, GISTSTATE *giststate);
static IndexTuple gistgetadjusted(Relation r, static IndexTuple gistgetadjusted(Relation r,
IndexTuple oldtup, IndexTuple oldtup,
IndexTuple addtup, IndexTuple addtup,
GISTSTATE *giststate); 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, static IndexTuple *gistSplit(Relation r,
Buffer buffer, Buffer buffer,
IndexTuple *itup, IndexTuple *itup,
...@@ -71,13 +89,18 @@ static void GISTInitBuffer(Buffer b, uint32 f); ...@@ -71,13 +89,18 @@ static void GISTInitBuffer(Buffer b, uint32 f);
static OffsetNumber gistchoose(Relation r, Page p, static OffsetNumber gistchoose(Relation r, Page p,
IndexTuple it, IndexTuple it,
GISTSTATE *giststate); GISTSTATE *giststate);
#ifdef GIST_PAGEADDITEM
static IndexTuple gist_tuple_replacekey(Relation r, static IndexTuple gist_tuple_replacekey(Relation r,
GISTENTRY entry, IndexTuple t); GISTENTRY entry, IndexTuple t);
static void gistcentryinit(GISTSTATE *giststate, #endif
GISTENTRY *e, char *pr, static void gistcentryinit(GISTSTATE *giststate, int nkey,
GISTENTRY *e, Datum k,
Relation r, Page pg, Relation r, Page pg,
OffsetNumber o, int b, bool l); 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 #undef GISTDEBUG
#ifdef GISTDEBUG #ifdef GISTDEBUG
...@@ -230,15 +253,15 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -230,15 +253,15 @@ gistbuild(PG_FUNCTION_ARGS)
/* immediately compress keys to normalize */ /* immediately compress keys to normalize */
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) 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, (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
-1 /* size is currently bogus */ , TRUE); -1 /* size is currently bogus */ , TRUE);
if (attdata[i] != (Datum) tmpcentry.pred && if (attdata[i] != tmpcentry.key &&
!(giststate.keytypbyval)) !(giststate.keytypbyval))
compvec[i] = TRUE; compvec[i] = TRUE;
else else
compvec[i] = FALSE; compvec[i] = FALSE;
attdata[i] = (Datum) tmpcentry.pred; attdata[i] = tmpcentry.key;
} }
/* form an index tuple and point it at the heap tuple */ /* form an index tuple and point it at the heap tuple */
...@@ -252,7 +275,6 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -252,7 +275,6 @@ gistbuild(PG_FUNCTION_ARGS)
* is the right thing to do if you're inserting single tups, but * is the right thing to do if you're inserting single tups, but
* not when you're initializing the whole index at once. * not when you're initializing the whole index at once.
*/ */
gistdoinsert(index, itup, NULL, &giststate); gistdoinsert(index, itup, NULL, &giststate);
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
...@@ -339,14 +361,14 @@ gistinsert(PG_FUNCTION_ARGS) ...@@ -339,14 +361,14 @@ gistinsert(PG_FUNCTION_ARGS)
compvec = (bool *) palloc(sizeof(bool) * r->rd_att->natts); compvec = (bool *) palloc(sizeof(bool) * r->rd_att->natts);
for (i = 0; i < r->rd_att->natts; i++) 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, (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
-1 /* size is currently bogus */ , TRUE); -1 /* size is currently bogus */ , TRUE);
if (datum[i] != (Datum) tmpentry.pred && !(giststate.keytypbyval)) if (datum[i] != tmpentry.key && !(giststate.keytypbyval))
compvec[i] = TRUE; compvec[i] = TRUE;
else else
compvec[i] = FALSE; compvec[i] = FALSE;
datum[i] = (Datum) tmpentry.pred; datum[i] = tmpentry.key;
} }
itup = index_formtuple(RelationGetDescr(r), datum, nulls); itup = index_formtuple(RelationGetDescr(r), datum, nulls);
itup->t_tid = *ht_ctid; itup->t_tid = *ht_ctid;
...@@ -361,13 +383,14 @@ gistinsert(PG_FUNCTION_ARGS) ...@@ -361,13 +383,14 @@ gistinsert(PG_FUNCTION_ARGS)
gistdoinsert(r, itup, &res, &giststate); gistdoinsert(r, itup, &res, &giststate);
for (i = 0; i < r->rd_att->natts; i++) for (i = 0; i < r->rd_att->natts; i++)
if (compvec[i] == TRUE) if (compvec[i] == TRUE)
pfree((char *) datum[i]); pfree(DatumGetPointer(datum[i]));
pfree(itup); pfree(itup);
pfree(compvec); pfree(compvec);
PG_RETURN_POINTER(res); PG_RETURN_POINTER(res);
} }
#ifdef GIST_PAGEADDITEM
/* /*
** Take a compressed entry, and install it on a page. Since we now know ** 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 ** where the entry will live, we decompress it and recompress it using
...@@ -388,16 +411,20 @@ gistPageAddItem(GISTSTATE *giststate, ...@@ -388,16 +411,20 @@ gistPageAddItem(GISTSTATE *giststate,
GISTENTRY tmpcentry; GISTENTRY tmpcentry;
IndexTuple itup = (IndexTuple) item; IndexTuple itup = (IndexTuple) item;
OffsetNumber retval; OffsetNumber retval;
Datum datum;
bool IsNull;
/* /*
* recompress the item given that we now know the exact page and * recompress the item given that we now know the exact page and
* offset for insertion * offset for insertion
*/ */
gistdentryinit(giststate, dentry, datum = index_getattr(itup, 1, r->rd_att, &IsNull);
(((char *) itup) + sizeof(IndexTupleData)), gistdentryinit(giststate, 0,dentry, datum,
(Relation) 0, (Page) 0, (OffsetNumber) InvalidOffsetNumber, (Relation) 0, (Page) 0,
IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE); (OffsetNumber) InvalidOffsetNumber,
gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page, ATTSIZE( datum, r, 1, IsNull ),
FALSE);
gistcentryinit(giststate, 0,&tmpcentry, dentry->key, r, page,
offsetNumber, dentry->bytes, FALSE); offsetNumber, dentry->bytes, FALSE);
*newtup = gist_tuple_replacekey(r, tmpcentry, itup); *newtup = gist_tuple_replacekey(r, tmpcentry, itup);
retval = PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup), retval = PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup),
...@@ -406,11 +433,13 @@ gistPageAddItem(GISTSTATE *giststate, ...@@ -406,11 +433,13 @@ gistPageAddItem(GISTSTATE *giststate,
elog(ERROR, "gist: failed to add index item to %s", elog(ERROR, "gist: failed to add index item to %s",
RelationGetRelationName(r)); RelationGetRelationName(r));
/* be tidy */ /* be tidy */
if (tmpcentry.pred && tmpcentry.pred != dentry->pred if (DatumGetPointer(tmpcentry.key) != NULL &&
&& tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData))) tmpcentry.key != dentry->key &&
pfree(tmpcentry.pred); tmpcentry.key != datum )
pfree(DatumGetPointer(tmpcentry.key));
return (retval); return (retval);
} }
#endif
static void static void
gistdoinsert(Relation r, gistdoinsert(Relation r,
...@@ -485,7 +514,6 @@ gistlayerinsert(Relation r, BlockNumber blkno, ...@@ -485,7 +514,6 @@ gistlayerinsert(Relation r, BlockNumber blkno,
if (!(ret & SPLITED)) if (!(ret & SPLITED))
{ {
IndexTuple newtup = gistgetadjusted(r, oldtup, (*itup)[0], giststate); IndexTuple newtup = gistgetadjusted(r, oldtup, (*itup)[0], giststate);
if (!newtup) if (!newtup)
{ {
/* not need to update key */ /* not need to update key */
...@@ -509,18 +537,23 @@ gistlayerinsert(Relation r, BlockNumber blkno, ...@@ -509,18 +537,23 @@ gistlayerinsert(Relation r, BlockNumber blkno,
if (gistnospace(page, (*itup), *len)) if (gistnospace(page, (*itup), *len))
{ {
/* no space for insertion */ /* no space for insertion */
IndexTuple *itvec; IndexTuple *itvec, *newitup;
int tlen; int tlen,oldlen;
ret |= SPLITED; ret |= SPLITED;
itvec = gistreadbuffer(r, buffer, &tlen); itvec = gistreadbuffer(r, buffer, &tlen);
itvec = gistjoinvector(itvec, &tlen, (*itup), *len); itvec = gistjoinvector(itvec, &tlen, (*itup), *len);
pfree((*itup)); oldlen = *len;
(*itup) = gistSplit(r, buffer, itvec, &tlen, giststate, newitup = gistSplit(r, buffer, itvec, &tlen, giststate,
(opaque->flags & F_LEAF) ? res : NULL); /* res only for (opaque->flags & F_LEAF) ? res : NULL); /* res only for
* inserting in leaf */ * inserting in leaf */
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
do
pfree( (*itup)[ oldlen-1 ] );
while ( (--oldlen) > 0 );
pfree((*itup));
pfree(itvec); pfree(itvec);
*itup = newitup;
*len = tlen; /* now tlen >= 2 */ *len = tlen; /* now tlen >= 2 */
} }
else else
...@@ -551,6 +584,7 @@ gistlayerinsert(Relation r, BlockNumber blkno, ...@@ -551,6 +584,7 @@ gistlayerinsert(Relation r, BlockNumber blkno,
* parent * parent
*/ */
IndexTuple newtup = gistunion(r, (*itup), *len, giststate); IndexTuple newtup = gistunion(r, (*itup), *len, giststate);
ItemPointerSet(&(newtup->t_tid), blkno, 1);
for (i = 0; i < *len; i++) for (i = 0; i < *len; i++)
pfree((*itup)[i]); pfree((*itup)[i]);
...@@ -571,19 +605,30 @@ gistwritebuffer(Relation r, Page page, IndexTuple *itup, ...@@ -571,19 +605,30 @@ gistwritebuffer(Relation r, Page page, IndexTuple *itup,
{ {
OffsetNumber l = InvalidOffsetNumber; OffsetNumber l = InvalidOffsetNumber;
int i; int i;
#ifdef GIST_PAGEADDITEM
GISTENTRY tmpdentry; GISTENTRY tmpdentry;
IndexTuple newtup; IndexTuple newtup;
bool IsNull;
#endif
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
{ {
#ifdef GIST_PAGEADDITEM
l = gistPageAddItem(giststate, r, page, l = gistPageAddItem(giststate, r, page,
(Item) itup[i], IndexTupleSize(itup[i]), (Item) itup[i], IndexTupleSize(itup[i]),
off, LP_USED, &tmpdentry, &newtup); off, LP_USED, &tmpdentry, &newtup);
off = OffsetNumberNext(off); off = OffsetNumberNext(off);
if (tmpdentry.pred != (((char *) itup[i]) + sizeof(IndexTupleData)) && tmpdentry.pred) if (DatumGetPointer(tmpdentry.key) != NULL &&
pfree(tmpdentry.pred); tmpdentry.key != index_getattr(itup[i], 1, r->rd_att, &IsNull))
pfree(DatumGetPointer(tmpdentry.key));
if (itup[i] != newtup) if (itup[i] != newtup)
pfree(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; return l;
} }
...@@ -598,7 +643,7 @@ gistnospace(Page page, IndexTuple *itvec, int len) ...@@ -598,7 +643,7 @@ gistnospace(Page page, IndexTuple *itvec, int len)
int i; int i;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
size += IndexTupleSize(itvec[i]) + 4; /* ??? */ size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
return (PageGetFreeSpace(page) < size); return (PageGetFreeSpace(page) < size);
} }
...@@ -614,11 +659,11 @@ gistreadbuffer(Relation r, Buffer buffer, int *len /* out */ ) ...@@ -614,11 +659,11 @@ gistreadbuffer(Relation r, Buffer buffer, int *len /* out */ )
IndexTuple *itvec; IndexTuple *itvec;
Page p = (Page) BufferGetPage(buffer); Page p = (Page) BufferGetPage(buffer);
*len = 0;
maxoff = PageGetMaxOffsetNumber(p); maxoff = PageGetMaxOffsetNumber(p);
*len = maxoff;
itvec = palloc(sizeof(IndexTuple) * maxoff); itvec = palloc(sizeof(IndexTuple) * maxoff);
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) 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; return itvec;
} }
...@@ -639,46 +684,66 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen) ...@@ -639,46 +684,66 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
* return union of itup vector * return union of itup vector
*/ */
static IndexTuple 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; bytea *evec;
char *datum; Datum datum;
int datumsize, int datumsize,
i; i,j;
GISTENTRY centry; GISTENTRY centry[INDEX_MAX_KEYS];
char isnull; bool *needfree;
IndexTuple newtup; IndexTuple newtup;
bool IsNull;
needfree = (bool *) palloc(len * sizeof(bool));
evec = (bytea *) palloc(len * sizeof(GISTENTRY) + VARHDRSZ); evec = (bytea *) palloc(len * sizeof(GISTENTRY) + VARHDRSZ);
VARATT_SIZEP(evec) = len * sizeof(GISTENTRY) + VARHDRSZ; VARATT_SIZEP(evec) = len * sizeof(GISTENTRY) + VARHDRSZ;
for (i = 0; i < len; i++) for (j = 0; j < r->rd_att->natts; j++) {
gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[i], for (i = 0; i < len; i++) {
(char *) itvec[i] + sizeof(IndexTupleData), datum = index_getattr(itvec[i], j+1, r->rd_att, &IsNull);
(Relation) NULL, (Page) NULL, (OffsetNumber) NULL, gistdentryinit(giststate, j,
IndexTupleSize((IndexTuple) itvec[i]) - sizeof(IndexTupleData), FALSE); &((GISTENTRY *) VARDATA(evec))[i],
datum,
datum = (char *) (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
DatumGetPointer(FunctionCall2(&giststate->unionFn, ATTSIZE( datum, r, j+1, IsNull ), FALSE);
PointerGetDatum(evec), if ( DatumGetPointer(((GISTENTRY *) VARDATA(evec))[i].key) != NULL
PointerGetDatum(&datumsize))); && ((GISTENTRY *) VARDATA(evec))[i].key != datum )
needfree[i] = TRUE;
else
needfree[i] = FALSE;
}
for (i = 0; i < len; i++) datum = FunctionCall2(&giststate->unionFn[j],
if (((GISTENTRY *) VARDATA(evec))[i].pred && PointerGetDatum(evec),
((GISTENTRY *) VARDATA(evec))[i].pred != PointerGetDatum(&datumsize));
((char *) (itvec[i]) + sizeof(IndexTupleData)))
pfree(((GISTENTRY *) VARDATA(evec))[i].pred); 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(evec);
pfree(needfree);
gistcentryinit(giststate, &centry, datum, newtup = (IndexTuple) index_formtuple(r->rd_att, attr, isnull);
(Relation) NULL, (Page) NULL, (OffsetNumber) NULL, for (j = 0; j < r->rd_att->natts; j++)
datumsize, FALSE); if ( whatfree[j] )
pfree(DatumGetPointer(attr[j]));
isnull = (centry.pred) ? ' ' : 'n';
newtup = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &centry.pred, &isnull);
if (centry.pred != datum)
pfree(datum);
return newtup; return newtup;
} }
...@@ -690,71 +755,232 @@ static IndexTuple ...@@ -690,71 +755,232 @@ static IndexTuple
gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate) gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
{ {
bytea *evec; bytea *evec;
char *datum; Datum datum;
int datumsize; int datumsize;
bool result; bool result, neednew = false;
char isnull; char isnull[INDEX_MAX_KEYS],
GISTENTRY centry, whatfree[INDEX_MAX_KEYS];
Datum attr[INDEX_MAX_KEYS];
GISTENTRY centry[INDEX_MAX_KEYS],
oldatt[INDEX_MAX_KEYS],
addatt[INDEX_MAX_KEYS],
*ev0p, *ev0p,
*ev1p; *ev1p;
bool olddec[INDEX_MAX_KEYS],
adddec[INDEX_MAX_KEYS];
IndexTuple newtup = NULL; IndexTuple newtup = NULL;
int j;
evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ); evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ);
VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ; VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
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]; 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]; 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 *) if (neednew) {
DatumGetPointer(FunctionCall2(&giststate->unionFn, /* need to update key */
PointerGetDatum(evec), newtup = (IndexTuple) index_formtuple(r->rd_att, attr, isnull);
PointerGetDatum(&datumsize))); newtup->t_tid = oldtup->t_tid;
if (!(ev0p->pred && ev1p->pred))
result = (ev0p->pred == NULL && ev1p->pred == NULL);
else
{
FunctionCall3(&giststate->equalFn,
PointerGetDatum(ev0p->pred),
PointerGetDatum(datum),
PointerGetDatum(&result));
} }
for (j = 0; j < r->rd_att->natts; j++)
if ( whatfree[j] )
pfree(DatumGetPointer(attr[j]));
if (result) return newtup;
{ }
/* not need to update key */
pfree(datum);
}
else
{
gistcentryinit(giststate, &centry, datum, ev0p->rel, ev0p->page,
ev0p->offset, datumsize, FALSE);
isnull = (centry.pred) ? ' ' : 'n'; static void
newtup = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &centry.pred, &isnull); gistunionsubkey( Relation r, GISTSTATE *giststate, IndexTuple *itvec, GIST_SPLITVEC * spl ) {
newtup->t_tid = oldtup->t_tid; int i,j,lr;
if (centry.pred != datum) Datum *attr;
pfree(datum); 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)) * find group in vector with equial value
pfree(ev0p->pred); */
if (ev1p->pred && static int
ev1p->pred != (char *) addtup + sizeof(IndexTupleData)) gistfindgroup( GISTSTATE *giststate, GISTENTRY *valvec, GIST_SPLITVEC * spl ) {
pfree(ev1p->pred); int i,j,len;
pfree(evec); 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, ...@@ -773,23 +999,20 @@ gistSplit(Relation r,
rightbuf; rightbuf;
Page left, Page left,
right; right;
OffsetNumber *spl_left,
*spl_right;
IndexTuple *lvectup, IndexTuple *lvectup,
*rvectup, *rvectup,
*newtup; *newtup;
int leftoff,
rightoff;
BlockNumber lbknum, BlockNumber lbknum,
rbknum; rbknum;
GISTPageOpaque opaque; GISTPageOpaque opaque;
char isnull;
GIST_SPLITVEC v; GIST_SPLITVEC v;
bytea *entryvec; bytea *entryvec;
bool *decompvec; bool *decompvec;
GISTENTRY tmpentry; int i,j,
int i,
nlen; nlen;
int MaxGrpId = 1;
Datum datum;
bool IsNull;
p = (Page) BufferGetPage(buffer); p = (Page) BufferGetPage(buffer);
opaque = (GISTPageOpaque) PageGetSpecialPointer(p); opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
...@@ -827,49 +1050,187 @@ gistSplit(Relation r, ...@@ -827,49 +1050,187 @@ gistSplit(Relation r,
VARATT_SIZEP(entryvec) = (*len + 1) * sizeof(GISTENTRY) + VARHDRSZ; VARATT_SIZEP(entryvec) = (*len + 1) * sizeof(GISTENTRY) + VARHDRSZ;
for (i = 1; i <= *len; i++) for (i = 1; i <= *len; i++)
{ {
gistdentryinit(giststate, &((GISTENTRY *) VARDATA(entryvec))[i], datum = index_getattr(itup[i - 1], 1, r->rd_att, &IsNull);
(((char *) itup[i - 1]) + sizeof(IndexTupleData)), gistdentryinit(giststate, 0,&((GISTENTRY *) VARDATA(entryvec))[i],
r, p, i, datum, r, p, i,
IndexTupleSize(itup[i - 1]) - sizeof(IndexTupleData), FALSE); ATTSIZE( datum, r, 1, IsNull ), FALSE);
if ((char *) (((GISTENTRY *) VARDATA(entryvec))[i].pred) if (((GISTENTRY *) VARDATA(entryvec))[i].key == datum ||
== (((char *) itup[i - 1]) + sizeof(IndexTupleData))) DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key) == NULL)
decompvec[i] = FALSE; decompvec[i] = FALSE;
else else
decompvec[i] = TRUE; decompvec[i] = TRUE;
} }
/* now let the user-defined picksplit function set up the split vector */ /* now let the user-defined picksplit function set up the split vector */
FunctionCall2(&giststate->picksplitFn, FunctionCall2(&giststate->picksplitFn[0],
PointerGetDatum(entryvec), PointerGetDatum(entryvec),
PointerGetDatum(&v)); 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++) for (i = 1; i <= *len; i++)
if (decompvec[i] && ((GISTENTRY *) VARDATA(entryvec))[i].pred) if (decompvec[i])
pfree(((GISTENTRY *) VARDATA(entryvec))[i].pred); pfree(DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key));
pfree(entryvec); pfree(entryvec);
pfree(decompvec); pfree(decompvec);
spl_left = v.spl_left;
spl_right = v.spl_right;
/* form left and right vector */ /* form left and right vector */
lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nleft); lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nleft);
rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nright); rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nright);
leftoff = rightoff = 0;
for (i = 1; i <= *len; i++) for(i=0; i<v.spl_nleft;i++)
{ lvectup[i] = itup[ v.spl_left[i] - 1 ];
if (i == *(spl_left) || (i == *len && *(spl_left) != FirstOffsetNumber))
{ for(i=0; i<v.spl_nright;i++)
lvectup[leftoff++] = itup[i - 1]; rvectup[i] = itup[ v.spl_right[i] - 1 ];
spl_left++;
}
else
{
rvectup[rightoff++] = itup[i - 1];
spl_right++;
}
}
/* write on disk (may be need another split) */ /* write on disk (may be need another split) */
if (gistnospace(right, rvectup, v.spl_nright)) if (gistnospace(right, rvectup, v.spl_nright))
...@@ -878,6 +1239,9 @@ gistSplit(Relation r, ...@@ -878,6 +1239,9 @@ gistSplit(Relation r,
newtup = gistSplit(r, rightbuf, rvectup, &nlen, giststate, newtup = gistSplit(r, rightbuf, rvectup, &nlen, giststate,
(res && rvectup[nlen - 1] == itup[*len - 1]) ? res : NULL); (res && rvectup[nlen - 1] == itup[*len - 1]) ? res : NULL);
ReleaseBuffer(rightbuf); 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 else
{ {
...@@ -888,20 +1252,14 @@ gistSplit(Relation r, ...@@ -888,20 +1252,14 @@ gistSplit(Relation r,
if (res) if (res)
ItemPointerSet(&((*res)->pointerData), rbknum, l); 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; nlen = 1;
newtup = (IndexTuple *) palloc(sizeof(IndexTuple) * 1); newtup = (IndexTuple *) palloc(sizeof(IndexTuple) * 1);
isnull = (v.spl_rdatum) ? ' ' : 'n'; newtup[0] = gistFormTuple( giststate, r, v.spl_rattr, v.spl_rattrsize );
newtup[0] = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &(v.spl_rdatum), &isnull);
ItemPointerSet(&(newtup[0]->t_tid), rbknum, 1); ItemPointerSet(&(newtup[0]->t_tid), rbknum, 1);
} }
if (gistnospace(left, lvectup, v.spl_nleft)) if (gistnospace(left, lvectup, v.spl_nleft))
{ {
int llen = v.spl_nleft; int llen = v.spl_nleft;
...@@ -911,6 +1269,10 @@ gistSplit(Relation r, ...@@ -911,6 +1269,10 @@ gistSplit(Relation r,
(res && lvectup[llen - 1] == itup[*len - 1]) ? res : NULL); (res && lvectup[llen - 1] == itup[*len - 1]) ? res : NULL);
ReleaseBuffer(leftbuf); 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); newtup = gistjoinvector(newtup, &nlen, lntup, llen);
pfree(lntup); pfree(lntup);
} }
...@@ -926,17 +1288,10 @@ gistSplit(Relation r, ...@@ -926,17 +1288,10 @@ gistSplit(Relation r,
if (res) if (res)
ItemPointerSet(&((*res)->pointerData), lbknum, l); 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; nlen += 1;
newtup = (IndexTuple *) repalloc((void *) newtup, sizeof(IndexTuple) * nlen); newtup = (IndexTuple *) repalloc((void *) newtup, sizeof(IndexTuple) * nlen);
isnull = (v.spl_ldatum) ? ' ' : 'n'; newtup[nlen - 1] = gistFormTuple( giststate, r, v.spl_lattr, v.spl_lattrsize );
newtup[nlen - 1] = (IndexTuple) index_formtuple(r->rd_att, (Datum *) &(v.spl_ldatum), &isnull);
ItemPointerSet(&(newtup[nlen - 1]->t_tid), lbknum, 1); ItemPointerSet(&(newtup[nlen - 1]->t_tid), lbknum, 1);
} }
...@@ -995,48 +1350,52 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */ ...@@ -995,48 +1350,52 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
{ {
OffsetNumber maxoff; OffsetNumber maxoff;
OffsetNumber i; OffsetNumber i;
char *id; Datum datum;
char *datum;
float usize; float usize;
OffsetNumber which; OffsetNumber which;
float which_grow; float sum_grow, which_grow[INDEX_MAX_KEYS];
GISTENTRY entry, GISTENTRY entry,
identry; identry[INDEX_MAX_KEYS];
int size, bool IsNull, decompvec[INDEX_MAX_KEYS];
idsize; int j;
idsize = IndexTupleSize(it) - sizeof(IndexTupleData);
id = ((char *) it) + sizeof(IndexTupleData);
maxoff = PageGetMaxOffsetNumber(p); maxoff = PageGetMaxOffsetNumber(p);
which_grow = -1.0; *which_grow = -1.0;
which = -1; which = -1;
sum_grow=1;
gistDeCompressAtt( giststate, r,
it, (Page) NULL, (OffsetNumber) 0,
identry, decompvec );
gistdentryinit(giststate, &identry, id, (Relation) NULL, (Page) NULL, for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
(OffsetNumber) 0, idsize, FALSE);
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
{ {
datum = (char *) PageGetItem(p, PageGetItemId(p, i)); sum_grow=0;
size = IndexTupleSize(datum) - sizeof(IndexTupleData); for( j=0; j<r->rd_att->natts; j++ ) {
datum += sizeof(IndexTupleData); datum = index_getattr( (IndexTuple)PageGetItem(p, PageGetItemId(p, i)), j+1, r->rd_att, &IsNull);
gistdentryinit(giststate, &entry, datum, r, p, i, size, FALSE); gistdentryinit(giststate, j, &entry, datum, r, p, i, ATTSIZE( datum, r, j+1, IsNull ), FALSE);
FunctionCall3(&giststate->penaltyFn, FunctionCall3(&giststate->penaltyFn[j],
PointerGetDatum(&entry), PointerGetDatum(&entry),
PointerGetDatum(&identry), PointerGetDatum(&identry[j]),
PointerGetDatum(&usize)); PointerGetDatum(&usize));
if (which_grow < 0 || usize < which_grow)
{ if (DatumGetPointer(entry.key) != NULL && entry.key != datum)
which = i; pfree(DatumGetPointer(entry.key));
which_grow = usize;
if (which_grow == 0) 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; 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; return which;
} }
...@@ -1104,21 +1463,28 @@ initGISTstate(GISTSTATE *giststate, Relation index) ...@@ -1104,21 +1463,28 @@ initGISTstate(GISTSTATE *giststate, Relation index)
HeapTuple htup; HeapTuple htup;
Form_pg_index itupform; Form_pg_index itupform;
Oid indexrelid; Oid indexrelid;
int i;
consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC);
union_proc = index_getprocid(index, 1, GIST_UNION_PROC); if (index->rd_att->natts >= INDEX_MAX_KEYS)
compress_proc = index_getprocid(index, 1, GIST_COMPRESS_PROC); elog(ERROR, "initGISTstate: numberOfAttributes %d > %d",
decompress_proc = index_getprocid(index, 1, GIST_DECOMPRESS_PROC); index->rd_att->natts, INDEX_MAX_KEYS);
penalty_proc = index_getprocid(index, 1, GIST_PENALTY_PROC);
picksplit_proc = index_getprocid(index, 1, GIST_PICKSPLIT_PROC); for(i=0; i<index->rd_att->natts; i++) {
equal_proc = index_getprocid(index, 1, GIST_EQUAL_PROC); consistent_proc = index_getprocid(index, i+1, GIST_CONSISTENT_PROC );
fmgr_info(consistent_proc, &giststate->consistentFn); union_proc = index_getprocid(index, i+1, GIST_UNION_PROC );
fmgr_info(union_proc, &giststate->unionFn); compress_proc = index_getprocid(index, i+1, GIST_COMPRESS_PROC );
fmgr_info(compress_proc, &giststate->compressFn); decompress_proc = index_getprocid(index, i+1, GIST_DECOMPRESS_PROC );
fmgr_info(decompress_proc, &giststate->decompressFn); penalty_proc = index_getprocid(index, i+1, GIST_PENALTY_PROC );
fmgr_info(penalty_proc, &giststate->penaltyFn); picksplit_proc = index_getprocid(index, i+1, GIST_PICKSPLIT_PROC );
fmgr_info(picksplit_proc, &giststate->picksplitFn); equal_proc = index_getprocid(index, i+1, GIST_EQUAL_PROC );
fmgr_info(equal_proc, &giststate->equalFn); 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 */ /* see if key type is different from type of attribute being indexed */
htup = SearchSysCache(INDEXRELID, htup = SearchSysCache(INDEXRELID,
...@@ -1149,21 +1515,31 @@ initGISTstate(GISTSTATE *giststate, Relation index) ...@@ -1149,21 +1515,31 @@ initGISTstate(GISTSTATE *giststate, Relation index)
giststate->keytypbyval = FALSE; giststate->keytypbyval = FALSE;
} }
#ifdef GIST_PAGEADDITEM
/* /*
** Given an IndexTuple to be inserted on a page, this routine replaces ** Given an IndexTuple to be inserted on a page, this routine replaces
** the key with another key, which may involve generating a new IndexTuple ** 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 static IndexTuple
gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t) 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 */ /* clear out old size */
t->t_info &= ~INDEX_SIZE_MASK; t->t_info &= ~INDEX_SIZE_MASK;
/* or in new size */ /* or in new size */
...@@ -1178,65 +1554,131 @@ gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t) ...@@ -1178,65 +1554,131 @@ gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
IndexTuple newtup; IndexTuple newtup;
char isnull; char isnull;
isnull = (entry.pred) ? ' ' : 'n'; isnull = DatumGetPointer(entry.key) != NULL ? ' ' : 'n';
newtup = (IndexTuple) index_formtuple(tupDesc, newtup = (IndexTuple) index_formtuple(tupDesc,
(Datum *) &(entry.pred), &(entry.key),
&isnull); &isnull);
newtup->t_tid = t->t_tid; newtup->t_tid = t->t_tid;
return newtup; return newtup;
} }
} }
#endif
/* /*
** initialize a GiST entry with a decompressed version of pred ** initialize a GiST entry with a decompressed version of key
*/ */
void void
gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r, gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
Page pg, OffsetNumber o, int b, bool l) Datum k, Relation r, Page pg, OffsetNumber o,
int b, bool l)
{ {
GISTENTRY *dep; GISTENTRY *dep;
gistentryinit(*e, pr, r, pg, o, b, l); gistentryinit(*e, k, r, pg, o, b, l);
if (giststate->haskeytype) if (giststate->haskeytype)
{ {
if ( b ) { if ( b ) {
dep = (GISTENTRY *) dep = (GISTENTRY *)
DatumGetPointer(FunctionCall1(&giststate->decompressFn, DatumGetPointer(FunctionCall1(&giststate->decompressFn[nkey],
PointerGetDatum(e))); 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); dep->leafkey);
if (dep != e) if (dep != e)
pfree(dep); pfree(dep);
} else { } 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 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) Page pg, OffsetNumber o, int b, bool l)
{ {
GISTENTRY *cep; GISTENTRY *cep;
gistentryinit(*e, pr, r, pg, o, b, l); gistentryinit(*e, k, r, pg, o, b, l);
if (giststate->haskeytype) if (giststate->haskeytype)
{ {
cep = (GISTENTRY *) cep = (GISTENTRY *)
DatumGetPointer(FunctionCall1(&giststate->compressFn, DatumGetPointer(FunctionCall1(&giststate->compressFn[nkey],
PointerGetDatum(e))); PointerGetDatum(e)));
gistentryinit(*e, cep->pred, cep->rel, cep->page, cep->offset, cep->bytes, gistentryinit(*e, cep->key, cep->rel, cep->page, cep->offset,
cep->leafkey); cep->bytes, cep->leafkey);
if (cep != e) if (cep != e)
pfree(cep); 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 #ifdef GISTDEBUG
static void static void
gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff) gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
...@@ -1261,7 +1703,9 @@ 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); 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)) for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
{ {
...@@ -1269,7 +1713,8 @@ gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff) ...@@ -1269,7 +1713,8 @@ gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
which = (IndexTuple) PageGetItem(page, iid); which = (IndexTuple) PageGetItem(page, iid);
cblk = ItemPointerGetBlockNumber(&(which->t_tid)); cblk = ItemPointerGetBlockNumber(&(which->t_tid));
#ifdef PRINTTUPLE #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 #endif
if (!(opaque->flags & F_LEAF)) if (!(opaque->flags & F_LEAF))
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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, ...@@ -238,16 +238,21 @@ gistindex_keytest(IndexTuple tuple,
while (scanKeySize > 0) while (scanKeySize > 0)
{ {
datum = index_getattr(tuple, datum = index_getattr(tuple,
1, key[0].sk_attno,
tupdesc, tupdesc,
&isNull); &isNull);
if (isNull || IndexTupleSize(tuple) == sizeof(IndexTupleData) ) if (isNull)
{ {
/* XXX eventually should check if SK_ISNULL */ /* XXX eventually should check if SK_ISNULL */
return false; 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), IndexTupleSize(tuple) - sizeof(IndexTupleData),
FALSE); FALSE);
...@@ -266,16 +271,16 @@ gistindex_keytest(IndexTuple tuple, ...@@ -266,16 +271,16 @@ gistindex_keytest(IndexTuple tuple,
ObjectIdGetDatum(key[0].sk_procedure)); ObjectIdGetDatum(key[0].sk_procedure));
} }
if ( (char*)de.pred != (char*)datum ) if ( de.key != datum )
if ( de.pred ) pfree( de.pred ); if ( DatumGetPointer(de.key) != NULL )
pfree( DatumGetPointer(de.key) );
if (DatumGetBool(test) == !!(key[0].sk_flags & SK_NEGATE)) if (DatumGetBool(test) == !!(key[0].sk_flags & SK_NEGATE))
return false; return false;
scanKeySize -= 1; scanKeySize--;
key++; key++;
} }
return true; return true;
} }
...@@ -284,7 +289,7 @@ static OffsetNumber ...@@ -284,7 +289,7 @@ static OffsetNumber
gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir) gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
{ {
OffsetNumber maxoff; OffsetNumber maxoff;
char *it; IndexTuple it;
GISTPageOpaque po; GISTPageOpaque po;
GISTScanOpaque so; GISTScanOpaque so;
GISTSTATE *giststate; GISTSTATE *giststate;
...@@ -307,8 +312,8 @@ gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir) ...@@ -307,8 +312,8 @@ gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
while (n >= FirstOffsetNumber && n <= maxoff) while (n >= FirstOffsetNumber && n <= maxoff)
{ {
it = (char *) PageGetItem(p, PageGetItemId(p, n)); it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
if (gistindex_keytest((IndexTuple) it, if (gistindex_keytest(it,
RelationGetDescr(s->relation), RelationGetDescr(s->relation),
s->numberOfKeys, s->keyData, giststate, s->numberOfKeys, s->keyData, giststate,
s->relation, p, n)) s->relation, p, n))
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -122,7 +122,7 @@ gistrescan(PG_FUNCTION_ARGS)
s->keyData[i].sk_procedure s->keyData[i].sk_procedure
= RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno, = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
s->keyData[i].sk_procedure); s->keyData[i].sk_procedure);
s->keyData[i].sk_func = p->giststate->consistentFn; s->keyData[i].sk_func = p->giststate->consistentFn[i];
} }
} }
else else
...@@ -153,7 +153,7 @@ gistrescan(PG_FUNCTION_ARGS) ...@@ -153,7 +153,7 @@ gistrescan(PG_FUNCTION_ARGS)
s->keyData[i].sk_procedure s->keyData[i].sk_procedure
= RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno, = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
s->keyData[i].sk_procedure); s->keyData[i].sk_procedure);
s->keyData[i].sk_func = p->giststate->consistentFn; s->keyData[i].sk_func = p->giststate->consistentFn[i];
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
* index_open - open an index relation by relationId * index_open - open an index relation by relationId
...@@ -410,13 +410,13 @@ index_getprocid(Relation irel, ...@@ -410,13 +410,13 @@ index_getprocid(Relation irel,
uint16 procnum) uint16 procnum)
{ {
RegProcedure *loc; RegProcedure *loc;
int natts; int nproc;
natts = irel->rd_rel->relnatts; nproc = irel->rd_am->amsupport;
loc = irel->rd_support; loc = irel->rd_support;
Assert(loc != NULL); Assert(loc != NULL);
return loc[(natts * (procnum - 1)) + (attnum - 1)]; return loc[(nproc * (attnum - 1)) + (procnum - 1)];
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -120,13 +120,15 @@ DefineIndex(char *heapRelationName,
/* /*
* XXX Hardwired hacks to check for limitations on supported index * XXX Hardwired hacks to check for limitations on supported index
* types. We really ought to be learning this info from entries in the * 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) if (unique && accessMethodId != BTREE_AM_OID)
elog(ERROR, "DefineIndex: unique indices are only available with the btree access method"); elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
if (numberOfAttributes > 1 && accessMethodId != BTREE_AM_OID) if (numberOfAttributes > 1 &&
elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method"); !( 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 * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -65,13 +65,13 @@ typedef struct GISTSTACK
typedef struct GISTSTATE typedef struct GISTSTATE
{ {
FmgrInfo consistentFn; FmgrInfo consistentFn[INDEX_MAX_KEYS];
FmgrInfo unionFn; FmgrInfo unionFn[INDEX_MAX_KEYS];
FmgrInfo compressFn; FmgrInfo compressFn[INDEX_MAX_KEYS];
FmgrInfo decompressFn; FmgrInfo decompressFn[INDEX_MAX_KEYS];
FmgrInfo penaltyFn; FmgrInfo penaltyFn[INDEX_MAX_KEYS];
FmgrInfo picksplitFn; FmgrInfo picksplitFn[INDEX_MAX_KEYS];
FmgrInfo equalFn; FmgrInfo equalFn[INDEX_MAX_KEYS];
bool haskeytype; bool haskeytype;
bool keytypbyval; bool keytypbyval;
} GISTSTATE; } GISTSTATE;
...@@ -121,21 +121,30 @@ typedef struct GIST_SPLITVEC ...@@ -121,21 +121,30 @@ typedef struct GIST_SPLITVEC
{ {
OffsetNumber *spl_left; /* array of entries that go left */ OffsetNumber *spl_left; /* array of entries that go left */
int spl_nleft; /* size of this array */ 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 */ OffsetNumber *spl_right; /* array of entries that go right */
int spl_nright; /* size of the array */ 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; } 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 * 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. * tell us if the entry is in a leaf node.
*/ */
typedef struct GISTENTRY typedef struct GISTENTRY
{ {
char *pred; Datum key;
Relation rel; Relation rel;
Page page; Page page;
OffsetNumber offset; OffsetNumber offset;
...@@ -146,43 +155,20 @@ typedef struct GISTENTRY ...@@ -146,43 +155,20 @@ typedef struct GISTENTRY
/* /*
* macro to initialize a GISTENTRY * macro to initialize a GISTENTRY
*/ */
#define gistentryinit(e, pr, r, pg, o, b, l)\ #define gistentryinit(e, k, 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) do { (e).key = (k); (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;
/* gist.c */
extern Datum gistbuild(PG_FUNCTION_ARGS); extern Datum gistbuild(PG_FUNCTION_ARGS);
extern Datum gistinsert(PG_FUNCTION_ARGS); extern Datum gistinsert(PG_FUNCTION_ARGS);
extern Datum gistdelete(PG_FUNCTION_ARGS); extern Datum gistdelete(PG_FUNCTION_ARGS);
extern void _gistdump(Relation r); extern void _gistdump(Relation r);
extern void gistfreestack(GISTSTACK *s); extern void gistfreestack(GISTSTACK *s);
extern void initGISTstate(GISTSTATE *giststate, Relation index); extern void initGISTstate(GISTSTATE *giststate, Relation index);
extern void gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, extern void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
Relation r, Page pg, OffsetNumber o, int b, bool l); Datum k, Relation r, Page pg, OffsetNumber o,
int b, bool l);
extern StrategyNumber RelationGetGISTStrategy(Relation, AttrNumber, extern StrategyNumber RelationGetGISTStrategy(Relation, AttrNumber,
RegProcedure); RegProcedure);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment