PostgreSQL Source Code  git master
gist.c File Reference
#include "postgres.h"
#include "access/gist_private.h"
#include "access/gistscan.h"
#include "catalog/pg_collation.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "utils/builtins.h"
#include "utils/index_selfuncs.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gist.c:

Go to the source code of this file.

Macros

#define ROTATEDIST(d)
 

Functions

static void gistfixsplit (GISTInsertState *state, GISTSTATE *giststate)
 
static bool gistinserttuple (GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple tuple, OffsetNumber oldoffnum)
 
static bool gistinserttuples (GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple *tuples, int ntup, OffsetNumber oldoffnum, Buffer leftchild, Buffer rightchild, bool unlockbuf, bool unlockleftchild)
 
static void gistfinishsplit (GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, List *splitinfo, bool unlockbuf)
 
static void gistprunepage (Relation rel, Page page, Buffer buffer, Relation heapRel)
 
Datum gisthandler (PG_FUNCTION_ARGS)
 
MemoryContext createTempGistContext (void)
 
void gistbuildempty (Relation index)
 
bool gistinsert (Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
 
bool gistplacetopage (Relation rel, Size freespace, GISTSTATE *giststate, Buffer buffer, IndexTuple *itup, int ntup, OffsetNumber oldoffnum, BlockNumber *newblkno, Buffer leftchildbuf, List **splitinfo, bool markfollowright, Relation heapRel, bool is_build)
 
void gistdoinsert (Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate, Relation heapRel, bool is_build)
 
static GISTInsertStackgistFindPath (Relation r, BlockNumber child, OffsetNumber *downlinkoffnum)
 
static void gistFindCorrectParent (Relation r, GISTInsertStack *child)
 
static IndexTuple gistformdownlink (Relation rel, Buffer buf, GISTSTATE *giststate, GISTInsertStack *stack)
 
SplitedPageLayoutgistSplit (Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
 
GISTSTATEinitGISTstate (Relation index)
 
void freeGISTstate (GISTSTATE *giststate)
 

Macro Definition Documentation

◆ ROTATEDIST

#define ROTATEDIST (   d)
Value:
do { \
SplitedPageLayout *tmp=(SplitedPageLayout*)palloc0(sizeof(SplitedPageLayout)); \
tmp->block.blkno = InvalidBlockNumber; \
tmp->buffer = InvalidBuffer; \
tmp->next = (d); \
(d)=tmp; \
} while(0)
#define InvalidBuffer
Definition: buf.h:25
void * palloc0(Size size)
Definition: mcxt.c:1093
#define InvalidBlockNumber
Definition: block.h:33

Definition at line 45 of file gist.c.

Referenced by gistSplit().

Function Documentation

◆ createTempGistContext()

MemoryContext createTempGistContext ( void  )

Definition at line 119 of file gist.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, and CurrentMemoryContext.

Referenced by gist_xlog_startup(), gistbeginscan(), gistbuild(), and gistinsert().

120 {
122  "GiST temporary context",
124 }
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42

◆ freeGISTstate()

void freeGISTstate ( GISTSTATE giststate)

Definition at line 1631 of file gist.c.

References MemoryContextDelete(), and GISTSTATE::scanCxt.

Referenced by gistbuild(), and gistendscan().

1632 {
1633  /* It's sufficient to delete the scanCxt */
1634  MemoryContextDelete(giststate->scanCxt);
1635 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
MemoryContext scanCxt
Definition: gist_private.h:77

◆ gistbuildempty()

void gistbuildempty ( Relation  index)

Definition at line 130 of file gist.c.

References BUFFER_LOCK_EXCLUSIVE, END_CRIT_SECTION, F_LEAF, GISTInitBuffer(), INIT_FORKNUM, LockBuffer(), log_newpage_buffer(), MarkBufferDirty(), P_NEW, RBM_NORMAL, ReadBufferExtended(), START_CRIT_SECTION, and UnlockReleaseBuffer().

Referenced by gisthandler().

131 {
132  Buffer buffer;
133 
134  /* Initialize the root page */
135  buffer = ReadBufferExtended(index, INIT_FORKNUM, P_NEW, RBM_NORMAL, NULL);
137 
138  /* Initialize and xlog buffer */
140  GISTInitBuffer(buffer, F_LEAF);
141  MarkBufferDirty(buffer);
142  log_newpage_buffer(buffer, true);
144 
145  /* Unlock and release the buffer */
146  UnlockReleaseBuffer(buffer);
147 }
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1144
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1565
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:741
#define END_CRIT_SECTION()
Definition: miscadmin.h:149
#define START_CRIT_SECTION()
Definition: miscadmin.h:147
#define P_NEW
Definition: bufmgr.h:91
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3791
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
#define F_LEAF
Definition: gist.h:46
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:772
int Buffer
Definition: buf.h:23

◆ gistdoinsert()

void gistdoinsert ( Relation  r,
IndexTuple  itup,
Size  freespace,
GISTSTATE giststate,
Relation  heapRel,
bool  is_build 
)

Definition at line 632 of file gist.c.

References Assert, GISTInsertStack::blkno, GISTInsertStack::buffer, BufferGetLSNAtomic(), BufferGetPage, GISTInsertStack::downlinkoffnum, ereport, errdetail(), errhint(), errmsg(), ERROR, GISTInsertState::freespace, GIST_EXCLUSIVE, GIST_ROOT_BLKNO, GIST_SHARE, GIST_UNLOCK, gistcheckpage(), gistchoose(), gistfixsplit(), GistFollowRight, gistgetadjusted(), gistinserttuple(), GistPageGetNSN, GistPageIsDeleted, GistPageIsLeaf, GistTupleIsInvalid, GISTInsertState::heapRel, InvalidOffsetNumber, GISTInsertState::is_build, ItemPointerGetBlockNumber, LockBuffer(), GISTInsertStack::lsn, GISTInsertStack::page, PageGetItem, PageGetItemId, PageGetLSN, palloc0(), GISTInsertStack::parent, GISTInsertState::r, ReadBuffer(), RelationGetRelationName, RelationNeedsWAL, ReleaseBuffer(), GISTInsertStack::retry_from_parent, GISTInsertState::stack, IndexTupleData::t_tid, UnlockReleaseBuffer(), and XLogRecPtrIsInvalid.

Referenced by gistBuildCallback(), and gistinsert().

634 {
635  ItemId iid;
636  IndexTuple idxtuple;
637  GISTInsertStack firststack;
638  GISTInsertStack *stack;
640  bool xlocked = false;
641 
642  memset(&state, 0, sizeof(GISTInsertState));
643  state.freespace = freespace;
644  state.r = r;
645  state.heapRel = heapRel;
646  state.is_build = is_build;
647 
648  /* Start from the root */
649  firststack.blkno = GIST_ROOT_BLKNO;
650  firststack.lsn = 0;
651  firststack.retry_from_parent = false;
652  firststack.parent = NULL;
653  firststack.downlinkoffnum = InvalidOffsetNumber;
654  state.stack = stack = &firststack;
655 
656  /*
657  * Walk down along the path of smallest penalty, updating the parent
658  * pointers with the key we're inserting as we go. If we crash in the
659  * middle, the tree is consistent, although the possible parent updates
660  * were a waste.
661  */
662  for (;;)
663  {
664  /*
665  * If we split an internal page while descending the tree, we have to
666  * retry at the parent. (Normally, the LSN-NSN interlock below would
667  * also catch this and cause us to retry. But LSNs are not updated
668  * during index build.)
669  */
670  while (stack->retry_from_parent)
671  {
672  if (xlocked)
673  LockBuffer(stack->buffer, GIST_UNLOCK);
674  xlocked = false;
675  ReleaseBuffer(stack->buffer);
676  state.stack = stack = stack->parent;
677  }
678 
679  if (XLogRecPtrIsInvalid(stack->lsn))
680  stack->buffer = ReadBuffer(state.r, stack->blkno);
681 
682  /*
683  * Be optimistic and grab shared lock first. Swap it for an exclusive
684  * lock later if we need to update the page.
685  */
686  if (!xlocked)
687  {
688  LockBuffer(stack->buffer, GIST_SHARE);
689  gistcheckpage(state.r, stack->buffer);
690  }
691 
692  stack->page = (Page) BufferGetPage(stack->buffer);
693  stack->lsn = xlocked ?
694  PageGetLSN(stack->page) : BufferGetLSNAtomic(stack->buffer);
695  Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
696 
697  /*
698  * If this page was split but the downlink was never inserted to the
699  * parent because the inserting backend crashed before doing that, fix
700  * that now.
701  */
702  if (GistFollowRight(stack->page))
703  {
704  if (!xlocked)
705  {
706  LockBuffer(stack->buffer, GIST_UNLOCK);
708  xlocked = true;
709  /* someone might've completed the split when we unlocked */
710  if (!GistFollowRight(stack->page))
711  continue;
712  }
713  gistfixsplit(&state, giststate);
714 
715  UnlockReleaseBuffer(stack->buffer);
716  xlocked = false;
717  state.stack = stack = stack->parent;
718  continue;
719  }
720 
721  if ((stack->blkno != GIST_ROOT_BLKNO &&
722  stack->parent->lsn < GistPageGetNSN(stack->page)) ||
723  GistPageIsDeleted(stack->page))
724  {
725  /*
726  * Concurrent split or page deletion detected. There's no
727  * guarantee that the downlink for this page is consistent with
728  * the tuple we're inserting anymore, so go back to parent and
729  * rechoose the best child.
730  */
731  UnlockReleaseBuffer(stack->buffer);
732  xlocked = false;
733  state.stack = stack = stack->parent;
734  continue;
735  }
736 
737  if (!GistPageIsLeaf(stack->page))
738  {
739  /*
740  * This is an internal page so continue to walk down the tree.
741  * Find the child node that has the minimum insertion penalty.
742  */
743  BlockNumber childblkno;
744  IndexTuple newtup;
745  GISTInsertStack *item;
746  OffsetNumber downlinkoffnum;
747 
748  downlinkoffnum = gistchoose(state.r, stack->page, itup, giststate);
749  iid = PageGetItemId(stack->page, downlinkoffnum);
750  idxtuple = (IndexTuple) PageGetItem(stack->page, iid);
751  childblkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
752 
753  /*
754  * Check that it's not a leftover invalid tuple from pre-9.1
755  */
756  if (GistTupleIsInvalid(idxtuple))
757  ereport(ERROR,
758  (errmsg("index \"%s\" contains an inner tuple marked as invalid",
760  errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
761  errhint("Please REINDEX it.")));
762 
763  /*
764  * Check that the key representing the target child node is
765  * consistent with the key we're inserting. Update it if it's not.
766  */
767  newtup = gistgetadjusted(state.r, idxtuple, itup, giststate);
768  if (newtup)
769  {
770  /*
771  * Swap shared lock for an exclusive one. Beware, the page may
772  * change while we unlock/lock the page...
773  */
774  if (!xlocked)
775  {
776  LockBuffer(stack->buffer, GIST_UNLOCK);
778  xlocked = true;
779  stack->page = (Page) BufferGetPage(stack->buffer);
780 
781  if (PageGetLSN(stack->page) != stack->lsn)
782  {
783  /* the page was changed while we unlocked it, retry */
784  continue;
785  }
786  }
787 
788  /*
789  * Update the tuple.
790  *
791  * We still hold the lock after gistinserttuple(), but it
792  * might have to split the page to make the updated tuple fit.
793  * In that case the updated tuple might migrate to the other
794  * half of the split, so we have to go back to the parent and
795  * descend back to the half that's a better fit for the new
796  * tuple.
797  */
798  if (gistinserttuple(&state, stack, giststate, newtup,
799  downlinkoffnum))
800  {
801  /*
802  * If this was a root split, the root page continues to be
803  * the parent and the updated tuple went to one of the
804  * child pages, so we just need to retry from the root
805  * page.
806  */
807  if (stack->blkno != GIST_ROOT_BLKNO)
808  {
809  UnlockReleaseBuffer(stack->buffer);
810  xlocked = false;
811  state.stack = stack = stack->parent;
812  }
813  continue;
814  }
815  }
816  LockBuffer(stack->buffer, GIST_UNLOCK);
817  xlocked = false;
818 
819  /* descend to the chosen child */
820  item = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
821  item->blkno = childblkno;
822  item->parent = stack;
823  item->downlinkoffnum = downlinkoffnum;
824  state.stack = stack = item;
825  }
826  else
827  {
828  /*
829  * Leaf page. Insert the new key. We've already updated all the
830  * parents on the way down, but we might have to split the page if
831  * it doesn't fit. gistinserttuple() will take care of that.
832  */
833 
834  /*
835  * Swap shared lock for an exclusive one. Be careful, the page may
836  * change while we unlock/lock the page...
837  */
838  if (!xlocked)
839  {
840  LockBuffer(stack->buffer, GIST_UNLOCK);
842  xlocked = true;
843  stack->page = (Page) BufferGetPage(stack->buffer);
844  stack->lsn = PageGetLSN(stack->page);
845 
846  if (stack->blkno == GIST_ROOT_BLKNO)
847  {
848  /*
849  * the only page that can become inner instead of leaf is
850  * the root page, so for root we should recheck it
851  */
852  if (!GistPageIsLeaf(stack->page))
853  {
854  /*
855  * very rare situation: during unlock/lock index with
856  * number of pages = 1 was increased
857  */
858  LockBuffer(stack->buffer, GIST_UNLOCK);
859  xlocked = false;
860  continue;
861  }
862 
863  /*
864  * we don't need to check root split, because checking
865  * leaf/inner is enough to recognize split for root
866  */
867  }
868  else if ((GistFollowRight(stack->page) ||
869  stack->parent->lsn < GistPageGetNSN(stack->page)) ||
870  GistPageIsDeleted(stack->page))
871  {
872  /*
873  * The page was split or deleted while we momentarily
874  * unlocked the page. Go back to parent.
875  */
876  UnlockReleaseBuffer(stack->buffer);
877  xlocked = false;
878  state.stack = stack = stack->parent;
879  continue;
880  }
881  }
882 
883  /* now state.stack->(page, buffer and blkno) points to leaf page */
884 
885  gistinserttuple(&state, stack, giststate, itup,
887  LockBuffer(stack->buffer, GIST_UNLOCK);
888 
889  /* Release any pins we might still hold before exiting */
890  for (; stack; stack = stack->parent)
891  ReleaseBuffer(stack->buffer);
892  break;
893  }
894  }
895 }
#define GistFollowRight(page)
Definition: gist.h:182
BlockNumber blkno
Definition: gist_private.h:210
#define GistPageGetNSN(page)
Definition: gist.h:186
static bool gistinserttuple(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple tuple, OffsetNumber oldoffnum)
Definition: gist.c:1227
#define GistPageIsDeleted(page)
Definition: gist.h:172
int errhint(const char *fmt,...)
Definition: elog.c:1156
static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate)
Definition: gist.c:1167
Relation heapRel
Definition: gist_private.h:254
ItemPointerData t_tid
Definition: itup.h:37
#define GistTupleIsInvalid(itup)
Definition: gist_private.h:288
#define GIST_UNLOCK
Definition: gist_private.h:44
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3768
IndexTuple gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
Definition: gistutil.c:315
uint16 OffsetNumber
Definition: off.h:24
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3791
#define ERROR
Definition: elog.h:46
GISTInsertStack * stack
Definition: gist_private.h:258
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3008
IndexTupleData * IndexTuple
Definition: itup.h:53
int errdetail(const char *fmt,...)
Definition: elog.c:1042
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
OffsetNumber gistchoose(Relation r, Page p, IndexTuple it, GISTSTATE *giststate)
Definition: gistutil.c:373
#define GistPageIsLeaf(page)
Definition: gist.h:169
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
OffsetNumber downlinkoffnum
Definition: gist_private.h:228
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void * palloc0(Size size)
Definition: mcxt.c:1093
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
#define InvalidOffsetNumber
Definition: off.h:26
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:784
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:694
#define GIST_SHARE
Definition: gist_private.h:42
#define RelationNeedsWAL(relation)
Definition: rel.h:601
#define PageGetLSN(page)
Definition: bufpage.h:366
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define GIST_EXCLUSIVE
Definition: gist_private.h:43
struct GISTInsertStack * parent
Definition: gist_private.h:231
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ gistFindCorrectParent()

static void gistFindCorrectParent ( Relation  r,
GISTInsertStack child 
)
static

Definition at line 1020 of file gist.c.

References GISTInsertStack::blkno, GISTInsertStack::buffer, BufferGetPage, GISTInsertStack::downlinkoffnum, FirstOffsetNumber, GIST_EXCLUSIVE, gistcheckpage(), gistFindPath(), GistPageGetOpaque, i, InvalidBlockNumber, InvalidOffsetNumber, ItemPointerGetBlockNumber, LockBuffer(), GISTInsertStack::lsn, OffsetNumberNext, GISTInsertStack::page, PageGetItem, PageGetItemId, PageGetLSN, PageGetMaxOffsetNumber, DataPageDeleteStack::parent, GISTInsertStack::parent, ReadBuffer(), ReleaseBuffer(), IndexTupleData::t_tid, and UnlockReleaseBuffer().

Referenced by gistfinishsplit(), and gistformdownlink().

1021 {
1022  GISTInsertStack *parent = child->parent;
1023 
1024  gistcheckpage(r, parent->buffer);
1025  parent->page = (Page) BufferGetPage(parent->buffer);
1026 
1027  /* here we don't need to distinguish between split and page update */
1028  if (child->downlinkoffnum == InvalidOffsetNumber ||
1029  parent->lsn != PageGetLSN(parent->page))
1030  {
1031  /* parent is changed, look child in right links until found */
1032  OffsetNumber i,
1033  maxoff;
1034  ItemId iid;
1035  IndexTuple idxtuple;
1036  GISTInsertStack *ptr;
1037 
1038  while (true)
1039  {
1040  maxoff = PageGetMaxOffsetNumber(parent->page);
1041  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
1042  {
1043  iid = PageGetItemId(parent->page, i);
1044  idxtuple = (IndexTuple) PageGetItem(parent->page, iid);
1045  if (ItemPointerGetBlockNumber(&(idxtuple->t_tid)) == child->blkno)
1046  {
1047  /* yes!!, found */
1048  child->downlinkoffnum = i;
1049  return;
1050  }
1051  }
1052 
1053  parent->blkno = GistPageGetOpaque(parent->page)->rightlink;
1054  UnlockReleaseBuffer(parent->buffer);
1055  if (parent->blkno == InvalidBlockNumber)
1056  {
1057  /*
1058  * End of chain and still didn't find parent. It's a very-very
1059  * rare situation when root splitted.
1060  */
1061  break;
1062  }
1063  parent->buffer = ReadBuffer(r, parent->blkno);
1064  LockBuffer(parent->buffer, GIST_EXCLUSIVE);
1065  gistcheckpage(r, parent->buffer);
1066  parent->page = (Page) BufferGetPage(parent->buffer);
1067  }
1068 
1069  /*
1070  * awful!!, we need search tree to find parent ... , but before we
1071  * should release all old parent
1072  */
1073 
1074  ptr = child->parent->parent; /* child->parent already released
1075  * above */
1076  while (ptr)
1077  {
1078  ReleaseBuffer(ptr->buffer);
1079  ptr = ptr->parent;
1080  }
1081 
1082  /* ok, find new path */
1083  ptr = parent = gistFindPath(r, child->blkno, &child->downlinkoffnum);
1084 
1085  /* read all buffers as expected by caller */
1086  /* note we don't lock them or gistcheckpage them here! */
1087  while (ptr)
1088  {
1089  ptr->buffer = ReadBuffer(r, ptr->blkno);
1090  ptr->page = (Page) BufferGetPage(ptr->buffer);
1091  ptr = ptr->parent;
1092  }
1093 
1094  /* install new chain of parents to stack */
1095  child->parent = parent;
1096 
1097  /* make recursive call to normal processing */
1099  gistFindCorrectParent(r, child);
1100  }
1101 }
BlockNumber blkno
Definition: gist_private.h:210
ItemPointerData t_tid
Definition: itup.h:37
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3768
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3791
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
OffsetNumber downlinkoffnum
Definition: gist_private.h:228
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
static void gistFindCorrectParent(Relation r, GISTInsertStack *child)
Definition: gist.c:1020
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
#define InvalidOffsetNumber
Definition: off.h:26
static GISTInsertStack * gistFindPath(Relation r, BlockNumber child, OffsetNumber *downlinkoffnum)
Definition: gist.c:907
#define GistPageGetOpaque(page)
Definition: gist.h:167
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:784
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:694
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define InvalidBlockNumber
Definition: block.h:33
#define PageGetLSN(page)
Definition: bufpage.h:366
int i
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define GIST_EXCLUSIVE
Definition: gist_private.h:43
struct GISTInsertStack * parent
Definition: gist_private.h:231
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ gistFindPath()

static GISTInsertStack* gistFindPath ( Relation  r,
BlockNumber  child,
OffsetNumber downlinkoffnum 
)
static

Definition at line 907 of file gist.c.

References Assert, DataPageDeleteStack::blkno, GISTInsertStack::blkno, BufferGetLSNAtomic(), BufferGetPage, GISTInsertStack::downlinkoffnum, elog, ERROR, FirstOffsetNumber, GIST_ROOT_BLKNO, GIST_SHARE, gistcheckpage(), GistFollowRight, GistPageGetNSN, GistPageGetOpaque, GistPageIsDeleted, GistPageIsLeaf, i, InvalidBlockNumber, InvalidOffsetNumber, ItemPointerGetBlockNumber, lappend(), lcons(), linitial, list_delete_first(), list_make1, LockBuffer(), GISTInsertStack::lsn, NIL, OffsetNumberNext, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, palloc0(), GISTInsertStack::parent, ReadBuffer(), RelationGetRelationName, IndexTupleData::t_tid, and UnlockReleaseBuffer().

Referenced by gistFindCorrectParent().

908 {
909  Page page;
910  Buffer buffer;
911  OffsetNumber i,
912  maxoff;
913  ItemId iid;
914  IndexTuple idxtuple;
915  List *fifo;
916  GISTInsertStack *top,
917  *ptr;
918  BlockNumber blkno;
919 
920  top = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
921  top->blkno = GIST_ROOT_BLKNO;
923 
924  fifo = list_make1(top);
925  while (fifo != NIL)
926  {
927  /* Get next page to visit */
928  top = linitial(fifo);
929  fifo = list_delete_first(fifo);
930 
931  buffer = ReadBuffer(r, top->blkno);
932  LockBuffer(buffer, GIST_SHARE);
933  gistcheckpage(r, buffer);
934  page = (Page) BufferGetPage(buffer);
935 
936  if (GistPageIsLeaf(page))
937  {
938  /*
939  * Because we scan the index top-down, all the rest of the pages
940  * in the queue must be leaf pages as well.
941  */
942  UnlockReleaseBuffer(buffer);
943  break;
944  }
945 
946  /* currently, internal pages are never deleted */
947  Assert(!GistPageIsDeleted(page));
948 
949  top->lsn = BufferGetLSNAtomic(buffer);
950 
951  /*
952  * If F_FOLLOW_RIGHT is set, the page to the right doesn't have a
953  * downlink. This should not normally happen..
954  */
955  if (GistFollowRight(page))
956  elog(ERROR, "concurrent GiST page split was incomplete");
957 
958  if (top->parent && top->parent->lsn < GistPageGetNSN(page) &&
959  GistPageGetOpaque(page)->rightlink != InvalidBlockNumber /* sanity check */ )
960  {
961  /*
962  * Page was split while we looked elsewhere. We didn't see the
963  * downlink to the right page when we scanned the parent, so add
964  * it to the queue now.
965  *
966  * Put the right page ahead of the queue, so that we visit it
967  * next. That's important, because if this is the lowest internal
968  * level, just above leaves, we might already have queued up some
969  * leaf pages, and we assume that there can't be any non-leaf
970  * pages behind leaf pages.
971  */
972  ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
973  ptr->blkno = GistPageGetOpaque(page)->rightlink;
975  ptr->parent = top->parent;
976 
977  fifo = lcons(ptr, fifo);
978  }
979 
980  maxoff = PageGetMaxOffsetNumber(page);
981 
982  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
983  {
984  iid = PageGetItemId(page, i);
985  idxtuple = (IndexTuple) PageGetItem(page, iid);
986  blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
987  if (blkno == child)
988  {
989  /* Found it! */
990  UnlockReleaseBuffer(buffer);
991  *downlinkoffnum = i;
992  return top;
993  }
994  else
995  {
996  /* Append this child to the list of pages to visit later */
997  ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
998  ptr->blkno = blkno;
999  ptr->downlinkoffnum = i;
1000  ptr->parent = top;
1001 
1002  fifo = lappend(fifo, ptr);
1003  }
1004  }
1005 
1006  UnlockReleaseBuffer(buffer);
1007  }
1008 
1009  elog(ERROR, "failed to re-find parent of a page in index \"%s\", block %u",
1010  RelationGetRelationName(r), child);
1011  return NULL; /* keep compiler quiet */
1012 }
#define GistFollowRight(page)
Definition: gist.h:182
#define NIL
Definition: pg_list.h:65
BlockNumber blkno
Definition: gist_private.h:210
#define GistPageGetNSN(page)
Definition: gist.h:186
#define GistPageIsDeleted(page)
Definition: gist.h:172
ItemPointerData t_tid
Definition: itup.h:37
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define list_make1(x1)
Definition: pg_list.h:206
#define linitial(l)
Definition: pg_list.h:174
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3791
#define ERROR
Definition: elog.h:46
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3008
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
List * lappend(List *list, void *datum)
Definition: list.c:336
#define GistPageIsLeaf(page)
Definition: gist.h:169
OffsetNumber downlinkoffnum
Definition: gist_private.h:228
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void * palloc0(Size size)
Definition: mcxt.c:1093
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
#define InvalidOffsetNumber
Definition: off.h:26
#define GistPageGetOpaque(page)
Definition: gist.h:167
List * lcons(void *datum, List *list)
Definition: list.c:468
#define Assert(condition)
Definition: c.h:804
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:784
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:694
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define InvalidBlockNumber
Definition: block.h:33
#define GIST_SHARE
Definition: gist_private.h:42
#define elog(elevel,...)
Definition: elog.h:232
int i
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
Definition: pg_list.h:50
int Buffer
Definition: buf.h:23
struct GISTInsertStack * parent
Definition: gist_private.h:231
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
List * list_delete_first(List *list)
Definition: list.c:875

◆ gistfinishsplit()

static void gistfinishsplit ( GISTInsertState state,
GISTInsertStack stack,
GISTSTATE giststate,
List splitinfo,
bool  unlockbuf 
)
static

Definition at line 1321 of file gist.c.

References Assert, GISTPageSplitInfo::buf, GISTInsertStack::buffer, GISTPageSplitInfo::downlink, GISTInsertStack::downlinkoffnum, GIST_EXCLUSIVE, gistFindCorrectParent(), gistinserttuples(), InvalidOffsetNumber, linitial, list_length(), list_nth(), LockBuffer(), lsecond, GISTInsertStack::parent, GISTInsertState::r, and GISTInsertStack::retry_from_parent.

Referenced by gistfixsplit(), and gistinserttuples().

1323 {
1324  GISTPageSplitInfo *right;
1325  GISTPageSplitInfo *left;
1326  IndexTuple tuples[2];
1327 
1328  /* A split always contains at least two halves */
1329  Assert(list_length(splitinfo) >= 2);
1330 
1331  /*
1332  * We need to insert downlinks for each new page, and update the downlink
1333  * for the original (leftmost) page in the split. Begin at the rightmost
1334  * page, inserting one downlink at a time until there's only two pages
1335  * left. Finally insert the downlink for the last new page and update the
1336  * downlink for the original page as one operation.
1337  */
1339 
1340  /*
1341  * Insert downlinks for the siblings from right to left, until there are
1342  * only two siblings left.
1343  */
1344  for (int pos = list_length(splitinfo) - 1; pos > 1; pos--)
1345  {
1346  right = (GISTPageSplitInfo *) list_nth(splitinfo, pos);
1347  left = (GISTPageSplitInfo *) list_nth(splitinfo, pos - 1);
1348 
1349  gistFindCorrectParent(state->r, stack);
1350  if (gistinserttuples(state, stack->parent, giststate,
1351  &right->downlink, 1,
1353  left->buf, right->buf, false, false))
1354  {
1355  /*
1356  * If the parent page was split, the existing downlink might have
1357  * moved.
1358  */
1360  }
1361  /* gistinserttuples() released the lock on right->buf. */
1362  }
1363 
1364  right = (GISTPageSplitInfo *) lsecond(splitinfo);
1365  left = (GISTPageSplitInfo *) linitial(splitinfo);
1366 
1367  /*
1368  * Finally insert downlink for the remaining right page and update the
1369  * downlink for the original page to not contain the tuples that were
1370  * moved to the new pages.
1371  */
1372  tuples[0] = left->downlink;
1373  tuples[1] = right->downlink;
1374  gistFindCorrectParent(state->r, stack);
1375  if (gistinserttuples(state, stack->parent, giststate,
1376  tuples, 2,
1377  stack->downlinkoffnum,
1378  left->buf, right->buf,
1379  true, /* Unlock parent */
1380  unlockbuf /* Unlock stack->buffer if caller wants
1381  * that */
1382  ))
1383  {
1384  /*
1385  * If the parent page was split, the downlink might have moved.
1386  */
1388  }
1389 
1390  Assert(left->buf == stack->buffer);
1391 
1392  /*
1393  * If we split the page because we had to adjust the downlink on an
1394  * internal page, while descending the tree for inserting a new tuple,
1395  * then this might no longer be the correct page for the new tuple. The
1396  * downlink to this page might not cover the new tuple anymore, it might
1397  * need to go to the newly-created right sibling instead. Tell the caller
1398  * to walk back up the stack, to re-check at the parent which page to
1399  * insert to.
1400  *
1401  * Normally, the LSN-NSN interlock during the tree descend would also
1402  * detect that a concurrent split happened (by ourselves), and cause us to
1403  * retry at the parent. But that mechanism doesn't work during index
1404  * build, because we don't do WAL-logging, and don't update LSNs, during
1405  * index build.
1406  */
1407  stack->retry_from_parent = true;
1408 }
#define lsecond(l)
Definition: pg_list.h:179
#define linitial(l)
Definition: pg_list.h:174
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
IndexTuple downlink
Definition: gist_private.h:422
OffsetNumber downlinkoffnum
Definition: gist_private.h:228
static void gistFindCorrectParent(Relation r, GISTInsertStack *child)
Definition: gist.c:1020
static bool gistinserttuples(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple *tuples, int ntup, OffsetNumber oldoffnum, Buffer leftchild, Buffer rightchild, bool unlockbuf, bool unlockleftchild)
Definition: gist.c:1261
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
#define GIST_EXCLUSIVE
Definition: gist_private.h:43
struct GISTInsertStack * parent
Definition: gist_private.h:231

◆ gistfixsplit()

static void gistfixsplit ( GISTInsertState state,
GISTSTATE giststate 
)
static

Definition at line 1167 of file gist.c.

References Assert, GISTInsertStack::blkno, buf, GISTPageSplitInfo::buf, GISTInsertStack::buffer, BufferGetPage, GISTPageSplitInfo::downlink, GISTInsertStack::downlinkoffnum, ereport, errmsg(), GIST_EXCLUSIVE, gistfinishsplit(), GistFollowRight, gistformdownlink(), GistPageGetOpaque, lappend(), LockBuffer(), LOG, NIL, OffsetNumberIsValid, GISTInsertStack::page, palloc(), GISTInsertState::r, ReadBuffer(), RelationGetRelationName, and GISTInsertState::stack.

Referenced by gistdoinsert().

1168 {
1169  GISTInsertStack *stack = state->stack;
1170  Buffer buf;
1171  Page page;
1172  List *splitinfo = NIL;
1173 
1174  ereport(LOG,
1175  (errmsg("fixing incomplete split in index \"%s\", block %u",
1176  RelationGetRelationName(state->r), stack->blkno)));
1177 
1178  Assert(GistFollowRight(stack->page));
1180 
1181  buf = stack->buffer;
1182 
1183  /*
1184  * Read the chain of split pages, following the rightlinks. Construct a
1185  * downlink tuple for each page.
1186  */
1187  for (;;)
1188  {
1190  IndexTuple downlink;
1191 
1192  page = BufferGetPage(buf);
1193 
1194  /* Form the new downlink tuples to insert to parent */
1195  downlink = gistformdownlink(state->r, buf, giststate, stack);
1196 
1197  si->buf = buf;
1198  si->downlink = downlink;
1199 
1200  splitinfo = lappend(splitinfo, si);
1201 
1202  if (GistFollowRight(page))
1203  {
1204  /* lock next page */
1205  buf = ReadBuffer(state->r, GistPageGetOpaque(page)->rightlink);
1206  LockBuffer(buf, GIST_EXCLUSIVE);
1207  }
1208  else
1209  break;
1210  }
1211 
1212  /* Insert the downlinks */
1213  gistfinishsplit(state, stack, giststate, splitinfo, false);
1214 }
#define GistFollowRight(page)
Definition: gist.h:182
#define NIL
Definition: pg_list.h:65
BlockNumber blkno
Definition: gist_private.h:210
#define LOG
Definition: elog.h:26
static IndexTuple gistformdownlink(Relation rel, Buffer buf, GISTSTATE *giststate, GISTInsertStack *stack)
Definition: gist.c:1107
IndexTuple downlink
Definition: gist_private.h:422
GISTInsertStack * stack
Definition: gist_private.h:258
static char * buf
Definition: pg_test_fsync.c:68
#define RelationGetRelationName(relation)
Definition: rel.h:511
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
List * lappend(List *list, void *datum)
Definition: list.c:336
OffsetNumber downlinkoffnum
Definition: gist_private.h:228
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
#define ereport(elevel,...)
Definition: elog.h:157
#define GistPageGetOpaque(page)
Definition: gist.h:167
#define Assert(condition)
Definition: c.h:804
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:694
static void gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, List *splitinfo, bool unlockbuf)
Definition: gist.c:1321
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:39
#define GIST_EXCLUSIVE
Definition: gist_private.h:43
Definition: pg_list.h:50
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ gistformdownlink()

static IndexTuple gistformdownlink ( Relation  rel,
Buffer  buf,
GISTSTATE giststate,
GISTInsertStack stack 
)
static

Definition at line 1107 of file gist.c.

References GISTInsertStack::buffer, BufferGetBlockNumber(), BufferGetPage, CopyIndexTuple(), GISTInsertStack::downlinkoffnum, FirstOffsetNumber, GIST_EXCLUSIVE, GIST_UNLOCK, gistFindCorrectParent(), gistgetadjusted(), GistTupleSetValid, ItemPointerSetBlockNumber, LockBuffer(), OffsetNumberNext, GISTInsertStack::page, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, GISTInsertStack::parent, and IndexTupleData::t_tid.

Referenced by gistfixsplit().

1109 {
1110  Page page = BufferGetPage(buf);
1111  OffsetNumber maxoff;
1112  OffsetNumber offset;
1113  IndexTuple downlink = NULL;
1114 
1115  maxoff = PageGetMaxOffsetNumber(page);
1116  for (offset = FirstOffsetNumber; offset <= maxoff; offset = OffsetNumberNext(offset))
1117  {
1118  IndexTuple ituple = (IndexTuple)
1119  PageGetItem(page, PageGetItemId(page, offset));
1120 
1121  if (downlink == NULL)
1122  downlink = CopyIndexTuple(ituple);
1123  else
1124  {
1125  IndexTuple newdownlink;
1126 
1127  newdownlink = gistgetadjusted(rel, downlink, ituple,
1128  giststate);
1129  if (newdownlink)
1130  downlink = newdownlink;
1131  }
1132  }
1133 
1134  /*
1135  * If the page is completely empty, we can't form a meaningful downlink
1136  * for it. But we have to insert a downlink for the page. Any key will do,
1137  * as long as its consistent with the downlink of parent page, so that we
1138  * can legally insert it to the parent. A minimal one that matches as few
1139  * scans as possible would be best, to keep scans from doing useless work,
1140  * but we don't know how to construct that. So we just use the downlink of
1141  * the original page that was split - that's as far from optimal as it can
1142  * get but will do..
1143  */
1144  if (!downlink)
1145  {
1146  ItemId iid;
1147 
1149  gistFindCorrectParent(rel, stack);
1150  iid = PageGetItemId(stack->parent->page, stack->downlinkoffnum);
1151  downlink = (IndexTuple) PageGetItem(stack->parent->page, iid);
1152  downlink = CopyIndexTuple(downlink);
1153  LockBuffer(stack->parent->buffer, GIST_UNLOCK);
1154  }
1155 
1157  GistTupleSetValid(downlink);
1158 
1159  return downlink;
1160 }
ItemPointerData t_tid
Definition: itup.h:37
#define GIST_UNLOCK
Definition: gist_private.h:44
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
IndexTuple gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
Definition: gistutil.c:315
uint16 OffsetNumber
Definition: off.h:24
IndexTuple CopyIndexTuple(IndexTuple source)
Definition: indextuple.c:528
static char * buf
Definition: pg_test_fsync.c:68
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define GistTupleSetValid(itup)
Definition: gist_private.h:289
OffsetNumber downlinkoffnum
Definition: gist_private.h:228
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
static void gistFindCorrectParent(Relation r, GISTInsertStack *child)
Definition: gist.c:1020
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define ItemPointerSetBlockNumber(pointer, blockNumber)
Definition: itemptr.h:138
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2748
#define GIST_EXCLUSIVE
Definition: gist_private.h:43
struct GISTInsertStack * parent
Definition: gist_private.h:231
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ gisthandler()

Datum gisthandler ( PG_FUNCTION_ARGS  )

Definition at line 59 of file gist.c.

References IndexAmRoutine::amadjustmembers, IndexAmRoutine::ambeginscan, IndexAmRoutine::ambuild, IndexAmRoutine::ambuildempty, IndexAmRoutine::ambuildphasename, IndexAmRoutine::ambulkdelete, IndexAmRoutine::amcanbackward, IndexAmRoutine::amcaninclude, IndexAmRoutine::amcanmulticol, IndexAmRoutine::amcanorder, IndexAmRoutine::amcanorderbyop, IndexAmRoutine::amcanparallel, IndexAmRoutine::amcanreturn, IndexAmRoutine::amcanunique, IndexAmRoutine::amclusterable, IndexAmRoutine::amcostestimate, IndexAmRoutine::amendscan, IndexAmRoutine::amestimateparallelscan, IndexAmRoutine::amgetbitmap, IndexAmRoutine::amgettuple, IndexAmRoutine::aminitparallelscan, IndexAmRoutine::aminsert, IndexAmRoutine::amkeytype, IndexAmRoutine::ammarkpos, IndexAmRoutine::amoptionalkey, IndexAmRoutine::amoptions, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amparallelrescan, IndexAmRoutine::amparallelvacuumoptions, IndexAmRoutine::ampredlocks, IndexAmRoutine::amproperty, IndexAmRoutine::amrescan, IndexAmRoutine::amrestrpos, IndexAmRoutine::amsearcharray, IndexAmRoutine::amsearchnulls, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, IndexAmRoutine::amusemaintenanceworkmem, IndexAmRoutine::amvacuumcleanup, IndexAmRoutine::amvalidate, GIST_OPTIONS_PROC, gistadjustmembers(), gistbeginscan(), gistbuild(), gistbuildempty(), gistbulkdelete(), gistcanreturn(), gistcostestimate(), gistendscan(), gistgetbitmap(), gistgettuple(), gistinsert(), GISTNProcs, gistoptions(), gistproperty(), gistrescan(), gistvacuumcleanup(), gistvalidate(), InvalidOid, makeNode, PG_RETURN_POINTER, VACUUM_OPTION_PARALLEL_BULKDEL, and VACUUM_OPTION_PARALLEL_COND_CLEANUP.

60 {
62 
63  amroutine->amstrategies = 0;
64  amroutine->amsupport = GISTNProcs;
65  amroutine->amoptsprocnum = GIST_OPTIONS_PROC;
66  amroutine->amcanorder = false;
67  amroutine->amcanorderbyop = true;
68  amroutine->amcanbackward = false;
69  amroutine->amcanunique = false;
70  amroutine->amcanmulticol = true;
71  amroutine->amoptionalkey = true;
72  amroutine->amsearcharray = false;
73  amroutine->amsearchnulls = true;
74  amroutine->amstorage = true;
75  amroutine->amclusterable = true;
76  amroutine->ampredlocks = true;
77  amroutine->amcanparallel = false;
78  amroutine->amcaninclude = true;
79  amroutine->amusemaintenanceworkmem = false;
80  amroutine->amparallelvacuumoptions =
82  amroutine->amkeytype = InvalidOid;
83 
84  amroutine->ambuild = gistbuild;
85  amroutine->ambuildempty = gistbuildempty;
86  amroutine->aminsert = gistinsert;
87  amroutine->ambulkdelete = gistbulkdelete;
89  amroutine->amcanreturn = gistcanreturn;
90  amroutine->amcostestimate = gistcostestimate;
91  amroutine->amoptions = gistoptions;
92  amroutine->amproperty = gistproperty;
93  amroutine->ambuildphasename = NULL;
94  amroutine->amvalidate = gistvalidate;
96  amroutine->ambeginscan = gistbeginscan;
97  amroutine->amrescan = gistrescan;
98  amroutine->amgettuple = gistgettuple;
99  amroutine->amgetbitmap = gistgetbitmap;
100  amroutine->amendscan = gistendscan;
101  amroutine->ammarkpos = NULL;
102  amroutine->amrestrpos = NULL;
103  amroutine->amestimateparallelscan = NULL;
104  amroutine->aminitparallelscan = NULL;
105  amroutine->amparallelrescan = NULL;
106 
107  PG_RETURN_POINTER(amroutine);
108 }
#define GIST_OPTIONS_PROC
Definition: gist.h:39
ambeginscan_function ambeginscan
Definition: amapi.h:271
uint8 amparallelvacuumoptions
Definition: amapi.h:248
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
ambulkdelete_function ambulkdelete
Definition: amapi.h:262
bool amcanmulticol
Definition: amapi.h:228
uint16 amsupport
Definition: amapi.h:216
amgettuple_function amgettuple
Definition: amapi.h:273
IndexBulkDeleteResult * gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: gistvacuum.c:75
bool amcanorderbyop
Definition: amapi.h:222
amproperty_function amproperty
Definition: amapi.h:267
IndexBulkDeleteResult * gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: gistvacuum.c:59
amparallelrescan_function amparallelrescan
Definition: amapi.h:282
bool amstorage
Definition: amapi.h:236
bool gistgettuple(IndexScanDesc scan, ScanDirection dir)
Definition: gistget.c:614
bool ampredlocks
Definition: amapi.h:240
aminsert_function aminsert
Definition: amapi.h:261
void gistadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
Definition: gistvalidate.c:291
bytea * gistoptions(Datum reloptions, bool validate)
Definition: gistutil.c:920
Oid amkeytype
Definition: amapi.h:250
bool amoptionalkey
Definition: amapi.h:230
amvalidate_function amvalidate
Definition: amapi.h:269
IndexBuildResult * gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: gistbuild.c:175
bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: gist.c:156
amgetbitmap_function amgetbitmap
Definition: amapi.h:274
ambuild_function ambuild
Definition: amapi.h:259
amoptions_function amoptions
Definition: amapi.h:266
bool amcaninclude
Definition: amapi.h:244
amcostestimate_function amcostestimate
Definition: amapi.h:265
bool amcanunique
Definition: amapi.h:226
void gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, ScanKey orderbys, int norderbys)
Definition: gistscan.c:127
void gistcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition: selfuncs.c:6961
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:263
amendscan_function amendscan
Definition: amapi.h:275
bool amcanbackward
Definition: amapi.h:224
amrescan_function amrescan
Definition: amapi.h:272
bool amcanparallel
Definition: amapi.h:242
int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: gistget.c:745
void gistbuildempty(Relation index)
Definition: gist.c:130
bool amsearchnulls
Definition: amapi.h:234
bool amclusterable
Definition: amapi.h:238
bool amsearcharray
Definition: amapi.h:232
#define InvalidOid
Definition: postgres_ext.h:36
bool amusemaintenanceworkmem
Definition: amapi.h:246
bool gistcanreturn(Relation index, int attno)
Definition: gistget.c:795
#define makeNode(_type_)
Definition: nodes.h:584
amadjustmembers_function amadjustmembers
Definition: amapi.h:270
#define VACUUM_OPTION_PARALLEL_COND_CLEANUP
Definition: vacuum.h:52
ammarkpos_function ammarkpos
Definition: amapi.h:276
bool amcanorder
Definition: amapi.h:220
ambuildphasename_function ambuildphasename
Definition: amapi.h:268
#define VACUUM_OPTION_PARALLEL_BULKDEL
Definition: vacuum.h:45
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:280
#define GISTNProcs
Definition: gist.h:41
uint16 amstrategies
Definition: amapi.h:214
bool gistvalidate(Oid opclassoid)
Definition: gistvalidate.c:34
uint16 amoptsprocnum
Definition: amapi.h:218
ambuildempty_function ambuildempty
Definition: amapi.h:260
IndexScanDesc gistbeginscan(Relation r, int nkeys, int norderbys)
Definition: gistscan.c:74
void gistendscan(IndexScanDesc scan)
Definition: gistscan.c:349
bool gistproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
Definition: gistutil.c:941
amcanreturn_function amcanreturn
Definition: amapi.h:264
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:281
amrestrpos_function amrestrpos
Definition: amapi.h:277

◆ gistinsert()

bool gistinsert ( Relation  r,
Datum values,
bool isnull,
ItemPointer  ht_ctid,
Relation  heapRel,
IndexUniqueCheck  checkUnique,
bool  indexUnchanged,
IndexInfo indexInfo 
)

Definition at line 156 of file gist.c.

References createTempGistContext(), gistdoinsert(), gistFormTuple(), IndexInfo::ii_AmCache, IndexInfo::ii_Context, initGISTstate(), MemoryContextReset(), MemoryContextSwitchTo(), and GISTSTATE::tempCxt.

Referenced by gisthandler().

161 {
162  GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
163  IndexTuple itup;
164  MemoryContext oldCxt;
165 
166  /* Initialize GISTSTATE cache if first call in this statement */
167  if (giststate == NULL)
168  {
169  oldCxt = MemoryContextSwitchTo(indexInfo->ii_Context);
170  giststate = initGISTstate(r);
171  giststate->tempCxt = createTempGistContext();
172  indexInfo->ii_AmCache = (void *) giststate;
173  MemoryContextSwitchTo(oldCxt);
174  }
175 
176  oldCxt = MemoryContextSwitchTo(giststate->tempCxt);
177 
178  itup = gistFormTuple(giststate, r,
179  values, isnull, true /* size is currently bogus */ );
180  itup->t_tid = *ht_ctid;
181 
182  gistdoinsert(r, itup, 0, giststate, heapRel, false);
183 
184  /* cleanup */
185  MemoryContextSwitchTo(oldCxt);
186  MemoryContextReset(giststate->tempCxt);
187 
188  return false;
189 }
MemoryContext ii_Context
Definition: execnodes.h:179
MemoryContext createTempGistContext(void)
Definition: gist.c:119
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:143
void gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate, Relation heapRel, bool is_build)
Definition: gist.c:632
MemoryContext tempCxt
Definition: gist_private.h:78
void * ii_AmCache
Definition: execnodes.h:178
GISTSTATE * initGISTstate(Relation index)
Definition: gist.c:1503
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum *attdata, bool *isnull, bool isleaf)
Definition: gistutil.c:574
static Datum values[MAXATTR]
Definition: bootstrap.c:156

◆ gistinserttuple()

static bool gistinserttuple ( GISTInsertState state,
GISTInsertStack stack,
GISTSTATE giststate,
IndexTuple  tuple,
OffsetNumber  oldoffnum 
)
static

Definition at line 1227 of file gist.c.

References gistinserttuples(), and InvalidBuffer.

Referenced by gistdoinsert().

1229 {
1230  return gistinserttuples(state, stack, giststate, &tuple, 1, oldoffnum,
1231  InvalidBuffer, InvalidBuffer, false, false);
1232 }
#define InvalidBuffer
Definition: buf.h:25
static bool gistinserttuples(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple *tuples, int ntup, OffsetNumber oldoffnum, Buffer leftchild, Buffer rightchild, bool unlockbuf, bool unlockleftchild)
Definition: gist.c:1261

◆ gistinserttuples()

static bool gistinserttuples ( GISTInsertState state,
GISTInsertStack stack,
GISTSTATE giststate,
IndexTuple tuples,
int  ntup,
OffsetNumber  oldoffnum,
Buffer  leftchild,
Buffer  rightchild,
bool  unlockbuf,
bool  unlockleftchild 
)
static

Definition at line 1261 of file gist.c.

References GISTInsertStack::buffer, BufferGetBlockNumber(), BufferIsValid, CheckForSerializableConflictIn(), GISTInsertState::freespace, GIST_UNLOCK, gistfinishsplit(), gistplacetopage(), GISTInsertState::heapRel, GISTInsertState::is_build, LockBuffer(), GISTInsertState::r, and UnlockReleaseBuffer().

Referenced by gistfinishsplit(), and gistinserttuple().

1266 {
1267  List *splitinfo;
1268  bool is_split;
1269 
1270  /*
1271  * Check for any rw conflicts (in serializable isolation level) just
1272  * before we intend to modify the page
1273  */
1275 
1276  /* Insert the tuple(s) to the page, splitting the page if necessary */
1277  is_split = gistplacetopage(state->r, state->freespace, giststate,
1278  stack->buffer,
1279  tuples, ntup,
1280  oldoffnum, NULL,
1281  leftchild,
1282  &splitinfo,
1283  true,
1284  state->heapRel,
1285  state->is_build);
1286 
1287  /*
1288  * Before recursing up in case the page was split, release locks on the
1289  * child pages. We don't need to keep them locked when updating the
1290  * parent.
1291  */
1294  if (BufferIsValid(leftchild) && unlockleftchild)
1296 
1297  /*
1298  * If we had to split, insert/update the downlinks in the parent. If the
1299  * caller requested us to release the lock on stack->buffer, tell
1300  * gistfinishsplit() to do that as soon as it's safe to do so. If we
1301  * didn't have to split, release it ourselves.
1302  */
1303  if (splitinfo)
1304  gistfinishsplit(state, stack, giststate, splitinfo, unlockbuf);
1305  else if (unlockbuf)
1306  LockBuffer(stack->buffer, GIST_UNLOCK);
1307 
1308  return is_split;
1309 }
Relation heapRel
Definition: gist_private.h:254
bool gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, Buffer buffer, IndexTuple *itup, int ntup, OffsetNumber oldoffnum, BlockNumber *newblkno, Buffer leftchildbuf, List **splitinfo, bool markfollowright, Relation heapRel, bool is_build)
Definition: gist.c:222
#define GIST_UNLOCK
Definition: gist_private.h:44
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3791
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4446
#define rightchild(x)
Definition: fsmpage.c:30
#define leftchild(x)
Definition: fsmpage.c:29
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
static void gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, List *splitinfo, bool unlockbuf)
Definition: gist.c:1321
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2748
Definition: pg_list.h:50

◆ gistplacetopage()

bool gistplacetopage ( Relation  rel,
Size  freespace,
GISTSTATE giststate,
Buffer  buffer,
IndexTuple itup,
int  ntup,
OffsetNumber  oldoffnum,
BlockNumber newblkno,
Buffer  leftchildbuf,
List **  splitinfo,
bool  markfollowright,
Relation  heapRel,
bool  is_build 
)

Definition at line 222 of file gist.c.

References Assert, DataPageDeleteStack::blkno, gistxlogPage::blkno, SplitedPageLayout::block, GISTPageSplitInfo::buf, SplitedPageLayout::buffer, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, GISTPageSplitInfo::downlink, elog, END_CRIT_SECTION, ERROR, F_LEAF, FirstOffsetNumber, GIST_MAX_SPLIT_PAGES, GIST_ROOT_BLKNO, GistBuildLSN, GistClearFollowRight, gistextractpage(), gistfillbuffer(), gistfillitupvec(), GistFollowRight, gistGetFakeLSN(), GISTInitBuffer(), gistjoinvector(), GistMarkFollowRight, gistNewBuffer(), gistnospace(), GistPageGetNSN, GistPageGetOpaque, GistPageHasGarbage, GistPageIsDeleted, GistPageIsLeaf, GistPageSetNSN, gistprunepage(), gistSplit(), GistTupleSetValid, gistXLogSplit(), gistXLogUpdate(), i, IndexTupleSize, InvalidBlockNumber, InvalidOffsetNumber, ItemPointerEquals(), ItemPointerSetBlockNumber, SplitedPageLayout::itup, lappend(), SplitedPageLayout::lenlist, SplitedPageLayout::list, MarkBufferDirty(), SplitedPageLayout::next, NIL, gistxlogPage::num, OffsetNumberIsValid, SplitedPageLayout::page, PageAddItem, PageGetTempPageCopySpecial(), PageIndexTupleDelete(), PageIndexTupleOverwrite(), PageRestoreTempPage(), PageSetLSN, palloc(), PredicateLockPageSplit(), RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, IndexTupleData::t_tid, UnlockReleaseBuffer(), and XLogEnsureRecordSpace().

Referenced by gistbufferinginserttuples(), and gistinserttuples().

231 {
232  BlockNumber blkno = BufferGetBlockNumber(buffer);
233  Page page = BufferGetPage(buffer);
234  bool is_leaf = (GistPageIsLeaf(page)) ? true : false;
235  XLogRecPtr recptr;
236  int i;
237  bool is_split;
238 
239  /*
240  * Refuse to modify a page that's incompletely split. This should not
241  * happen because we finish any incomplete splits while we walk down the
242  * tree. However, it's remotely possible that another concurrent inserter
243  * splits a parent page, and errors out before completing the split. We
244  * will just throw an error in that case, and leave any split we had in
245  * progress unfinished too. The next insert that comes along will clean up
246  * the mess.
247  */
248  if (GistFollowRight(page))
249  elog(ERROR, "concurrent GiST page split was incomplete");
250 
251  /* should never try to insert to a deleted page */
252  Assert(!GistPageIsDeleted(page));
253 
254  *splitinfo = NIL;
255 
256  /*
257  * if isupdate, remove old key: This node's key has been modified, either
258  * because a child split occurred or because we needed to adjust our key
259  * for an insert in a child node. Therefore, remove the old version of
260  * this node's key.
261  *
262  * for WAL replay, in the non-split case we handle this by setting up a
263  * one-element todelete array; in the split case, it's handled implicitly
264  * because the tuple vector passed to gistSplit won't include this tuple.
265  */
266  is_split = gistnospace(page, itup, ntup, oldoffnum, freespace);
267 
268  /*
269  * If leaf page is full, try at first to delete dead tuples. And then
270  * check again.
271  */
272  if (is_split && GistPageIsLeaf(page) && GistPageHasGarbage(page))
273  {
274  gistprunepage(rel, page, buffer, heapRel);
275  is_split = gistnospace(page, itup, ntup, oldoffnum, freespace);
276  }
277 
278  if (is_split)
279  {
280  /* no space for insertion */
281  IndexTuple *itvec;
282  int tlen;
283  SplitedPageLayout *dist = NULL,
284  *ptr;
285  BlockNumber oldrlink = InvalidBlockNumber;
286  GistNSN oldnsn = 0;
287  SplitedPageLayout rootpg;
288  bool is_rootsplit;
289  int npage;
290 
291  is_rootsplit = (blkno == GIST_ROOT_BLKNO);
292 
293  /*
294  * Form index tuples vector to split. If we're replacing an old tuple,
295  * remove the old version from the vector.
296  */
297  itvec = gistextractpage(page, &tlen);
298  if (OffsetNumberIsValid(oldoffnum))
299  {
300  /* on inner page we should remove old tuple */
301  int pos = oldoffnum - FirstOffsetNumber;
302 
303  tlen--;
304  if (pos != tlen)
305  memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
306  }
307  itvec = gistjoinvector(itvec, &tlen, itup, ntup);
308  dist = gistSplit(rel, page, itvec, tlen, giststate);
309 
310  /*
311  * Check that split didn't produce too many pages.
312  */
313  npage = 0;
314  for (ptr = dist; ptr; ptr = ptr->next)
315  npage++;
316  /* in a root split, we'll add one more page to the list below */
317  if (is_rootsplit)
318  npage++;
319  if (npage > GIST_MAX_SPLIT_PAGES)
320  elog(ERROR, "GiST page split into too many halves (%d, maximum %d)",
321  npage, GIST_MAX_SPLIT_PAGES);
322 
323  /*
324  * Set up pages to work with. Allocate new buffers for all but the
325  * leftmost page. The original page becomes the new leftmost page, and
326  * is just replaced with the new contents.
327  *
328  * For a root-split, allocate new buffers for all child pages, the
329  * original page is overwritten with new root page containing
330  * downlinks to the new child pages.
331  */
332  ptr = dist;
333  if (!is_rootsplit)
334  {
335  /* save old rightlink and NSN */
336  oldrlink = GistPageGetOpaque(page)->rightlink;
337  oldnsn = GistPageGetNSN(page);
338 
339  dist->buffer = buffer;
340  dist->block.blkno = BufferGetBlockNumber(buffer);
342 
343  /* clean all flags except F_LEAF */
344  GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
345 
346  ptr = ptr->next;
347  }
348  for (; ptr; ptr = ptr->next)
349  {
350  /* Allocate new page */
351  ptr->buffer = gistNewBuffer(rel);
352  GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
353  ptr->page = BufferGetPage(ptr->buffer);
354  ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
356  BufferGetBlockNumber(buffer),
357  BufferGetBlockNumber(ptr->buffer));
358  }
359 
360  /*
361  * Now that we know which blocks the new pages go to, set up downlink
362  * tuples to point to them.
363  */
364  for (ptr = dist; ptr; ptr = ptr->next)
365  {
366  ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
367  GistTupleSetValid(ptr->itup);
368  }
369 
370  /*
371  * If this is a root split, we construct the new root page with the
372  * downlinks here directly, instead of requiring the caller to insert
373  * them. Add the new root page to the list along with the child pages.
374  */
375  if (is_rootsplit)
376  {
377  IndexTuple *downlinks;
378  int ndownlinks = 0;
379  int i;
380 
381  rootpg.buffer = buffer;
383  GistPageGetOpaque(rootpg.page)->flags = 0;
384 
385  /* Prepare a vector of all the downlinks */
386  for (ptr = dist; ptr; ptr = ptr->next)
387  ndownlinks++;
388  downlinks = palloc(sizeof(IndexTuple) * ndownlinks);
389  for (i = 0, ptr = dist; ptr; ptr = ptr->next)
390  downlinks[i++] = ptr->itup;
391 
392  rootpg.block.blkno = GIST_ROOT_BLKNO;
393  rootpg.block.num = ndownlinks;
394  rootpg.list = gistfillitupvec(downlinks, ndownlinks,
395  &(rootpg.lenlist));
396  rootpg.itup = NULL;
397 
398  rootpg.next = dist;
399  dist = &rootpg;
400  }
401  else
402  {
403  /* Prepare split-info to be returned to caller */
404  for (ptr = dist; ptr; ptr = ptr->next)
405  {
407 
408  si->buf = ptr->buffer;
409  si->downlink = ptr->itup;
410  *splitinfo = lappend(*splitinfo, si);
411  }
412  }
413 
414  /*
415  * Fill all pages. All the pages are new, ie. freshly allocated empty
416  * pages, or a temporary copy of the old page.
417  */
418  for (ptr = dist; ptr; ptr = ptr->next)
419  {
420  char *data = (char *) (ptr->list);
421 
422  for (i = 0; i < ptr->block.num; i++)
423  {
424  IndexTuple thistup = (IndexTuple) data;
425 
426  if (PageAddItem(ptr->page, (Item) data, IndexTupleSize(thistup), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)
427  elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(rel));
428 
429  /*
430  * If this is the first inserted/updated tuple, let the caller
431  * know which page it landed on.
432  */
433  if (newblkno && ItemPointerEquals(&thistup->t_tid, &(*itup)->t_tid))
434  *newblkno = ptr->block.blkno;
435 
436  data += IndexTupleSize(thistup);
437  }
438 
439  /* Set up rightlinks */
440  if (ptr->next && ptr->block.blkno != GIST_ROOT_BLKNO)
441  GistPageGetOpaque(ptr->page)->rightlink =
442  ptr->next->block.blkno;
443  else
444  GistPageGetOpaque(ptr->page)->rightlink = oldrlink;
445 
446  /*
447  * Mark the all but the right-most page with the follow-right
448  * flag. It will be cleared as soon as the downlink is inserted
449  * into the parent, but this ensures that if we error out before
450  * that, the index is still consistent. (in buffering build mode,
451  * any error will abort the index build anyway, so this is not
452  * needed.)
453  */
454  if (ptr->next && !is_rootsplit && markfollowright)
455  GistMarkFollowRight(ptr->page);
456  else
457  GistClearFollowRight(ptr->page);
458 
459  /*
460  * Copy the NSN of the original page to all pages. The
461  * F_FOLLOW_RIGHT flags ensure that scans will follow the
462  * rightlinks until the downlinks are inserted.
463  */
464  GistPageSetNSN(ptr->page, oldnsn);
465  }
466 
467  /*
468  * gistXLogSplit() needs to WAL log a lot of pages, prepare WAL
469  * insertion for that. NB: The number of pages and data segments
470  * specified here must match the calculations in gistXLogSplit()!
471  */
472  if (!is_build && RelationNeedsWAL(rel))
473  XLogEnsureRecordSpace(npage, 1 + npage * 2);
474 
476 
477  /*
478  * Must mark buffers dirty before XLogInsert, even though we'll still
479  * be changing their opaque fields below.
480  */
481  for (ptr = dist; ptr; ptr = ptr->next)
482  MarkBufferDirty(ptr->buffer);
483  if (BufferIsValid(leftchildbuf))
484  MarkBufferDirty(leftchildbuf);
485 
486  /*
487  * The first page in the chain was a temporary working copy meant to
488  * replace the old page. Copy it over the old page.
489  */
491  dist->page = BufferGetPage(dist->buffer);
492 
493  /*
494  * Write the WAL record.
495  *
496  * If we're building a new index, however, we don't WAL-log changes
497  * yet. The LSN-NSN interlock between parent and child requires that
498  * LSNs never move backwards, so set the LSNs to a value that's
499  * smaller than any real or fake unlogged LSN that might be generated
500  * later. (There can't be any concurrent scans during index build, so
501  * we don't need to be able to detect concurrent splits yet.)
502  */
503  if (is_build)
504  recptr = GistBuildLSN;
505  else
506  {
507  if (RelationNeedsWAL(rel))
508  recptr = gistXLogSplit(is_leaf,
509  dist, oldrlink, oldnsn, leftchildbuf,
510  markfollowright);
511  else
512  recptr = gistGetFakeLSN(rel);
513  }
514 
515  for (ptr = dist; ptr; ptr = ptr->next)
516  PageSetLSN(ptr->page, recptr);
517 
518  /*
519  * Return the new child buffers to the caller.
520  *
521  * If this was a root split, we've already inserted the downlink
522  * pointers, in the form of a new root page. Therefore we can release
523  * all the new buffers, and keep just the root page locked.
524  */
525  if (is_rootsplit)
526  {
527  for (ptr = dist->next; ptr; ptr = ptr->next)
528  UnlockReleaseBuffer(ptr->buffer);
529  }
530  }
531  else
532  {
533  /*
534  * Enough space. We always get here if ntup==0.
535  */
537 
538  /*
539  * Delete old tuple if any, then insert new tuple(s) if any. If
540  * possible, use the fast path of PageIndexTupleOverwrite.
541  */
542  if (OffsetNumberIsValid(oldoffnum))
543  {
544  if (ntup == 1)
545  {
546  /* One-for-one replacement, so use PageIndexTupleOverwrite */
547  if (!PageIndexTupleOverwrite(page, oldoffnum, (Item) *itup,
548  IndexTupleSize(*itup)))
549  elog(ERROR, "failed to add item to index page in \"%s\"",
551  }
552  else
553  {
554  /* Delete old, then append new tuple(s) to page */
555  PageIndexTupleDelete(page, oldoffnum);
556  gistfillbuffer(page, itup, ntup, InvalidOffsetNumber);
557  }
558  }
559  else
560  {
561  /* Just append new tuples at the end of the page */
562  gistfillbuffer(page, itup, ntup, InvalidOffsetNumber);
563  }
564 
565  MarkBufferDirty(buffer);
566 
567  if (BufferIsValid(leftchildbuf))
568  MarkBufferDirty(leftchildbuf);
569 
570  if (is_build)
571  recptr = GistBuildLSN;
572  else
573  {
574  if (RelationNeedsWAL(rel))
575  {
576  OffsetNumber ndeloffs = 0,
577  deloffs[1];
578 
579  if (OffsetNumberIsValid(oldoffnum))
580  {
581  deloffs[0] = oldoffnum;
582  ndeloffs = 1;
583  }
584 
585  recptr = gistXLogUpdate(buffer,
586  deloffs, ndeloffs, itup, ntup,
587  leftchildbuf);
588  }
589  else
590  recptr = gistGetFakeLSN(rel);
591  }
592  PageSetLSN(page, recptr);
593 
594  if (newblkno)
595  *newblkno = blkno;
596  }
597 
598  /*
599  * If we inserted the downlink for a child page, set NSN and clear
600  * F_FOLLOW_RIGHT flag on the left child, so that concurrent scans know to
601  * follow the rightlink if and only if they looked at the parent page
602  * before we inserted the downlink.
603  *
604  * Note that we do this *after* writing the WAL record. That means that
605  * the possible full page image in the WAL record does not include these
606  * changes, and they must be replayed even if the page is restored from
607  * the full page image. There's a chicken-and-egg problem: if we updated
608  * the child pages first, we wouldn't know the recptr of the WAL record
609  * we're about to write.
610  */
611  if (BufferIsValid(leftchildbuf))
612  {
613  Page leftpg = BufferGetPage(leftchildbuf);
614 
615  GistPageSetNSN(leftpg, recptr);
616  GistClearFollowRight(leftpg);
617 
618  PageSetLSN(leftpg, recptr);
619  }
620 
622 
623  return is_split;
624 }
#define GistFollowRight(page)
Definition: gist.h:182
#define NIL
Definition: pg_list.h:65
#define GistPageGetNSN(page)
Definition: gist.h:186
#define GistBuildLSN
Definition: gist.h:69
#define GistPageIsDeleted(page)
Definition: gist.h:172
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:424
BlockNumber blkno
Definition: gist_private.h:186
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1045
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1565
ItemPointerData t_tid
Definition: itup.h:37
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition: gistutil.c:33
#define END_CRIT_SECTION()
Definition: miscadmin.h:149
Pointer Item
Definition: item.h:17
#define GistPageSetNSN(page, val)
Definition: gist.h:187
#define START_CRIT_SECTION()
Definition: miscadmin.h:147
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
#define GistPageHasGarbage(page)
Definition: gist.h:178
uint32 BlockNumber
Definition: block.h:31
IndexTupleData * list
Definition: gist_private.h:194
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:1024
uint16 OffsetNumber
Definition: off.h:24
Page PageGetTempPageCopySpecial(Page page)
Definition: bufpage.c:402
gistxlogPage block
Definition: gist_private.h:193
XLogRecPtr gistXLogSplit(bool page_is_leaf, SplitedPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
Definition: gistxlog.c:500
IndexTuple * gistextractpage(Page page, int *len)
Definition: gistutil.c:94
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3791
#define ERROR
Definition: elog.h:46
#define GIST_MAX_SPLIT_PAGES
Definition: gist_private.h:39
IndexTuple downlink
Definition: gist_private.h:422
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1398
static void gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel)
Definition: gist.c:1642
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
Definition: gistutil.c:58
#define RelationGetRelationName(relation)
Definition: rel.h:511
struct SplitedPageLayout * next
Definition: gist_private.h:200
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
List * lappend(List *list, void *datum)
Definition: list.c:336
#define GistPageIsLeaf(page)
Definition: gist.h:169
#define GistTupleSetValid(itup)
Definition: gist_private.h:289
#define GistClearFollowRight(page)
Definition: gist.h:184
IndexTuple * gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
Definition: gistutil.c:113
SplitedPageLayout * gistSplit(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition: gist.c:1416
#define InvalidOffsetNumber
Definition: off.h:26
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition: gistxlog.c:632
#define GistPageGetOpaque(page)
Definition: gist.h:167
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:804
IndexTupleData * gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
Definition: gistutil.c:126
#define InvalidBlockNumber
Definition: block.h:33
void XLogEnsureRecordSpace(int max_block_id, int ndatas)
Definition: xloginsert.c:161
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
#define ItemPointerSetBlockNumber(pointer, blockNumber)
Definition: itemptr.h:138
#define GistMarkFollowRight(page)
Definition: gist.h:183
#define RelationNeedsWAL(relation)
Definition: rel.h:601
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
XLogRecPtr GistNSN
Definition: gist.h:62
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2748
void * palloc(Size size)
Definition: mcxt.c:1062
#define F_LEAF
Definition: gist.h:46
#define elog(elevel,...)
Definition: elog.h:232
int i
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:39
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:772
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
Buffer gistNewBuffer(Relation r)
Definition: gistutil.c:823
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3167
Pointer Page
Definition: bufpage.h:78
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gistprunepage()

static void gistprunepage ( Relation  rel,
Page  page,
Buffer  buffer,
Relation  heapRel 
)
static

Definition at line 1642 of file gist.c.

References Assert, END_CRIT_SECTION, FirstOffsetNumber, GistClearPageHasGarbage, gistGetFakeLSN(), GistPageIsLeaf, gistXLogDelete(), index_compute_xid_horizon_for_tuples(), InvalidTransactionId, ItemIdIsDead, MarkBufferDirty(), MaxIndexTuplesPerPage, OffsetNumberNext, PageGetItemId, PageGetMaxOffsetNumber, PageIndexMultiDelete(), PageSetLSN, RelationNeedsWAL, START_CRIT_SECTION, and XLogStandbyInfoActive.

Referenced by gistplacetopage().

1643 {
1645  int ndeletable = 0;
1646  OffsetNumber offnum,
1647  maxoff;
1648 
1649  Assert(GistPageIsLeaf(page));
1650 
1651  /*
1652  * Scan over all items to see which ones need to be deleted according to
1653  * LP_DEAD flags.
1654  */
1655  maxoff = PageGetMaxOffsetNumber(page);
1656  for (offnum = FirstOffsetNumber;
1657  offnum <= maxoff;
1658  offnum = OffsetNumberNext(offnum))
1659  {
1660  ItemId itemId = PageGetItemId(page, offnum);
1661 
1662  if (ItemIdIsDead(itemId))
1663  deletable[ndeletable++] = offnum;
1664  }
1665 
1666  if (ndeletable > 0)
1667  {
1668  TransactionId latestRemovedXid = InvalidTransactionId;
1669 
1671  latestRemovedXid =
1672  index_compute_xid_horizon_for_tuples(rel, heapRel, buffer,
1673  deletable, ndeletable);
1674 
1676 
1677  PageIndexMultiDelete(page, deletable, ndeletable);
1678 
1679  /*
1680  * Mark the page as not containing any LP_DEAD items. This is not
1681  * certainly true (there might be some that have recently been marked,
1682  * but weren't included in our target-item list), but it will almost
1683  * always be true and it doesn't seem worth an additional page scan to
1684  * check it. Remember that F_HAS_GARBAGE is only a hint anyway.
1685  */
1687 
1688  MarkBufferDirty(buffer);
1689 
1690  /* XLOG stuff */
1691  if (RelationNeedsWAL(rel))
1692  {
1693  XLogRecPtr recptr;
1694 
1695  recptr = gistXLogDelete(buffer,
1696  deletable, ndeletable,
1697  latestRemovedXid);
1698 
1699  PageSetLSN(page, recptr);
1700  }
1701  else
1702  PageSetLSN(page, gistGetFakeLSN(rel));
1703 
1704  END_CRIT_SECTION();
1705  }
1706 
1707  /*
1708  * Note: if we didn't find any LP_DEAD items, then the page's
1709  * F_HAS_GARBAGE hint bit is falsely set. We do not bother expending a
1710  * separate write to clear it, however. We will clear it when we split
1711  * the page.
1712  */
1713 }
uint32 TransactionId
Definition: c.h:587
#define GistClearPageHasGarbage(page)
Definition: gist.h:180
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1565
#define END_CRIT_SECTION()
Definition: miscadmin.h:149
#define START_CRIT_SECTION()
Definition: miscadmin.h:147
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:1024
XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete, TransactionId latestRemovedXid)
Definition: gistxlog.c:673
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
#define InvalidTransactionId
Definition: transam.h:31
#define GistPageIsLeaf(page)
Definition: gist.h:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define XLogStandbyInfoActive()
Definition: xlog.h:180
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:804
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1154
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define RelationNeedsWAL(relation)
Definition: rel.h:601
#define MaxIndexTuplesPerPage
Definition: itup.h:145
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
TransactionId index_compute_xid_horizon_for_tuples(Relation irel, Relation hrel, Buffer ibuf, OffsetNumber *itemnos, int nitems)
Definition: genam.c:293

◆ gistSplit()

SplitedPageLayout* gistSplit ( Relation  r,
Page  page,
IndexTuple itup,
int  len,
GISTSTATE giststate 
)

Definition at line 1416 of file gist.c.

References Assert, SplitedPageLayout::block, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, gistfillitupvec(), gistfitpage(), gistFormTuple(), GiSTPageSize, gistSplit(), gistSplitByKey(), i, IndexTupleSize, SplitedPageLayout::itup, SplitedPageLayout::lenlist, SplitedPageLayout::list, TupleDescData::natts, SplitedPageLayout::next, GISTSTATE::nonLeafTupdesc, gistxlogPage::num, palloc(), RelationGetRelationName, ROTATEDIST, GistSplitVector::spl_lattr, GIST_SPLITVEC::spl_left, GistSplitVector::spl_lisnull, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GistSplitVector::spl_rattr, GIST_SPLITVEC::spl_right, GistSplitVector::spl_risnull, and GistSplitVector::splitVector.

Referenced by gistplacetopage(), and gistSplit().

1421 {
1422  IndexTuple *lvectup,
1423  *rvectup;
1424  GistSplitVector v;
1425  int i;
1426  SplitedPageLayout *res = NULL;
1427 
1428  /* this should never recurse very deeply, but better safe than sorry */
1430 
1431  /* there's no point in splitting an empty page */
1432  Assert(len > 0);
1433 
1434  /*
1435  * If a single tuple doesn't fit on a page, no amount of splitting will
1436  * help.
1437  */
1438  if (len == 1)
1439  ereport(ERROR,
1440  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1441  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
1442  IndexTupleSize(itup[0]), GiSTPageSize,
1444 
1445  memset(v.spl_lisnull, true,
1446  sizeof(bool) * giststate->nonLeafTupdesc->natts);
1447  memset(v.spl_risnull, true,
1448  sizeof(bool) * giststate->nonLeafTupdesc->natts);
1449  gistSplitByKey(r, page, itup, len, giststate, &v, 0);
1450 
1451  /* form left and right vector */
1452  lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
1453  rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
1454 
1455  for (i = 0; i < v.splitVector.spl_nleft; i++)
1456  lvectup[i] = itup[v.splitVector.spl_left[i] - 1];
1457 
1458  for (i = 0; i < v.splitVector.spl_nright; i++)
1459  rvectup[i] = itup[v.splitVector.spl_right[i] - 1];
1460 
1461  /* finalize splitting (may need another split) */
1462  if (!gistfitpage(rvectup, v.splitVector.spl_nright))
1463  {
1464  res = gistSplit(r, page, rvectup, v.splitVector.spl_nright, giststate);
1465  }
1466  else
1467  {
1468  ROTATEDIST(res);
1469  res->block.num = v.splitVector.spl_nright;
1470  res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &(res->lenlist));
1471  res->itup = gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false);
1472  }
1473 
1474  if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
1475  {
1476  SplitedPageLayout *resptr,
1477  *subres;
1478 
1479  resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
1480 
1481  /* install on list's tail */
1482  while (resptr->next)
1483  resptr = resptr->next;
1484 
1485  resptr->next = res;
1486  res = subres;
1487  }
1488  else
1489  {
1490  ROTATEDIST(res);
1491  res->block.num = v.splitVector.spl_nleft;
1492  res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &(res->lenlist));
1493  res->itup = gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false);
1494  }
1495 
1496  return res;
1497 }
Datum spl_lattr[INDEX_MAX_KEYS]
Definition: gist_private.h:239
OffsetNumber * spl_left
Definition: gist.h:142
GIST_SPLITVEC splitVector
Definition: gist_private.h:237
int errcode(int sqlerrcode)
Definition: elog.c:698
int spl_nleft
Definition: gist.h:143
IndexTupleData * list
Definition: gist_private.h:194
void gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate, GistSplitVector *v, int attno)
Definition: gistsplit.c:623
Datum spl_rattr[INDEX_MAX_KEYS]
Definition: gist_private.h:243
gistxlogPage block
Definition: gist_private.h:193
#define ERROR
Definition: elog.h:46
int spl_nright
Definition: gist.h:148
void check_stack_depth(void)
Definition: postgres.c:3469
#define RelationGetRelationName(relation)
Definition: rel.h:511
struct SplitedPageLayout * next
Definition: gist_private.h:200
#define GiSTPageSize
Definition: gist_private.h:475
#define ROTATEDIST(d)
Definition: gist.c:45
SplitedPageLayout * gistSplit(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition: gist.c:1416
TupleDesc nonLeafTupdesc
Definition: gist_private.h:81
#define ereport(elevel,...)
Definition: elog.h:157
bool gistfitpage(IndexTuple *itvec, int len)
Definition: gistutil.c:78
#define Assert(condition)
Definition: c.h:804
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum *attdata, bool *isnull, bool isleaf)
Definition: gistutil.c:574
IndexTupleData * gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
Definition: gistutil.c:126
OffsetNumber * spl_right
Definition: gist.h:147
bool spl_risnull[INDEX_MAX_KEYS]
Definition: gist_private.h:245
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
bool spl_lisnull[INDEX_MAX_KEYS]
Definition: gist_private.h:241
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ initGISTstate()

GISTSTATE* initGISTstate ( Relation  index)

Definition at line 1503 of file gist.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, GISTSTATE::compressFn, GISTSTATE::consistentFn, CreateTupleDescCopyConstr(), CurrentMemoryContext, GISTSTATE::decompressFn, GISTSTATE::distanceFn, elog, GISTSTATE::equalFn, ERROR, GISTSTATE::fetchFn, fmgr_info_copy(), FmgrInfo::fn_oid, GIST_COMPRESS_PROC, GIST_CONSISTENT_PROC, GIST_DECOMPRESS_PROC, GIST_DISTANCE_PROC, GIST_EQUAL_PROC, GIST_FETCH_PROC, GIST_PENALTY_PROC, GIST_PICKSPLIT_PROC, GIST_UNION_PROC, i, index_getprocid(), index_getprocinfo(), INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, InvalidOid, GISTSTATE::leafTupdesc, MemoryContextSwitchTo(), TupleDescData::natts, GISTSTATE::nonLeafTupdesc, OidIsValid, palloc(), GISTSTATE::penaltyFn, GISTSTATE::picksplitFn, RelationData::rd_att, RelationData::rd_indcollation, GISTSTATE::scanCxt, GISTSTATE::supportCollation, GISTSTATE::tempCxt, and GISTSTATE::unionFn.

Referenced by gistbeginscan(), gistbuild(), and gistinsert().

1504 {
1505  GISTSTATE *giststate;
1506  MemoryContext scanCxt;
1507  MemoryContext oldCxt;
1508  int i;
1509 
1510  /* safety check to protect fixed-size arrays in GISTSTATE */
1511  if (index->rd_att->natts > INDEX_MAX_KEYS)
1512  elog(ERROR, "numberOfAttributes %d > %d",
1513  index->rd_att->natts, INDEX_MAX_KEYS);
1514 
1515  /* Create the memory context that will hold the GISTSTATE */
1517  "GiST scan context",
1519  oldCxt = MemoryContextSwitchTo(scanCxt);
1520 
1521  /* Create and fill in the GISTSTATE */
1522  giststate = (GISTSTATE *) palloc(sizeof(GISTSTATE));
1523 
1524  giststate->scanCxt = scanCxt;
1525  giststate->tempCxt = scanCxt; /* caller must change this if needed */
1526  giststate->leafTupdesc = index->rd_att;
1527 
1528  /*
1529  * The truncated tupdesc for non-leaf index tuples, which doesn't contain
1530  * the INCLUDE attributes.
1531  *
1532  * It is used to form tuples during tuple adjustment and page split.
1533  * B-tree creates shortened tuple descriptor for every truncated tuple,
1534  * because it is doing this less often: it does not have to form truncated
1535  * tuples during page split. Also, B-tree is not adjusting tuples on
1536  * internal pages the way GiST does.
1537  */
1538  giststate->nonLeafTupdesc = CreateTupleDescCopyConstr(index->rd_att);
1539  giststate->nonLeafTupdesc->natts =
1541 
1542  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(index); i++)
1543  {
1544  fmgr_info_copy(&(giststate->consistentFn[i]),
1545  index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC),
1546  scanCxt);
1547  fmgr_info_copy(&(giststate->unionFn[i]),
1548  index_getprocinfo(index, i + 1, GIST_UNION_PROC),
1549  scanCxt);
1550 
1551  /* opclasses are not required to provide a Compress method */
1552  if (OidIsValid(index_getprocid(index, i + 1, GIST_COMPRESS_PROC)))
1553  fmgr_info_copy(&(giststate->compressFn[i]),
1554  index_getprocinfo(index, i + 1, GIST_COMPRESS_PROC),
1555  scanCxt);
1556  else
1557  giststate->compressFn[i].fn_oid = InvalidOid;
1558 
1559  /* opclasses are not required to provide a Decompress method */
1560  if (OidIsValid(index_getprocid(index, i + 1, GIST_DECOMPRESS_PROC)))
1561  fmgr_info_copy(&(giststate->decompressFn[i]),
1562  index_getprocinfo(index, i + 1, GIST_DECOMPRESS_PROC),
1563  scanCxt);
1564  else
1565  giststate->decompressFn[i].fn_oid = InvalidOid;
1566 
1567  fmgr_info_copy(&(giststate->penaltyFn[i]),
1568  index_getprocinfo(index, i + 1, GIST_PENALTY_PROC),
1569  scanCxt);
1570  fmgr_info_copy(&(giststate->picksplitFn[i]),
1571  index_getprocinfo(index, i + 1, GIST_PICKSPLIT_PROC),
1572  scanCxt);
1573  fmgr_info_copy(&(giststate->equalFn[i]),
1574  index_getprocinfo(index, i + 1, GIST_EQUAL_PROC),
1575  scanCxt);
1576 
1577  /* opclasses are not required to provide a Distance method */
1578  if (OidIsValid(index_getprocid(index, i + 1, GIST_DISTANCE_PROC)))
1579  fmgr_info_copy(&(giststate->distanceFn[i]),
1580  index_getprocinfo(index, i + 1, GIST_DISTANCE_PROC),
1581  scanCxt);
1582  else
1583  giststate->distanceFn[i].fn_oid = InvalidOid;
1584 
1585  /* opclasses are not required to provide a Fetch method */
1586  if (OidIsValid(index_getprocid(index, i + 1, GIST_FETCH_PROC)))
1587  fmgr_info_copy(&(giststate->fetchFn[i]),
1588  index_getprocinfo(index, i + 1, GIST_FETCH_PROC),
1589  scanCxt);
1590  else
1591  giststate->fetchFn[i].fn_oid = InvalidOid;
1592 
1593  /*
1594  * If the index column has a specified collation, we should honor that
1595  * while doing comparisons. However, we may have a collatable storage
1596  * type for a noncollatable indexed data type. If there's no index
1597  * collation then specify default collation in case the support
1598  * functions need collation. This is harmless if the support
1599  * functions don't care about collation, so we just do it
1600  * unconditionally. (We could alternatively call get_typcollation,
1601  * but that seems like expensive overkill --- there aren't going to be
1602  * any cases where a GiST storage type has a nondefault collation.)
1603  */
1604  if (OidIsValid(index->rd_indcollation[i]))
1605  giststate->supportCollation[i] = index->rd_indcollation[i];
1606  else
1607  giststate->supportCollation[i] = DEFAULT_COLLATION_OID;
1608  }
1609 
1610  /* No opclass information for INCLUDE attributes */
1611  for (; i < index->rd_att->natts; i++)
1612  {
1613  giststate->consistentFn[i].fn_oid = InvalidOid;
1614  giststate->unionFn[i].fn_oid = InvalidOid;
1615  giststate->compressFn[i].fn_oid = InvalidOid;
1616  giststate->decompressFn[i].fn_oid = InvalidOid;
1617  giststate->penaltyFn[i].fn_oid = InvalidOid;
1618  giststate->picksplitFn[i].fn_oid = InvalidOid;
1619  giststate->equalFn[i].fn_oid = InvalidOid;
1620  giststate->distanceFn[i].fn_oid = InvalidOid;
1621  giststate->fetchFn[i].fn_oid = InvalidOid;
1622  giststate->supportCollation[i] = InvalidOid;
1623  }
1624 
1625  MemoryContextSwitchTo(oldCxt);
1626 
1627  return giststate;
1628 }
#define AllocSetContextCreate
Definition: memutils.h:173
#define GIST_FETCH_PROC
Definition: gist.h:38
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:803
FmgrInfo fetchFn[INDEX_MAX_KEYS]
Definition: gist_private.h:94
#define GIST_EQUAL_PROC
Definition: gist.h:36
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
FmgrInfo compressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:88
FmgrInfo equalFn[INDEX_MAX_KEYS]
Definition: gist_private.h:92
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define OidIsValid(objectId)
Definition: c.h:710
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gist_private.h:86
#define GIST_PICKSPLIT_PROC
Definition: gist.h:35
Oid * rd_indcollation
Definition: rel.h:212
#define ERROR
Definition: elog.h:46
#define GIST_COMPRESS_PROC
Definition: gist.h:32
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:608
MemoryContext tempCxt
Definition: gist_private.h:78
FmgrInfo picksplitFn[INDEX_MAX_KEYS]
Definition: gist_private.h:91
FmgrInfo penaltyFn[INDEX_MAX_KEYS]
Definition: gist_private.h:90
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:496
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:151
FmgrInfo decompressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:89
TupleDesc leafTupdesc
Definition: gist_private.h:80
TupleDesc rd_att
Definition: rel.h:110
#define InvalidOid
Definition: postgres_ext.h:36
TupleDesc nonLeafTupdesc
Definition: gist_private.h:81
Oid fn_oid
Definition: fmgr.h:59
#define GIST_CONSISTENT_PROC
Definition: gist.h:30
#define GIST_UNION_PROC
Definition: gist.h:31
#define INDEX_MAX_KEYS
#define GIST_PENALTY_PROC
Definition: gist.h:34
#define GIST_DISTANCE_PROC
Definition: gist.h:37
FmgrInfo distanceFn[INDEX_MAX_KEYS]
Definition: gist_private.h:93
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i
MemoryContext scanCxt
Definition: gist_private.h:77
#define GIST_DECOMPRESS_PROC
Definition: gist.h:33
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:87
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769