~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/access/gist/gist.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * gist.c
 
4
 *        interface routines for the postgres GiST index access method.
 
5
 *
 
6
 *
 
7
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
8
 * Portions Copyright (c) 1994, Regents of the University of California
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.112 2004-12-31 21:59:10 pgsql Exp $
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
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 "commands/vacuum.h"
 
23
#include "miscadmin.h"
 
24
 
 
25
 
 
26
#undef GIST_PAGEADDITEM
 
27
 
 
28
#define ATTSIZE( datum, TupDesc, i, isnull ) \
 
29
        ( \
 
30
                ( isnull ) ? 0 : \
 
31
                        att_addlength(0, (TupDesc)->attrs[(i)-1]->attlen, (datum)) \
 
32
        )
 
33
 
 
34
/* result's status */
 
35
#define INSERTED        0x01
 
36
#define SPLITED         0x02
 
37
 
 
38
/* group flags ( in gistSplit ) */
 
39
#define LEFT_ADDED      0x01
 
40
#define RIGHT_ADDED 0x02
 
41
#define BOTH_ADDED      ( LEFT_ADDED | RIGHT_ADDED )
 
42
 
 
43
/*
 
44
 * This defines only for shorter code, used in gistgetadjusted
 
45
 * and gistadjsubkey only
 
46
 */
 
47
#define FILLITEM(evp, isnullkey, okey, okeyb, rkey, rkeyb)       do { \
 
48
                if ( isnullkey ) {                                                                                \
 
49
                                gistentryinit((evp), rkey, r, NULL,                               \
 
50
                                                (OffsetNumber) 0, rkeyb, FALSE);                  \
 
51
                } else {                                                                                                  \
 
52
                                gistentryinit((evp), okey, r, NULL,                               \
 
53
                                                (OffsetNumber) 0, okeyb, FALSE);                  \
 
54
                }                                                                                                                 \
 
55
} while(0)
 
56
 
 
57
#define FILLEV(isnull1, key1, key1b, isnull2, key2, key2b) do { \
 
58
        FILLITEM(*ev0p, isnull1, key1, key1b, key2, key2b);             \
 
59
        FILLITEM(*ev1p, isnull2, key2, key2b, key1, key1b);             \
 
60
} while(0);
 
61
 
 
62
/* Working state for gistbuild and its callback */
 
63
typedef struct
 
64
{
 
65
        GISTSTATE       giststate;
 
66
        int                     numindexattrs;
 
67
        double          indtuples;
 
68
} GISTBuildState;
 
69
 
 
70
 
 
71
/* non-export function prototypes */
 
72
static void gistbuildCallback(Relation index,
 
73
                                  HeapTuple htup,
 
74
                                  Datum *attdata,
 
75
                                  char *nulls,
 
76
                                  bool tupleIsAlive,
 
77
                                  void *state);
 
78
static void gistdoinsert(Relation r,
 
79
                         IndexTuple itup,
 
80
                         InsertIndexResult *res,
 
81
                         GISTSTATE *GISTstate);
 
82
static int gistlayerinsert(Relation r, BlockNumber blkno,
 
83
                                IndexTuple **itup,
 
84
                                int *len,
 
85
                                InsertIndexResult *res,
 
86
                                GISTSTATE *giststate);
 
87
static OffsetNumber gistwritebuffer(Relation r,
 
88
                                Page page,
 
89
                                IndexTuple *itup,
 
90
                                int len,
 
91
                                OffsetNumber off);
 
92
static int gistnospace(Page page,
 
93
                        IndexTuple *itvec, int len);
 
94
static IndexTuple *gistreadbuffer(Buffer buffer, int *len);
 
95
static IndexTuple *gistjoinvector(
 
96
                           IndexTuple *itvec, int *len,
 
97
                           IndexTuple *additvec, int addlen);
 
98
static IndexTuple gistunion(Relation r, IndexTuple *itvec,
 
99
                  int len, GISTSTATE *giststate);
 
100
 
 
101
static IndexTuple gistgetadjusted(Relation r,
 
102
                                IndexTuple oldtup,
 
103
                                IndexTuple addtup,
 
104
                                GISTSTATE *giststate);
 
105
static int gistfindgroup(GISTSTATE *giststate,
 
106
                          GISTENTRY *valvec, GIST_SPLITVEC *spl);
 
107
static void gistadjsubkey(Relation r,
 
108
                          IndexTuple *itup, int *len,
 
109
                          GIST_SPLITVEC *v,
 
110
                          GISTSTATE *giststate);
 
111
static IndexTuple gistFormTuple(GISTSTATE *giststate,
 
112
                        Relation r, Datum attdata[], int datumsize[], bool isnull[]);
 
113
static IndexTuple *gistSplit(Relation r,
 
114
                  Buffer buffer,
 
115
                  IndexTuple *itup,
 
116
                  int *len,
 
117
                  GISTSTATE *giststate,
 
118
                  InsertIndexResult *res);
 
119
static void gistnewroot(Relation r,
 
120
                        IndexTuple *itup, int len);
 
121
static void GISTInitBuffer(Buffer b, uint32 f);
 
122
static OffsetNumber gistchoose(Relation r, Page p,
 
123
                   IndexTuple it,
 
124
                   GISTSTATE *giststate);
 
125
static void gistdelete(Relation r, ItemPointer tid);
 
126
 
 
127
#ifdef GIST_PAGEADDITEM
 
128
static IndexTuple gist_tuple_replacekey(Relation r,
 
129
                                          GISTENTRY entry, IndexTuple t);
 
130
#endif
 
131
static void gistcentryinit(GISTSTATE *giststate, int nkey,
 
132
                           GISTENTRY *e, Datum k,
 
133
                           Relation r, Page pg,
 
134
                           OffsetNumber o, int b, bool l, bool isNull);
 
135
static void gistDeCompressAtt(GISTSTATE *giststate, Relation r,
 
136
                                  IndexTuple tuple, Page p, OffsetNumber o,
 
137
                                  GISTENTRY attdata[], bool decompvec[], bool isnull[]);
 
138
static void gistFreeAtt(Relation r, GISTENTRY attdata[], bool decompvec[]);
 
139
static void gistpenalty(GISTSTATE *giststate, int attno,
 
140
                        GISTENTRY *key1, bool isNull1,
 
141
                        GISTENTRY *key2, bool isNull2,
 
142
                        float *penalty);
 
143
 
 
144
#undef GISTDEBUG
 
145
 
 
146
#ifdef GISTDEBUG
 
147
static void gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff);
 
148
#endif
 
149
 
 
150
/*
 
151
 * routine to build an index.  Basically calls insert over and over
 
152
 */
 
153
Datum
 
154
gistbuild(PG_FUNCTION_ARGS)
 
155
{
 
156
        Relation        heap = (Relation) PG_GETARG_POINTER(0);
 
157
        Relation        index = (Relation) PG_GETARG_POINTER(1);
 
158
        IndexInfo  *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
 
159
        double          reltuples;
 
160
        GISTBuildState buildstate;
 
161
        Buffer          buffer;
 
162
 
 
163
        /* no locking is needed */
 
164
 
 
165
        initGISTstate(&buildstate.giststate, index);
 
166
 
 
167
        /*
 
168
         * We expect to be called exactly once for any index relation. If
 
169
         * that's not the case, big trouble's what we have.
 
170
         */
 
171
        if (RelationGetNumberOfBlocks(index) != 0)
 
172
                elog(ERROR, "index \"%s\" already contains data",
 
173
                         RelationGetRelationName(index));
 
174
 
 
175
        /* initialize the root page */
 
176
        buffer = ReadBuffer(index, P_NEW);
 
177
        GISTInitBuffer(buffer, F_LEAF);
 
178
        WriteBuffer(buffer);
 
179
 
 
180
        /* build the index */
 
181
        buildstate.numindexattrs = indexInfo->ii_NumIndexAttrs;
 
182
        buildstate.indtuples = 0;
 
183
 
 
184
        /* do the heap scan */
 
185
        reltuples = IndexBuildHeapScan(heap, index, indexInfo,
 
186
                                                                gistbuildCallback, (void *) &buildstate);
 
187
 
 
188
        /* okay, all heap tuples are indexed */
 
189
 
 
190
        /*
 
191
         * Since we just counted the tuples in the heap, we update its stats
 
192
         * in pg_class to guarantee that the planner takes advantage of the
 
193
         * index we just created.  But, only update statistics during normal
 
194
         * index definitions, not for indices on system catalogs created
 
195
         * during bootstrap processing.  We must close the relations before
 
196
         * updating statistics to guarantee that the relcache entries are
 
197
         * flushed when we increment the command counter in UpdateStats(). But
 
198
         * we do not release any locks on the relations; those will be held
 
199
         * until end of transaction.
 
200
         */
 
201
        if (IsNormalProcessingMode())
 
202
        {
 
203
                Oid                     hrelid = RelationGetRelid(heap);
 
204
                Oid                     irelid = RelationGetRelid(index);
 
205
 
 
206
                heap_close(heap, NoLock);
 
207
                index_close(index);
 
208
                UpdateStats(hrelid, reltuples);
 
209
                UpdateStats(irelid, buildstate.indtuples);
 
210
        }
 
211
 
 
212
        freeGISTstate(&buildstate.giststate);
 
213
#ifdef GISTDEBUG
 
214
        gist_dumptree(index, 0, GISTP_ROOT, 0);
 
215
#endif
 
216
 
 
217
        PG_RETURN_VOID();
 
218
}
 
219
 
 
220
/*
 
221
 * Per-tuple callback from IndexBuildHeapScan
 
222
 */
 
223
static void
 
224
gistbuildCallback(Relation index,
 
225
                                  HeapTuple htup,
 
226
                                  Datum *attdata,
 
227
                                  char *nulls,
 
228
                                  bool tupleIsAlive,
 
229
                                  void *state)
 
230
{
 
231
        GISTBuildState *buildstate = (GISTBuildState *) state;
 
232
        IndexTuple      itup;
 
233
        bool            compvec[INDEX_MAX_KEYS];
 
234
        GISTENTRY       tmpcentry;
 
235
        int                     i;
 
236
 
 
237
        /* GiST cannot index tuples with leading NULLs */
 
238
        if (nulls[0] == 'n')
 
239
                return;
 
240
 
 
241
        /* immediately compress keys to normalize */
 
242
        for (i = 0; i < buildstate->numindexattrs; i++)
 
243
        {
 
244
                if (nulls[i] == 'n')
 
245
                {
 
246
                        attdata[i] = (Datum) 0;
 
247
                        compvec[i] = FALSE;
 
248
                }
 
249
                else
 
250
                {
 
251
                        gistcentryinit(&buildstate->giststate, i, &tmpcentry, attdata[i],
 
252
                                                   NULL, NULL, (OffsetNumber) 0,
 
253
                                                 -1 /* size is currently bogus */ , TRUE, FALSE);
 
254
                        if (attdata[i] != tmpcentry.key &&
 
255
                                !(isAttByVal(&buildstate->giststate, i)))
 
256
                                compvec[i] = TRUE;
 
257
                        else
 
258
                                compvec[i] = FALSE;
 
259
                        attdata[i] = tmpcentry.key;
 
260
                }
 
261
        }
 
262
 
 
263
        /* form an index tuple and point it at the heap tuple */
 
264
        itup = index_formtuple(buildstate->giststate.tupdesc, attdata, nulls);
 
265
        itup->t_tid = htup->t_self;
 
266
 
 
267
        /*
 
268
         * Since we already have the index relation locked, we call
 
269
         * gistdoinsert directly.  Normal access method calls dispatch through
 
270
         * gistinsert, which locks the relation for write.      This is the right
 
271
         * thing to do if you're inserting single tups, but not when you're
 
272
         * initializing the whole index at once.
 
273
         */
 
274
        gistdoinsert(index, itup, NULL, &buildstate->giststate);
 
275
 
 
276
        buildstate->indtuples += 1;
 
277
 
 
278
        for (i = 0; i < buildstate->numindexattrs; i++)
 
279
                if (compvec[i])
 
280
                        pfree(DatumGetPointer(attdata[i]));
 
281
 
 
282
        pfree(itup);
 
283
}
 
284
 
 
285
/*
 
286
 *      gistinsert -- wrapper for GiST tuple insertion.
 
287
 *
 
288
 *        This is the public interface routine for tuple insertion in GiSTs.
 
289
 *        It doesn't do any work; just locks the relation and passes the buck.
 
290
 */
 
291
Datum
 
292
gistinsert(PG_FUNCTION_ARGS)
 
293
{
 
294
        Relation        r = (Relation) PG_GETARG_POINTER(0);
 
295
        Datum      *datum = (Datum *) PG_GETARG_POINTER(1);
 
296
        char       *nulls = (char *) PG_GETARG_POINTER(2);
 
297
        ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
 
298
 
 
299
#ifdef NOT_USED
 
300
        Relation        heapRel = (Relation) PG_GETARG_POINTER(4);
 
301
        bool            checkUnique = PG_GETARG_BOOL(5);
 
302
#endif
 
303
        InsertIndexResult res;
 
304
        IndexTuple      itup;
 
305
        GISTSTATE       giststate;
 
306
        GISTENTRY       tmpentry;
 
307
        int                     i;
 
308
        bool            compvec[INDEX_MAX_KEYS];
 
309
 
 
310
        /*
 
311
         * Since GIST is not marked "amconcurrent" in pg_am, caller should
 
312
         * have acquired exclusive lock on index relation.      We need no locking
 
313
         * here.
 
314
         */
 
315
 
 
316
        /* GiST cannot index tuples with leading NULLs */
 
317
        if (nulls[0] == 'n')
 
318
        {
 
319
                res = NULL;
 
320
                PG_RETURN_POINTER(res);
 
321
        }
 
322
 
 
323
        initGISTstate(&giststate, r);
 
324
 
 
325
        /* immediately compress keys to normalize */
 
326
        for (i = 0; i < r->rd_att->natts; i++)
 
327
        {
 
328
                if (nulls[i] == 'n')
 
329
                {
 
330
                        datum[i] = (Datum) 0;
 
331
                        compvec[i] = FALSE;
 
332
                }
 
333
                else
 
334
                {
 
335
                        gistcentryinit(&giststate, i, &tmpentry, datum[i],
 
336
                                                   NULL, NULL, (OffsetNumber) 0,
 
337
                                                 -1 /* size is currently bogus */ , TRUE, FALSE);
 
338
                        if (datum[i] != tmpentry.key && !(isAttByVal(&giststate, i)))
 
339
                                compvec[i] = TRUE;
 
340
                        else
 
341
                                compvec[i] = FALSE;
 
342
                        datum[i] = tmpentry.key;
 
343
                }
 
344
        }
 
345
        itup = index_formtuple(giststate.tupdesc, datum, nulls);
 
346
        itup->t_tid = *ht_ctid;
 
347
 
 
348
        res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
 
349
        gistdoinsert(r, itup, &res, &giststate);
 
350
 
 
351
        for (i = 0; i < r->rd_att->natts; i++)
 
352
                if (compvec[i] == TRUE)
 
353
                        pfree(DatumGetPointer(datum[i]));
 
354
        pfree(itup);
 
355
        freeGISTstate(&giststate);
 
356
 
 
357
        PG_RETURN_POINTER(res);
 
358
}
 
359
 
 
360
#ifdef GIST_PAGEADDITEM
 
361
/*
 
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.)
 
366
 */
 
367
static OffsetNumber
 
368
gistPageAddItem(GISTSTATE *giststate,
 
369
                                Relation r,
 
370
                                Page page,
 
371
                                Item item,
 
372
                                Size size,
 
373
                                OffsetNumber offsetNumber,
 
374
                                ItemIdFlags flags,
 
375
                                GISTENTRY *dentry,
 
376
                                IndexTuple *newtup)
 
377
{
 
378
        GISTENTRY       tmpcentry;
 
379
        IndexTuple      itup = (IndexTuple) item;
 
380
        OffsetNumber retval;
 
381
        Datum           datum;
 
382
        bool            IsNull;
 
383
 
 
384
        /*
 
385
         * recompress the item given that we now know the exact page and
 
386
         * offset for insertion
 
387
         */
 
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),
 
393
                                   FALSE, 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, "failed to add index item to \"%s\"",
 
401
                         RelationGetRelationName(r));
 
402
        /* be tidy */
 
403
        if (DatumGetPointer(tmpcentry.key) != NULL &&
 
404
                tmpcentry.key != dentry->key &&
 
405
                tmpcentry.key != datum)
 
406
                pfree(DatumGetPointer(tmpcentry.key));
 
407
        return (retval);
 
408
}
 
409
#endif
 
410
 
 
411
static void
 
412
gistdoinsert(Relation r,
 
413
                         IndexTuple itup,
 
414
                         InsertIndexResult *res,
 
415
                         GISTSTATE *giststate)
 
416
{
 
417
        IndexTuple *instup;
 
418
        int                     i,
 
419
                                ret,
 
420
                                len = 1;
 
421
 
 
422
        instup = (IndexTuple *) palloc(sizeof(IndexTuple));
 
423
        instup[0] = (IndexTuple) palloc(IndexTupleSize(itup));
 
424
        memcpy(instup[0], itup, IndexTupleSize(itup));
 
425
 
 
426
        ret = gistlayerinsert(r, GISTP_ROOT, &instup, &len, res, giststate);
 
427
        if (ret & SPLITED)
 
428
                gistnewroot(r, instup, len);
 
429
 
 
430
        for (i = 0; i < len; i++)
 
431
                pfree(instup[i]);
 
432
        pfree(instup);
 
433
}
 
434
 
 
435
static int
 
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)
 
441
{
 
442
        Buffer          buffer;
 
443
        Page            page;
 
444
        OffsetNumber child;
 
445
        int                     ret;
 
446
        GISTPageOpaque opaque;
 
447
 
 
448
        buffer = ReadBuffer(r, blkno);
 
449
        page = (Page) BufferGetPage(buffer);
 
450
        opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
 
451
 
 
452
        if (!(opaque->flags & F_LEAF))
 
453
        {
 
454
                /* internal page, so we must walk on tree */
 
455
                /* len IS equal 1 */
 
456
                ItemId          iid;
 
457
                BlockNumber nblkno;
 
458
                ItemPointerData oldtid;
 
459
                IndexTuple      oldtup;
 
460
 
 
461
                child = gistchoose(r, page, *(*itup), giststate);
 
462
                iid = PageGetItemId(page, child);
 
463
                oldtup = (IndexTuple) PageGetItem(page, iid);
 
464
                nblkno = ItemPointerGetBlockNumber(&(oldtup->t_tid));
 
465
 
 
466
                /*
 
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 adjustment of current key
 
470
                 */
 
471
                ret = gistlayerinsert(r, nblkno, itup, len, res, giststate);
 
472
 
 
473
                /* nothing inserted in child */
 
474
                if (!(ret & INSERTED))
 
475
                {
 
476
                        ReleaseBuffer(buffer);
 
477
                        return 0x00;
 
478
                }
 
479
 
 
480
                /* child does not splited */
 
481
                if (!(ret & SPLITED))
 
482
                {
 
483
                        IndexTuple      newtup = gistgetadjusted(r, oldtup, (*itup)[0], giststate);
 
484
 
 
485
                        if (!newtup)
 
486
                        {
 
487
                                /* not need to update key */
 
488
                                ReleaseBuffer(buffer);
 
489
                                return 0x00;
 
490
                        }
 
491
 
 
492
                        pfree((*itup)[0]);      /* !!! */
 
493
                        (*itup)[0] = newtup;
 
494
                }
 
495
 
 
496
                /* key is modified, so old version must be deleted */
 
497
                ItemPointerSet(&oldtid, blkno, child);
 
498
                gistdelete(r, &oldtid);
 
499
 
 
500
                /*
 
501
                 * if child was splitted, new key for child will be inserted in
 
502
                 * the end list of child, so we must say to any scans that page is
 
503
                 * changed beginning from 'child' offset
 
504
                 */
 
505
                if (ret & SPLITED)
 
506
                        gistadjscans(r, GISTOP_SPLIT, blkno, child);
 
507
        }
 
508
 
 
509
        ret = INSERTED;
 
510
 
 
511
        if (gistnospace(page, (*itup), *len))
 
512
        {
 
513
                /* no space for insertion */
 
514
                IndexTuple *itvec,
 
515
                                   *newitup;
 
516
                int                     tlen,
 
517
                                        oldlen;
 
518
 
 
519
                ret |= SPLITED;
 
520
                itvec = gistreadbuffer(buffer, &tlen);
 
521
                itvec = gistjoinvector(itvec, &tlen, (*itup), *len);
 
522
                oldlen = *len;
 
523
                newitup = gistSplit(r, buffer, itvec, &tlen, giststate,
 
524
                                                        (opaque->flags & F_LEAF) ? res : NULL);         /* res only for
 
525
                                                                                                                                                 * inserting in leaf */
 
526
                ReleaseBuffer(buffer);
 
527
                do
 
528
                        pfree((*itup)[oldlen - 1]);
 
529
                while ((--oldlen) > 0);
 
530
                pfree((*itup));
 
531
                pfree(itvec);
 
532
                *itup = newitup;
 
533
                *len = tlen;                    /* now tlen >= 2 */
 
534
        }
 
535
        else
 
536
        {
 
537
                /* enogth space */
 
538
                OffsetNumber off,
 
539
                                        l;
 
540
 
 
541
                off = (PageIsEmpty(page)) ?
 
542
                        FirstOffsetNumber
 
543
                        :
 
544
                        OffsetNumberNext(PageGetMaxOffsetNumber(page));
 
545
                l = gistwritebuffer(r, page, (*itup), *len, off);
 
546
                WriteBuffer(buffer);
 
547
 
 
548
                /*
 
549
                 * set res if insert into leaf page, in this case, len = 1 always
 
550
                 */
 
551
                if (res && (opaque->flags & F_LEAF))
 
552
                        ItemPointerSet(&((*res)->pointerData), blkno, l);
 
553
 
 
554
                if (*len > 1)
 
555
                {                                               /* previous insert ret & SPLITED != 0 */
 
556
                        int                     i;
 
557
 
 
558
                        /*
 
559
                         * child was splited, so we must form union for insertion in
 
560
                         * parent
 
561
                         */
 
562
                        IndexTuple      newtup = gistunion(r, (*itup), *len, giststate);
 
563
 
 
564
                        ItemPointerSet(&(newtup->t_tid), blkno, 1);
 
565
 
 
566
                        for (i = 0; i < *len; i++)
 
567
                                pfree((*itup)[i]);
 
568
                        (*itup)[0] = newtup;
 
569
                        *len = 1;
 
570
                }
 
571
        }
 
572
 
 
573
        return ret;
 
574
}
 
575
 
 
576
/*
 
577
 * Write itup vector to page, has no control of free space
 
578
 */
 
579
static OffsetNumber
 
580
gistwritebuffer(Relation r, Page page, IndexTuple *itup,
 
581
                                int len, OffsetNumber off)
 
582
{
 
583
        OffsetNumber l = InvalidOffsetNumber;
 
584
        int                     i;
 
585
 
 
586
#ifdef GIST_PAGEADDITEM
 
587
        GISTENTRY       tmpdentry;
 
588
        IndexTuple      newtup;
 
589
        bool            IsNull;
 
590
#endif
 
591
        for (i = 0; i < len; i++)
 
592
        {
 
593
#ifdef GIST_PAGEADDITEM
 
594
                l = gistPageAddItem(giststate, r, page,
 
595
                                                        (Item) itup[i], IndexTupleSize(itup[i]),
 
596
                                                        off, LP_USED, &tmpdentry, &newtup);
 
597
                off = OffsetNumberNext(off);
 
598
                if (DatumGetPointer(tmpdentry.key) != NULL &&
 
599
                  tmpdentry.key != index_getattr(itup[i], 1, r->rd_att, &IsNull))
 
600
                        pfree(DatumGetPointer(tmpdentry.key));
 
601
                if (itup[i] != newtup)
 
602
                        pfree(newtup);
 
603
#else
 
604
                l = PageAddItem(page, (Item) itup[i], IndexTupleSize(itup[i]),
 
605
                                                off, LP_USED);
 
606
                if (l == InvalidOffsetNumber)
 
607
                        elog(ERROR, "failed to add index item to \"%s\"",
 
608
                                 RelationGetRelationName(r));
 
609
#endif
 
610
        }
 
611
        return l;
 
612
}
 
613
 
 
614
/*
 
615
 * Check space for itup vector on page
 
616
 */
 
617
static int
 
618
gistnospace(Page page, IndexTuple *itvec, int len)
 
619
{
 
620
        unsigned int size = 0;
 
621
        int                     i;
 
622
 
 
623
        for (i = 0; i < len; i++)
 
624
                size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
 
625
 
 
626
        return (PageGetFreeSpace(page) < size);
 
627
}
 
628
 
 
629
/*
 
630
 * Read buffer into itup vector
 
631
 */
 
632
static IndexTuple *
 
633
gistreadbuffer(Buffer buffer, int *len /* out */ )
 
634
{
 
635
        OffsetNumber i,
 
636
                                maxoff;
 
637
        IndexTuple *itvec;
 
638
        Page            p = (Page) BufferGetPage(buffer);
 
639
 
 
640
        maxoff = PageGetMaxOffsetNumber(p);
 
641
        *len = maxoff;
 
642
        itvec = palloc(sizeof(IndexTuple) * maxoff);
 
643
        for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 
644
                itvec[i - 1] = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
 
645
 
 
646
        return itvec;
 
647
}
 
648
 
 
649
/*
 
650
 * join two vectors into one
 
651
 */
 
652
static IndexTuple *
 
653
gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
 
654
{
 
655
        itvec = (IndexTuple *) repalloc((void *) itvec, sizeof(IndexTuple) * ((*len) + addlen));
 
656
        memmove(&itvec[*len], additvec, sizeof(IndexTuple) * addlen);
 
657
        *len += addlen;
 
658
        return itvec;
 
659
}
 
660
 
 
661
/*
 
662
 * return union of itup vector
 
663
 */
 
664
static IndexTuple
 
665
gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
 
666
{
 
667
        Datum           attr[INDEX_MAX_KEYS];
 
668
        bool            whatfree[INDEX_MAX_KEYS];
 
669
        char            isnull[INDEX_MAX_KEYS];
 
670
        GistEntryVector *evec;
 
671
        Datum           datum;
 
672
        int                     datumsize,
 
673
                                i,
 
674
                                j;
 
675
        GISTENTRY       centry[INDEX_MAX_KEYS];
 
676
        bool       *needfree;
 
677
        IndexTuple      newtup;
 
678
        bool            IsNull;
 
679
        int                     reallen;
 
680
 
 
681
        needfree = (bool *) palloc(((len == 1) ? 2 : len) * sizeof(bool));
 
682
        evec = (GistEntryVector *) palloc(((len == 1) ? 2 : len) * sizeof(GISTENTRY) + GEVHDRSZ);
 
683
 
 
684
        for (j = 0; j < r->rd_att->natts; j++)
 
685
        {
 
686
                reallen = 0;
 
687
                for (i = 0; i < len; i++)
 
688
                {
 
689
                        datum = index_getattr(itvec[i], j + 1, giststate->tupdesc, &IsNull);
 
690
                        if (IsNull)
 
691
                                continue;
 
692
 
 
693
                        gistdentryinit(giststate, j,
 
694
                                                   &(evec->vector[reallen]),
 
695
                                                   datum,
 
696
                                                   NULL, NULL, (OffsetNumber) 0,
 
697
                                                   ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull);
 
698
                        if ((!isAttByVal(giststate, j)) &&
 
699
                                evec->vector[reallen].key != datum)
 
700
                                needfree[reallen] = TRUE;
 
701
                        else
 
702
                                needfree[reallen] = FALSE;
 
703
                        reallen++;
 
704
                }
 
705
 
 
706
                if (reallen == 0)
 
707
                {
 
708
                        attr[j] = (Datum) 0;
 
709
                        isnull[j] = 'n';
 
710
                        whatfree[j] = FALSE;
 
711
                }
 
712
                else
 
713
                {
 
714
                        if (reallen == 1)
 
715
                        {
 
716
                                evec->n = 2;
 
717
                                gistentryinit(evec->vector[1],
 
718
                                                          evec->vector[0].key, r, NULL,
 
719
                                                 (OffsetNumber) 0, evec->vector[0].bytes, FALSE);
 
720
 
 
721
                        }
 
722
                        else
 
723
                                evec->n = reallen;
 
724
                        datum = FunctionCall2(&giststate->unionFn[j],
 
725
                                                                  PointerGetDatum(evec),
 
726
                                                                  PointerGetDatum(&datumsize));
 
727
 
 
728
                        for (i = 0; i < reallen; i++)
 
729
                                if (needfree[i])
 
730
                                        pfree(DatumGetPointer(evec->vector[i].key));
 
731
 
 
732
                        gistcentryinit(giststate, j, &centry[j], datum,
 
733
                                                   NULL, NULL, (OffsetNumber) 0,
 
734
                                                   datumsize, FALSE, FALSE);
 
735
                        isnull[j] = ' ';
 
736
                        attr[j] = centry[j].key;
 
737
                        if (!isAttByVal(giststate, j))
 
738
                        {
 
739
                                whatfree[j] = TRUE;
 
740
                                if (centry[j].key != datum)
 
741
                                        pfree(DatumGetPointer(datum));
 
742
                        }
 
743
                        else
 
744
                                whatfree[j] = FALSE;
 
745
                }
 
746
        }
 
747
 
 
748
        pfree(evec);
 
749
        pfree(needfree);
 
750
 
 
751
        newtup = (IndexTuple) index_formtuple(giststate->tupdesc, attr, isnull);
 
752
        for (j = 0; j < r->rd_att->natts; j++)
 
753
                if (whatfree[j])
 
754
                        pfree(DatumGetPointer(attr[j]));
 
755
 
 
756
        return newtup;
 
757
}
 
758
 
 
759
 
 
760
/*
 
761
 * Forms union of oldtup and addtup, if union == oldtup then return NULL
 
762
 */
 
763
static IndexTuple
 
764
gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
 
765
{
 
766
        GistEntryVector *evec;
 
767
        Datum           datum;
 
768
        int                     datumsize;
 
769
        bool            result,
 
770
                                neednew = false;
 
771
        char            isnull[INDEX_MAX_KEYS],
 
772
                                whatfree[INDEX_MAX_KEYS];
 
773
        Datum           attr[INDEX_MAX_KEYS];
 
774
        GISTENTRY       centry[INDEX_MAX_KEYS],
 
775
                                oldatt[INDEX_MAX_KEYS],
 
776
                                addatt[INDEX_MAX_KEYS],
 
777
                           *ev0p,
 
778
                           *ev1p;
 
779
        bool            olddec[INDEX_MAX_KEYS],
 
780
                                adddec[INDEX_MAX_KEYS];
 
781
        bool            oldisnull[INDEX_MAX_KEYS],
 
782
                                addisnull[INDEX_MAX_KEYS];
 
783
        IndexTuple      newtup = NULL;
 
784
        int                     j;
 
785
 
 
786
        evec = palloc(2 * sizeof(GISTENTRY) + GEVHDRSZ);
 
787
        evec->n = 2;
 
788
        ev0p = &(evec->vector[0]);
 
789
        ev1p = &(evec->vector[1]);
 
790
 
 
791
        gistDeCompressAtt(giststate, r, oldtup, NULL,
 
792
                                          (OffsetNumber) 0, oldatt, olddec, oldisnull);
 
793
 
 
794
        gistDeCompressAtt(giststate, r, addtup, NULL,
 
795
                                          (OffsetNumber) 0, addatt, adddec, addisnull);
 
796
 
 
797
 
 
798
        for (j = 0; j < r->rd_att->natts; j++)
 
799
        {
 
800
                if (oldisnull[j] && addisnull[j])
 
801
                {
 
802
                        isnull[j] = 'n';
 
803
                        attr[j] = (Datum) 0;
 
804
                        whatfree[j] = FALSE;
 
805
                }
 
806
                else
 
807
                {
 
808
                        FILLEV(
 
809
                                   oldisnull[j], oldatt[j].key, oldatt[j].bytes,
 
810
                                   addisnull[j], addatt[j].key, addatt[j].bytes
 
811
                                );
 
812
 
 
813
                        datum = FunctionCall2(&giststate->unionFn[j],
 
814
                                                                  PointerGetDatum(evec),
 
815
                                                                  PointerGetDatum(&datumsize));
 
816
 
 
817
                        if (oldisnull[j] || addisnull[j])
 
818
                        {
 
819
                                if (oldisnull[j])
 
820
                                        neednew = true;
 
821
                        }
 
822
                        else
 
823
                        {
 
824
                                FunctionCall3(&giststate->equalFn[j],
 
825
                                                          ev0p->key,
 
826
                                                          datum,
 
827
                                                          PointerGetDatum(&result));
 
828
 
 
829
                                if (!result)
 
830
                                        neednew = true;
 
831
                        }
 
832
 
 
833
                        if (olddec[j])
 
834
                                pfree(DatumGetPointer(oldatt[j].key));
 
835
                        if (adddec[j])
 
836
                                pfree(DatumGetPointer(addatt[j].key));
 
837
 
 
838
                        gistcentryinit(giststate, j, &centry[j], datum,
 
839
                                                   NULL, NULL, (OffsetNumber) 0,
 
840
                                                   datumsize, FALSE, FALSE);
 
841
 
 
842
                        isnull[j] = ' ';
 
843
                        attr[j] = centry[j].key;
 
844
                        if ((!isAttByVal(giststate, j)))
 
845
                        {
 
846
                                whatfree[j] = TRUE;
 
847
                                if (centry[j].key != datum)
 
848
                                        pfree(DatumGetPointer(datum));
 
849
                        }
 
850
                        else
 
851
                                whatfree[j] = FALSE;
 
852
                }
 
853
        }
 
854
        pfree(evec);
 
855
 
 
856
        if (neednew)
 
857
        {
 
858
                /* need to update key */
 
859
                newtup = (IndexTuple) index_formtuple(giststate->tupdesc, attr, isnull);
 
860
                newtup->t_tid = oldtup->t_tid;
 
861
        }
 
862
 
 
863
        for (j = 0; j < r->rd_att->natts; j++)
 
864
                if (whatfree[j])
 
865
                        pfree(DatumGetPointer(attr[j]));
 
866
 
 
867
        return newtup;
 
868
}
 
869
 
 
870
static void
 
871
gistunionsubkey(Relation r, GISTSTATE *giststate, IndexTuple *itvec, GIST_SPLITVEC *spl)
 
872
{
 
873
        int                     i,
 
874
                                j,
 
875
                                lr;
 
876
        Datum      *attr;
 
877
        bool       *needfree,
 
878
                                IsNull;
 
879
        int                     len,
 
880
                           *attrsize;
 
881
        OffsetNumber *entries;
 
882
        GistEntryVector *evec;
 
883
        Datum           datum;
 
884
        int                     datumsize;
 
885
        int                     reallen;
 
886
        bool       *isnull;
 
887
 
 
888
        for (lr = 0; lr <= 1; lr++)
 
889
        {
 
890
                if (lr)
 
891
                {
 
892
                        attrsize = spl->spl_lattrsize;
 
893
                        attr = spl->spl_lattr;
 
894
                        len = spl->spl_nleft;
 
895
                        entries = spl->spl_left;
 
896
                        isnull = spl->spl_lisnull;
 
897
                }
 
898
                else
 
899
                {
 
900
                        attrsize = spl->spl_rattrsize;
 
901
                        attr = spl->spl_rattr;
 
902
                        len = spl->spl_nright;
 
903
                        entries = spl->spl_right;
 
904
                        isnull = spl->spl_risnull;
 
905
                }
 
906
 
 
907
                needfree = (bool *) palloc(((len == 1) ? 2 : len) * sizeof(bool));
 
908
                evec = palloc(((len == 1) ? 2 : len) * sizeof(GISTENTRY) + GEVHDRSZ);
 
909
 
 
910
                for (j = 1; j < r->rd_att->natts; j++)
 
911
                {
 
912
                        reallen = 0;
 
913
                        for (i = 0; i < len; i++)
 
914
                        {
 
915
                                if (spl->spl_idgrp[entries[i]])
 
916
                                        continue;
 
917
                                datum = index_getattr(itvec[entries[i] - 1], j + 1,
 
918
                                                                          giststate->tupdesc, &IsNull);
 
919
                                if (IsNull)
 
920
                                        continue;
 
921
                                gistdentryinit(giststate, j,
 
922
                                                           &(evec->vector[reallen]),
 
923
                                                           datum,
 
924
                                                           NULL, NULL, (OffsetNumber) 0,
 
925
                                                           ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull);
 
926
                                if ((!isAttByVal(giststate, j)) &&
 
927
                                        evec->vector[reallen].key != datum)
 
928
                                        needfree[reallen] = TRUE;
 
929
                                else
 
930
                                        needfree[reallen] = FALSE;
 
931
                                reallen++;
 
932
 
 
933
                        }
 
934
                        if (reallen == 0)
 
935
                        {
 
936
                                datum = (Datum) 0;
 
937
                                datumsize = 0;
 
938
                                isnull[j] = true;
 
939
                        }
 
940
                        else
 
941
                        {
 
942
                                /*
 
943
                                 * evec->vector[0].bytes may be not defined, so form union
 
944
                                 * with itself
 
945
                                 */
 
946
                                if (reallen == 1)
 
947
                                {
 
948
                                        evec->n = 2;
 
949
                                        memcpy((void *) &(evec->vector[1]),
 
950
                                                   (void *) &(evec->vector[0]),
 
951
                                                   sizeof(GISTENTRY));
 
952
                                }
 
953
                                else
 
954
                                        evec->n = reallen;
 
955
                                datum = FunctionCall2(&giststate->unionFn[j],
 
956
                                                                          PointerGetDatum(evec),
 
957
                                                                          PointerGetDatum(&datumsize));
 
958
                                isnull[j] = false;
 
959
                        }
 
960
 
 
961
                        for (i = 0; i < reallen; i++)
 
962
                                if (needfree[i])
 
963
                                        pfree(DatumGetPointer(evec->vector[i].key));
 
964
 
 
965
                        attr[j] = datum;
 
966
                        attrsize[j] = datumsize;
 
967
                }
 
968
                pfree(evec);
 
969
                pfree(needfree);
 
970
        }
 
971
}
 
972
 
 
973
/*
 
974
 * find group in vector with equial value
 
975
 */
 
976
static int
 
977
gistfindgroup(GISTSTATE *giststate, GISTENTRY *valvec, GIST_SPLITVEC *spl)
 
978
{
 
979
        int                     i,
 
980
                                j,
 
981
                                len;
 
982
        int                     curid = 1;
 
983
        bool            result;
 
984
 
 
985
        /*
 
986
         * first key is always not null (see gistinsert), so we may not check
 
987
         * for nulls
 
988
         */
 
989
 
 
990
        for (i = 0; i < spl->spl_nleft; i++)
 
991
        {
 
992
                if (spl->spl_idgrp[spl->spl_left[i]])
 
993
                        continue;
 
994
                len = 0;
 
995
                /* find all equal value in right part */
 
996
                for (j = 0; j < spl->spl_nright; j++)
 
997
                {
 
998
                        if (spl->spl_idgrp[spl->spl_right[j]])
 
999
                                continue;
 
1000
                        FunctionCall3(&giststate->equalFn[0],
 
1001
                                                  valvec[spl->spl_left[i]].key,
 
1002
                                                  valvec[spl->spl_right[j]].key,
 
1003
                                                  PointerGetDatum(&result));
 
1004
                        if (result)
 
1005
                        {
 
1006
                                spl->spl_idgrp[spl->spl_right[j]] = curid;
 
1007
                                len++;
 
1008
                        }
 
1009
                }
 
1010
                /* find all other equal value in left part */
 
1011
                if (len)
 
1012
                {
 
1013
                        /* add current val to list of equial values */
 
1014
                        spl->spl_idgrp[spl->spl_left[i]] = curid;
 
1015
                        /* searching .. */
 
1016
                        for (j = i + 1; j < spl->spl_nleft; j++)
 
1017
                        {
 
1018
                                if (spl->spl_idgrp[spl->spl_left[j]])
 
1019
                                        continue;
 
1020
                                FunctionCall3(&giststate->equalFn[0],
 
1021
                                                          valvec[spl->spl_left[i]].key,
 
1022
                                                          valvec[spl->spl_left[j]].key,
 
1023
                                                          PointerGetDatum(&result));
 
1024
                                if (result)
 
1025
                                {
 
1026
                                        spl->spl_idgrp[spl->spl_left[j]] = curid;
 
1027
                                        len++;
 
1028
                                }
 
1029
                        }
 
1030
                        spl->spl_ngrp[curid] = len + 1;
 
1031
                        curid++;
 
1032
                }
 
1033
        }
 
1034
 
 
1035
        return curid;
 
1036
}
 
1037
 
 
1038
/*
 
1039
 * Insert equivalent tuples to left or right page
 
1040
 * with minimize penalty
 
1041
 */
 
1042
static void
 
1043
gistadjsubkey(Relation r,
 
1044
                          IndexTuple *itup, /* contains compressed entry */
 
1045
                          int *len,
 
1046
                          GIST_SPLITVEC *v,
 
1047
                          GISTSTATE *giststate
 
1048
)
 
1049
{
 
1050
        int                     curlen;
 
1051
        OffsetNumber *curwpos;
 
1052
        bool            decfree[INDEX_MAX_KEYS];
 
1053
        GISTENTRY       entry,
 
1054
                                identry[INDEX_MAX_KEYS],
 
1055
                           *ev0p,
 
1056
                           *ev1p;
 
1057
        float           lpenalty,
 
1058
                                rpenalty;
 
1059
        GistEntryVector *evec;
 
1060
        int                     datumsize;
 
1061
        bool            isnull[INDEX_MAX_KEYS];
 
1062
        int                     i,
 
1063
                                j;
 
1064
        Datum           datum;
 
1065
 
 
1066
        /* clear vectors */
 
1067
        curlen = v->spl_nleft;
 
1068
        curwpos = v->spl_left;
 
1069
        for (i = 0; i < v->spl_nleft; i++)
 
1070
                if (v->spl_idgrp[v->spl_left[i]] == 0)
 
1071
                {
 
1072
                        *curwpos = v->spl_left[i];
 
1073
                        curwpos++;
 
1074
                }
 
1075
                else
 
1076
                        curlen--;
 
1077
        v->spl_nleft = curlen;
 
1078
 
 
1079
        curlen = v->spl_nright;
 
1080
        curwpos = v->spl_right;
 
1081
        for (i = 0; i < v->spl_nright; i++)
 
1082
                if (v->spl_idgrp[v->spl_right[i]] == 0)
 
1083
                {
 
1084
                        *curwpos = v->spl_right[i];
 
1085
                        curwpos++;
 
1086
                }
 
1087
                else
 
1088
                        curlen--;
 
1089
        v->spl_nright = curlen;
 
1090
 
 
1091
        evec = palloc(2 * sizeof(GISTENTRY) + GEVHDRSZ);
 
1092
        evec->n = 2;
 
1093
        ev0p = &(evec->vector[0]);
 
1094
        ev1p = &(evec->vector[1]);
 
1095
 
 
1096
        /* add equivalent tuple */
 
1097
        for (i = 0; i < *len; i++)
 
1098
        {
 
1099
                if (v->spl_idgrp[i + 1] == 0)   /* already inserted */
 
1100
                        continue;
 
1101
                gistDeCompressAtt(giststate, r, itup[i], NULL, (OffsetNumber) 0,
 
1102
                                                  identry, decfree, isnull);
 
1103
 
 
1104
                v->spl_ngrp[v->spl_idgrp[i + 1]]--;
 
1105
                if (v->spl_ngrp[v->spl_idgrp[i + 1]] == 0 &&
 
1106
                (v->spl_grpflag[v->spl_idgrp[i + 1]] & BOTH_ADDED) != BOTH_ADDED)
 
1107
                {
 
1108
 
 
1109
                        /* force last in group */
 
1110
                        rpenalty = 1.0;
 
1111
                        lpenalty = (v->spl_grpflag[v->spl_idgrp[i + 1]] & LEFT_ADDED) ? 2.0 : 0.0;
 
1112
                }
 
1113
                else
 
1114
                {
 
1115
                        /* where? */
 
1116
                        for (j = 1; j < r->rd_att->natts; j++)
 
1117
                        {
 
1118
                                gistentryinit(entry, v->spl_lattr[j], r, NULL,
 
1119
                                                   (OffsetNumber) 0, v->spl_lattrsize[j], FALSE);
 
1120
                                gistpenalty(giststate, j, &entry, v->spl_lisnull[j],
 
1121
                                                        &identry[j], isnull[j], &lpenalty);
 
1122
 
 
1123
                                gistentryinit(entry, v->spl_rattr[j], r, NULL,
 
1124
                                                   (OffsetNumber) 0, v->spl_rattrsize[j], FALSE);
 
1125
                                gistpenalty(giststate, j, &entry, v->spl_risnull[j],
 
1126
                                                        &identry[j], isnull[j], &rpenalty);
 
1127
 
 
1128
                                if (lpenalty != rpenalty)
 
1129
                                        break;
 
1130
                        }
 
1131
                }
 
1132
                /* add */
 
1133
                if (lpenalty < rpenalty)
 
1134
                {
 
1135
                        v->spl_grpflag[v->spl_idgrp[i + 1]] |= LEFT_ADDED;
 
1136
                        v->spl_left[v->spl_nleft] = i + 1;
 
1137
                        v->spl_nleft++;
 
1138
                        for (j = 1; j < r->rd_att->natts; j++)
 
1139
                        {
 
1140
                                if (isnull[j] && v->spl_lisnull[j])
 
1141
                                {
 
1142
                                        v->spl_lattr[j] = (Datum) 0;
 
1143
                                        v->spl_lattrsize[j] = 0;
 
1144
                                }
 
1145
                                else
 
1146
                                {
 
1147
                                        FILLEV(
 
1148
                                                   v->spl_lisnull[j], v->spl_lattr[j], v->spl_lattrsize[j],
 
1149
                                                   isnull[j], identry[j].key, identry[j].bytes
 
1150
                                                );
 
1151
 
 
1152
                                        datum = FunctionCall2(&giststate->unionFn[j],
 
1153
                                                                                  PointerGetDatum(evec),
 
1154
                                                                                  PointerGetDatum(&datumsize));
 
1155
 
 
1156
                                        if ((!isAttByVal(giststate, j)) && !v->spl_lisnull[j])
 
1157
                                                pfree(DatumGetPointer(v->spl_lattr[j]));
 
1158
                                        v->spl_lattr[j] = datum;
 
1159
                                        v->spl_lattrsize[j] = datumsize;
 
1160
                                        v->spl_lisnull[j] = false;
 
1161
                                }
 
1162
                        }
 
1163
                }
 
1164
                else
 
1165
                {
 
1166
                        v->spl_grpflag[v->spl_idgrp[i + 1]] |= RIGHT_ADDED;
 
1167
                        v->spl_right[v->spl_nright] = i + 1;
 
1168
                        v->spl_nright++;
 
1169
                        for (j = 1; j < r->rd_att->natts; j++)
 
1170
                        {
 
1171
                                if (isnull[j] && v->spl_risnull[j])
 
1172
                                {
 
1173
                                        v->spl_rattr[j] = (Datum) 0;
 
1174
                                        v->spl_rattrsize[j] = 0;
 
1175
                                }
 
1176
                                else
 
1177
                                {
 
1178
                                        FILLEV(
 
1179
                                                   v->spl_risnull[j], v->spl_rattr[j], v->spl_rattrsize[j],
 
1180
                                                   isnull[j], identry[j].key, identry[j].bytes
 
1181
                                                );
 
1182
 
 
1183
                                        datum = FunctionCall2(&giststate->unionFn[j],
 
1184
                                                                                  PointerGetDatum(evec),
 
1185
                                                                                  PointerGetDatum(&datumsize));
 
1186
 
 
1187
                                        if ((!isAttByVal(giststate, j)) && !v->spl_risnull[j])
 
1188
                                                pfree(DatumGetPointer(v->spl_rattr[j]));
 
1189
 
 
1190
                                        v->spl_rattr[j] = datum;
 
1191
                                        v->spl_rattrsize[j] = datumsize;
 
1192
                                        v->spl_risnull[j] = false;
 
1193
                                }
 
1194
                        }
 
1195
 
 
1196
                }
 
1197
                gistFreeAtt(r, identry, decfree);
 
1198
        }
 
1199
        pfree(evec);
 
1200
}
 
1201
 
 
1202
/*
 
1203
 *      gistSplit -- split a page in the tree.
 
1204
 */
 
1205
static IndexTuple *
 
1206
gistSplit(Relation r,
 
1207
                  Buffer buffer,
 
1208
                  IndexTuple *itup,             /* contains compressed entry */
 
1209
                  int *len,
 
1210
                  GISTSTATE *giststate,
 
1211
                  InsertIndexResult *res)
 
1212
{
 
1213
        Page            p;
 
1214
        Buffer          leftbuf,
 
1215
                                rightbuf;
 
1216
        Page            left,
 
1217
                                right;
 
1218
        IndexTuple *lvectup,
 
1219
                           *rvectup,
 
1220
                           *newtup;
 
1221
        BlockNumber lbknum,
 
1222
                                rbknum;
 
1223
        GISTPageOpaque opaque;
 
1224
        GIST_SPLITVEC v;
 
1225
        GistEntryVector *entryvec;
 
1226
        bool       *decompvec;
 
1227
        int                     i,
 
1228
                                j,
 
1229
                                nlen;
 
1230
        int                     MaxGrpId = 1;
 
1231
        Datum           datum;
 
1232
        bool            IsNull;
 
1233
 
 
1234
        p = (Page) BufferGetPage(buffer);
 
1235
        opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
 
1236
 
 
1237
        /*
 
1238
         * The root of the tree is the first block in the relation.  If we're
 
1239
         * about to split the root, we need to do some hocus-pocus to enforce
 
1240
         * this guarantee.
 
1241
         */
 
1242
 
 
1243
        if (BufferGetBlockNumber(buffer) == GISTP_ROOT)
 
1244
        {
 
1245
                leftbuf = ReadBuffer(r, P_NEW);
 
1246
                GISTInitBuffer(leftbuf, opaque->flags);
 
1247
                lbknum = BufferGetBlockNumber(leftbuf);
 
1248
                left = (Page) BufferGetPage(leftbuf);
 
1249
        }
 
1250
        else
 
1251
        {
 
1252
                leftbuf = buffer;
 
1253
                IncrBufferRefCount(buffer);
 
1254
                lbknum = BufferGetBlockNumber(buffer);
 
1255
                left = (Page) PageGetTempPage(p, sizeof(GISTPageOpaqueData));
 
1256
        }
 
1257
 
 
1258
        rightbuf = ReadBuffer(r, P_NEW);
 
1259
        GISTInitBuffer(rightbuf, opaque->flags);
 
1260
        rbknum = BufferGetBlockNumber(rightbuf);
 
1261
        right = (Page) BufferGetPage(rightbuf);
 
1262
 
 
1263
        /* generate the item array */
 
1264
        entryvec = palloc(GEVHDRSZ + (*len + 1) * sizeof(GISTENTRY));
 
1265
        entryvec->n = *len + 1;
 
1266
        decompvec = (bool *) palloc((*len + 1) * sizeof(bool));
 
1267
        for (i = 1; i <= *len; i++)
 
1268
        {
 
1269
                datum = index_getattr(itup[i - 1], 1, giststate->tupdesc, &IsNull);
 
1270
                gistdentryinit(giststate, 0, &(entryvec->vector[i]),
 
1271
                                           datum, r, p, i,
 
1272
                   ATTSIZE(datum, giststate->tupdesc, 1, IsNull), FALSE, IsNull);
 
1273
                if ((!isAttByVal(giststate, 0)) && entryvec->vector[i].key != datum)
 
1274
                        decompvec[i] = TRUE;
 
1275
                else
 
1276
                        decompvec[i] = FALSE;
 
1277
        }
 
1278
 
 
1279
        /*
 
1280
         * now let the user-defined picksplit function set up the split
 
1281
         * vector; in entryvec have no null value!!
 
1282
         */
 
1283
        FunctionCall2(&giststate->picksplitFn[0],
 
1284
                                  PointerGetDatum(entryvec),
 
1285
                                  PointerGetDatum(&v));
 
1286
 
 
1287
        /* compatibility with old code */
 
1288
        if (v.spl_left[v.spl_nleft - 1] == InvalidOffsetNumber)
 
1289
                v.spl_left[v.spl_nleft - 1] = (OffsetNumber) *len;
 
1290
        if (v.spl_right[v.spl_nright - 1] == InvalidOffsetNumber)
 
1291
                v.spl_right[v.spl_nright - 1] = (OffsetNumber) *len;
 
1292
 
 
1293
        v.spl_lattr[0] = v.spl_ldatum;
 
1294
        v.spl_rattr[0] = v.spl_rdatum;
 
1295
        v.spl_lisnull[0] = false;
 
1296
        v.spl_risnull[0] = false;
 
1297
 
 
1298
        /*
 
1299
         * if index is multikey, then we must to try get smaller bounding box
 
1300
         * for subkey(s)
 
1301
         */
 
1302
        if (r->rd_att->natts > 1)
 
1303
        {
 
1304
                v.spl_idgrp = (int *) palloc0(sizeof(int) * (*len + 1));
 
1305
                v.spl_grpflag = (char *) palloc0(sizeof(char) * (*len + 1));
 
1306
                v.spl_ngrp = (int *) palloc(sizeof(int) * (*len + 1));
 
1307
 
 
1308
                MaxGrpId = gistfindgroup(giststate, entryvec->vector, &v);
 
1309
 
 
1310
                /* form union of sub keys for each page (l,p) */
 
1311
                gistunionsubkey(r, giststate, itup, &v);
 
1312
 
 
1313
                /*
 
1314
                 * if possible, we insert equivalent tuples with control by
 
1315
                 * penalty for a subkey(s)
 
1316
                 */
 
1317
                if (MaxGrpId > 1)
 
1318
                        gistadjsubkey(r, itup, len, &v, giststate);
 
1319
 
 
1320
                pfree(v.spl_idgrp);
 
1321
                pfree(v.spl_grpflag);
 
1322
                pfree(v.spl_ngrp);
 
1323
        }
 
1324
 
 
1325
        /* clean up the entry vector: its keys need to be deleted, too */
 
1326
        for (i = 1; i <= *len; i++)
 
1327
                if (decompvec[i])
 
1328
                        pfree(DatumGetPointer(entryvec->vector[i].key));
 
1329
        pfree(entryvec);
 
1330
        pfree(decompvec);
 
1331
 
 
1332
        /* form left and right vector */
 
1333
        lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nleft);
 
1334
        rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * v.spl_nright);
 
1335
 
 
1336
        for (i = 0; i < v.spl_nleft; i++)
 
1337
                lvectup[i] = itup[v.spl_left[i] - 1];
 
1338
 
 
1339
        for (i = 0; i < v.spl_nright; i++)
 
1340
                rvectup[i] = itup[v.spl_right[i] - 1];
 
1341
 
 
1342
 
 
1343
        /* write on disk (may be need another split) */
 
1344
        if (gistnospace(right, rvectup, v.spl_nright))
 
1345
        {
 
1346
                nlen = v.spl_nright;
 
1347
                newtup = gistSplit(r, rightbuf, rvectup, &nlen, giststate,
 
1348
                          (res && rvectup[nlen - 1] == itup[*len - 1]) ? res : NULL);
 
1349
                ReleaseBuffer(rightbuf);
 
1350
                for (j = 1; j < r->rd_att->natts; j++)
 
1351
                        if ((!isAttByVal(giststate, j)) && !v.spl_risnull[j])
 
1352
                                pfree(DatumGetPointer(v.spl_rattr[j]));
 
1353
        }
 
1354
        else
 
1355
        {
 
1356
                OffsetNumber l;
 
1357
 
 
1358
                l = gistwritebuffer(r, right, rvectup, v.spl_nright, FirstOffsetNumber);
 
1359
                WriteBuffer(rightbuf);
 
1360
 
 
1361
                if (res)
 
1362
                        ItemPointerSet(&((*res)->pointerData), rbknum, l);
 
1363
 
 
1364
                nlen = 1;
 
1365
                newtup = (IndexTuple *) palloc(sizeof(IndexTuple) * 1);
 
1366
                newtup[0] = gistFormTuple(giststate, r, v.spl_rattr, v.spl_rattrsize, v.spl_risnull);
 
1367
                ItemPointerSet(&(newtup[0]->t_tid), rbknum, 1);
 
1368
        }
 
1369
 
 
1370
 
 
1371
        if (gistnospace(left, lvectup, v.spl_nleft))
 
1372
        {
 
1373
                int                     llen = v.spl_nleft;
 
1374
                IndexTuple *lntup;
 
1375
 
 
1376
                lntup = gistSplit(r, leftbuf, lvectup, &llen, giststate,
 
1377
                          (res && lvectup[llen - 1] == itup[*len - 1]) ? res : NULL);
 
1378
                ReleaseBuffer(leftbuf);
 
1379
 
 
1380
                for (j = 1; j < r->rd_att->natts; j++)
 
1381
                        if ((!isAttByVal(giststate, j)) && !v.spl_lisnull[j])
 
1382
                                pfree(DatumGetPointer(v.spl_lattr[j]));
 
1383
 
 
1384
                newtup = gistjoinvector(newtup, &nlen, lntup, llen);
 
1385
                pfree(lntup);
 
1386
        }
 
1387
        else
 
1388
        {
 
1389
                OffsetNumber l;
 
1390
 
 
1391
                l = gistwritebuffer(r, left, lvectup, v.spl_nleft, FirstOffsetNumber);
 
1392
                if (BufferGetBlockNumber(buffer) != GISTP_ROOT)
 
1393
                        PageRestoreTempPage(left, p);
 
1394
 
 
1395
                WriteBuffer(leftbuf);
 
1396
 
 
1397
                if (res)
 
1398
                        ItemPointerSet(&((*res)->pointerData), lbknum, l);
 
1399
 
 
1400
                nlen += 1;
 
1401
                newtup = (IndexTuple *) repalloc((void *) newtup, sizeof(IndexTuple) * nlen);
 
1402
                newtup[nlen - 1] = gistFormTuple(giststate, r, v.spl_lattr, v.spl_lattrsize, v.spl_lisnull);
 
1403
                ItemPointerSet(&(newtup[nlen - 1]->t_tid), lbknum, 1);
 
1404
        }
 
1405
 
 
1406
        /* !!! pfree */
 
1407
        pfree(rvectup);
 
1408
        pfree(lvectup);
 
1409
        pfree(v.spl_left);
 
1410
        pfree(v.spl_right);
 
1411
 
 
1412
        *len = nlen;
 
1413
        return newtup;
 
1414
}
 
1415
 
 
1416
static void
 
1417
gistnewroot(Relation r, IndexTuple *itup, int len)
 
1418
{
 
1419
        Buffer          b;
 
1420
        Page            p;
 
1421
 
 
1422
        b = ReadBuffer(r, GISTP_ROOT);
 
1423
        GISTInitBuffer(b, 0);
 
1424
        p = BufferGetPage(b);
 
1425
 
 
1426
        gistwritebuffer(r, p, itup, len, FirstOffsetNumber);
 
1427
        WriteBuffer(b);
 
1428
}
 
1429
 
 
1430
static void
 
1431
GISTInitBuffer(Buffer b, uint32 f)
 
1432
{
 
1433
        GISTPageOpaque opaque;
 
1434
        Page            page;
 
1435
        Size            pageSize;
 
1436
 
 
1437
        pageSize = BufferGetPageSize(b);
 
1438
 
 
1439
        page = BufferGetPage(b);
 
1440
 
 
1441
        PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
 
1442
 
 
1443
        opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
 
1444
        opaque->flags = f;
 
1445
}
 
1446
 
 
1447
 
 
1448
/*
 
1449
** find entry with lowest penalty
 
1450
*/
 
1451
static OffsetNumber
 
1452
gistchoose(Relation r, Page p, IndexTuple it,   /* it has compressed entry */
 
1453
                   GISTSTATE *giststate)
 
1454
{
 
1455
        OffsetNumber maxoff;
 
1456
        OffsetNumber i;
 
1457
        Datum           datum;
 
1458
        float           usize;
 
1459
        OffsetNumber which;
 
1460
        float           sum_grow,
 
1461
                                which_grow[INDEX_MAX_KEYS];
 
1462
        GISTENTRY       entry,
 
1463
                                identry[INDEX_MAX_KEYS];
 
1464
        bool            IsNull,
 
1465
                                decompvec[INDEX_MAX_KEYS],
 
1466
                                isnull[INDEX_MAX_KEYS];
 
1467
        int                     j;
 
1468
 
 
1469
        maxoff = PageGetMaxOffsetNumber(p);
 
1470
        *which_grow = -1.0;
 
1471
        which = -1;
 
1472
        sum_grow = 1;
 
1473
        gistDeCompressAtt(giststate, r,
 
1474
                                          it, NULL, (OffsetNumber) 0,
 
1475
                                          identry, decompvec, isnull);
 
1476
 
 
1477
        for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
 
1478
        {
 
1479
                IndexTuple      itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
 
1480
 
 
1481
                sum_grow = 0;
 
1482
                for (j = 0; j < r->rd_att->natts; j++)
 
1483
                {
 
1484
                        datum = index_getattr(itup, j + 1, giststate->tupdesc, &IsNull);
 
1485
                        gistdentryinit(giststate, j, &entry, datum, r, p, i, ATTSIZE(datum, giststate->tupdesc, j + 1, IsNull), FALSE, IsNull);
 
1486
                        gistpenalty(giststate, j, &entry, IsNull, &identry[j], isnull[j], &usize);
 
1487
 
 
1488
                        if ((!isAttByVal(giststate, j)) && entry.key != datum)
 
1489
                                pfree(DatumGetPointer(entry.key));
 
1490
 
 
1491
                        if (which_grow[j] < 0 || usize < which_grow[j])
 
1492
                        {
 
1493
                                which = i;
 
1494
                                which_grow[j] = usize;
 
1495
                                if (j < r->rd_att->natts - 1 && i == FirstOffsetNumber)
 
1496
                                        which_grow[j + 1] = -1;
 
1497
                                sum_grow += which_grow[j];
 
1498
                        }
 
1499
                        else if (which_grow[j] == usize)
 
1500
                                sum_grow += usize;
 
1501
                        else
 
1502
                        {
 
1503
                                sum_grow = 1;
 
1504
                                break;
 
1505
                        }
 
1506
                }
 
1507
        }
 
1508
 
 
1509
        gistFreeAtt(r, identry, decompvec);
 
1510
        return which;
 
1511
}
 
1512
 
 
1513
void
 
1514
gistfreestack(GISTSTACK *s)
 
1515
{
 
1516
        GISTSTACK  *p;
 
1517
 
 
1518
        while (s != NULL)
 
1519
        {
 
1520
                p = s->gs_parent;
 
1521
                pfree(s);
 
1522
                s = p;
 
1523
        }
 
1524
}
 
1525
 
 
1526
 
 
1527
/*
 
1528
 * Retail deletion of a single tuple.
 
1529
 *
 
1530
 * NB: this is no longer called externally, but is still needed by
 
1531
 * gistlayerinsert().  That dependency will have to be fixed if GIST
 
1532
 * is ever going to allow concurrent insertions.
 
1533
 */
 
1534
static void
 
1535
gistdelete(Relation r, ItemPointer tid)
 
1536
{
 
1537
        BlockNumber blkno;
 
1538
        OffsetNumber offnum;
 
1539
        Buffer          buf;
 
1540
        Page            page;
 
1541
 
 
1542
        /*
 
1543
         * Since GIST is not marked "amconcurrent" in pg_am, caller should
 
1544
         * have acquired exclusive lock on index relation.      We need no locking
 
1545
         * here.
 
1546
         */
 
1547
 
 
1548
        blkno = ItemPointerGetBlockNumber(tid);
 
1549
        offnum = ItemPointerGetOffsetNumber(tid);
 
1550
 
 
1551
        /* adjust any scans that will be affected by this deletion */
 
1552
        /* NB: this works only for scans in *this* backend! */
 
1553
        gistadjscans(r, GISTOP_DEL, blkno, offnum);
 
1554
 
 
1555
        /* delete the index tuple */
 
1556
        buf = ReadBuffer(r, blkno);
 
1557
        page = BufferGetPage(buf);
 
1558
 
 
1559
        PageIndexTupleDelete(page, offnum);
 
1560
 
 
1561
        WriteBuffer(buf);
 
1562
}
 
1563
 
 
1564
/*
 
1565
 * Bulk deletion of all index entries pointing to a set of heap tuples.
 
1566
 * The set of target tuples is specified via a callback routine that tells
 
1567
 * whether any given heap tuple (identified by ItemPointer) is being deleted.
 
1568
 *
 
1569
 * Result: a palloc'd struct containing statistical info for VACUUM displays.
 
1570
 */
 
1571
Datum
 
1572
gistbulkdelete(PG_FUNCTION_ARGS)
 
1573
{
 
1574
        Relation        rel = (Relation) PG_GETARG_POINTER(0);
 
1575
        IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
 
1576
        void       *callback_state = (void *) PG_GETARG_POINTER(2);
 
1577
        IndexBulkDeleteResult *result;
 
1578
        BlockNumber num_pages;
 
1579
        double          tuples_removed;
 
1580
        double          num_index_tuples;
 
1581
        IndexScanDesc iscan;
 
1582
 
 
1583
        tuples_removed = 0;
 
1584
        num_index_tuples = 0;
 
1585
 
 
1586
        /*
 
1587
         * Since GIST is not marked "amconcurrent" in pg_am, caller should
 
1588
         * have acquired exclusive lock on index relation.      We need no locking
 
1589
         * here.
 
1590
         */
 
1591
 
 
1592
        /*
 
1593
         * XXX generic implementation --- should be improved!
 
1594
         */
 
1595
 
 
1596
        /* walk through the entire index */
 
1597
        iscan = index_beginscan(NULL, rel, SnapshotAny, 0, NULL);
 
1598
        /* including killed tuples */
 
1599
        iscan->ignore_killed_tuples = false;
 
1600
 
 
1601
        while (index_getnext_indexitem(iscan, ForwardScanDirection))
 
1602
        {
 
1603
                vacuum_delay_point();
 
1604
 
 
1605
                if (callback(&iscan->xs_ctup.t_self, callback_state))
 
1606
                {
 
1607
                        ItemPointerData indextup = iscan->currentItemData;
 
1608
                        BlockNumber blkno;
 
1609
                        OffsetNumber offnum;
 
1610
                        Buffer          buf;
 
1611
                        Page            page;
 
1612
 
 
1613
                        blkno = ItemPointerGetBlockNumber(&indextup);
 
1614
                        offnum = ItemPointerGetOffsetNumber(&indextup);
 
1615
 
 
1616
                        /* adjust any scans that will be affected by this deletion */
 
1617
                        gistadjscans(rel, GISTOP_DEL, blkno, offnum);
 
1618
 
 
1619
                        /* delete the index tuple */
 
1620
                        buf = ReadBuffer(rel, blkno);
 
1621
                        page = BufferGetPage(buf);
 
1622
 
 
1623
                        PageIndexTupleDelete(page, offnum);
 
1624
 
 
1625
                        WriteBuffer(buf);
 
1626
 
 
1627
                        tuples_removed += 1;
 
1628
                }
 
1629
                else
 
1630
                        num_index_tuples += 1;
 
1631
        }
 
1632
 
 
1633
        index_endscan(iscan);
 
1634
 
 
1635
        /* return statistics */
 
1636
        num_pages = RelationGetNumberOfBlocks(rel);
 
1637
 
 
1638
        result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
 
1639
        result->num_pages = num_pages;
 
1640
        result->num_index_tuples = num_index_tuples;
 
1641
        result->tuples_removed = tuples_removed;
 
1642
 
 
1643
        PG_RETURN_POINTER(result);
 
1644
}
 
1645
 
 
1646
 
 
1647
void
 
1648
initGISTstate(GISTSTATE *giststate, Relation index)
 
1649
{
 
1650
        int                     i;
 
1651
 
 
1652
        if (index->rd_att->natts > INDEX_MAX_KEYS)
 
1653
                elog(ERROR, "numberOfAttributes %d > %d",
 
1654
                         index->rd_att->natts, INDEX_MAX_KEYS);
 
1655
 
 
1656
        giststate->tupdesc = index->rd_att;
 
1657
 
 
1658
        for (i = 0; i < index->rd_att->natts; i++)
 
1659
        {
 
1660
                fmgr_info_copy(&(giststate->consistentFn[i]),
 
1661
                                   index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC),
 
1662
                                           CurrentMemoryContext);
 
1663
                fmgr_info_copy(&(giststate->unionFn[i]),
 
1664
                                           index_getprocinfo(index, i + 1, GIST_UNION_PROC),
 
1665
                                           CurrentMemoryContext);
 
1666
                fmgr_info_copy(&(giststate->compressFn[i]),
 
1667
                                         index_getprocinfo(index, i + 1, GIST_COMPRESS_PROC),
 
1668
                                           CurrentMemoryContext);
 
1669
                fmgr_info_copy(&(giststate->decompressFn[i]),
 
1670
                                   index_getprocinfo(index, i + 1, GIST_DECOMPRESS_PROC),
 
1671
                                           CurrentMemoryContext);
 
1672
                fmgr_info_copy(&(giststate->penaltyFn[i]),
 
1673
                                           index_getprocinfo(index, i + 1, GIST_PENALTY_PROC),
 
1674
                                           CurrentMemoryContext);
 
1675
                fmgr_info_copy(&(giststate->picksplitFn[i]),
 
1676
                                        index_getprocinfo(index, i + 1, GIST_PICKSPLIT_PROC),
 
1677
                                           CurrentMemoryContext);
 
1678
                fmgr_info_copy(&(giststate->equalFn[i]),
 
1679
                                           index_getprocinfo(index, i + 1, GIST_EQUAL_PROC),
 
1680
                                           CurrentMemoryContext);
 
1681
        }
 
1682
}
 
1683
 
 
1684
void
 
1685
freeGISTstate(GISTSTATE *giststate)
 
1686
{
 
1687
        /* no work */
 
1688
}
 
1689
 
 
1690
#ifdef GIST_PAGEADDITEM
 
1691
/*
 
1692
** Given an IndexTuple to be inserted on a page, this routine replaces
 
1693
** the key with another key, which may involve generating a new IndexTuple
 
1694
** if the sizes don't match or if the null status changes.
 
1695
**
 
1696
** XXX this only works for a single-column index tuple!
 
1697
*/
 
1698
static IndexTuple
 
1699
gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
 
1700
{
 
1701
        bool            IsNull;
 
1702
        Datum           datum = index_getattr(t, 1, r->rd_att, &IsNull);
 
1703
 
 
1704
        /*
 
1705
         * If new entry fits in index tuple, copy it in.  To avoid worrying
 
1706
         * about null-value bitmask, pass it off to the general
 
1707
         * index_formtuple routine if either the previous or new value is
 
1708
         * NULL.
 
1709
         */
 
1710
        if (!IsNull && DatumGetPointer(entry.key) != NULL &&
 
1711
                (Size) entry.bytes <= ATTSIZE(datum, r, 1, IsNull))
 
1712
        {
 
1713
                memcpy(DatumGetPointer(datum),
 
1714
                           DatumGetPointer(entry.key),
 
1715
                           entry.bytes);
 
1716
                /* clear out old size */
 
1717
                t->t_info &= ~INDEX_SIZE_MASK;
 
1718
                /* or in new size */
 
1719
                t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData));
 
1720
 
 
1721
                return t;
 
1722
        }
 
1723
        else
 
1724
        {
 
1725
                /* generate a new index tuple for the compressed entry */
 
1726
                TupleDesc       tupDesc = r->rd_att;
 
1727
                IndexTuple      newtup;
 
1728
                char            isnull;
 
1729
 
 
1730
                isnull = DatumGetPointer(entry.key) != NULL ? ' ' : 'n';
 
1731
                newtup = (IndexTuple) index_formtuple(tupDesc,
 
1732
                                                                                          &(entry.key),
 
1733
                                                                                          &isnull);
 
1734
                newtup->t_tid = t->t_tid;
 
1735
                return newtup;
 
1736
        }
 
1737
}
 
1738
#endif
 
1739
 
 
1740
/*
 
1741
** initialize a GiST entry with a decompressed version of key
 
1742
*/
 
1743
void
 
1744
gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
 
1745
                           Datum k, Relation r, Page pg, OffsetNumber o,
 
1746
                           int b, bool l, bool isNull)
 
1747
{
 
1748
        if (b && !isNull)
 
1749
        {
 
1750
                GISTENTRY  *dep;
 
1751
 
 
1752
                gistentryinit(*e, k, r, pg, o, b, l);
 
1753
                dep = (GISTENTRY *)
 
1754
                        DatumGetPointer(FunctionCall1(&giststate->decompressFn[nkey],
 
1755
                                                                                  PointerGetDatum(e)));
 
1756
                /* decompressFn may just return the given pointer */
 
1757
                if (dep != e)
 
1758
                {
 
1759
                        gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
 
1760
                                                  dep->bytes, dep->leafkey);
 
1761
                        pfree(dep);
 
1762
                }
 
1763
        }
 
1764
        else
 
1765
                gistentryinit(*e, (Datum) 0, r, pg, o, 0, l);
 
1766
}
 
1767
 
 
1768
 
 
1769
/*
 
1770
** initialize a GiST entry with a compressed version of key
 
1771
*/
 
1772
static void
 
1773
gistcentryinit(GISTSTATE *giststate, int nkey,
 
1774
                           GISTENTRY *e, Datum k, Relation r,
 
1775
                           Page pg, OffsetNumber o, int b, bool l, bool isNull)
 
1776
{
 
1777
        if (!isNull)
 
1778
        {
 
1779
                GISTENTRY  *cep;
 
1780
 
 
1781
                gistentryinit(*e, k, r, pg, o, b, l);
 
1782
                cep = (GISTENTRY *)
 
1783
                        DatumGetPointer(FunctionCall1(&giststate->compressFn[nkey],
 
1784
                                                                                  PointerGetDatum(e)));
 
1785
                /* compressFn may just return the given pointer */
 
1786
                if (cep != e)
 
1787
                {
 
1788
                        gistentryinit(*e, cep->key, cep->rel, cep->page, cep->offset,
 
1789
                                                  cep->bytes, cep->leafkey);
 
1790
                        pfree(cep);
 
1791
                }
 
1792
        }
 
1793
        else
 
1794
                gistentryinit(*e, (Datum) 0, r, pg, o, 0, l);
 
1795
}
 
1796
 
 
1797
static IndexTuple
 
1798
gistFormTuple(GISTSTATE *giststate, Relation r,
 
1799
                          Datum attdata[], int datumsize[], bool isnull[])
 
1800
{
 
1801
        IndexTuple      tup;
 
1802
        char            isnullchar[INDEX_MAX_KEYS];
 
1803
        bool            whatfree[INDEX_MAX_KEYS];
 
1804
        GISTENTRY       centry[INDEX_MAX_KEYS];
 
1805
        Datum           compatt[INDEX_MAX_KEYS];
 
1806
        int                     j;
 
1807
 
 
1808
        for (j = 0; j < r->rd_att->natts; j++)
 
1809
        {
 
1810
                if (isnull[j])
 
1811
                {
 
1812
                        isnullchar[j] = 'n';
 
1813
                        compatt[j] = (Datum) 0;
 
1814
                        whatfree[j] = FALSE;
 
1815
                }
 
1816
                else
 
1817
                {
 
1818
                        gistcentryinit(giststate, j, &centry[j], attdata[j],
 
1819
                                                   NULL, NULL, (OffsetNumber) 0,
 
1820
                                                   datumsize[j], FALSE, FALSE);
 
1821
                        isnullchar[j] = ' ';
 
1822
                        compatt[j] = centry[j].key;
 
1823
                        if (!isAttByVal(giststate, j))
 
1824
                        {
 
1825
                                whatfree[j] = TRUE;
 
1826
                                if (centry[j].key != attdata[j])
 
1827
                                        pfree(DatumGetPointer(attdata[j]));
 
1828
                        }
 
1829
                        else
 
1830
                                whatfree[j] = FALSE;
 
1831
                }
 
1832
        }
 
1833
 
 
1834
        tup = (IndexTuple) index_formtuple(giststate->tupdesc, compatt, isnullchar);
 
1835
        for (j = 0; j < r->rd_att->natts; j++)
 
1836
                if (whatfree[j])
 
1837
                        pfree(DatumGetPointer(compatt[j]));
 
1838
 
 
1839
        return tup;
 
1840
}
 
1841
 
 
1842
static void
 
1843
gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,
 
1844
        OffsetNumber o, GISTENTRY attdata[], bool decompvec[], bool isnull[])
 
1845
{
 
1846
        int                     i;
 
1847
        Datum           datum;
 
1848
 
 
1849
        for (i = 0; i < r->rd_att->natts; i++)
 
1850
        {
 
1851
                datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
 
1852
                gistdentryinit(giststate, i, &attdata[i],
 
1853
                                           datum, r, p, o,
 
1854
                                           ATTSIZE(datum, giststate->tupdesc, i + 1, isnull[i]), FALSE, isnull[i]);
 
1855
                if (isAttByVal(giststate, i))
 
1856
                        decompvec[i] = FALSE;
 
1857
                else
 
1858
                {
 
1859
                        if (attdata[i].key == datum || isnull[i])
 
1860
                                decompvec[i] = FALSE;
 
1861
                        else
 
1862
                                decompvec[i] = TRUE;
 
1863
                }
 
1864
        }
 
1865
}
 
1866
 
 
1867
static void
 
1868
gistFreeAtt(Relation r, GISTENTRY attdata[], bool decompvec[])
 
1869
{
 
1870
        int                     i;
 
1871
 
 
1872
        for (i = 0; i < r->rd_att->natts; i++)
 
1873
                if (decompvec[i])
 
1874
                        pfree(DatumGetPointer(attdata[i].key));
 
1875
}
 
1876
 
 
1877
static void
 
1878
gistpenalty(GISTSTATE *giststate, int attno,
 
1879
                        GISTENTRY *key1, bool isNull1,
 
1880
                        GISTENTRY *key2, bool isNull2, float *penalty)
 
1881
{
 
1882
        if (giststate->penaltyFn[attno].fn_strict && (isNull1 || isNull2))
 
1883
                *penalty = 0.0;
 
1884
        else
 
1885
                FunctionCall3(&giststate->penaltyFn[attno],
 
1886
                                          PointerGetDatum(key1),
 
1887
                                          PointerGetDatum(key2),
 
1888
                                          PointerGetDatum(penalty));
 
1889
}
 
1890
 
 
1891
#ifdef GISTDEBUG
 
1892
static void
 
1893
gist_dumptree(Relation r, int level, BlockNumber blk, OffsetNumber coff)
 
1894
{
 
1895
        Buffer          buffer;
 
1896
        Page            page;
 
1897
        GISTPageOpaque opaque;
 
1898
        IndexTuple      which;
 
1899
        ItemId          iid;
 
1900
        OffsetNumber i,
 
1901
                                maxoff;
 
1902
        BlockNumber cblk;
 
1903
        char       *pred;
 
1904
 
 
1905
        pred = (char *) palloc(sizeof(char) * level + 1);
 
1906
        MemSet(pred, '\t', level);
 
1907
        pred[level] = '\0';
 
1908
 
 
1909
        buffer = ReadBuffer(r, blk);
 
1910
        page = (Page) BufferGetPage(buffer);
 
1911
        opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
 
1912
 
 
1913
        maxoff = PageGetMaxOffsetNumber(page);
 
1914
 
 
1915
        elog(DEBUG4, "%sPage: %d %s blk: %d maxoff: %d free: %d", pred,
 
1916
                 coff, (opaque->flags & F_LEAF) ? "LEAF" : "INTE", (int) blk,
 
1917
                 (int) maxoff, PageGetFreeSpace(page));
 
1918
 
 
1919
        for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 
1920
        {
 
1921
                iid = PageGetItemId(page, i);
 
1922
                which = (IndexTuple) PageGetItem(page, iid);
 
1923
                cblk = ItemPointerGetBlockNumber(&(which->t_tid));
 
1924
#ifdef PRINTTUPLE
 
1925
                elog(DEBUG4, "%s  Tuple. blk: %d size: %d", pred, (int) cblk,
 
1926
                         IndexTupleSize(which));
 
1927
#endif
 
1928
 
 
1929
                if (!(opaque->flags & F_LEAF))
 
1930
                        gist_dumptree(r, level + 1, cblk, i);
 
1931
        }
 
1932
        ReleaseBuffer(buffer);
 
1933
        pfree(pred);
 
1934
}
 
1935
#endif   /* defined GISTDEBUG */
 
1936
 
 
1937
void
 
1938
gist_redo(XLogRecPtr lsn, XLogRecord *record)
 
1939
{
 
1940
        elog(PANIC, "gist_redo: unimplemented");
 
1941
}
 
1942
 
 
1943
void
 
1944
gist_undo(XLogRecPtr lsn, XLogRecord *record)
 
1945
{
 
1946
        elog(PANIC, "gist_undo: unimplemented");
 
1947
}
 
1948
 
 
1949
void
 
1950
gist_desc(char *buf, uint8 xl_info, char *rec)
 
1951
{
 
1952
}