PostgreSQL Source Code  git master
spgutils.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/spgist_private.h"
#include "access/toast_compression.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/pg_amop.h"
#include "commands/vacuum.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_coerce.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/index_selfuncs.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for spgutils.c:

Go to the source code of this file.

Macros

#define GET_LUP(c, f)   (&(c)->lastUsedPages.cachedPage[((unsigned int) (f)) % SPGIST_CACHED_PAGES])
 

Functions

Datum spghandler (PG_FUNCTION_ARGS)
 
static Oid GetIndexInputType (Relation index, AttrNumber indexcol)
 
static void fillTypeDesc (SpGistTypeDesc *desc, Oid type)
 
SpGistCachespgGetCache (Relation index)
 
TupleDesc getSpGistTupleDesc (Relation index, SpGistTypeDesc *keyType)
 
void initSpGistState (SpGistState *state, Relation index)
 
Buffer SpGistNewBuffer (Relation index)
 
void SpGistUpdateMetaPage (Relation index)
 
static Buffer allocNewBuffer (Relation index, int flags)
 
Buffer SpGistGetBuffer (Relation index, int flags, int needSpace, bool *isNew)
 
void SpGistSetLastUsedPage (Relation index, Buffer buffer)
 
void SpGistInitPage (Page page, uint16 f)
 
void SpGistInitBuffer (Buffer b, uint16 f)
 
void SpGistInitMetapage (Page page)
 
byteaspgoptions (Datum reloptions, bool validate)
 
unsigned int SpGistGetInnerTypeSize (SpGistTypeDesc *att, Datum datum)
 
static void memcpyInnerDatum (void *target, SpGistTypeDesc *att, Datum datum)
 
Size SpGistGetLeafTupleSize (TupleDesc tupleDescriptor, Datum *datums, bool *isnulls)
 
SpGistLeafTuple spgFormLeafTuple (SpGistState *state, ItemPointer heapPtr, Datum *datums, bool *isnulls)
 
SpGistNodeTuple spgFormNodeTuple (SpGistState *state, Datum label, bool isnull)
 
SpGistInnerTuple spgFormInnerTuple (SpGistState *state, bool hasPrefix, Datum prefix, int nNodes, SpGistNodeTuple *nodes)
 
SpGistDeadTuple spgFormDeadTuple (SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
 
void spgDeformLeafTuple (SpGistLeafTuple tup, TupleDesc tupleDescriptor, Datum *datums, bool *isnulls, bool keyColumnIsNull)
 
DatumspgExtractNodeLabels (SpGistState *state, SpGistInnerTuple innerTuple)
 
OffsetNumber SpGistPageAddNewItem (SpGistState *state, Page page, Item item, Size size, OffsetNumber *startOffset, bool errorOK)
 
bool spgproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
 

Macro Definition Documentation

◆ GET_LUP

#define GET_LUP (   c,
 
)    (&(c)->lastUsedPages.cachedPage[((unsigned int) (f)) % SPGIST_CACHED_PAGES])

Definition at line 471 of file spgutils.c.

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

Definition at line 494 of file spgutils.c.

495 {
496  SpGistCache *cache = spgGetCache(index);
497  uint16 pageflags = 0;
498 
499  if (GBUF_REQ_LEAF(flags))
500  pageflags |= SPGIST_LEAF;
501  if (GBUF_REQ_NULLS(flags))
502  pageflags |= SPGIST_NULLS;
503 
504  for (;;)
505  {
506  Buffer buffer;
507 
508  buffer = SpGistNewBuffer(index);
509  SpGistInitBuffer(buffer, pageflags);
510 
511  if (pageflags & SPGIST_LEAF)
512  {
513  /* Leaf pages have no parity concerns, so just use it */
514  return buffer;
515  }
516  else
517  {
518  BlockNumber blkno = BufferGetBlockNumber(buffer);
519  int blkFlags = GBUF_INNER_PARITY(blkno);
520 
521  if ((flags & GBUF_PARITY_MASK) == blkFlags)
522  {
523  /* Page has right parity, use it */
524  return buffer;
525  }
526  else
527  {
528  /* Page has wrong parity, record it in cache and try again */
529  if (pageflags & SPGIST_NULLS)
530  blkFlags |= GBUF_NULLS;
531  cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
532  cache->lastUsedPages.cachedPage[blkFlags].freeSpace =
534  UnlockReleaseBuffer(buffer);
535  }
536  }
537  }
538 }
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2748
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3791
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:951
unsigned short uint16
Definition: c.h:440
#define GBUF_NULLS
#define GBUF_PARITY_MASK
#define SPGIST_NULLS
#define GBUF_REQ_NULLS(flags)
#define GBUF_INNER_PARITY(x)
#define GBUF_REQ_LEAF(flags)
#define SPGIST_LEAF
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:366
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:703
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:180
SpGistLUPCache lastUsedPages
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
Definition: type.h:90

References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage, SpGistLUPCache::cachedPage, SpGistLastUsedPage::freeSpace, GBUF_INNER_PARITY, GBUF_NULLS, GBUF_PARITY_MASK, GBUF_REQ_LEAF, GBUF_REQ_NULLS, SpGistCache::lastUsedPages, PageGetExactFreeSpace(), spgGetCache(), SPGIST_LEAF, SPGIST_NULLS, SpGistInitBuffer(), SpGistNewBuffer(), and UnlockReleaseBuffer().

Referenced by SpGistGetBuffer().

◆ fillTypeDesc()

static void fillTypeDesc ( SpGistTypeDesc desc,
Oid  type 
)
static

Definition at line 158 of file spgutils.c.

159 {
160  HeapTuple tp;
161  Form_pg_type typtup;
162 
163  desc->type = type;
165  if (!HeapTupleIsValid(tp))
166  elog(ERROR, "cache lookup failed for type %u", type);
167  typtup = (Form_pg_type) GETSTRUCT(tp);
168  desc->attlen = typtup->typlen;
169  desc->attbyval = typtup->typbyval;
170  desc->attalign = typtup->typalign;
171  desc->attstorage = typtup->typstorage;
172  ReleaseSysCache(tp);
173 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1198
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1150
@ TYPEOID
Definition: syscache.h:112

References SpGistTypeDesc::attalign, SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, SpGistTypeDesc::attstorage, elog, ERROR, GETSTRUCT, HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), SearchSysCache1(), generate_unaccent_rules::type, SpGistTypeDesc::type, and TYPEOID.

Referenced by spgGetCache().

◆ GetIndexInputType()

static Oid GetIndexInputType ( Relation  index,
AttrNumber  indexcol 
)
static

Definition at line 113 of file spgutils.c.

114 {
115  Oid opcintype;
116  AttrNumber heapcol;
117  List *indexprs;
118  ListCell *indexpr_item;
119 
120  Assert(index->rd_index != NULL);
121  Assert(indexcol > 0 && indexcol <= index->rd_index->indnkeyatts);
122  opcintype = index->rd_opcintype[indexcol - 1];
123  if (!IsPolymorphicType(opcintype))
124  return opcintype;
125  heapcol = index->rd_index->indkey.values[indexcol - 1];
126  if (heapcol != 0) /* Simple index column? */
127  return getBaseType(get_atttype(index->rd_index->indrelid, heapcol));
128 
129  /*
130  * If the index expressions are already cached, skip calling
131  * RelationGetIndexExpressions, as it will make a copy which is overkill.
132  * We're not going to modify the trees, and we're not going to do anything
133  * that would invalidate the relcache entry before we're done.
134  */
135  if (index->rd_indexprs)
136  indexprs = index->rd_indexprs;
137  else
139  indexpr_item = list_head(indexprs);
140  for (int i = 1; i <= index->rd_index->indnkeyatts; i++)
141  {
142  if (index->rd_index->indkey.values[i - 1] == 0)
143  {
144  /* expression column */
145  if (indexpr_item == NULL)
146  elog(ERROR, "wrong number of index expressions");
147  if (i == indexcol)
148  return getBaseType(exprType((Node *) lfirst(indexpr_item)));
149  indexpr_item = lnext(indexprs, indexpr_item);
150  }
151  }
152  elog(ERROR, "wrong number of index expressions");
153  return InvalidOid; /* keep compiler quiet */
154 }
int16 AttrNumber
Definition: attnum.h:21
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2468
Oid get_atttype(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:938
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
#define lfirst(lc)
Definition: pg_list.h:169
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:4910
Definition: pg_list.h:51
Definition: nodes.h:539

References Assert(), elog, ERROR, exprType(), get_atttype(), getBaseType(), i, InvalidOid, lfirst, list_head(), lnext(), and RelationGetIndexExpressions().

Referenced by spgGetCache().

◆ getSpGistTupleDesc()

TupleDesc getSpGistTupleDesc ( Relation  index,
SpGistTypeDesc keyType 
)

Definition at line 300 of file spgutils.c.

301 {
302  TupleDesc outTupDesc;
303  Form_pg_attribute att;
304 
305  if (keyType->type ==
307  outTupDesc = RelationGetDescr(index);
308  else
309  {
311  att = TupleDescAttr(outTupDesc, spgKeyColumn);
312  /* It's sufficient to update the type-dependent fields of the column */
313  att->atttypid = keyType->type;
314  att->atttypmod = -1;
315  att->attlen = keyType->attlen;
316  att->attbyval = keyType->attbyval;
317  att->attalign = keyType->attalign;
318  att->attstorage = keyType->attstorage;
319  /* We shouldn't need to bother with making these valid: */
320  att->attcompression = InvalidCompressionMethod;
321  att->attcollation = InvalidOid;
322  /* In case we changed typlen, we'd better reset following offsets */
323  for (int i = spgFirstIncludeColumn; i < outTupDesc->natts; i++)
324  TupleDescAttr(outTupDesc, i)->attcacheoff = -1;
325  }
326  return outTupDesc;
327 }
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#define RelationGetDescr(relation)
Definition: rel.h:504
#define spgFirstIncludeColumn
#define spgKeyColumn
#define InvalidCompressionMethod
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References SpGistTypeDesc::attalign, SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, SpGistTypeDesc::attstorage, CreateTupleDescCopy(), i, InvalidCompressionMethod, InvalidOid, TupleDescData::natts, RelationGetDescr, spgFirstIncludeColumn, spgKeyColumn, TupleDescAttr, and SpGistTypeDesc::type.

Referenced by initSpGistState(), and spgbeginscan().

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 331 of file spgutils.c.

332 {
333  SpGistCache *cache;
334 
335  state->index = index;
336 
337  /* Get cached static information about index */
338  cache = spgGetCache(index);
339 
340  state->config = cache->config;
341  state->attType = cache->attType;
342  state->attLeafType = cache->attLeafType;
343  state->attPrefixType = cache->attPrefixType;
344  state->attLabelType = cache->attLabelType;
345 
346  /* Ensure we have a valid descriptor for leaf tuples */
347  state->leafTupDesc = getSpGistTupleDesc(state->index, &state->attLeafType);
348 
349  /* Make workspace for constructing dead tuples */
350  state->deadTupleStorage = palloc0(SGDTSIZE);
351 
352  /* Set XID to use in redirection tuples */
353  state->myXid = GetTopTransactionIdIfAny();
354 
355  /* Assume we're not in an index build (spgbuild will override) */
356  state->isBuild = false;
357 }
void * palloc0(Size size)
Definition: mcxt.c:1093
#define SGDTSIZE
TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType)
Definition: spgutils.c:300
SpGistTypeDesc attPrefixType
SpGistTypeDesc attLeafType
SpGistTypeDesc attType
spgConfigOut config
SpGistTypeDesc attLabelType
Definition: regguts.h:318
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:427

References SpGistCache::attLabelType, SpGistCache::attLeafType, SpGistCache::attPrefixType, SpGistCache::attType, SpGistCache::config, getSpGistTupleDesc(), GetTopTransactionIdIfAny(), palloc0(), SGDTSIZE, and spgGetCache().

Referenced by spgbeginscan(), spgbuild(), spginsert(), and spgvacuumscan().

◆ memcpyInnerDatum()

static void memcpyInnerDatum ( void *  target,
SpGistTypeDesc att,
Datum  datum 
)
static

Definition at line 779 of file spgutils.c.

780 {
781  unsigned int size;
782 
783  if (att->attbyval)
784  {
785  memcpy(target, &datum, sizeof(Datum));
786  }
787  else
788  {
789  size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
790  memcpy(target, DatumGetPointer(datum), size);
791  }
792 }
uintptr_t Datum
Definition: postgres.h:411
#define VARSIZE_ANY(PTR)
Definition: postgres.h:348
#define DatumGetPointer(X)
Definition: postgres.h:593

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, DatumGetPointer, and VARSIZE_ANY.

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

◆ spgDeformLeafTuple()

void spgDeformLeafTuple ( SpGistLeafTuple  tup,
TupleDesc  tupleDescriptor,
Datum datums,
bool isnulls,
bool  keyColumnIsNull 
)

Definition at line 1098 of file spgutils.c.

1100 {
1101  bool hasNullsMask = SGLT_GET_HASNULLMASK(tup);
1102  char *tp; /* ptr to tuple data */
1103  bits8 *bp; /* ptr to null bitmap in tuple */
1104 
1105  if (keyColumnIsNull && tupleDescriptor->natts == 1)
1106  {
1107  /*
1108  * Trivial case: there is only the key attribute and we're in a nulls
1109  * tree. The hasNullsMask bit in the tuple header should not be set
1110  * (and thus we can't use index_deform_tuple_internal), but
1111  * nonetheless the result is NULL.
1112  *
1113  * Note: currently this is dead code, because noplace calls this when
1114  * there is only the key attribute. But we should cover the case.
1115  */
1116  Assert(!hasNullsMask);
1117 
1118  datums[spgKeyColumn] = (Datum) 0;
1119  isnulls[spgKeyColumn] = true;
1120  return;
1121  }
1122 
1123  tp = (char *) tup + SGLTHDRSZ(hasNullsMask);
1124  bp = (bits8 *) ((char *) tup + sizeof(SpGistLeafTupleData));
1125 
1126  index_deform_tuple_internal(tupleDescriptor,
1127  datums, isnulls,
1128  tp, bp, hasNullsMask);
1129 
1130  /*
1131  * Key column isnull value from the tuple should be consistent with
1132  * keyColumnIsNull flag from the caller.
1133  */
1134  Assert(keyColumnIsNull == isnulls[spgKeyColumn]);
1135 }
uint8 bits8
Definition: c.h:448
void index_deform_tuple_internal(TupleDesc tupleDescriptor, Datum *values, bool *isnull, char *tp, bits8 *bp, int hasnulls)
Definition: indextuple.c:460
#define SGLT_GET_HASNULLMASK(spgLeafTuple)
#define SGLTHDRSZ(hasnulls)
struct SpGistLeafTupleData SpGistLeafTupleData

References Assert(), index_deform_tuple_internal(), TupleDescData::natts, SGLT_GET_HASNULLMASK, SGLTHDRSZ, and spgKeyColumn.

Referenced by doPickSplit(), and storeGettuple().

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 1143 of file spgutils.c.

1144 {
1145  Datum *nodeLabels;
1146  int i;
1147  SpGistNodeTuple node;
1148 
1149  /* Either all the labels must be NULL, or none. */
1150  node = SGITNODEPTR(innerTuple);
1151  if (IndexTupleHasNulls(node))
1152  {
1153  SGITITERATE(innerTuple, i, node)
1154  {
1155  if (!IndexTupleHasNulls(node))
1156  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1157  }
1158  /* They're all null, so just return NULL */
1159  return NULL;
1160  }
1161  else
1162  {
1163  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
1164  SGITITERATE(innerTuple, i, node)
1165  {
1166  if (IndexTupleHasNulls(node))
1167  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1168  nodeLabels[i] = SGNTDATUM(node, state);
1169  }
1170  return nodeLabels;
1171  }
1172 }
#define IndexTupleHasNulls(itup)
Definition: itup.h:71
void * palloc(Size size)
Definition: mcxt.c:1062
#define SGITITERATE(x, i, nt)
#define SGNTDATUM(x, s)
#define SGITNODEPTR(x)

References elog, ERROR, i, IndexTupleHasNulls, SpGistInnerTupleData::nNodes, palloc(), SGITITERATE, SGITNODEPTR, and SGNTDATUM.

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

◆ spgFormDeadTuple()

SpGistDeadTuple spgFormDeadTuple ( SpGistState state,
int  tupstate,
BlockNumber  blkno,
OffsetNumber  offnum 
)

Definition at line 1067 of file spgutils.c.

1069 {
1070  SpGistDeadTuple tuple = (SpGistDeadTuple) state->deadTupleStorage;
1071 
1072  tuple->tupstate = tupstate;
1073  tuple->size = SGDTSIZE;
1075 
1076  if (tupstate == SPGIST_REDIRECT)
1077  {
1078  ItemPointerSet(&tuple->pointer, blkno, offnum);
1080  tuple->xid = state->myXid;
1081  }
1082  else
1083  {
1084  ItemPointerSetInvalid(&tuple->pointer);
1085  tuple->xid = InvalidTransactionId;
1086  }
1087 
1088  return tuple;
1089 }
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define InvalidOffsetNumber
Definition: off.h:26
SpGistDeadTupleData * SpGistDeadTuple
#define SPGIST_REDIRECT
#define SGLT_SET_NEXTOFFSET(spgLeafTuple, offsetNumber)
unsigned int tupstate
ItemPointerData pointer
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsValid(xid)
Definition: transam.h:41

References Assert(), InvalidOffsetNumber, InvalidTransactionId, ItemPointerSet, ItemPointerSetInvalid, SpGistDeadTupleData::pointer, SGDTSIZE, SGLT_SET_NEXTOFFSET, SpGistDeadTupleData::size, SPGIST_REDIRECT, TransactionIdIsValid, SpGistDeadTupleData::tupstate, and SpGistDeadTupleData::xid.

Referenced by spgAddNodeAction(), spgPageIndexMultiDelete(), and spgRedoAddNode().

◆ spgFormInnerTuple()

SpGistInnerTuple spgFormInnerTuple ( SpGistState state,
bool  hasPrefix,
Datum  prefix,
int  nNodes,
SpGistNodeTuple nodes 
)

Definition at line 984 of file spgutils.c.

986 {
987  SpGistInnerTuple tup;
988  unsigned int size;
989  unsigned int prefixSize;
990  int i;
991  char *ptr;
992 
993  /* Compute size needed */
994  if (hasPrefix)
995  prefixSize = SpGistGetInnerTypeSize(&state->attPrefixType, prefix);
996  else
997  prefixSize = 0;
998 
999  size = SGITHDRSZ + prefixSize;
1000 
1001  /* Note: we rely on node tuple sizes to be maxaligned already */
1002  for (i = 0; i < nNodes; i++)
1003  size += IndexTupleSize(nodes[i]);
1004 
1005  /*
1006  * Ensure that we can replace the tuple with a dead tuple later. This
1007  * test is unnecessary given current tuple layouts, but let's be safe.
1008  */
1009  if (size < SGDTSIZE)
1010  size = SGDTSIZE;
1011 
1012  /*
1013  * Inner tuple should be small enough to fit on a page
1014  */
1015  if (size > SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))
1016  ereport(ERROR,
1017  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1018  errmsg("SP-GiST inner tuple size %zu exceeds maximum %zu",
1019  (Size) size,
1020  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData)),
1021  errhint("Values larger than a buffer page cannot be indexed.")));
1022 
1023  /*
1024  * Check for overflow of header fields --- probably can't fail if the
1025  * above succeeded, but let's be paranoid
1026  */
1027  if (size > SGITMAXSIZE ||
1028  prefixSize > SGITMAXPREFIXSIZE ||
1029  nNodes > SGITMAXNNODES)
1030  elog(ERROR, "SPGiST inner tuple header field is too small");
1031 
1032  /* OK, form the tuple */
1033  tup = (SpGistInnerTuple) palloc0(size);
1034 
1035  tup->nNodes = nNodes;
1036  tup->prefixSize = prefixSize;
1037  tup->size = size;
1038 
1039  if (hasPrefix)
1040  memcpyInnerDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
1041 
1042  ptr = (char *) SGITNODEPTR(tup);
1043 
1044  for (i = 0; i < nNodes; i++)
1045  {
1046  SpGistNodeTuple node = nodes[i];
1047 
1048  memcpy(ptr, node, IndexTupleSize(node));
1049  ptr += IndexTupleSize(node);
1050  }
1051 
1052  return tup;
1053 }
size_t Size
Definition: c.h:540
int errhint(const char *fmt,...)
Definition: elog.c:1156
int errcode(int sqlerrcode)
Definition: elog.c:698
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define ereport(elevel,...)
Definition: elog.h:143
#define IndexTupleSize(itup)
Definition: itup.h:70
SpGistInnerTupleData * SpGistInnerTuple
#define SGITDATAPTR(x)
#define SGITMAXSIZE
#define SGITMAXPREFIXSIZE
#define SGITHDRSZ
#define SPGIST_PAGE_CAPACITY
#define SGITMAXNNODES
static void memcpyInnerDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:779
unsigned int SpGistGetInnerTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:761
unsigned int prefixSize

References elog, ereport, errcode(), errhint(), errmsg(), ERROR, i, IndexTupleSize, memcpyInnerDatum(), SpGistInnerTupleData::nNodes, palloc0(), SpGistInnerTupleData::prefixSize, SGDTSIZE, SGITDATAPTR, SGITHDRSZ, SGITMAXNNODES, SGITMAXPREFIXSIZE, SGITMAXSIZE, SGITNODEPTR, SpGistInnerTupleData::size, SPGIST_PAGE_CAPACITY, and SpGistGetInnerTypeSize().

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

◆ spgFormLeafTuple()

SpGistLeafTuple spgFormLeafTuple ( SpGistState state,
ItemPointer  heapPtr,
Datum datums,
bool isnulls 
)

Definition at line 853 of file spgutils.c.

855 {
856  SpGistLeafTuple tup;
857  TupleDesc tupleDescriptor = state->leafTupDesc;
858  Size size;
859  Size hoff;
860  Size data_size;
861  bool needs_null_mask = false;
862  int natts = tupleDescriptor->natts;
863  char *tp; /* ptr to tuple data */
864  uint16 tupmask = 0; /* unused heap_fill_tuple output */
865 
866  /*
867  * Decide whether we need a nulls bitmask.
868  *
869  * If there is only a key attribute (natts == 1), never use a bitmask, for
870  * compatibility with the pre-v14 layout of leaf tuples. Otherwise, we
871  * need one if any attribute is null.
872  */
873  if (natts > 1)
874  {
875  for (int i = 0; i < natts; i++)
876  {
877  if (isnulls[i])
878  {
879  needs_null_mask = true;
880  break;
881  }
882  }
883  }
884 
885  /*
886  * Calculate size of the data part; same as for heap tuples.
887  */
888  data_size = heap_compute_data_size(tupleDescriptor, datums, isnulls);
889 
890  /*
891  * Compute total size.
892  */
893  hoff = SGLTHDRSZ(needs_null_mask);
894  size = hoff + data_size;
895  size = MAXALIGN(size);
896 
897  /*
898  * Ensure that we can replace the tuple with a dead tuple later. This test
899  * is unnecessary when there are any non-null attributes, but be safe.
900  */
901  if (size < SGDTSIZE)
902  size = SGDTSIZE;
903 
904  /* OK, form the tuple */
905  tup = (SpGistLeafTuple) palloc0(size);
906 
907  tup->size = size;
909  tup->heapPtr = *heapPtr;
910 
911  tp = (char *) tup + hoff;
912 
913  if (needs_null_mask)
914  {
915  bits8 *bp; /* ptr to null bitmap in tuple */
916 
917  /* Set nullmask presence bit in SpGistLeafTuple header */
918  SGLT_SET_HASNULLMASK(tup, true);
919  /* Fill the data area and null mask */
920  bp = (bits8 *) ((char *) tup + sizeof(SpGistLeafTupleData));
921  heap_fill_tuple(tupleDescriptor, datums, isnulls, tp, data_size,
922  &tupmask, bp);
923  }
924  else if (natts > 1 || !isnulls[spgKeyColumn])
925  {
926  /* Fill data area only */
927  heap_fill_tuple(tupleDescriptor, datums, isnulls, tp, data_size,
928  &tupmask, (bits8 *) NULL);
929  }
930  /* otherwise we have no data, nor a bitmap, to fill */
931 
932  return tup;
933 }
#define MAXALIGN(LEN)
Definition: c.h:757
Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:119
void heap_fill_tuple(TupleDesc tupleDesc, Datum *values, bool *isnull, char *data, Size data_size, uint16 *infomask, bits8 *bit)
Definition: heaptuple.c:304
#define SGLT_SET_HASNULLMASK(spgLeafTuple, hasnulls)
struct SpGistLeafTupleData * SpGistLeafTuple
ItemPointerData heapPtr

References heap_compute_data_size(), heap_fill_tuple(), SpGistLeafTupleData::heapPtr, i, InvalidOffsetNumber, MAXALIGN, TupleDescData::natts, palloc0(), SGDTSIZE, SGLT_SET_HASNULLMASK, SGLT_SET_NEXTOFFSET, SGLTHDRSZ, SpGistLeafTupleData::size, and spgKeyColumn.

Referenced by doPickSplit(), and spgdoinsert().

◆ spgFormNodeTuple()

SpGistNodeTuple spgFormNodeTuple ( SpGistState state,
Datum  label,
bool  isnull 
)

Definition at line 942 of file spgutils.c.

943 {
944  SpGistNodeTuple tup;
945  unsigned int size;
946  unsigned short infomask = 0;
947 
948  /* compute space needed (note result is already maxaligned) */
949  size = SGNTHDRSZ;
950  if (!isnull)
951  size += SpGistGetInnerTypeSize(&state->attLabelType, label);
952 
953  /*
954  * Here we make sure that the size will fit in the field reserved for it
955  * in t_info.
956  */
957  if ((size & INDEX_SIZE_MASK) != size)
958  ereport(ERROR,
959  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
960  errmsg("index row requires %zu bytes, maximum size is %zu",
961  (Size) size, (Size) INDEX_SIZE_MASK)));
962 
963  tup = (SpGistNodeTuple) palloc0(size);
964 
965  if (isnull)
966  infomask |= INDEX_NULL_MASK;
967  /* we don't bother setting the INDEX_VAR_MASK bit */
968  infomask |= size;
969  tup->t_info = infomask;
970 
971  /* The TID field will be filled in later */
973 
974  if (!isnull)
975  memcpyInnerDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
976 
977  return tup;
978 }
#define INDEX_NULL_MASK
Definition: itup.h:68
#define INDEX_SIZE_MASK
Definition: itup.h:65
static char * label
#define SGNTDATAPTR(x)
SpGistNodeTupleData * SpGistNodeTuple
#define SGNTHDRSZ
ItemPointerData t_tid
Definition: itup.h:37
unsigned short t_info
Definition: itup.h:49

References ereport, errcode(), errmsg(), ERROR, INDEX_NULL_MASK, INDEX_SIZE_MASK, ItemPointerSetInvalid, label, memcpyInnerDatum(), palloc0(), SGNTDATAPTR, SGNTHDRSZ, SpGistGetInnerTypeSize(), IndexTupleData::t_info, and IndexTupleData::t_tid.

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 180 of file spgutils.c.

181 {
182  SpGistCache *cache;
183 
184  if (index->rd_amcache == NULL)
185  {
186  Oid atttype;
187  spgConfigIn in;
188  FmgrInfo *procinfo;
189  Buffer metabuffer;
190  SpGistMetaPageData *metadata;
191 
192  cache = MemoryContextAllocZero(index->rd_indexcxt,
193  sizeof(SpGistCache));
194 
195  /* SPGiST must have one key column and can also have INCLUDE columns */
198 
199  /*
200  * Get the actual (well, nominal) data type of the key column. We
201  * pass this to the opclass config function so that polymorphic
202  * opclasses are possible.
203  */
204  atttype = GetIndexInputType(index, spgKeyColumn + 1);
205 
206  /* Call the config function to get config info for the opclass */
207  in.attType = atttype;
208 
210  FunctionCall2Coll(procinfo,
211  index->rd_indcollation[spgKeyColumn],
212  PointerGetDatum(&in),
213  PointerGetDatum(&cache->config));
214 
215  /*
216  * If leafType isn't specified, use the declared index column type,
217  * which index.c will have derived from the opclass's opcintype.
218  * (Although we now make spgvalidate.c warn if these aren't the same,
219  * old user-defined opclasses may not set the STORAGE parameter
220  * correctly, so believe leafType if it's given.)
221  */
222  if (!OidIsValid(cache->config.leafType))
223  {
224  cache->config.leafType =
226 
227  /*
228  * If index column type is binary-coercible to atttype (for
229  * example, it's a domain over atttype), treat it as plain atttype
230  * to avoid thinking we need to compress.
231  */
232  if (cache->config.leafType != atttype &&
233  IsBinaryCoercible(cache->config.leafType, atttype))
234  cache->config.leafType = atttype;
235  }
236 
237  /* Get the information we need about each relevant datatype */
238  fillTypeDesc(&cache->attType, atttype);
239 
240  if (cache->config.leafType != atttype)
241  {
243  ereport(ERROR,
244  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
245  errmsg("compress method must be defined when leaf type is different from input type")));
246 
247  fillTypeDesc(&cache->attLeafType, cache->config.leafType);
248  }
249  else
250  {
251  /* Save lookups in this common case */
252  cache->attLeafType = cache->attType;
253  }
254 
255  fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
256  fillTypeDesc(&cache->attLabelType, cache->config.labelType);
257 
258  /* Last, get the lastUsedPages data from the metapage */
259  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
260  LockBuffer(metabuffer, BUFFER_LOCK_SHARE);
261 
262  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
263 
264  if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
265  elog(ERROR, "index \"%s\" is not an SP-GiST index",
267 
268  cache->lastUsedPages = metadata->lastUsedPages;
269 
270  UnlockReleaseBuffer(metabuffer);
271 
272  index->rd_amcache = (void *) cache;
273  }
274  else
275  {
276  /* assume it's up to date */
277  cache = (SpGistCache *) index->rd_amcache;
278  }
279 
280  return cache;
281 }
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:694
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
#define OidIsValid(objectId)
Definition: c.h:710
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:803
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define INDEX_MAX_KEYS
#define PointerGetDatum(X)
Definition: postgres.h:600
#define RelationGetRelationName(relation)
Definition: rel.h:512
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:490
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:497
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:28
#define SPGIST_CONFIG_PROC
Definition: spgist.h:23
#define SpGistPageGetMeta(p)
#define SPGIST_METAPAGE_BLKNO
#define SPGIST_MAGIC_NUMBER
static Oid GetIndexInputType(Relation index, AttrNumber indexcol)
Definition: spgutils.c:113
static void fillTypeDesc(SpGistTypeDesc *desc, Oid type)
Definition: spgutils.c:158
Definition: fmgr.h:57
SpGistLUPCache lastUsedPages
Oid attType
Definition: spgist.h:38
Oid leafType
Definition: spgist.h:45
Oid labelType
Definition: spgist.h:44
Oid prefixType
Definition: spgist.h:43

References Assert(), SpGistCache::attLabelType, SpGistCache::attLeafType, SpGistCache::attPrefixType, spgConfigIn::attType, SpGistCache::attType, BUFFER_LOCK_SHARE, BufferGetPage, SpGistCache::config, elog, ereport, errcode(), errmsg(), ERROR, fillTypeDesc(), FunctionCall2Coll(), GetIndexInputType(), index_getprocid(), index_getprocinfo(), INDEX_MAX_KEYS, IndexRelationGetNumberOfAttributes, IndexRelationGetNumberOfKeyAttributes, IsBinaryCoercible(), spgConfigOut::labelType, SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, spgConfigOut::leafType, LockBuffer(), SpGistMetaPageData::magicNumber, MemoryContextAllocZero(), OidIsValid, PointerGetDatum, spgConfigOut::prefixType, ReadBuffer(), RelationGetDescr, RelationGetRelationName, SPGIST_COMPRESS_PROC, SPGIST_CONFIG_PROC, SPGIST_MAGIC_NUMBER, SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, spgKeyColumn, TupleDescAttr, and UnlockReleaseBuffer().

Referenced by allocNewBuffer(), initSpGistState(), spgcanreturn(), SpGistGetBuffer(), and SpGistSetLastUsedPage().

◆ spghandler()

Datum spghandler ( PG_FUNCTION_ARGS  )

Definition at line 44 of file spgutils.c.

45 {
47 
48  amroutine->amstrategies = 0;
49  amroutine->amsupport = SPGISTNProc;
51  amroutine->amcanorder = false;
52  amroutine->amcanorderbyop = true;
53  amroutine->amcanbackward = false;
54  amroutine->amcanunique = false;
55  amroutine->amcanmulticol = false;
56  amroutine->amoptionalkey = true;
57  amroutine->amsearcharray = false;
58  amroutine->amsearchnulls = true;
59  amroutine->amstorage = true;
60  amroutine->amclusterable = false;
61  amroutine->ampredlocks = false;
62  amroutine->amcanparallel = false;
63  amroutine->amcaninclude = true;
64  amroutine->amusemaintenanceworkmem = false;
65  amroutine->amhotblocking = true;
66  amroutine->amparallelvacuumoptions =
68  amroutine->amkeytype = InvalidOid;
69 
70  amroutine->ambuild = spgbuild;
71  amroutine->ambuildempty = spgbuildempty;
72  amroutine->aminsert = spginsert;
73  amroutine->ambulkdelete = spgbulkdelete;
74  amroutine->amvacuumcleanup = spgvacuumcleanup;
75  amroutine->amcanreturn = spgcanreturn;
76  amroutine->amcostestimate = spgcostestimate;
77  amroutine->amoptions = spgoptions;
78  amroutine->amproperty = spgproperty;
79  amroutine->ambuildphasename = NULL;
80  amroutine->amvalidate = spgvalidate;
81  amroutine->amadjustmembers = spgadjustmembers;
82  amroutine->ambeginscan = spgbeginscan;
83  amroutine->amrescan = spgrescan;
84  amroutine->amgettuple = spggettuple;
85  amroutine->amgetbitmap = spggetbitmap;
86  amroutine->amendscan = spgendscan;
87  amroutine->ammarkpos = NULL;
88  amroutine->amrestrpos = NULL;
89  amroutine->amestimateparallelscan = NULL;
90  amroutine->aminitparallelscan = NULL;
91  amroutine->amparallelrescan = NULL;
92 
93  PG_RETURN_POINTER(amroutine);
94 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define makeNode(_type_)
Definition: nodes.h:586
void spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition: selfuncs.c:7018
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: spginsert.c:207
void spgbuildempty(Relation index)
Definition: spginsert.c:156
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:75
#define SPGIST_OPTIONS_PROC
Definition: spgist.h:29
#define SPGISTNProc
Definition: spgist.h:31
IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz)
Definition: spgscan.c:304
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:1085
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:1027
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:429
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:380
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:943
bytea * spgoptions(Datum reloptions, bool validate)
Definition: spgutils.c:740
bool spgproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
Definition: spgutils.c:1281
IndexBulkDeleteResult * spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: spgvacuum.c:937
IndexBulkDeleteResult * spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: spgvacuum.c:906
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:39
void spgadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
Definition: spgvalidate.c:332
ambuildphasename_function ambuildphasename
Definition: amapi.h:270
ambuildempty_function ambuildempty
Definition: amapi.h:262
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:265
bool amclusterable
Definition: amapi.h:238
amoptions_function amoptions
Definition: amapi.h:268
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:282
amrestrpos_function amrestrpos
Definition: amapi.h:279
aminsert_function aminsert
Definition: amapi.h:263
amendscan_function amendscan
Definition: amapi.h:277
uint16 amoptsprocnum
Definition: amapi.h:218
amparallelrescan_function amparallelrescan
Definition: amapi.h:284
Oid amkeytype
Definition: amapi.h:252
bool ampredlocks
Definition: amapi.h:240
uint16 amsupport
Definition: amapi.h:216
amcostestimate_function amcostestimate
Definition: amapi.h:267
bool amcanorderbyop
Definition: amapi.h:222
amadjustmembers_function amadjustmembers
Definition: amapi.h:272
ambuild_function ambuild
Definition: amapi.h:261
bool amstorage
Definition: amapi.h:236
uint16 amstrategies
Definition: amapi.h:214
bool amoptionalkey
Definition: amapi.h:230
amgettuple_function amgettuple
Definition: amapi.h:275
amcanreturn_function amcanreturn
Definition: amapi.h:266
bool amcanunique
Definition: amapi.h:226
amgetbitmap_function amgetbitmap
Definition: amapi.h:276
amproperty_function amproperty
Definition: amapi.h:269
ambulkdelete_function ambulkdelete
Definition: amapi.h:264
bool amsearcharray
Definition: amapi.h:232
amvalidate_function amvalidate
Definition: amapi.h:271
ammarkpos_function ammarkpos
Definition: amapi.h:278
bool amcanmulticol
Definition: amapi.h:228
bool amusemaintenanceworkmem
Definition: amapi.h:246
ambeginscan_function ambeginscan
Definition: amapi.h:273
bool amcanparallel
Definition: amapi.h:242
amrescan_function amrescan
Definition: amapi.h:274
bool amcanorder
Definition: amapi.h:220
bool amhotblocking
Definition: amapi.h:248
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:283
uint8 amparallelvacuumoptions
Definition: amapi.h:250
bool amcanbackward
Definition: amapi.h:224
bool amcaninclude
Definition: amapi.h:244
bool amsearchnulls
Definition: amapi.h:234
#define VACUUM_OPTION_PARALLEL_BULKDEL
Definition: vacuum.h:45
#define VACUUM_OPTION_PARALLEL_COND_CLEANUP
Definition: vacuum.h:52

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::amhotblocking, 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, InvalidOid, makeNode, PG_RETURN_POINTER, spgadjustmembers(), spgbeginscan(), spgbuild(), spgbuildempty(), spgbulkdelete(), spgcanreturn(), spgcostestimate(), spgendscan(), spggetbitmap(), spggettuple(), spginsert(), SPGIST_OPTIONS_PROC, SPGISTNProc, spgoptions(), spgproperty(), spgrescan(), spgvacuumcleanup(), spgvalidate(), VACUUM_OPTION_PARALLEL_BULKDEL, and VACUUM_OPTION_PARALLEL_COND_CLEANUP.

◆ SpGistGetBuffer()

Buffer SpGistGetBuffer ( Relation  index,
int  flags,
int  needSpace,
bool isNew 
)

Definition at line 550 of file spgutils.c.

551 {
552  SpGistCache *cache = spgGetCache(index);
553  SpGistLastUsedPage *lup;
554 
555  /* Bail out if even an empty page wouldn't meet the demand */
556  if (needSpace > SPGIST_PAGE_CAPACITY)
557  elog(ERROR, "desired SPGiST tuple size is too big");
558 
559  /*
560  * If possible, increase the space request to include relation's
561  * fillfactor. This ensures that when we add unrelated tuples to a page,
562  * we try to keep 100-fillfactor% available for adding tuples that are
563  * related to the ones already on it. But fillfactor mustn't cause an
564  * error for requests that would otherwise be legal.
565  */
566  needSpace += SpGistGetTargetPageFreeSpace(index);
567  needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY);
568 
569  /* Get the cache entry for this flags setting */
570  lup = GET_LUP(cache, flags);
571 
572  /* If we have nothing cached, just turn it over to allocNewBuffer */
573  if (lup->blkno == InvalidBlockNumber)
574  {
575  *isNew = true;
576  return allocNewBuffer(index, flags);
577  }
578 
579  /* fixed pages should never be in cache */
581 
582  /* If cached freeSpace isn't enough, don't bother looking at the page */
583  if (lup->freeSpace >= needSpace)
584  {
585  Buffer buffer;
586  Page page;
587 
588  buffer = ReadBuffer(index, lup->blkno);
589 
590  if (!ConditionalLockBuffer(buffer))
591  {
592  /*
593  * buffer is locked by another process, so return a new buffer
594  */
595  ReleaseBuffer(buffer);
596  *isNew = true;
597  return allocNewBuffer(index, flags);
598  }
599 
600  page = BufferGetPage(buffer);
601 
602  if (PageIsNew(page) || SpGistPageIsDeleted(page) || PageIsEmpty(page))
603  {
604  /* OK to initialize the page */
605  uint16 pageflags = 0;
606 
607  if (GBUF_REQ_LEAF(flags))
608  pageflags |= SPGIST_LEAF;
609  if (GBUF_REQ_NULLS(flags))
610  pageflags |= SPGIST_NULLS;
611  SpGistInitBuffer(buffer, pageflags);
612  lup->freeSpace = PageGetExactFreeSpace(page) - needSpace;
613  *isNew = true;
614  return buffer;
615  }
616 
617  /*
618  * Check that page is of right type and has enough space. We must
619  * recheck this since our cache isn't necessarily up to date.
620  */
621  if ((GBUF_REQ_LEAF(flags) ? SpGistPageIsLeaf(page) : !SpGistPageIsLeaf(page)) &&
623  {
624  int freeSpace = PageGetExactFreeSpace(page);
625 
626  if (freeSpace >= needSpace)
627  {
628  /* Success, update freespace info and return the buffer */
629  lup->freeSpace = freeSpace - needSpace;
630  *isNew = false;
631  return buffer;
632  }
633  }
634 
635  /*
636  * fallback to allocation of new buffer
637  */
638  UnlockReleaseBuffer(buffer);
639  }
640 
641  /* No success with cache, so return a new buffer */
642  *isNew = true;
643  return allocNewBuffer(index, flags);
644 }
#define InvalidBlockNumber
Definition: block.h:33
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:4033
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3768
Pointer Page
Definition: bufpage.h:78
#define PageIsEmpty(page)
Definition: bufpage.h:221
#define PageIsNew(page)
Definition: bufpage.h:228
#define Min(x, y)
Definition: c.h:986
#define SpGistPageStoresNulls(page)
#define SpGistGetTargetPageFreeSpace(relation)
#define SpGistPageIsLeaf(page)
#define SpGistPageIsDeleted(page)
#define SpGistBlockIsFixed(blkno)
static Buffer allocNewBuffer(Relation index, int flags)
Definition: spgutils.c:494
#define GET_LUP(c, f)
Definition: spgutils.c:471

References allocNewBuffer(), Assert(), SpGistLastUsedPage::blkno, BufferGetPage, ConditionalLockBuffer(), elog, ERROR, SpGistLastUsedPage::freeSpace, GBUF_REQ_LEAF, GBUF_REQ_NULLS, GET_LUP, InvalidBlockNumber, Min, PageGetExactFreeSpace(), PageIsEmpty, PageIsNew, ReadBuffer(), ReleaseBuffer(), spgGetCache(), SPGIST_LEAF, SPGIST_NULLS, SPGIST_PAGE_CAPACITY, SpGistBlockIsFixed, SpGistGetTargetPageFreeSpace, SpGistInitBuffer(), SpGistPageIsDeleted, SpGistPageIsLeaf, SpGistPageStoresNulls, and UnlockReleaseBuffer().

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), and spgSplitNodeAction().

◆ SpGistGetInnerTypeSize()

unsigned int SpGistGetInnerTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 761 of file spgutils.c.

762 {
763  unsigned int size;
764 
765  if (att->attbyval)
766  size = sizeof(Datum);
767  else if (att->attlen > 0)
768  size = att->attlen;
769  else
770  size = VARSIZE_ANY(datum);
771 
772  return MAXALIGN(size);
773 }

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, MAXALIGN, and VARSIZE_ANY.

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

◆ SpGistGetLeafTupleSize()

Size SpGistGetLeafTupleSize ( TupleDesc  tupleDescriptor,
Datum datums,
bool isnulls 
)

Definition at line 800 of file spgutils.c.

802 {
803  Size size;
804  Size data_size;
805  bool needs_null_mask = false;
806  int natts = tupleDescriptor->natts;
807 
808  /*
809  * Decide whether we need a nulls bitmask.
810  *
811  * If there is only a key attribute (natts == 1), never use a bitmask, for
812  * compatibility with the pre-v14 layout of leaf tuples. Otherwise, we
813  * need one if any attribute is null.
814  */
815  if (natts > 1)
816  {
817  for (int i = 0; i < natts; i++)
818  {
819  if (isnulls[i])
820  {
821  needs_null_mask = true;
822  break;
823  }
824  }
825  }
826 
827  /*
828  * Calculate size of the data part; same as for heap tuples.
829  */
830  data_size = heap_compute_data_size(tupleDescriptor, datums, isnulls);
831 
832  /*
833  * Compute total size.
834  */
835  size = SGLTHDRSZ(needs_null_mask);
836  size += data_size;
837  size = MAXALIGN(size);
838 
839  /*
840  * Ensure that we can replace the tuple with a dead tuple later. This test
841  * is unnecessary when there are any non-null attributes, but be safe.
842  */
843  if (size < SGDTSIZE)
844  size = SGDTSIZE;
845 
846  return size;
847 }

References heap_compute_data_size(), i, MAXALIGN, TupleDescData::natts, SGDTSIZE, and SGLTHDRSZ.

Referenced by spgdoinsert().

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 703 of file spgutils.c.

704 {
705  Assert(BufferGetPageSize(b) == BLCKSZ);
707 }
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
int b
Definition: isn.c:70
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:689

References Assert(), b, BufferGetPage, BufferGetPageSize, and SpGistInitPage().

Referenced by allocNewBuffer(), doPickSplit(), spgbuild(), SpGistGetBuffer(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), and spgRedoSplitTuple().

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 713 of file spgutils.c.

714 {
715  SpGistMetaPageData *metadata;
716  int i;
717 
719  metadata = SpGistPageGetMeta(page);
720  memset(metadata, 0, sizeof(SpGistMetaPageData));
721  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
722 
723  /* initialize last-used-page cache to empty */
724  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
726 
727  /*
728  * Set pd_lower just past the end of the metadata. This is essential,
729  * because without doing so, metadata will be lost if xlog.c compresses
730  * the page.
731  */
732  ((PageHeader) page)->pd_lower =
733  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
734 }
#define SPGIST_META
#define SPGIST_CACHED_PAGES

References SpGistLastUsedPage::blkno, SpGistLUPCache::cachedPage, i, InvalidBlockNumber, SpGistMetaPageData::lastUsedPages, SpGistMetaPageData::magicNumber, SPGIST_CACHED_PAGES, SPGIST_MAGIC_NUMBER, SPGIST_META, SpGistInitPage(), and SpGistPageGetMeta.

Referenced by spgbuild(), and spgbuildempty().

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 689 of file spgutils.c.

690 {
691  SpGistPageOpaque opaque;
692 
693  PageInit(page, BLCKSZ, sizeof(SpGistPageOpaqueData));
694  opaque = SpGistPageGetOpaque(page);
695  opaque->flags = f;
696  opaque->spgist_page_id = SPGIST_PAGE_ID;
697 }
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42
#define SpGistPageGetOpaque(page)
#define SPGIST_PAGE_ID

References SpGistPageOpaqueData::flags, PageInit(), SpGistPageOpaqueData::spgist_page_id, SPGIST_PAGE_ID, and SpGistPageGetOpaque.

Referenced by spgbuildempty(), SpGistInitBuffer(), and SpGistInitMetapage().

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 366 of file spgutils.c.

367 {
368  Buffer buffer;
369  bool needLock;
370 
371  /* First, try to get a page from FSM */
372  for (;;)
373  {
375 
376  if (blkno == InvalidBlockNumber)
377  break; /* nothing known to FSM */
378 
379  /*
380  * The fixed pages shouldn't ever be listed in FSM, but just in case
381  * one is, ignore it.
382  */
383  if (SpGistBlockIsFixed(blkno))
384  continue;
385 
386  buffer = ReadBuffer(index, blkno);
387 
388  /*
389  * We have to guard against the possibility that someone else already
390  * recycled this page; the buffer may be locked if so.
391  */
392  if (ConditionalLockBuffer(buffer))
393  {
394  Page page = BufferGetPage(buffer);
395 
396  if (PageIsNew(page))
397  return buffer; /* OK to use, if never initialized */
398 
399  if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
400  return buffer; /* OK to use */
401 
403  }
404 
405  /* Can't use it, so release buffer and try again */
406  ReleaseBuffer(buffer);
407  }
408 
409  /* Must extend the file */
410  needLock = !RELATION_IS_LOCAL(index);
411  if (needLock)
413 
414  buffer = ReadBuffer(index, P_NEW);
416 
417  if (needLock)
419 
420  return buffer;
421 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define P_NEW
Definition: bufmgr.h:91
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:403
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:453
#define ExclusiveLock
Definition: lockdefs.h:42
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:622

References BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsEmpty, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), SpGistBlockIsFixed, SpGistPageIsDeleted, and UnlockRelationForExtension().

Referenced by allocNewBuffer(), and spgbuild().

◆ SpGistPageAddNewItem()

OffsetNumber SpGistPageAddNewItem ( SpGistState state,
Page  page,
Item  item,
Size  size,
OffsetNumber startOffset,
bool  errorOK 
)

Definition at line 1186 of file spgutils.c.

1188 {
1189  SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
1190  OffsetNumber i,
1191  maxoff,
1192  offnum;
1193 
1194  if (opaque->nPlaceholder > 0 &&
1195  PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
1196  {
1197  /* Try to replace a placeholder */
1198  maxoff = PageGetMaxOffsetNumber(page);
1199  offnum = InvalidOffsetNumber;
1200 
1201  for (;;)
1202  {
1203  if (startOffset && *startOffset != InvalidOffsetNumber)
1204  i = *startOffset;
1205  else
1206  i = FirstOffsetNumber;
1207  for (; i <= maxoff; i++)
1208  {
1210  PageGetItemId(page, i));
1211 
1212  if (it->tupstate == SPGIST_PLACEHOLDER)
1213  {
1214  offnum = i;
1215  break;
1216  }
1217  }
1218 
1219  /* Done if we found a placeholder */
1220  if (offnum != InvalidOffsetNumber)
1221  break;
1222 
1223  if (startOffset && *startOffset != InvalidOffsetNumber)
1224  {
1225  /* Hint was no good, re-search from beginning */
1226  *startOffset = InvalidOffsetNumber;
1227  continue;
1228  }
1229 
1230  /* Hmm, no placeholder found? */
1231  opaque->nPlaceholder = 0;
1232  break;
1233  }
1234 
1235  if (offnum != InvalidOffsetNumber)
1236  {
1237  /* Replace the placeholder tuple */
1238  PageIndexTupleDelete(page, offnum);
1239 
1240  offnum = PageAddItem(page, item, size, offnum, false, false);
1241 
1242  /*
1243  * We should not have failed given the size check at the top of
1244  * the function, but test anyway. If we did fail, we must PANIC
1245  * because we've already deleted the placeholder tuple, and
1246  * there's no other way to keep the damage from getting to disk.
1247  */
1248  if (offnum != InvalidOffsetNumber)
1249  {
1250  Assert(opaque->nPlaceholder > 0);
1251  opaque->nPlaceholder--;
1252  if (startOffset)
1253  *startOffset = offnum + 1;
1254  }
1255  else
1256  elog(PANIC, "failed to add item of size %zu to SPGiST index page",
1257  size);
1258 
1259  return offnum;
1260  }
1261  }
1262 
1263  /* No luck in replacing a placeholder, so just add it to the page */
1264  offnum = PageAddItem(page, item, size,
1265  InvalidOffsetNumber, false, false);
1266 
1267  if (offnum == InvalidOffsetNumber && !errorOK)
1268  elog(ERROR, "failed to add item of size %zu to SPGiST index page",
1269  size);
1270 
1271  return offnum;
1272 }
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1045
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:356
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:234
#define PageGetItem(page, itemId)
Definition: bufpage.h:339
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:415
#define PANIC
Definition: elog.h:36
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
#define SPGIST_PLACEHOLDER

References Assert(), elog, ERROR, FirstOffsetNumber, i, InvalidOffsetNumber, MAXALIGN, SpGistPageOpaqueData::nPlaceholder, PageAddItem, PageGetExactFreeSpace(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageIndexTupleDelete(), PANIC, SGDTSIZE, SPGIST_PLACEHOLDER, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.

Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), and spgSplitNodeAction().

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 654 of file spgutils.c.

655 {
656  SpGistCache *cache = spgGetCache(index);
657  SpGistLastUsedPage *lup;
658  int freeSpace;
659  Page page = BufferGetPage(buffer);
660  BlockNumber blkno = BufferGetBlockNumber(buffer);
661  int flags;
662 
663  /* Never enter fixed pages (root pages) in cache, though */
664  if (SpGistBlockIsFixed(blkno))
665  return;
666 
667  if (SpGistPageIsLeaf(page))
668  flags = GBUF_LEAF;
669  else
670  flags = GBUF_INNER_PARITY(blkno);
671  if (SpGistPageStoresNulls(page))
672  flags |= GBUF_NULLS;
673 
674  lup = GET_LUP(cache, flags);
675 
676  freeSpace = PageGetExactFreeSpace(page);
677  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
678  lup->freeSpace < freeSpace)
679  {
680  lup->blkno = blkno;
681  lup->freeSpace = freeSpace;
682  }
683 }
#define GBUF_LEAF

References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage, SpGistLastUsedPage::freeSpace, GBUF_INNER_PARITY, GBUF_LEAF, GBUF_NULLS, GET_LUP, InvalidBlockNumber, PageGetExactFreeSpace(), spgGetCache(), SpGistBlockIsFixed, SpGistPageIsLeaf, and SpGistPageStoresNulls.

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), and spgvacuumpage().

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 431 of file spgutils.c.

432 {
433  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
434 
435  if (cache != NULL)
436  {
437  Buffer metabuffer;
438 
439  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
440 
441  if (ConditionalLockBuffer(metabuffer))
442  {
443  Page metapage = BufferGetPage(metabuffer);
444  SpGistMetaPageData *metadata = SpGistPageGetMeta(metapage);
445 
446  metadata->lastUsedPages = cache->lastUsedPages;
447 
448  /*
449  * Set pd_lower just past the end of the metadata. This is
450  * essential, because without doing so, metadata will be lost if
451  * xlog.c compresses the page. (We must do this here because
452  * pre-v11 versions of PG did not set the metapage's pd_lower
453  * correctly, so a pg_upgraded index might contain the wrong
454  * value.)
455  */
456  ((PageHeader) metapage)->pd_lower =
457  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
458 
459  MarkBufferDirty(metabuffer);
460  UnlockReleaseBuffer(metabuffer);
461  }
462  else
463  {
464  ReleaseBuffer(metabuffer);
465  }
466  }
467 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1565
PageHeaderData * PageHeader
Definition: bufpage.h:166

References BufferGetPage, ConditionalLockBuffer(), if(), SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, MarkBufferDirty(), ReadBuffer(), ReleaseBuffer(), SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, and UnlockReleaseBuffer().

Referenced by spgbuild(), spginsert(), and spgvacuumscan().

◆ spgoptions()

bytea* spgoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 740 of file spgutils.c.

741 {
742  static const relopt_parse_elt tab[] = {
744  };
745 
746  return (bytea *) build_reloptions(reloptions, validate,
748  sizeof(SpGistOptions),
749  tab, lengthof(tab));
750 
751 }
#define offsetof(type, field)
Definition: c.h:727
#define lengthof(array)
Definition: c.h:734
int fillfactor
Definition: pgbench.c:198
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1904
@ RELOPT_KIND_SPGIST
Definition: reloptions.h:50
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
Definition: c.h:622

References build_reloptions(), fillfactor, lengthof, offsetof, RELOPT_KIND_SPGIST, and RELOPT_TYPE_INT.

Referenced by spghandler().

◆ spgproperty()

bool spgproperty ( Oid  index_oid,
int  attno,
IndexAMProperty  prop,
const char *  propname,
bool res,
bool isnull 
)

Definition at line 1281 of file spgutils.c.

1284 {
1285  Oid opclass,
1286  opfamily,
1287  opcintype;
1288  CatCList *catlist;
1289  int i;
1290 
1291  /* Only answer column-level inquiries */
1292  if (attno == 0)
1293  return false;
1294 
1295  switch (prop)
1296  {
1298  break;
1299  default:
1300  return false;
1301  }
1302 
1303  /*
1304  * Currently, SP-GiST distance-ordered scans require that there be a
1305  * distance operator in the opclass with the default types. So we assume
1306  * that if such a operator exists, then there's a reason for it.
1307  */
1308 
1309  /* First we need to know the column's opclass. */
1310  opclass = get_index_column_opclass(index_oid, attno);
1311  if (!OidIsValid(opclass))
1312  {
1313  *isnull = true;
1314  return true;
1315  }
1316 
1317  /* Now look up the opclass family and input datatype. */
1318  if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1319  {
1320  *isnull = true;
1321  return true;
1322  }
1323 
1324  /* And now we can check whether the operator is provided. */
1326  ObjectIdGetDatum(opfamily));
1327 
1328  *res = false;
1329 
1330  for (i = 0; i < catlist->n_members; i++)
1331  {
1332  HeapTuple amoptup = &catlist->members[i]->tuple;
1333  Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(amoptup);
1334 
1335  if (amopform->amoppurpose == AMOP_ORDER &&
1336  (amopform->amoplefttype == opcintype ||
1337  amopform->amoprighttype == opcintype) &&
1338  opfamily_can_sort_type(amopform->amopsortfamily,
1339  get_op_rettype(amopform->amopopr)))
1340  {
1341  *res = true;
1342  break;
1343  }
1344  }
1345 
1346  ReleaseSysCacheList(catlist);
1347 
1348  *isnull = false;
1349 
1350  return true;
1351 }
@ AMPROP_DISTANCE_ORDERABLE
Definition: amapi.h:42
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:271
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1228
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1304
Oid get_index_column_opclass(Oid index_oid, int attno)
Definition: lsyscache.c:3462
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
int n_members
Definition: catcache.h:176
HeapTupleData tuple
Definition: catcache.h:121
@ AMOPSTRATEGY
Definition: syscache.h:38
#define ReleaseSysCacheList(x)
Definition: syscache.h:220
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:213

References AMOPSTRATEGY, AMPROP_DISTANCE_ORDERABLE, get_index_column_opclass(), get_op_rettype(), get_opclass_opfamily_and_input_type(), GETSTRUCT, i, catclist::members, catclist::n_members, ObjectIdGetDatum, OidIsValid, opfamily_can_sort_type(), ReleaseSysCacheList, res, SearchSysCacheList1, and catctup::tuple.

Referenced by spghandler().