1 /*-------------------------------------------------------------------------
4 * interface routines for the postgres rtree indexed access method.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.49 2000/06/14 05:24:43 tgl Exp $
13 *-------------------------------------------------------------------------
18 #include "access/genam.h"
19 #include "access/heapam.h"
20 #include "access/rtree.h"
21 #include "catalog/index.h"
22 #include "executor/executor.h"
23 #include "miscadmin.h"
26 typedef struct SPLITVEC
28 OffsetNumber *spl_left;
31 OffsetNumber *spl_right;
36 typedef struct RTSTATE
38 FmgrInfo unionFn; /* union function */
39 FmgrInfo sizeFn; /* size function */
40 FmgrInfo interFn; /* intersection function */
43 /* non-export function prototypes */
44 static InsertIndexResult rtdoinsert(Relation r, IndexTuple itup,
46 static void rttighten(Relation r, RTSTACK *stk, char *datum, int att_size,
48 static InsertIndexResult dosplit(Relation r, Buffer buffer, RTSTACK *stack,
49 IndexTuple itup, RTSTATE *rtstate);
50 static void rtintinsert(Relation r, RTSTACK *stk, IndexTuple ltup,
51 IndexTuple rtup, RTSTATE *rtstate);
52 static void rtnewroot(Relation r, IndexTuple lt, IndexTuple rt);
53 static void picksplit(Relation r, Page page, SPLITVEC *v, IndexTuple itup,
55 static void RTInitBuffer(Buffer b, uint32 f);
56 static OffsetNumber choose(Relation r, Page p, IndexTuple it,
58 static int nospace(Page p, IndexTuple it);
59 static void initRtstate(RTSTATE *rtstate, Relation index);
63 rtbuild(PG_FUNCTION_ARGS)
65 Relation heap = (Relation) PG_GETARG_POINTER(0);
66 Relation index = (Relation) PG_GETARG_POINTER(1);
67 int32 natts = PG_GETARG_INT32(2);
68 AttrNumber *attnum = (AttrNumber *) PG_GETARG_POINTER(3);
70 IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
71 uint16 pcount = PG_GETARG_UINT16(5);
72 Datum *params = (Datum *) PG_GETARG_POINTER(6);
74 FuncIndexInfo *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(7);
75 PredInfo *predInfo = (PredInfo *) PG_GETARG_POINTER(8);
82 InsertIndexResult res;
85 Buffer buffer = InvalidBuffer;
90 #ifndef OMIT_PARTIAL_INDEX
91 ExprContext *econtext;
92 TupleTable tupleTable;
100 initRtstate(&rtState, index);
102 pred = predInfo->pred;
103 oldPred = predInfo->oldPred;
106 * We expect to be called exactly once for any index relation. If
107 * that's not the case, big trouble's what we have.
110 if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
111 elog(ERROR, "%s already contains data", RelationGetRelationName(index));
113 /* initialize the root page (if this is a new index) */
116 buffer = ReadBuffer(index, P_NEW);
117 RTInitBuffer(buffer, F_LEAF);
121 /* init the tuple descriptors and get set for a heap scan */
122 hd = RelationGetDescr(heap);
123 id = RelationGetDescr(index);
124 d = (Datum *) palloc(natts * sizeof(*d));
125 nulls = (bool *) palloc(natts * sizeof(*nulls));
128 * If this is a predicate (partial) index, we will need to evaluate
129 * the predicate using ExecQual, which requires the current tuple to
130 * be in a slot of a TupleTable. In addition, ExecQual must have an
131 * ExprContext referring to that slot. Here, we initialize dummy
132 * TupleTable and ExprContext objects for this purpose. --Nels, Feb
135 #ifndef OMIT_PARTIAL_INDEX
136 if (pred != NULL || oldPred != NULL)
138 tupleTable = ExecCreateTupleTable(1);
139 slot = ExecAllocTableSlot(tupleTable);
140 econtext = makeNode(ExprContext);
141 FillDummyExprContext(econtext, slot, hd, InvalidBuffer);
149 #endif /* OMIT_PARTIAL_INDEX */
151 /* count the tuples as we insert them */
154 scan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
156 while (HeapTupleIsValid(htup = heap_getnext(scan, 0)))
161 * If oldPred != NULL, this is an EXTEND INDEX command, so skip
162 * this tuple if it was already in the existing partial index
166 #ifndef OMIT_PARTIAL_INDEX
167 /* SetSlotContents(slot, htup); */
169 if (ExecQual((List *) oldPred, econtext, false))
174 #endif /* OMIT_PARTIAL_INDEX */
178 * Skip this tuple if it doesn't satisfy the partial-index
183 #ifndef OMIT_PARTIAL_INDEX
184 /* SetSlotContents(slot, htup); */
186 if (!ExecQual((List *) pred, econtext, false))
188 #endif /* OMIT_PARTIAL_INDEX */
194 * For the current heap tuple, extract all the attributes we use
195 * in this index, and note which are null.
198 for (i = 1; i <= natts; i++)
204 * Offsets are from the start of the tuple, and are
205 * zero-based; indices are one-based. The next call returns i
206 * - 1. That's data hiding for you.
209 attoff = AttrNumberGetAttrOffset(i);
212 * d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
214 d[attoff] = GetIndexValue(htup,
220 nulls[attoff] = (attnull ? 'n' : ' ');
223 /* form an index tuple and point it at the heap tuple */
224 itup = index_formtuple(id, &d[0], nulls);
225 itup->t_tid = htup->t_self;
228 * Since we already have the index relation locked, we call
229 * rtdoinsert directly. Normal access method calls dispatch
230 * through rtinsert, which locks the relation for write. This is
231 * the right thing to do if you're inserting single tups, but not
232 * when you're initializing the whole index at once.
235 res = rtdoinsert(index, itup, &rtState);
240 /* okay, all heap tuples are indexed */
243 if (pred != NULL || oldPred != NULL)
245 #ifndef OMIT_PARTIAL_INDEX
246 ExecDropTupleTable(tupleTable, true);
248 #endif /* OMIT_PARTIAL_INDEX */
252 * Since we just counted the tuples in the heap, we update its stats
253 * in pg_class to guarantee that the planner takes advantage of the
254 * index we just created. But, only update statistics during normal
255 * index definitions, not for indices on system catalogs created
256 * during bootstrap processing. We must close the relations before
257 * updating statistics to guarantee that the relcache entries are
258 * flushed when we increment the command counter in UpdateStats(). But
259 * we do not release any locks on the relations; those will be held
260 * until end of transaction.
262 if (IsNormalProcessingMode())
264 Oid hrelid = RelationGetRelid(heap);
265 Oid irelid = RelationGetRelid(index);
266 bool inplace = IsReindexProcessing();
268 heap_close(heap, NoLock);
270 UpdateStats(hrelid, nh, inplace);
271 UpdateStats(irelid, ni, inplace);
272 if (oldPred != NULL && !inplace)
276 UpdateIndexPredicate(irelid, oldPred, pred);
288 * rtinsert -- wrapper for rtree tuple insertion.
290 * This is the public interface routine for tuple insertion in rtrees.
291 * It doesn't do any work; just locks the relation and passes the buck.
294 rtinsert(PG_FUNCTION_ARGS)
296 Relation r = (Relation) PG_GETARG_POINTER(0);
297 Datum *datum = (Datum *) PG_GETARG_POINTER(1);
298 char *nulls = (char *) PG_GETARG_POINTER(2);
299 ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
301 Relation heapRel = (Relation) PG_GETARG_POINTER(4);
303 InsertIndexResult res;
307 /* generate an index tuple */
308 itup = index_formtuple(RelationGetDescr(r), datum, nulls);
309 itup->t_tid = *ht_ctid;
310 initRtstate(&rtState, r);
313 * Notes in ExecUtils:ExecOpenIndices()
315 * RelationSetLockForWrite(r);
318 res = rtdoinsert(r, itup, &rtState);
320 PG_RETURN_POINTER(res);
323 static InsertIndexResult
324 rtdoinsert(Relation r, IndexTuple itup, RTSTATE *rtstate)
332 InsertIndexResult res;
333 RTreePageOpaque opaque;
337 buffer = InvalidBuffer;
338 stack = (RTSTACK *) NULL;
342 /* let go of current buffer before getting next */
343 if (buffer != InvalidBuffer)
344 ReleaseBuffer(buffer);
346 /* get next buffer */
347 buffer = ReadBuffer(r, blk);
348 page = (Page) BufferGetPage(buffer);
350 opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
351 if (!(opaque->flags & F_LEAF))
356 n = (RTSTACK *) palloc(sizeof(RTSTACK));
357 n->rts_parent = stack;
359 n->rts_child = choose(r, page, itup, rtstate);
362 iid = PageGetItemId(page, n->rts_child);
363 which = (IndexTuple) PageGetItem(page, iid);
364 blk = ItemPointerGetBlockNumber(&(which->t_tid));
366 } while (!(opaque->flags & F_LEAF));
368 if (nospace(page, itup))
370 /* need to do a split */
371 res = dosplit(r, buffer, stack, itup, rtstate);
373 WriteBuffer(buffer); /* don't forget to release buffer! */
377 /* add the item and write the buffer */
378 if (PageIsEmpty(page))
380 l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
386 l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
387 OffsetNumberNext(PageGetMaxOffsetNumber(page)),
393 datum = (((char *) itup) + sizeof(IndexTupleData));
395 /* now expand the page boundary in the parent to include the new child */
396 rttighten(r, stack, datum,
397 (IndexTupleSize(itup) - sizeof(IndexTupleData)), rtstate);
400 /* build and return an InsertIndexResult for this insertion */
401 res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
402 ItemPointerSet(&(res->pointerData), blk, l);
408 rttighten(Relation r,
421 if (stk == (RTSTACK *) NULL)
424 b = ReadBuffer(r, stk->rts_blk);
425 p = BufferGetPage(b);
427 oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->rts_child));
428 oldud += sizeof(IndexTupleData);
430 FunctionCall2(&rtstate->sizeFn,
431 PointerGetDatum(oldud),
432 PointerGetDatum(&old_size));
435 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
436 PointerGetDatum(oldud),
437 PointerGetDatum(datum)));
439 FunctionCall2(&rtstate->sizeFn,
440 PointerGetDatum(datum),
441 PointerGetDatum(&newd_size));
443 if (newd_size != old_size)
445 TupleDesc td = RelationGetDescr(r);
447 if (td->attrs[0]->attlen < 0)
451 * This is an internal page, so 'oldud' had better be a union
452 * (constant-length) key, too. (See comment below.)
454 Assert(VARSIZE(datum) == VARSIZE(oldud));
455 memmove(oldud, datum, VARSIZE(datum));
458 memmove(oldud, datum, att_size);
462 * The user may be defining an index on variable-sized data (like
463 * polygons). If so, we need to get a constant-sized datum for
464 * insertion on the internal page. We do this by calling the
465 * union proc, which is guaranteed to return a rectangle.
469 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
470 PointerGetDatum(datum),
471 PointerGetDatum(datum)));
472 rttighten(r, stk->rts_parent, tdatum, att_size, rtstate);
481 * dosplit -- split a page in the tree.
483 * This is the quadratic-cost split algorithm Guttman describes in
484 * his paper. The reason we chose it is that you can implement this
485 * with less information about the data types on which you're operating.
487 static InsertIndexResult
505 OffsetNumber leftoff,
509 BlockNumber bufblock;
510 RTreePageOpaque opaque;
512 InsertIndexResult res;
517 isnull = (char *) palloc(r->rd_rel->relnatts);
518 for (blank = 0; blank < r->rd_rel->relnatts; blank++)
520 p = (Page) BufferGetPage(buffer);
521 opaque = (RTreePageOpaque) PageGetSpecialPointer(p);
524 * The root of the tree is the first block in the relation. If we're
525 * about to split the root, we need to do some hocus-pocus to enforce
529 if (BufferGetBlockNumber(buffer) == P_ROOT)
531 leftbuf = ReadBuffer(r, P_NEW);
532 RTInitBuffer(leftbuf, opaque->flags);
533 lbknum = BufferGetBlockNumber(leftbuf);
534 left = (Page) BufferGetPage(leftbuf);
539 IncrBufferRefCount(buffer);
540 lbknum = BufferGetBlockNumber(buffer);
541 left = (Page) PageGetTempPage(p, sizeof(RTreePageOpaqueData));
544 rightbuf = ReadBuffer(r, P_NEW);
545 RTInitBuffer(rightbuf, opaque->flags);
546 rbknum = BufferGetBlockNumber(rightbuf);
547 right = (Page) BufferGetPage(rightbuf);
549 picksplit(r, p, &v, itup, rtstate);
551 leftoff = rightoff = FirstOffsetNumber;
552 maxoff = PageGetMaxOffsetNumber(p);
553 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
555 itemid = PageGetItemId(p, i);
556 item = (IndexTuple) PageGetItem(p, itemid);
558 if (i == *(v.spl_left))
560 PageAddItem(left, (Item) item, IndexTupleSize(item),
562 leftoff = OffsetNumberNext(leftoff);
563 v.spl_left++; /* advance in left split vector */
567 PageAddItem(right, (Item) item, IndexTupleSize(item),
569 rightoff = OffsetNumberNext(rightoff);
570 v.spl_right++; /* advance in right split vector */
574 /* build an InsertIndexResult for this insertion */
575 res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
577 /* now insert the new index tuple */
578 if (*(v.spl_left) != FirstOffsetNumber)
580 PageAddItem(left, (Item) itup, IndexTupleSize(itup),
582 leftoff = OffsetNumberNext(leftoff);
583 ItemPointerSet(&(res->pointerData), lbknum, leftoff);
587 PageAddItem(right, (Item) itup, IndexTupleSize(itup),
589 rightoff = OffsetNumberNext(rightoff);
590 ItemPointerSet(&(res->pointerData), rbknum, rightoff);
593 if ((bufblock = BufferGetBlockNumber(buffer)) != P_ROOT)
594 PageRestoreTempPage(left, p);
595 WriteBuffer(leftbuf);
596 WriteBuffer(rightbuf);
599 * Okay, the page is split. We have three things left to do:
601 * 1) Adjust any active scans on this index to cope with changes we
602 * introduced in its structure by splitting this page.
604 * 2) "Tighten" the bounding box of the pointer to the left page in the
605 * parent node in the tree, if any. Since we moved a bunch of stuff
606 * off the left page, we expect it to get smaller. This happens in
607 * the internal insertion routine.
609 * 3) Insert a pointer to the right page in the parent. This may cause
610 * the parent to split. If it does, we need to repeat steps one and
611 * two for each split node in the tree.
614 /* adjust active scans */
615 rtadjscans(r, RTOP_SPLIT, bufblock, FirstOffsetNumber);
618 ltup = (IndexTuple) index_formtuple(tupDesc,
619 (Datum *) &(v.spl_ldatum), isnull);
620 rtup = (IndexTuple) index_formtuple(tupDesc,
621 (Datum *) &(v.spl_rdatum), isnull);
624 /* set pointers to new child pages in the internal index tuples */
625 ItemPointerSet(&(ltup->t_tid), lbknum, 1);
626 ItemPointerSet(&(rtup->t_tid), rbknum, 1);
628 rtintinsert(r, stack, ltup, rtup, rtstate);
637 rtintinsert(Relation r,
649 InsertIndexResult res;
651 if (stk == (RTSTACK *) NULL)
653 rtnewroot(r, ltup, rtup);
657 b = ReadBuffer(r, stk->rts_blk);
658 p = BufferGetPage(b);
659 old = (IndexTuple) PageGetItem(p, PageGetItemId(p, stk->rts_child));
662 * This is a hack. Right now, we force rtree keys to be constant
663 * size. To fix this, need delete the old key and add both left and
664 * right for the two new pages. The insertion of left may force a
665 * split if the new left key is bigger than the old key.
668 if (IndexTupleSize(old) != IndexTupleSize(ltup))
669 elog(ERROR, "Variable-length rtree keys are not supported.");
671 /* install pointer to left child */
672 memmove(old, ltup, IndexTupleSize(ltup));
674 if (nospace(p, rtup))
676 newdatum = (((char *) ltup) + sizeof(IndexTupleData));
677 rttighten(r, stk->rts_parent, newdatum,
678 (IndexTupleSize(ltup) - sizeof(IndexTupleData)), rtstate);
679 res = dosplit(r, b, stk->rts_parent, rtup, rtstate);
680 WriteBuffer(b); /* don't forget to release buffer! -
686 PageAddItem(p, (Item) rtup, IndexTupleSize(rtup),
687 PageGetMaxOffsetNumber(p), LP_USED);
689 ldatum = (((char *) ltup) + sizeof(IndexTupleData));
690 rdatum = (((char *) rtup) + sizeof(IndexTupleData));
692 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
693 PointerGetDatum(ldatum),
694 PointerGetDatum(rdatum)));
696 rttighten(r, stk->rts_parent, newdatum,
697 (IndexTupleSize(rtup) - sizeof(IndexTupleData)), rtstate);
704 rtnewroot(Relation r, IndexTuple lt, IndexTuple rt)
709 b = ReadBuffer(r, P_ROOT);
711 p = BufferGetPage(b);
712 PageAddItem(p, (Item) lt, IndexTupleSize(lt),
713 FirstOffsetNumber, LP_USED);
714 PageAddItem(p, (Item) rt, IndexTupleSize(rt),
715 OffsetNumberNext(FirstOffsetNumber), LP_USED);
720 picksplit(Relation r,
749 OffsetNumber seed_1 = 0,
754 maxoff = PageGetMaxOffsetNumber(page);
756 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
757 v->spl_left = (OffsetNumber *) palloc(nbytes);
758 v->spl_right = (OffsetNumber *) palloc(nbytes);
763 for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
765 item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
766 datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
767 for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
769 item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, j));
770 datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
772 /* compute the wasted space by unioning these guys */
774 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
775 PointerGetDatum(datum_alpha),
776 PointerGetDatum(datum_beta)));
777 FunctionCall2(&rtstate->sizeFn,
778 PointerGetDatum(union_d),
779 PointerGetDatum(&size_union));
781 DatumGetPointer(FunctionCall2(&rtstate->interFn,
782 PointerGetDatum(datum_alpha),
783 PointerGetDatum(datum_beta)));
784 FunctionCall2(&rtstate->sizeFn,
785 PointerGetDatum(inter_d),
786 PointerGetDatum(&size_inter));
787 size_waste = size_union - size_inter;
791 if (inter_d != (char *) NULL)
795 * are these a more promising split that what we've already
799 if (size_waste > waste || firsttime)
811 right = v->spl_right;
814 item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_1));
815 datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
817 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
818 PointerGetDatum(datum_alpha),
819 PointerGetDatum(datum_alpha)));
820 FunctionCall2(&rtstate->sizeFn,
821 PointerGetDatum(datum_l),
822 PointerGetDatum(&size_l));
823 item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_2));
824 datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
826 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
827 PointerGetDatum(datum_beta),
828 PointerGetDatum(datum_beta)));
829 FunctionCall2(&rtstate->sizeFn,
830 PointerGetDatum(datum_r),
831 PointerGetDatum(&size_r));
834 * Now split up the regions between the two seeds. An important
835 * property of this split algorithm is that the split vector v has the
836 * indices of items to be split in order in its left and right
837 * vectors. We exploit this property by doing a merge in the code
838 * that actually splits the page.
840 * For efficiency, we also place the new index tuple in this loop. This
841 * is handled at the very end, when we have placed all the existing
842 * tuples and i == maxoff + 1.
845 maxoff = OffsetNumberNext(maxoff);
846 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
850 * If we've already decided where to place this item, just put it
851 * on the right list. Otherwise, we need to figure out which page
852 * needs the least enlargement in order to store the item.
861 else if (i == seed_2)
868 /* okay, which page needs least enlargement? */
872 item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
874 datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
876 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
877 PointerGetDatum(datum_l),
878 PointerGetDatum(datum_alpha)));
880 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
881 PointerGetDatum(datum_r),
882 PointerGetDatum(datum_alpha)));
883 FunctionCall2(&rtstate->sizeFn,
884 PointerGetDatum(union_dl),
885 PointerGetDatum(&size_alpha));
886 FunctionCall2(&rtstate->sizeFn,
887 PointerGetDatum(union_dr),
888 PointerGetDatum(&size_beta));
890 /* pick which page to add it to */
891 if (size_alpha - size_l < size_beta - size_r)
910 *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
912 v->spl_ldatum = datum_l;
913 v->spl_rdatum = datum_r;
917 RTInitBuffer(Buffer b, uint32 f)
919 RTreePageOpaque opaque;
923 pageSize = BufferGetPageSize(b);
925 page = BufferGetPage(b);
926 MemSet(page, 0, (int) pageSize);
927 PageInit(page, pageSize, sizeof(RTreePageOpaqueData));
929 opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
934 choose(Relation r, Page p, IndexTuple it, RTSTATE *rtstate)
946 id = ((char *) it) + sizeof(IndexTupleData);
947 maxoff = PageGetMaxOffsetNumber(p);
951 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
953 datum = (char *) PageGetItem(p, PageGetItemId(p, i));
954 datum += sizeof(IndexTupleData);
955 FunctionCall2(&rtstate->sizeFn,
956 PointerGetDatum(datum),
957 PointerGetDatum(&dsize));
959 DatumGetPointer(FunctionCall2(&rtstate->unionFn,
960 PointerGetDatum(datum),
961 PointerGetDatum(id)));
962 FunctionCall2(&rtstate->sizeFn,
964 PointerGetDatum(&usize));
966 if (which_grow < 0 || usize - dsize < which_grow)
969 which_grow = usize - dsize;
979 nospace(Page p, IndexTuple it)
981 return PageGetFreeSpace(p) < IndexTupleSize(it);
985 freestack(RTSTACK *s)
989 while (s != (RTSTACK *) NULL)
998 rtdelete(PG_FUNCTION_ARGS)
1000 Relation r = (Relation) PG_GETARG_POINTER(0);
1001 ItemPointer tid = (ItemPointer) PG_GETARG_POINTER(1);
1003 OffsetNumber offnum;
1008 * Notes in ExecUtils:ExecOpenIndices() Also note that only vacuum
1009 * deletes index tuples now...
1011 * RelationSetLockForWrite(r);
1014 blkno = ItemPointerGetBlockNumber(tid);
1015 offnum = ItemPointerGetOffsetNumber(tid);
1017 /* adjust any scans that will be affected by this deletion */
1018 rtadjscans(r, RTOP_DEL, blkno, offnum);
1020 /* delete the index tuple */
1021 buf = ReadBuffer(r, blkno);
1022 page = BufferGetPage(buf);
1024 PageIndexTupleDelete(page, offnum);
1032 initRtstate(RTSTATE *rtstate, Relation index)
1034 RegProcedure union_proc,
1038 union_proc = index_getprocid(index, 1, RT_UNION_PROC);
1039 size_proc = index_getprocid(index, 1, RT_SIZE_PROC);
1040 inter_proc = index_getprocid(index, 1, RT_INTER_PROC);
1041 fmgr_info(union_proc, &rtstate->unionFn);
1042 fmgr_info(size_proc, &rtstate->sizeFn);
1043 fmgr_info(inter_proc, &rtstate->interFn);
1054 OffsetNumber offnum,
1057 BlockNumber nblocks;
1060 BlockNumber itblkno;
1061 OffsetNumber itoffno;
1065 nblocks = RelationGetNumberOfBlocks(r);
1066 for (blkno = 0; blkno < nblocks; blkno++)
1068 buf = ReadBuffer(r, blkno);
1069 page = BufferGetPage(buf);
1070 po = (RTreePageOpaque) PageGetSpecialPointer(page);
1071 maxoff = PageGetMaxOffsetNumber(page);
1072 printf("Page %d maxoff %d <%s>\n", blkno, maxoff,
1073 (po->flags & F_LEAF ? "LEAF" : "INTERNAL"));
1075 if (PageIsEmpty(page))
1081 for (offnum = FirstOffsetNumber;
1083 offnum = OffsetNumberNext(offnum))
1085 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
1086 itblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
1087 itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid));
1088 datum = ((char *) itup);
1089 datum += sizeof(IndexTupleData);
1090 itkey = (char *) box_out((BOX *) datum);
1091 printf("\t[%d] size %d heap <%d,%d> key:%s\n",
1092 offnum, IndexTupleSize(itup), itblkno, itoffno, itkey);
1100 #endif /* defined RTDEBUG */