1 /*-------------------------------------------------------------------------
4 * interface routines for the postgres GiST index access method.
7 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.88 2002/02/11 22:41:59 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/gist.h"
19 #include "access/gistscan.h"
20 #include "access/heapam.h"
21 #include "catalog/index.h"
22 #include "miscadmin.h"
25 #undef GIST_PAGEADDITEM
27 #define ATTSIZE( datum, TupDesc, i, isnull ) \
30 att_addlength(0, (TupDesc)->attrs[(i)-1]->attlen, (datum)) \
37 /* group flags ( in gistSplit ) */
38 #define LEFT_ADDED 0x01
39 #define RIGHT_ADDED 0x02
40 #define BOTH_ADDED ( LEFT_ADDED | RIGHT_ADDED )
43 * This defines only for shorter code, used in gistgetadjusted
44 * and gistadjsubkey only
46 #define FILLITEM(evp, isnullkey, okey, okeyb, rkey, rkeyb) do { \
48 gistentryinit((evp), rkey, r, (Page) NULL , \
49 (OffsetNumber) 0, rkeyb, FALSE); \
51 gistentryinit((evp), okey, r, (Page) NULL, \
52 (OffsetNumber) 0, okeyb, FALSE); \
56 #define FILLEV(isnull1, key1, key1b, isnull2, key2, key2b) do { \
57 FILLITEM(*ev0p, isnull1, key1, key1b, key2, key2b); \
58 FILLITEM(*ev1p, isnull2, key2, key2b, key1, key1b); \
61 /* Working state for gistbuild and its callback */
70 /* non-export function prototypes */
71 static void gistbuildCallback(Relation index,
77 static void gistdoinsert(Relation r,
79 InsertIndexResult *res,
80 GISTSTATE *GISTstate);
81 static int gistlayerinsert(Relation r, BlockNumber blkno,
84 InsertIndexResult *res,
85 GISTSTATE *giststate);
86 static OffsetNumber gistwritebuffer(Relation r,
91 GISTSTATE *giststate);
92 static int gistnospace(Page page,
93 IndexTuple *itvec, int len);
94 static IndexTuple *gistreadbuffer(Relation r,
95 Buffer buffer, int *len);
96 static IndexTuple *gistjoinvector(
97 IndexTuple *itvec, int *len,
98 IndexTuple *additvec, int addlen);
99 static IndexTuple gistunion(Relation r, IndexTuple *itvec,
100 int len, GISTSTATE *giststate);
102 static IndexTuple gistgetadjusted(Relation r,
105 GISTSTATE *giststate);
106 static int gistfindgroup(GISTSTATE *giststate,
107 GISTENTRY *valvec, GIST_SPLITVEC *spl);
108 static void gistadjsubkey(Relation r,
109 IndexTuple *itup, int *len,
111 GISTSTATE *giststate);
112 static IndexTuple gistFormTuple(GISTSTATE *giststate,
113 Relation r, Datum attdata[], int datumsize[], bool isnull[]);
114 static IndexTuple *gistSplit(Relation r,
118 GISTSTATE *giststate,
119 InsertIndexResult *res);
120 static void gistnewroot(GISTSTATE *giststate, Relation r,
121 IndexTuple *itup, int len);
122 static void GISTInitBuffer(Buffer b, uint32 f);
123 static OffsetNumber gistchoose(Relation r, Page p,
125 GISTSTATE *giststate);
126 static void gistdelete(Relation r, ItemPointer tid);
128 #ifdef GIST_PAGEADDITEM
129 static IndexTuple gist_tuple_replacekey(Relation r,
130 GISTENTRY entry, IndexTuple t);
132 static void gistcentryinit(GISTSTATE *giststate, int nkey,
133 GISTENTRY *e, Datum k,
135 OffsetNumber o, int b, bool l, bool isNull);
136 static void gistDeCompressAtt(GISTSTATE *giststate, Relation r,
137 IndexTuple tuple, Page p, OffsetNumber o,
138 GISTENTRY attdata[], bool decompvec[], bool isnull[]);
139 static void gistFreeAtt(Relation r, GISTENTRY attdata[], bool decompvec[]);
140 static void gistpenalty(GISTSTATE *giststate, int attno,
141 GISTENTRY *key1, bool isNull1,
142 GISTENTRY *key2, bool isNull2,
148 static void gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff);
152 * routine to build an index. Basically calls insert over and over
155 gistbuild(PG_FUNCTION_ARGS)
157 Relation heap = (Relation) PG_GETARG_POINTER(0);
158 Relation index = (Relation) PG_GETARG_POINTER(1);
159 IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
161 GISTBuildState buildstate;
164 /* no locking is needed */
166 initGISTstate(&buildstate.giststate, index);
169 * We expect to be called exactly once for any index relation. If
170 * that's not the case, big trouble's what we have.
172 if (RelationGetNumberOfBlocks(index) != 0)
173 elog(ERROR, "%s already contains data",
174 RelationGetRelationName(index));
176 /* initialize the root page */
177 buffer = ReadBuffer(index, P_NEW);
178 GISTInitBuffer(buffer, F_LEAF);
181 /* build the index */
182 buildstate.numindexattrs = indexInfo->ii_NumIndexAttrs;
183 buildstate.indtuples = 0;
185 /* do the heap scan */
186 reltuples = IndexBuildHeapScan(heap, index, indexInfo,
187 gistbuildCallback, (void *) &buildstate);
189 /* okay, all heap tuples are indexed */
192 * Since we just counted the tuples in the heap, we update its stats
193 * in pg_class to guarantee that the planner takes advantage of the
194 * index we just created. But, only update statistics during normal
195 * index definitions, not for indices on system catalogs created
196 * during bootstrap processing. We must close the relations before
197 * updating statistics to guarantee that the relcache entries are
198 * flushed when we increment the command counter in UpdateStats(). But
199 * we do not release any locks on the relations; those will be held
200 * until end of transaction.
202 if (IsNormalProcessingMode())
204 Oid hrelid = RelationGetRelid(heap);
205 Oid irelid = RelationGetRelid(index);
207 heap_close(heap, NoLock);
209 UpdateStats(hrelid, reltuples);
210 UpdateStats(irelid, buildstate.indtuples);
213 freeGISTstate(&buildstate.giststate);
215 gist_dumptree(index, 0, GISTP_ROOT, 0);
222 * Per-tuple callback from IndexBuildHeapScan
225 gistbuildCallback(Relation index,
232 GISTBuildState *buildstate = (GISTBuildState *) state;
234 bool compvec[INDEX_MAX_KEYS];
238 /* GiST cannot index tuples with leading NULLs */
242 /* immediately compress keys to normalize */
243 for (i = 0; i < buildstate->numindexattrs; i++)
247 attdata[i] = (Datum) 0;
252 gistcentryinit(&buildstate->giststate, i, &tmpcentry, attdata[i],
253 (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
254 -1 /* size is currently bogus */ , TRUE, FALSE);
255 if (attdata[i] != tmpcentry.key &&
256 !(isAttByVal(&buildstate->giststate, i)))
260 attdata[i] = tmpcentry.key;
264 /* form an index tuple and point it at the heap tuple */
265 itup = index_formtuple(buildstate->giststate.tupdesc, attdata, nulls);
266 itup->t_tid = htup->t_self;
269 * Since we already have the index relation locked, we call
270 * gistdoinsert directly. Normal access method calls dispatch through
271 * gistinsert, which locks the relation for write. This is the right
272 * thing to do if you're inserting single tups, but not when you're
273 * initializing the whole index at once.
275 gistdoinsert(index, itup, NULL, &buildstate->giststate);
277 buildstate->indtuples += 1;
279 for (i = 0; i < buildstate->numindexattrs; i++)
281 pfree(DatumGetPointer(attdata[i]));
287 * gistinsert -- wrapper for GiST tuple insertion.
289 * This is the public interface routine for tuple insertion in GiSTs.
290 * It doesn't do any work; just locks the relation and passes the buck.
293 gistinsert(PG_FUNCTION_ARGS)
295 Relation r = (Relation) PG_GETARG_POINTER(0);
296 Datum *datum = (Datum *) PG_GETARG_POINTER(1);
297 char *nulls = (char *) PG_GETARG_POINTER(2);
298 ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
301 Relation heapRel = (Relation) PG_GETARG_POINTER(4);
303 InsertIndexResult res;
308 bool compvec[INDEX_MAX_KEYS];
311 * Since GIST is not marked "amconcurrent" in pg_am, caller should
312 * have acquired exclusive lock on index relation. We need no locking
316 /* GiST cannot index tuples with leading NULLs */
320 PG_RETURN_POINTER(res);
323 initGISTstate(&giststate, r);
325 /* immediately compress keys to normalize */
326 for (i = 0; i < r->rd_att->natts; i++)
330 datum[i] = (Datum) 0;
335 gistcentryinit(&giststate, i, &tmpentry, datum[i],
336 (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
337 -1 /* size is currently bogus */ , TRUE, FALSE);
338 if (datum[i] != tmpentry.key && !(isAttByVal(&giststate, i)))
342 datum[i] = tmpentry.key;
345 itup = index_formtuple(giststate.tupdesc, datum, nulls);
346 itup->t_tid = *ht_ctid;
348 res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
349 gistdoinsert(r, itup, &res, &giststate);
351 for (i = 0; i < r->rd_att->natts; i++)
352 if (compvec[i] == TRUE)
353 pfree(DatumGetPointer(datum[i]));
355 freeGISTstate(&giststate);
357 PG_RETURN_POINTER(res);
360 #ifdef GIST_PAGEADDITEM
362 ** Take a compressed entry, and install it on a page. Since we now know
363 ** where the entry will live, we decompress it and recompress it using
364 ** that knowledge (some compression routines may want to fish around
365 ** on the page, for example, or do something special for leaf nodes.)
368 gistPageAddItem(GISTSTATE *giststate,
373 OffsetNumber offsetNumber,
379 IndexTuple itup = (IndexTuple) item;
385 * recompress the item given that we now know the exact page and
386 * offset for insertion
388 datum = index_getattr(itup, 1, r->rd_att, &IsNull);
389 gistdentryinit(giststate, 0, dentry, datum,
390 (Relation) 0, (Page) 0,
391 (OffsetNumber) InvalidOffsetNumber,
392 ATTSIZE(datum, r, 1, IsNull),
394 gistcentryinit(giststate, 0, &tmpcentry, dentry->key, r, page,
395 offsetNumber, dentry->bytes, FALSE);
396 *newtup = gist_tuple_replacekey(r, tmpcentry, itup);
397 retval = PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup),
398 offsetNumber, flags);
399 if (retval == InvalidOffsetNumber)
400 elog(ERROR, "gist: failed to add index item to %s",
401 RelationGetRelationName(r));
403 if (DatumGetPointer(tmpcentry.key) != NULL &&
404 tmpcentry.key != dentry->key &&
405 tmpcentry.key != datum)
406 pfree(DatumGetPointer(tmpcentry.key));
412 gistdoinsert(Relation r,
414 InsertIndexResult *res,
415 GISTSTATE *giststate)
422 instup = (IndexTuple *) palloc(sizeof(IndexTuple));
423 instup[0] = (IndexTuple) palloc(IndexTupleSize(itup));
424 memcpy(instup[0], itup, IndexTupleSize(itup));
426 ret = gistlayerinsert(r, GISTP_ROOT, &instup, &len, res, giststate);
428 gistnewroot(giststate, r, instup, len);
430 for (i = 0; i < len; i++)
436 gistlayerinsert(Relation r, BlockNumber blkno,
437 IndexTuple **itup, /* in - out, has compressed entry */
438 int *len, /* in - out */
439 InsertIndexResult *res, /* out */
440 GISTSTATE *giststate)
446 GISTPageOpaque opaque;
448 buffer = ReadBuffer(r, blkno);
449 page = (Page) BufferGetPage(buffer);
450 opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
452 if (!(opaque->flags & F_LEAF))
454 /* internal page, so we must walk on tree */
455 /* len IS equial 1 */
458 ItemPointerData oldtid;
461 child = gistchoose(r, page, *(*itup), giststate);
462 iid = PageGetItemId(page, child);
463 oldtup = (IndexTuple) PageGetItem(page, iid);
464 nblkno = ItemPointerGetBlockNumber(&(oldtup->t_tid));
467 * After this call: 1. if child page was splited, then itup
468 * contains keys for each page 2. if child page wasn't splited,
469 * then itup contains additional for adjustement of current key
471 ret = gistlayerinsert(r, nblkno, itup, len, res, giststate);
473 /* nothing inserted in child */
474 if (!(ret & INSERTED))
476 ReleaseBuffer(buffer);
480 /* child does not splited */
481 if (!(ret & SPLITED))
483 IndexTuple newtup = gistgetadjusted(r, oldtup, (*itup)[0], giststate);
487 /* not need to update key */
488 ReleaseBuffer(buffer);
492 pfree((*itup)[0]); /* !!! */
496 /* key is modified, so old version must be deleted */
497 ItemPointerSet(&oldtid, blkno, child);
498 gistdelete(r, &oldtid);
503 if (gistnospace(page, (*itup), *len))
505 /* no space for insertion */
512 itvec = gistreadbuffer(r, buffer, &tlen);
513 itvec = gistjoinvector(itvec, &tlen, (*itup), *len);
515 newitup = gistSplit(r, buffer, itvec, &tlen, giststate,
516 (opaque->flags & F_LEAF) ? res : NULL); /* res only for
517 * inserting in leaf */
518 ReleaseBuffer(buffer);
520 pfree((*itup)[oldlen - 1]);
521 while ((--oldlen) > 0);
525 *len = tlen; /* now tlen >= 2 */
533 off = (PageIsEmpty(page)) ?
536 OffsetNumberNext(PageGetMaxOffsetNumber(page));
537 l = gistwritebuffer(r, page, (*itup), *len, off, giststate);
541 * set res if insert into leaf page, in this case, len = 1 always
543 if (res && (opaque->flags & F_LEAF))
544 ItemPointerSet(&((*res)->pointerData), blkno, l);
547 { /* previos insert ret & SPLITED != 0 */
551 * child was splited, so we must form union for insertion in
554 IndexTuple newtup = gistunion(r, (*itup), *len, giststate);
556 ItemPointerSet(&(newtup->t_tid), blkno, 1);
558 for (i = 0; i < *len; i++)
569 * Write itup vector to page, has no control of free space
572 gistwritebuffer(Relation r, Page page, IndexTuple *itup,
573 int len, OffsetNumber off, GISTSTATE *giststate)
575 OffsetNumber l = InvalidOffsetNumber;
578 #ifdef GIST_PAGEADDITEM
583 for (i = 0; i < len; i++)
585 #ifdef GIST_PAGEADDITEM
586 l = gistPageAddItem(giststate, r, page,
587 (Item) itup[i], IndexTupleSize(itup[i]),
588 off, LP_USED, &tmpdentry, &newtup);
589 off = OffsetNumberNext(off);
590 if (DatumGetPointer(tmpdentry.key) != NULL &&
591 tmpdentry.key != index_getattr(itup[i], 1, r->rd_att, &IsNull))
592 pfree(DatumGetPointer(tmpdentry.key));
593 if (itup[i] != newtup)
596 l = PageAddItem(page, (Item) itup[i], IndexTupleSize(itup[i]),
598 if (l == InvalidOffsetNumber)
599 elog(ERROR, "gist: failed to add index item to %s",
600 RelationGetRelationName(r));
607 * Check space for itup vector on page
610 gistnospace(Page page, IndexTuple *itvec, int len)
615 for (i = 0; i < len; i++)
616 size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
618 return (PageGetFreeSpace(page) < size);
622 * Read buffer into itup vector
625 gistreadbuffer(Relation r, Buffer buffer, int *len /* out */ )
630 Page p = (Page) BufferGetPage(buffer);
632 maxoff = PageGetMaxOffsetNumber(p);
634 itvec = palloc(sizeof(IndexTuple) * maxoff);
635 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
636 itvec[i - 1] = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
642 * join two vectors into one
645 gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
647 itvec = (IndexTuple *) repalloc((void *) itvec, sizeof(IndexTuple) * ((*len) + addlen));
648 memmove(&itvec[*len], additvec, sizeof(IndexTuple) * addlen);
654 * return union of itup vector
657 gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
659 Datum attr[INDEX_MAX_KEYS];
660 bool whatfree[INDEX_MAX_KEYS];
661 char isnull[INDEX_MAX_KEYS];
668 GISTENTRY centry[INDEX_MAX_KEYS];
674 needfree = (bool *) palloc(((len == 1) ? 2 : len) * sizeof(bool));
675 /* workaround for 64-bit: ensure GISTENTRY array is maxaligned */
676 storage = (char*)palloc( ((len == 1) ? 2 : len) * sizeof(GISTENTRY) + MAXALIGN(VARHDRSZ));
677 evec = (bytea *) (storage + MAXALIGN(VARHDRSZ) - VARHDRSZ);
679 for (j = 0; j < r->rd_att->natts; j++)
682 for (i = 0; i < len; i++)
684 datum = index_getattr(itvec[i], j + 1, giststate->tupdesc, &IsNull);
688 gistdentryinit(giststate, j,
689 &((GISTENTRY *) VARDATA(evec))[reallen],
691 (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
692 ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull);
693 if ((!isAttByVal(giststate, j)) &&
694 ((GISTENTRY *) VARDATA(evec))[reallen].key != datum)
695 needfree[reallen] = TRUE;
697 needfree[reallen] = FALSE;
711 VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
712 gistentryinit(((GISTENTRY *) VARDATA(evec))[1],
713 ((GISTENTRY *) VARDATA(evec))[0].key, r, (Page) NULL,
714 (OffsetNumber) 0, ((GISTENTRY *) VARDATA(evec))[0].bytes, FALSE);
718 VARATT_SIZEP(evec) = reallen * sizeof(GISTENTRY) + VARHDRSZ;
719 datum = FunctionCall2(&giststate->unionFn[j],
720 PointerGetDatum(evec),
721 PointerGetDatum(&datumsize));
723 for (i = 0; i < reallen; i++)
725 pfree(DatumGetPointer(((GISTENTRY *) VARDATA(evec))[i].key));
727 gistcentryinit(giststate, j, ¢ry[j], datum,
728 (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
729 datumsize, FALSE, FALSE);
731 attr[j] = centry[j].key;
732 if (!isAttByVal(giststate, j))
735 if (centry[j].key != datum)
736 pfree(DatumGetPointer(datum));
743 pfree(storage); /* pfree(evec); */
746 newtup = (IndexTuple) index_formtuple(giststate->tupdesc, attr, isnull);
747 for (j = 0; j < r->rd_att->natts; j++)
749 pfree(DatumGetPointer(attr[j]));
756 * Forms union of oldtup and addtup, if union == oldtup then return NULL
759 gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
766 char isnull[INDEX_MAX_KEYS],
767 whatfree[INDEX_MAX_KEYS];
768 Datum attr[INDEX_MAX_KEYS];
769 GISTENTRY centry[INDEX_MAX_KEYS],
770 oldatt[INDEX_MAX_KEYS],
771 addatt[INDEX_MAX_KEYS],
774 bool olddec[INDEX_MAX_KEYS],
775 adddec[INDEX_MAX_KEYS];
776 bool oldisnull[INDEX_MAX_KEYS],
777 addisnull[INDEX_MAX_KEYS];
778 IndexTuple newtup = NULL;
782 /* workaround for 64-bit: ensure GISTENTRY array is maxaligned */
783 storage = (char*) palloc( 2 * sizeof(GISTENTRY) + MAXALIGN(VARHDRSZ));
784 evec = (bytea *) (storage + MAXALIGN(VARHDRSZ) - VARHDRSZ);
785 VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
786 ev0p = &((GISTENTRY *) VARDATA(evec))[0];
787 ev1p = &((GISTENTRY *) VARDATA(evec))[1];
789 gistDeCompressAtt(giststate, r, oldtup, (Page) NULL,
790 (OffsetNumber) 0, oldatt, olddec, oldisnull);
792 gistDeCompressAtt(giststate, r, addtup, (Page) NULL,
793 (OffsetNumber) 0, addatt, adddec, addisnull);
796 for (j = 0; j < r->rd_att->natts; j++)
798 if (oldisnull[j] && addisnull[j])
807 oldisnull[j], oldatt[j].key, oldatt[j].bytes,
808 addisnull[j], addatt[j].key, addatt[j].bytes
811 datum = FunctionCall2(&giststate->unionFn[j],
812 PointerGetDatum(evec),
813 PointerGetDatum(&datumsize));
815 if (oldisnull[j] || addisnull[j])
822 FunctionCall3(&giststate->equalFn[j],
825 PointerGetDatum(&result));
832 pfree(DatumGetPointer(oldatt[j].key));
834 pfree(DatumGetPointer(addatt[j].key));
836 gistcentryinit(giststate, j, ¢ry[j], datum,
837 (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
838 datumsize, FALSE, FALSE);
841 attr[j] = centry[j].key;
842 if ((!isAttByVal(giststate, j)))
845 if (centry[j].key != datum)
846 pfree(DatumGetPointer(datum));
852 pfree(storage); /* pfree(evec); */
856 /* need to update key */
857 newtup = (IndexTuple) index_formtuple(giststate->tupdesc, attr, isnull);
858 newtup->t_tid = oldtup->t_tid;
861 for (j = 0; j < r->rd_att->natts; j++)
863 pfree(DatumGetPointer(attr[j]));
869 gistunionsubkey(Relation r, GISTSTATE *giststate, IndexTuple *itvec, GIST_SPLITVEC *spl)
879 OffsetNumber *entries;
887 for (lr = 0; lr <= 1; lr++)
891 attrsize = spl->spl_lattrsize;
892 attr = spl->spl_lattr;
893 len = spl->spl_nleft;
894 entries = spl->spl_left;
895 isnull = spl->spl_lisnull;
899 attrsize = spl->spl_rattrsize;
900 attr = spl->spl_rattr;
901 len = spl->spl_nright;
902 entries = spl->spl_right;
903 isnull = spl->spl_risnull;
906 needfree = (bool *) palloc(((len == 1) ? 2 : len) * sizeof(bool));
907 /* workaround for 64-bit: ensure GISTENTRY array is maxaligned */
908 storage = (char*)palloc( ((len == 1) ? 2 : len) * sizeof(GISTENTRY) + MAXALIGN(VARHDRSZ));
909 evec = (bytea *) (storage + MAXALIGN(VARHDRSZ) - VARHDRSZ);
911 for (j = 1; j < r->rd_att->natts; j++)
914 for (i = 0; i < len; i++)
916 if (spl->spl_idgrp[entries[i]])
918 datum = index_getattr(itvec[entries[i] - 1], j + 1,
919 giststate->tupdesc, &IsNull);
922 gistdentryinit(giststate, j,
923 &((GISTENTRY *) VARDATA(evec))[reallen],
925 (Relation) NULL, (Page) NULL,
927 ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull);
928 if ((!isAttByVal(giststate, j)) &&
929 ((GISTENTRY *) VARDATA(evec))[reallen].key != datum)
930 needfree[reallen] = TRUE;
932 needfree[reallen] = FALSE;
945 * ((GISTENTRY *) VARDATA(evec))[0].bytes may be not
946 * defined, so form union with itself
950 VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
951 memcpy((void *) &((GISTENTRY *) VARDATA(evec))[1],
952 (void *) &((GISTENTRY *) VARDATA(evec))[0],
956 VARATT_SIZEP(evec) = reallen * sizeof(GISTENTRY) + VARHDRSZ;
957 datum = FunctionCall2(&giststate->unionFn[j],
958 PointerGetDatum(evec),
959 PointerGetDatum(&datumsize));
963 for (i = 0; i < reallen; i++)
965 pfree(DatumGetPointer(((GISTENTRY *) VARDATA(evec))[i].key));
968 attrsize[j] = datumsize;
970 pfree(storage); /* pfree(evec); */
976 * find group in vector with equial value
979 gistfindgroup(GISTSTATE *giststate, GISTENTRY *valvec, GIST_SPLITVEC *spl)
988 * first key is always not null (see gistinsert), so we may not check
992 for (i = 0; i < spl->spl_nleft; i++)
994 if (spl->spl_idgrp[spl->spl_left[i]])
997 /* find all equal value in right part */
998 for (j = 0; j < spl->spl_nright; j++)
1000 if (spl->spl_idgrp[spl->spl_right[j]])
1002 FunctionCall3(&giststate->equalFn[0],
1003 valvec[spl->spl_left[i]].key,
1004 valvec[spl->spl_right[j]].key,
1005 PointerGetDatum(&result));
1008 spl->spl_idgrp[spl->spl_right[j]] = curid;
1012 /* find all other equal value in left part */
1015 /* add current val to list of equial values */
1016 spl->spl_idgrp[spl->spl_left[i]] = curid;
1018 for (j = i + 1; j < spl->spl_nleft; j++)
1020 if (spl->spl_idgrp[spl->spl_left[j]])
1022 FunctionCall3(&giststate->equalFn[0],
1023 valvec[spl->spl_left[i]].key,
1024 valvec[spl->spl_left[j]].key,
1025 PointerGetDatum(&result));
1028 spl->spl_idgrp[spl->spl_left[j]] = curid;
1032 spl->spl_ngrp[curid] = len + 1;
1041 * Insert equivalent tuples to left or right page
1042 * with minimize penalty
1045 gistadjsubkey(Relation r,
1046 IndexTuple *itup, /* contains compressed entry */
1049 GISTSTATE *giststate
1053 OffsetNumber *curwpos;
1054 bool decfree[INDEX_MAX_KEYS];
1056 identry[INDEX_MAX_KEYS],
1064 bool isnull[INDEX_MAX_KEYS];
1070 curlen = v->spl_nleft;
1071 curwpos = v->spl_left;
1072 for (i = 0; i < v->spl_nleft; i++)
1073 if (v->spl_idgrp[v->spl_left[i]] == 0)
1075 *curwpos = v->spl_left[i];
1080 v->spl_nleft = curlen;
1082 curlen = v->spl_nright;
1083 curwpos = v->spl_right;
1084 for (i = 0; i < v->spl_nright; i++)
1085 if (v->spl_idgrp[v->spl_right[i]] == 0)
1087 *curwpos = v->spl_right[i];
1092 v->spl_nright = curlen;
1094 /* workaround for 64-bit: ensure GISTENTRY array is maxaligned */
1095 storage = (char*)palloc( 2 * sizeof(GISTENTRY) + MAXALIGN(VARHDRSZ));
1096 evec = (bytea *) (storage + MAXALIGN(VARHDRSZ) - VARHDRSZ);
1097 VARATT_SIZEP(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
1098 ev0p = &((GISTENTRY *) VARDATA(evec))[0];
1099 ev1p = &((GISTENTRY *) VARDATA(evec))[1];
1101 /* add equivalent tuple */
1102 for (i = 0; i < *len; i++)
1104 if (v->spl_idgrp[i + 1] == 0) /* already inserted */
1106 gistDeCompressAtt(giststate, r, itup[i], (Page) NULL, (OffsetNumber) 0,
1107 identry, decfree, isnull);
1109 v->spl_ngrp[v->spl_idgrp[i + 1]]--;
1110 if (v->spl_ngrp[v->spl_idgrp[i + 1]] == 0 &&
1111 (v->spl_grpflag[v->spl_idgrp[i + 1]] & BOTH_ADDED) != BOTH_ADDED)
1114 /* force last in group */
1116 lpenalty = (v->spl_grpflag[v->spl_idgrp[i + 1]] & LEFT_ADDED) ? 2.0 : 0.0;
1121 for (j = 1; j < r->rd_att->natts; j++)
1123 gistentryinit(entry, v->spl_lattr[j], r, (Page) NULL,
1124 (OffsetNumber) 0, v->spl_lattrsize[j], FALSE);
1125 gistpenalty(giststate, j, &entry, v->spl_lisnull[j],
1126 &identry[j], isnull[j], &lpenalty);
1128 gistentryinit(entry, v->spl_rattr[j], r, (Page) NULL,
1129 (OffsetNumber) 0, v->spl_rattrsize[j], FALSE);
1130 gistpenalty(giststate, j, &entry, v->spl_risnull[j],
1131 &identry[j], isnull[j], &rpenalty);
1133 if (lpenalty != rpenalty)
1138 if (lpenalty < rpenalty)
1140 v->spl_grpflag[v->spl_idgrp[i + 1]] |= LEFT_ADDED;
1141 v->spl_left[v->spl_nleft] = i + 1;
1143 for (j = 1; j < r->rd_att->natts; j++)
1145 if (isnull[j] && v->spl_lisnull[j])
1147 v->spl_lattr[j] = (Datum) 0;
1148 v->spl_lattrsize[j] = 0;
1153 v->spl_lisnull[j], v->spl_lattr[j], v->spl_lattrsize[j],
1154 isnull[j], identry[j].key, identry[j].bytes
1157 datum = FunctionCall2(&giststate->unionFn[j],
1158 PointerGetDatum(evec),
1159 PointerGetDatum(&datumsize));
1161 if ((!isAttByVal(giststate, j)) && !v->spl_lisnull[j])
1162 pfree(DatumGetPointer(v->spl_lattr[j]));
1163 v->spl_lattr[j] = datum;
1164 v->spl_lattrsize[j] = datumsize;
1165 v->spl_lisnull[j] = false;
1171 v->spl_grpflag[v->spl_idgrp[i + 1]] |= RIGHT_ADDED;
1172 v->spl_right[v->spl_nright] = i + 1;
1174 for (j = 1; j < r->rd_att->natts; j++)
1176 if (isnull[j] && v->spl_risnull[j])
1178 v->spl_rattr[j] = (Datum) 0;
1179 v->spl_rattrsize[j] = 0;
1184 v->spl_risnull[j], v->spl_rattr[j], v->spl_rattrsize[j],
1185 isnull[j], identry[j].key, identry[j].bytes
1188 datum = FunctionCall2(&giststate->unionFn[j],
1189 PointerGetDatum(evec),
1190 PointerGetDatum(&datumsize));
1192 if ((!isAttByVal(giststate, j)) && !v->spl_risnull[j])
1193 pfree(DatumGetPointer(v->spl_rattr[j]));
1195 v->spl_rattr[j] = datum;
1196 v->spl_rattrsize[j] = datumsize;
1197 v->spl_risnull[j] = false;
1202 gistFreeAtt(r, identry, decfree);
1204 pfree(storage); /* pfree(evec); */
1208 * gistSplit -- split a page in the tree.
1211 gistSplit(Relation r,
1213 IndexTuple *itup, /* contains compressed entry */
1215 GISTSTATE *giststate,
1216 InsertIndexResult *res)
1223 IndexTuple *lvectup,
1228 GISTPageOpaque opaque;
1240 p = (Page) BufferGetPage(buffer);
1241 opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
1244 * The root of the tree is the first block in the relation. If we're
1245 * about to split the root, we need to do some hocus-pocus to enforce
1249 if (BufferGetBlockNumber(buffer) == GISTP_ROOT)
1251 leftbuf = ReadBuffer(r, P_NEW);
1252 GISTInitBuffer(leftbuf, opaque->flags);
1253 lbknum = BufferGetBlockNumber(leftbuf);
1254 left = (Page) BufferGetPage(leftbuf);
1259 IncrBufferRefCount(buffer);
1260 lbknum = BufferGetBlockNumber(buffer);
1261 left = (Page) PageGetTempPage(p, sizeof(GISTPageOpaqueData));
1264 rightbuf = ReadBuffer(r, P_NEW);
1265 GISTInitBuffer(rightbuf, opaque->flags);
1266 rbknum = BufferGetBlockNumber(rightbuf);
1267 right = (Page) BufferGetPage(rightbuf);
1269 /* generate the item array */
1270 /* workaround for 64-bit: ensure GISTENTRY array is maxaligned */
1271 storage = palloc(MAXALIGN(VARHDRSZ) + (*len + 1) * sizeof(GISTENTRY));
1272 entryvec = (bytea *) (storage + MAXALIGN(VARHDRSZ) - VARHDRSZ);
1273 decompvec = (bool *) palloc( (*len + 1) * sizeof(bool));
1274 VARATT_SIZEP(entryvec) = (*len + 1) * sizeof(GISTENTRY) + VARHDRSZ;
1275 for (i = 1; i <= *len; i++)
1277 datum = index_getattr(itup[i - 1], 1, giststate->tupdesc, &IsNull);
1278 gistdentryinit(giststate, 0, &((GISTENTRY *) VARDATA(entryvec))[i],
1280 ATTSIZE(datum, giststate->tupdesc, 1, IsNull), FALSE, IsNull);
1281 if ((!isAttByVal(giststate, 0)) && ((GISTENTRY *) VARDATA(entryvec))[i].key != datum)
1282 decompvec[i] = TRUE;
1284 decompvec[i] = FALSE;
1288 * now let the user-defined picksplit function set up the split
1289 * vector; in entryvec have no null value!!
1291 FunctionCall2(&giststate->picksplitFn[0],
1292 PointerGetDatum(entryvec),
1293 PointerGetDatum(&v));
1295 /* compatibility with old code */
1296 if (v.spl_left[v.spl_nleft - 1] == InvalidOffsetNumber)
1297 v.spl_left[v.spl_nleft - 1] = (OffsetNumber) *len;
1298 if (v.spl_right[v.spl_nright - 1] == InvalidOffsetNumber)
1299 v.spl_right[v.spl_nright - 1] = (OffsetNumber) *len;
1301 v.spl_lattr[0] = v.spl_ldatum;
1302 v.spl_rattr[0] = v.spl_rdatum;
1303 v.spl_lisnull[0] = false;
1304 v.spl_risnull[0] = false;
1307 * if index is multikey, then we must to try get smaller bounding box
1310 if (r->rd_att->natts > 1)
1312 v.spl_idgrp = (int *) palloc(sizeof(int) * (*len + 1));
1313 MemSet((void *) v.spl_idgrp, 0, sizeof(int) * (*len + 1));
1314 v.spl_grpflag = (char *) palloc(sizeof(char) * (*len + 1));
1315 MemSet((void *) v.spl_grpflag, 0, sizeof(char) * (*len + 1));
1316 v.spl_ngrp = (int *) palloc(sizeof(int) * (*len + 1));
1318 MaxGrpId = gistfindgroup(giststate, (GISTENTRY *) VARDATA(entryvec), &v);
1320 /* form union of sub keys for each page (l,p) */
1321 gistunionsubkey(r, giststate, itup, &v);
1324 * if possible, we insert equivalent tuples with control by
1325 * penalty for a subkey(s)
1328 gistadjsubkey(r, itup, len, &v, giststate);
1331 pfree(v.spl_grpflag);
1335 /* clean up the entry vector: its keys need to be deleted, too */
1336 for (i = 1; i <= *len; i++)
1338 pfree(DatumGetPointer(((GISTENTRY *) VARDATA(entryvec))[i].key));
1339 pfree(storage); /* pfree(entryvec); */
1342 /* form left and right vector */
1343 lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nleft);
1344 rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nright);
1346 for (i = 0; i < v.spl_nleft; i++)
1347 lvectup[i] = itup[v.spl_left[i] - 1];
1349 for (i = 0; i < v.spl_nright; i++)
1350 rvectup[i] = itup[v.spl_right[i] - 1];
1353 /* write on disk (may be need another split) */
1354 if (gistnospace(right, rvectup, v.spl_nright))
1356 nlen = v.spl_nright;
1357 newtup = gistSplit(r, rightbuf, rvectup, &nlen, giststate,
1358 (res && rvectup[nlen - 1] == itup[*len - 1]) ? res : NULL);
1359 ReleaseBuffer(rightbuf);
1360 for (j = 1; j < r->rd_att->natts; j++)
1361 if ((!isAttByVal(giststate, j)) && !v.spl_risnull[j])
1362 pfree(DatumGetPointer(v.spl_rattr[j]));
1368 l = gistwritebuffer(r, right, rvectup, v.spl_nright, FirstOffsetNumber, giststate);
1369 WriteBuffer(rightbuf);
1372 ItemPointerSet(&((*res)->pointerData), rbknum, l);
1375 newtup = (IndexTuple *) palloc(sizeof(IndexTuple) * 1);
1376 newtup[0] = gistFormTuple(giststate, r, v.spl_rattr, v.spl_rattrsize, v.spl_risnull);
1377 ItemPointerSet(&(newtup[0]->t_tid), rbknum, 1);
1381 if (gistnospace(left, lvectup, v.spl_nleft))
1383 int llen = v.spl_nleft;
1386 lntup = gistSplit(r, leftbuf, lvectup, &llen, giststate,
1387 (res && lvectup[llen - 1] == itup[*len - 1]) ? res : NULL);
1388 ReleaseBuffer(leftbuf);
1390 for (j = 1; j < r->rd_att->natts; j++)
1391 if ((!isAttByVal(giststate, j)) && !v.spl_lisnull[j])
1392 pfree(DatumGetPointer(v.spl_lattr[j]));
1394 newtup = gistjoinvector(newtup, &nlen, lntup, llen);
1401 l = gistwritebuffer(r, left, lvectup, v.spl_nleft, FirstOffsetNumber, giststate);
1402 if (BufferGetBlockNumber(buffer) != GISTP_ROOT)
1403 PageRestoreTempPage(left, p);
1405 WriteBuffer(leftbuf);
1408 ItemPointerSet(&((*res)->pointerData), lbknum, l);
1411 newtup = (IndexTuple *) repalloc((void *) newtup, sizeof(IndexTuple) * nlen);
1412 newtup[nlen - 1] = gistFormTuple(giststate, r, v.spl_lattr, v.spl_lattrsize, v.spl_lisnull);
1413 ItemPointerSet(&(newtup[nlen - 1]->t_tid), lbknum, 1);
1417 /* adjust active scans */
1418 gistadjscans(r, GISTOP_SPLIT, BufferGetBlockNumber(buffer), FirstOffsetNumber);
1431 gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple *itup, int len)
1436 b = ReadBuffer(r, GISTP_ROOT);
1437 GISTInitBuffer(b, 0);
1438 p = BufferGetPage(b);
1440 gistwritebuffer(r, p, itup, len, FirstOffsetNumber, giststate);
1445 GISTInitBuffer(Buffer b, uint32 f)
1447 GISTPageOpaque opaque;
1451 pageSize = BufferGetPageSize(b);
1453 page = BufferGetPage(b);
1455 PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
1457 opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
1463 ** find entry with lowest penalty
1466 gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
1467 GISTSTATE *giststate)
1469 OffsetNumber maxoff;
1475 which_grow[INDEX_MAX_KEYS];
1477 identry[INDEX_MAX_KEYS];
1479 decompvec[INDEX_MAX_KEYS],
1480 isnull[INDEX_MAX_KEYS];
1483 maxoff = PageGetMaxOffsetNumber(p);
1487 gistDeCompressAtt(giststate, r,
1488 it, (Page) NULL, (OffsetNumber) 0,
1489 identry, decompvec, isnull);
1491 for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
1493 IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
1496 for (j = 0; j < r->rd_att->natts; j++)
1498 datum = index_getattr(itup, j + 1, giststate->tupdesc, &IsNull);
1499 gistdentryinit(giststate, j, &entry, datum, r, p, i, ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull);
1500 gistpenalty(giststate, j, &entry, IsNull, &identry[j], isnull[j], &usize);
1502 if ((!isAttByVal(giststate, j)) && entry.key != datum)
1503 pfree(DatumGetPointer(entry.key));
1505 if (which_grow[j] < 0 || usize < which_grow[j])
1508 which_grow[j] = usize;
1509 if (j < r->rd_att->natts - 1 && i == FirstOffsetNumber)
1510 which_grow[j + 1] = -1;
1511 sum_grow += which_grow[j];
1513 else if (which_grow[j] == usize)
1523 gistFreeAtt(r, identry, decompvec);
1528 gistfreestack(GISTSTACK *s)
1532 while (s != (GISTSTACK *) NULL)
1542 * Retail deletion of a single tuple.
1544 * NB: this is no longer called externally, but is still needed by
1545 * gistlayerinsert(). That dependency will have to be fixed if GIST
1546 * is ever going to allow concurrent insertions.
1549 gistdelete(Relation r, ItemPointer tid)
1552 OffsetNumber offnum;
1557 * Since GIST is not marked "amconcurrent" in pg_am, caller should
1558 * have acquired exclusive lock on index relation. We need no locking
1562 blkno = ItemPointerGetBlockNumber(tid);
1563 offnum = ItemPointerGetOffsetNumber(tid);
1565 /* adjust any scans that will be affected by this deletion */
1566 /* NB: this works only for scans in *this* backend! */
1567 gistadjscans(r, GISTOP_DEL, blkno, offnum);
1569 /* delete the index tuple */
1570 buf = ReadBuffer(r, blkno);
1571 page = BufferGetPage(buf);
1573 PageIndexTupleDelete(page, offnum);
1579 * Bulk deletion of all index entries pointing to a set of heap tuples.
1580 * The set of target tuples is specified via a callback routine that tells
1581 * whether any given heap tuple (identified by ItemPointer) is being deleted.
1583 * Result: a palloc'd struct containing statistical info for VACUUM displays.
1586 gistbulkdelete(PG_FUNCTION_ARGS)
1588 Relation rel = (Relation) PG_GETARG_POINTER(0);
1589 IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
1590 void *callback_state = (void *) PG_GETARG_POINTER(2);
1591 IndexBulkDeleteResult *result;
1592 BlockNumber num_pages;
1593 double tuples_removed;
1594 double num_index_tuples;
1595 RetrieveIndexResult res;
1596 IndexScanDesc iscan;
1599 num_index_tuples = 0;
1602 * Since GIST is not marked "amconcurrent" in pg_am, caller should
1603 * have acquired exclusive lock on index relation. We need no locking
1608 * XXX generic implementation --- should be improved!
1611 /* walk through the entire index */
1612 iscan = index_beginscan(rel, false, 0, (ScanKey) NULL);
1614 while ((res = index_getnext(iscan, ForwardScanDirection))
1615 != (RetrieveIndexResult) NULL)
1617 ItemPointer heapptr = &res->heap_iptr;
1619 if (callback(heapptr, callback_state))
1621 ItemPointer indexptr = &res->index_iptr;
1623 OffsetNumber offnum;
1627 blkno = ItemPointerGetBlockNumber(indexptr);
1628 offnum = ItemPointerGetOffsetNumber(indexptr);
1630 /* adjust any scans that will be affected by this deletion */
1631 gistadjscans(rel, GISTOP_DEL, blkno, offnum);
1633 /* delete the index tuple */
1634 buf = ReadBuffer(rel, blkno);
1635 page = BufferGetPage(buf);
1637 PageIndexTupleDelete(page, offnum);
1641 tuples_removed += 1;
1644 num_index_tuples += 1;
1649 index_endscan(iscan);
1651 /* return statistics */
1652 num_pages = RelationGetNumberOfBlocks(rel);
1654 result = (IndexBulkDeleteResult *) palloc(sizeof(IndexBulkDeleteResult));
1655 result->num_pages = num_pages;
1656 result->tuples_removed = tuples_removed;
1657 result->num_index_tuples = num_index_tuples;
1659 PG_RETURN_POINTER(result);
1664 initGISTstate(GISTSTATE *giststate, Relation index)
1668 if (index->rd_att->natts > INDEX_MAX_KEYS)
1669 elog(ERROR, "initGISTstate: numberOfAttributes %d > %d",
1670 index->rd_att->natts, INDEX_MAX_KEYS);
1672 giststate->tupdesc = index->rd_att;
1674 for (i = 0; i < index->rd_att->natts; i++)
1676 fmgr_info_copy(&(giststate->consistentFn[i]),
1677 index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC),
1678 CurrentMemoryContext);
1679 fmgr_info_copy(&(giststate->unionFn[i]),
1680 index_getprocinfo(index, i + 1, GIST_UNION_PROC),
1681 CurrentMemoryContext);
1682 fmgr_info_copy(&(giststate->compressFn[i]),
1683 index_getprocinfo(index, i + 1, GIST_COMPRESS_PROC),
1684 CurrentMemoryContext);
1685 fmgr_info_copy(&(giststate->decompressFn[i]),
1686 index_getprocinfo(index, i + 1, GIST_DECOMPRESS_PROC),
1687 CurrentMemoryContext);
1688 fmgr_info_copy(&(giststate->penaltyFn[i]),
1689 index_getprocinfo(index, i + 1, GIST_PENALTY_PROC),
1690 CurrentMemoryContext);
1691 fmgr_info_copy(&(giststate->picksplitFn[i]),
1692 index_getprocinfo(index, i + 1, GIST_PICKSPLIT_PROC),
1693 CurrentMemoryContext);
1694 fmgr_info_copy(&(giststate->equalFn[i]),
1695 index_getprocinfo(index, i + 1, GIST_EQUAL_PROC),
1696 CurrentMemoryContext);
1701 freeGISTstate(GISTSTATE *giststate)
1706 #ifdef GIST_PAGEADDITEM
1708 ** Given an IndexTuple to be inserted on a page, this routine replaces
1709 ** the key with another key, which may involve generating a new IndexTuple
1710 ** if the sizes don't match or if the null status changes.
1712 ** XXX this only works for a single-column index tuple!
1715 gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
1718 Datum datum = index_getattr(t, 1, r->rd_att, &IsNull);
1721 * If new entry fits in index tuple, copy it in. To avoid worrying
1722 * about null-value bitmask, pass it off to the general
1723 * index_formtuple routine if either the previous or new value is
1726 if (!IsNull && DatumGetPointer(entry.key) != NULL &&
1727 (Size) entry.bytes <= ATTSIZE(datum, r, 1, IsNull))
1729 memcpy(DatumGetPointer(datum),
1730 DatumGetPointer(entry.key),
1732 /* clear out old size */
1733 t->t_info &= ~INDEX_SIZE_MASK;
1734 /* or in new size */
1735 t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData));
1741 /* generate a new index tuple for the compressed entry */
1742 TupleDesc tupDesc = r->rd_att;
1746 isnull = DatumGetPointer(entry.key) != NULL ? ' ' : 'n';
1747 newtup = (IndexTuple) index_formtuple(tupDesc,
1750 newtup->t_tid = t->t_tid;
1757 ** initialize a GiST entry with a decompressed version of key
1760 gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
1761 Datum k, Relation r, Page pg, OffsetNumber o,
1762 int b, bool l, bool isNull)
1768 gistentryinit(*e, k, r, pg, o, b, l);
1770 DatumGetPointer(FunctionCall1(&giststate->decompressFn[nkey],
1771 PointerGetDatum(e)));
1772 /* decompressFn may just return the given pointer */
1775 gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
1776 dep->bytes, dep->leafkey);
1781 gistentryinit(*e, (Datum) 0, r, pg, o, 0, l);
1786 ** initialize a GiST entry with a compressed version of key
1789 gistcentryinit(GISTSTATE *giststate, int nkey,
1790 GISTENTRY *e, Datum k, Relation r,
1791 Page pg, OffsetNumber o, int b, bool l, bool isNull)
1797 gistentryinit(*e, k, r, pg, o, b, l);
1799 DatumGetPointer(FunctionCall1(&giststate->compressFn[nkey],
1800 PointerGetDatum(e)));
1801 /* compressFn may just return the given pointer */
1804 gistentryinit(*e, cep->key, cep->rel, cep->page, cep->offset,
1805 cep->bytes, cep->leafkey);
1810 gistentryinit(*e, (Datum) 0, r, pg, o, 0, l);
1814 gistFormTuple(GISTSTATE *giststate, Relation r,
1815 Datum attdata[], int datumsize[], bool isnull[])
1818 char isnullchar[INDEX_MAX_KEYS];
1819 bool whatfree[INDEX_MAX_KEYS];
1820 GISTENTRY centry[INDEX_MAX_KEYS];
1821 Datum compatt[INDEX_MAX_KEYS];
1824 for (j = 0; j < r->rd_att->natts; j++)
1828 isnullchar[j] = 'n';
1829 compatt[j] = (Datum) 0;
1830 whatfree[j] = FALSE;
1834 gistcentryinit(giststate, j, ¢ry[j], attdata[j],
1835 (Relation) NULL, (Page) NULL, (OffsetNumber) NULL,
1836 datumsize[j], FALSE, FALSE);
1837 isnullchar[j] = ' ';
1838 compatt[j] = centry[j].key;
1839 if (!isAttByVal(giststate, j))
1842 if (centry[j].key != attdata[j])
1843 pfree(DatumGetPointer(attdata[j]));
1846 whatfree[j] = FALSE;
1850 tup = (IndexTuple) index_formtuple(giststate->tupdesc, compatt, isnullchar);
1851 for (j = 0; j < r->rd_att->natts; j++)
1853 pfree(DatumGetPointer(compatt[j]));
1859 gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,
1860 OffsetNumber o, GISTENTRY attdata[], bool decompvec[], bool isnull[])
1865 for (i = 0; i < r->rd_att->natts; i++)
1867 datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
1868 gistdentryinit(giststate, i, &attdata[i],
1870 ATTSIZE(datum, giststate->tupdesc, i + 1, isnull[i]), FALSE, isnull[i]);
1871 if (isAttByVal(giststate, i))
1872 decompvec[i] = FALSE;
1875 if (attdata[i].key == datum || isnull[i])
1876 decompvec[i] = FALSE;
1878 decompvec[i] = TRUE;
1884 gistFreeAtt(Relation r, GISTENTRY attdata[], bool decompvec[])
1888 for (i = 0; i < r->rd_att->natts; i++)
1890 pfree(DatumGetPointer(attdata[i].key));
1894 gistpenalty(GISTSTATE *giststate, int attno,
1895 GISTENTRY *key1, bool isNull1,
1896 GISTENTRY *key2, bool isNull2, float *penalty)
1898 if (giststate->penaltyFn[attno].fn_strict && (isNull1 || isNull2))
1901 FunctionCall3(&giststate->penaltyFn[attno],
1902 PointerGetDatum(key1),
1903 PointerGetDatum(key2),
1904 PointerGetDatum(penalty));
1909 gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
1913 GISTPageOpaque opaque;
1921 pred = (char *) palloc(sizeof(char) * level + 1);
1922 MemSet(pred, '\t', level);
1925 buffer = ReadBuffer(r, blk);
1926 page = (Page) BufferGetPage(buffer);
1927 opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
1929 maxoff = PageGetMaxOffsetNumber(page);
1931 elog(NOTICE, "%sPage: %d %s blk: %d maxoff: %d free: %d", pred,
1932 coff, (opaque->flags & F_LEAF) ? "LEAF" : "INTE", (int) blk,
1933 (int) maxoff, PageGetFreeSpace(page));
1935 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1937 iid = PageGetItemId(page, i);
1938 which = (IndexTuple) PageGetItem(page, iid);
1939 cblk = ItemPointerGetBlockNumber(&(which->t_tid));
1941 elog(NOTICE, "%s Tuple. blk: %d size: %d", pred, (int) cblk,
1942 IndexTupleSize(which));
1945 if (!(opaque->flags & F_LEAF))
1946 gist_dumptree(r, level + 1, cblk, i);
1948 ReleaseBuffer(buffer);
1951 #endif /* defined GISTDEBUG */
1954 gist_redo(XLogRecPtr lsn, XLogRecord *record)
1956 elog(STOP, "gist_redo: unimplemented");
1960 gist_undo(XLogRecPtr lsn, XLogRecord *record)
1962 elog(STOP, "gist_undo: unimplemented");
1966 gist_desc(char *buf, uint8 xl_info, char *rec)