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 "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 458 of file spgutils.c.

Referenced by SpGistGetBuffer(), and SpGistSetLastUsedPage().

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

Definition at line 481 of file spgutils.c.

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().

482 {
483  SpGistCache *cache = spgGetCache(index);
484  uint16 pageflags = 0;
485 
486  if (GBUF_REQ_LEAF(flags))
487  pageflags |= SPGIST_LEAF;
488  if (GBUF_REQ_NULLS(flags))
489  pageflags |= SPGIST_NULLS;
490 
491  for (;;)
492  {
493  Buffer buffer;
494 
495  buffer = SpGistNewBuffer(index);
496  SpGistInitBuffer(buffer, pageflags);
497 
498  if (pageflags & SPGIST_LEAF)
499  {
500  /* Leaf pages have no parity concerns, so just use it */
501  return buffer;
502  }
503  else
504  {
505  BlockNumber blkno = BufferGetBlockNumber(buffer);
506  int blkFlags = GBUF_INNER_PARITY(blkno);
507 
508  if ((flags & GBUF_PARITY_MASK) == blkFlags)
509  {
510  /* Page has right parity, use it */
511  return buffer;
512  }
513  else
514  {
515  /* Page has wrong parity, record it in cache and try again */
516  if (pageflags & SPGIST_NULLS)
517  blkFlags |= GBUF_NULLS;
518  cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
519  cache->lastUsedPages.cachedPage[blkFlags].freeSpace =
521  UnlockReleaseBuffer(buffer);
522  }
523  }
524  }
525 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:178
#define SPGIST_NULLS
uint32 BlockNumber
Definition: block.h:31
SpGistLUPCache lastUsedPages
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
#define GBUF_REQ_NULLS(flags)
unsigned short uint16
Definition: c.h:440
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3807
#define GBUF_INNER_PARITY(x)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:690
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:353
#define GBUF_PARITY_MASK
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:951
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2758
#define SPGIST_LEAF
int Buffer
Definition: buf.h:23
#define GBUF_REQ_LEAF(flags)

◆ fillTypeDesc()

static void fillTypeDesc ( SpGistTypeDesc desc,
Oid  type 
)
static

Definition at line 156 of file spgutils.c.

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

Referenced by spgGetCache().

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

◆ GetIndexInputType()

static Oid GetIndexInputType ( Relation  index,
AttrNumber  indexcol 
)
static

Definition at line 111 of file spgutils.c.

References Assert, elog, ERROR, exprType(), get_atttype(), getBaseType(), i, InvalidOid, lfirst, list_head(), lnext(), RelationData::rd_index, RelationData::rd_indexprs, RelationData::rd_opcintype, and RelationGetIndexExpressions().

Referenced by spgGetCache().

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

◆ getSpGistTupleDesc()

TupleDesc getSpGistTupleDesc ( Relation  index,
SpGistTypeDesc keyType 
)

Definition at line 287 of file spgutils.c.

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().

288 {
289  TupleDesc outTupDesc;
290  Form_pg_attribute att;
291 
292  if (keyType->type ==
293  TupleDescAttr(RelationGetDescr(index), spgKeyColumn)->atttypid)
294  outTupDesc = RelationGetDescr(index);
295  else
296  {
297  outTupDesc = CreateTupleDescCopy(RelationGetDescr(index));
298  att = TupleDescAttr(outTupDesc, spgKeyColumn);
299  /* It's sufficient to update the type-dependent fields of the column */
300  att->atttypid = keyType->type;
301  att->atttypmod = -1;
302  att->attlen = keyType->attlen;
303  att->attbyval = keyType->attbyval;
304  att->attalign = keyType->attalign;
305  att->attstorage = keyType->attstorage;
306  /* We shouldn't need to bother with making these valid: */
307  att->attcollation = InvalidOid;
308  att->attcompression = InvalidCompressionMethod;
309  /* In case we changed typlen, we'd better reset following offsets */
310  for (int i = spgFirstIncludeColumn; i < outTupDesc->natts; i++)
311  TupleDescAttr(outTupDesc, i)->attcacheoff = -1;
312  }
313  return outTupDesc;
314 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111
#define RelationGetDescr(relation)
Definition: rel.h:495
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:203
#define spgKeyColumn
#define spgFirstIncludeColumn
#define InvalidOid
Definition: postgres_ext.h:36
#define InvalidCompressionMethod
int i

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 318 of file spgutils.c.

References SpGistState::attLabelType, SpGistCache::attLabelType, SpGistState::attLeafType, SpGistCache::attLeafType, SpGistState::attPrefixType, SpGistCache::attPrefixType, SpGistState::attType, SpGistCache::attType, SpGistState::config, SpGistCache::config, SpGistState::deadTupleStorage, getSpGistTupleDesc(), GetTopTransactionIdIfAny(), SpGistState::index, SpGistState::isBuild, SpGistState::leafTupDesc, SpGistState::myXid, palloc0(), SGDTSIZE, and spgGetCache().

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

319 {
320  SpGistCache *cache;
321 
322  state->index = index;
323 
324  /* Get cached static information about index */
325  cache = spgGetCache(index);
326 
327  state->config = cache->config;
328  state->attType = cache->attType;
329  state->attLeafType = cache->attLeafType;
330  state->attPrefixType = cache->attPrefixType;
331  state->attLabelType = cache->attLabelType;
332 
333  /* Ensure we have a valid descriptor for leaf tuples */
334  state->leafTupDesc = getSpGistTupleDesc(state->index, &state->attLeafType);
335 
336  /* Make workspace for constructing dead tuples */
338 
339  /* Set XID to use in redirection tuples */
340  state->myXid = GetTopTransactionIdIfAny();
341 
342  /* Assume we're not in an index build (spgbuild will override) */
343  state->isBuild = false;
344 }
SpGistTypeDesc attLeafType
SpGistTypeDesc attPrefixType
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:178
#define SGDTSIZE
SpGistTypeDesc attLeafType
SpGistTypeDesc attType
SpGistTypeDesc attLabelType
SpGistTypeDesc attType
spgConfigOut config
TransactionId myXid
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:425
spgConfigOut config
void * palloc0(Size size)
Definition: mcxt.c:1093
char * deadTupleStorage
TupleDesc leafTupDesc
SpGistTypeDesc attLabelType
TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType)
Definition: spgutils.c:287
SpGistTypeDesc attPrefixType
Relation index

◆ memcpyInnerDatum()

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

Definition at line 766 of file spgutils.c.

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

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

767 {
768  unsigned int size;
769 
770  if (att->attbyval)
771  {
772  memcpy(target, &datum, sizeof(Datum));
773  }
774  else
775  {
776  size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
777  memcpy(target, DatumGetPointer(datum), size);
778  }
779 }
uintptr_t Datum
Definition: postgres.h:411
#define VARSIZE_ANY(PTR)
Definition: postgres.h:348
#define DatumGetPointer(X)
Definition: postgres.h:593

◆ spgDeformLeafTuple()

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

Definition at line 1085 of file spgutils.c.

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

Referenced by doPickSplit(), and storeGettuple().

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

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 1130 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

1131 {
1132  Datum *nodeLabels;
1133  int i;
1134  SpGistNodeTuple node;
1135 
1136  /* Either all the labels must be NULL, or none. */
1137  node = SGITNODEPTR(innerTuple);
1138  if (IndexTupleHasNulls(node))
1139  {
1140  SGITITERATE(innerTuple, i, node)
1141  {
1142  if (!IndexTupleHasNulls(node))
1143  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1144  }
1145  /* They're all null, so just return NULL */
1146  return NULL;
1147  }
1148  else
1149  {
1150  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
1151  SGITITERATE(innerTuple, i, node)
1152  {
1153  if (IndexTupleHasNulls(node))
1154  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1155  nodeLabels[i] = SGNTDATUM(node, state);
1156  }
1157  return nodeLabels;
1158  }
1159 }
#define SGITNODEPTR(x)
#define SGITITERATE(x, i, nt)
#define IndexTupleHasNulls(itup)
Definition: itup.h:72
#define ERROR
Definition: elog.h:46
uintptr_t Datum
Definition: postgres.h:411
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i
#define SGNTDATUM(x, s)

◆ spgFormDeadTuple()

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

Definition at line 1054 of file spgutils.c.

References Assert, SpGistState::deadTupleStorage, InvalidOffsetNumber, InvalidTransactionId, ItemPointerSet, ItemPointerSetInvalid, SpGistState::myXid, SpGistDeadTupleData::pointer, SGDTSIZE, SGLT_SET_NEXTOFFSET, SpGistDeadTupleData::size, SPGIST_REDIRECT, TransactionIdIsValid, SpGistDeadTupleData::tupstate, and SpGistDeadTupleData::xid.

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

1056 {
1058 
1059  tuple->tupstate = tupstate;
1060  tuple->size = SGDTSIZE;
1062 
1063  if (tupstate == SPGIST_REDIRECT)
1064  {
1065  ItemPointerSet(&tuple->pointer, blkno, offnum);
1067  tuple->xid = state->myXid;
1068  }
1069  else
1070  {
1071  ItemPointerSetInvalid(&tuple->pointer);
1072  tuple->xid = InvalidTransactionId;
1073  }
1074 
1075  return tuple;
1076 }
#define SGDTSIZE
#define SGLT_SET_NEXTOFFSET(spgLeafTuple, offsetNumber)
#define SPGIST_REDIRECT
ItemPointerData pointer
SpGistDeadTupleData * SpGistDeadTuple
#define InvalidTransactionId
Definition: transam.h:31
TransactionId myXid
unsigned int tupstate
char * deadTupleStorage
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:804
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127

◆ spgFormInnerTuple()

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

Definition at line 971 of file spgutils.c.

References SpGistState::attPrefixType, 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().

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

◆ spgFormLeafTuple()

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

Definition at line 840 of file spgutils.c.

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

Referenced by doPickSplit(), and spgdoinsert().

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

◆ spgFormNodeTuple()

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

Definition at line 929 of file spgutils.c.

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

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

930 {
931  SpGistNodeTuple tup;
932  unsigned int size;
933  unsigned short infomask = 0;
934 
935  /* compute space needed (note result is already maxaligned) */
936  size = SGNTHDRSZ;
937  if (!isnull)
938  size += SpGistGetInnerTypeSize(&state->attLabelType, label);
939 
940  /*
941  * Here we make sure that the size will fit in the field reserved for it
942  * in t_info.
943  */
944  if ((size & INDEX_SIZE_MASK) != size)
945  ereport(ERROR,
946  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
947  errmsg("index row requires %zu bytes, maximum size is %zu",
948  (Size) size, (Size) INDEX_SIZE_MASK)));
949 
950  tup = (SpGistNodeTuple) palloc0(size);
951 
952  if (isnull)
953  infomask |= INDEX_NULL_MASK;
954  /* we don't bother setting the INDEX_VAR_MASK bit */
955  infomask |= size;
956  tup->t_info = infomask;
957 
958  /* The TID field will be filled in later */
960 
961  if (!isnull)
963 
964  return tup;
965 }
ItemPointerData t_tid
Definition: itup.h:37
#define INDEX_SIZE_MASK
Definition: itup.h:65
int errcode(int sqlerrcode)
Definition: elog.c:698
SpGistTypeDesc attLabelType
#define SGNTHDRSZ
#define ERROR
Definition: elog.h:46
#define INDEX_NULL_MASK
Definition: itup.h:69
void * palloc0(Size size)
Definition: mcxt.c:1093
static char * label
static void memcpyInnerDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:766
#define ereport(elevel,...)
Definition: elog.h:157
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:540
unsigned int SpGistGetInnerTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:748
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
int errmsg(const char *fmt,...)
Definition: elog.c:909
unsigned short t_info
Definition: itup.h:49
SpGistNodeTupleData * SpGistNodeTuple

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 178 of file spgutils.c.

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, spgConfigOut::labelType, SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, spgConfigOut::leafType, LockBuffer(), SpGistMetaPageData::magicNumber, MemoryContextAllocZero(), OidIsValid, PointerGetDatum, spgConfigOut::prefixType, RelationData::rd_amcache, RelationData::rd_indcollation, RelationData::rd_indexcxt, 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().

179 {
180  SpGistCache *cache;
181 
182  if (index->rd_amcache == NULL)
183  {
184  Oid atttype;
185  spgConfigIn in;
186  FmgrInfo *procinfo;
187  Buffer metabuffer;
188  SpGistMetaPageData *metadata;
189 
190  cache = MemoryContextAllocZero(index->rd_indexcxt,
191  sizeof(SpGistCache));
192 
193  /* SPGiST must have one key column and can also have INCLUDE columns */
196 
197  /*
198  * Get the actual (well, nominal) data type of the key column. We
199  * pass this to the opclass config function so that polymorphic
200  * opclasses are possible.
201  */
202  atttype = GetIndexInputType(index, spgKeyColumn + 1);
203 
204  /* Call the config function to get config info for the opclass */
205  in.attType = atttype;
206 
207  procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC);
208  FunctionCall2Coll(procinfo,
210  PointerGetDatum(&in),
211  PointerGetDatum(&cache->config));
212 
213  /*
214  * If leafType isn't specified, use the declared index column type,
215  * which index.c will have derived from the opclass's opcintype.
216  * (Although we now make spgvalidate.c warn if these aren't the same,
217  * old user-defined opclasses may not set the STORAGE parameter
218  * correctly, so believe leafType if it's given.)
219  */
220  if (!OidIsValid(cache->config.leafType))
221  cache->config.leafType =
222  TupleDescAttr(RelationGetDescr(index), spgKeyColumn)->atttypid;
223 
224  /* Get the information we need about each relevant datatype */
225  fillTypeDesc(&cache->attType, atttype);
226 
227  if (cache->config.leafType != atttype)
228  {
230  ereport(ERROR,
231  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
232  errmsg("compress method must be defined when leaf type is different from input type")));
233 
234  fillTypeDesc(&cache->attLeafType, cache->config.leafType);
235  }
236  else
237  {
238  /* Save lookups in this common case */
239  cache->attLeafType = cache->attType;
240  }
241 
242  fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
243  fillTypeDesc(&cache->attLabelType, cache->config.labelType);
244 
245  /* Last, get the lastUsedPages data from the metapage */
246  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
247  LockBuffer(metabuffer, BUFFER_LOCK_SHARE);
248 
249  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
250 
251  if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
252  elog(ERROR, "index \"%s\" is not an SP-GiST index",
253  RelationGetRelationName(index));
254 
255  cache->lastUsedPages = metadata->lastUsedPages;
256 
257  UnlockReleaseBuffer(metabuffer);
258 
259  index->rd_amcache = (void *) cache;
260  }
261  else
262  {
263  /* assume it's up to date */
264  cache = (SpGistCache *) index->rd_amcache;
265  }
266 
267  return cache;
268 }
SpGistTypeDesc attLeafType
Definition: fmgr.h:56
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:803
#define RelationGetDescr(relation)
Definition: rel.h:495
#define PointerGetDatum(X)
Definition: postgres.h:600
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:698
Oid attType
Definition: spgist.h:38
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1148
unsigned int Oid
Definition: postgres_ext.h:31
SpGistTypeDesc attType
#define OidIsValid(objectId)
Definition: c.h:710
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3807
Oid * rd_indcollation
Definition: rel.h:212
#define ERROR
Definition: elog.h:46
#define SPGIST_METAPAGE_BLKNO
#define IndexRelationGetNumberOfAttributes(relation)
Definition: rel.h:481
#define RelationGetRelationName(relation)
Definition: rel.h:503
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:488
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define SPGIST_MAGIC_NUMBER
spgConfigOut config
#define spgKeyColumn
SpGistLUPCache lastUsedPages
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4023
Oid prefixType
Definition: spgist.h:43
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:28
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:697
#define INDEX_MAX_KEYS
#define SPGIST_CONFIG_PROC
Definition: spgist.h:23
#define SpGistPageGetMeta(p)
SpGistTypeDesc attLabelType
int errmsg(const char *fmt,...)
Definition: elog.c:909
static Oid GetIndexInputType(Relation index, AttrNumber indexcol)
Definition: spgutils.c:111
#define elog(elevel,...)
Definition: elog.h:232
MemoryContext rd_indexcxt
Definition: rel.h:199
Oid labelType
Definition: spgist.h:44
Oid leafType
Definition: spgist.h:45
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
SpGistTypeDesc attPrefixType
static void fillTypeDesc(SpGistTypeDesc *desc, Oid type)
Definition: spgutils.c:156
void * rd_amcache
Definition: rel.h:224
int Buffer
Definition: buf.h:23
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769

◆ spghandler()

Datum spghandler ( PG_FUNCTION_ARGS  )

Definition at line 43 of file spgutils.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, 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.

44 {
46 
47  amroutine->amstrategies = 0;
48  amroutine->amsupport = SPGISTNProc;
50  amroutine->amcanorder = false;
51  amroutine->amcanorderbyop = true;
52  amroutine->amcanbackward = false;
53  amroutine->amcanunique = false;
54  amroutine->amcanmulticol = false;
55  amroutine->amoptionalkey = true;
56  amroutine->amsearcharray = false;
57  amroutine->amsearchnulls = true;
58  amroutine->amstorage = true;
59  amroutine->amclusterable = false;
60  amroutine->ampredlocks = false;
61  amroutine->amcanparallel = false;
62  amroutine->amcaninclude = true;
63  amroutine->amusemaintenanceworkmem = false;
64  amroutine->amparallelvacuumoptions =
66  amroutine->amkeytype = InvalidOid;
67 
68  amroutine->ambuild = spgbuild;
69  amroutine->ambuildempty = spgbuildempty;
70  amroutine->aminsert = spginsert;
71  amroutine->ambulkdelete = spgbulkdelete;
72  amroutine->amvacuumcleanup = spgvacuumcleanup;
73  amroutine->amcanreturn = spgcanreturn;
74  amroutine->amcostestimate = spgcostestimate;
75  amroutine->amoptions = spgoptions;
76  amroutine->amproperty = spgproperty;
77  amroutine->ambuildphasename = NULL;
78  amroutine->amvalidate = spgvalidate;
79  amroutine->amadjustmembers = spgadjustmembers;
80  amroutine->ambeginscan = spgbeginscan;
81  amroutine->amrescan = spgrescan;
82  amroutine->amgettuple = spggettuple;
83  amroutine->amgetbitmap = spggetbitmap;
84  amroutine->amendscan = spgendscan;
85  amroutine->ammarkpos = NULL;
86  amroutine->amrestrpos = NULL;
87  amroutine->amestimateparallelscan = NULL;
88  amroutine->aminitparallelscan = NULL;
89  amroutine->amparallelrescan = NULL;
90 
91  PG_RETURN_POINTER(amroutine);
92 }
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
#define SPGIST_OPTIONS_PROC
Definition: spgist.h:29
amgettuple_function amgettuple
Definition: amapi.h:273
bool amcanorderbyop
Definition: amapi.h:222
amproperty_function amproperty
Definition: amapi.h:267
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: spginsert.c:207
bool spgproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
Definition: spgutils.c:1268
IndexBulkDeleteResult * spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: spgvacuum.c:937
amparallelrescan_function amparallelrescan
Definition: amapi.h:282
bool amstorage
Definition: amapi.h:236
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:379
bool ampredlocks
Definition: amapi.h:240
aminsert_function aminsert
Definition: amapi.h:261
Oid amkeytype
Definition: amapi.h:250
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:425
bool amoptionalkey
Definition: amapi.h:230
amvalidate_function amvalidate
Definition: amapi.h:269
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:1081
amgetbitmap_function amgetbitmap
Definition: amapi.h:274
IndexBulkDeleteResult * spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: spgvacuum.c:906
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
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:263
amendscan_function amendscan
Definition: amapi.h:275
bool amcanbackward
Definition: amapi.h:224
void spgadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
Definition: spgvalidate.c:332
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:939
void spgbuildempty(Relation index)
Definition: spginsert.c:156
amrescan_function amrescan
Definition: amapi.h:272
bool amcanparallel
Definition: amapi.h:242
bytea * spgoptions(Datum reloptions, bool validate)
Definition: spgutils.c:727
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
void spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition: selfuncs.c:6997
#define makeNode(_type_)
Definition: nodes.h:587
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
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:75
uint16 amstrategies
Definition: amapi.h:214
#define SPGISTNProc
Definition: spgist.h:31
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:39
uint16 amoptsprocnum
Definition: amapi.h:218
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:1023
ambuildempty_function ambuildempty
Definition: amapi.h:260
IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz)
Definition: spgscan.c:303
amcanreturn_function amcanreturn
Definition: amapi.h:264
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:281
amrestrpos_function amrestrpos
Definition: amapi.h:277

◆ SpGistGetBuffer()

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

Definition at line 537 of file spgutils.c.

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().

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

◆ SpGistGetInnerTypeSize()

unsigned int SpGistGetInnerTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 748 of file spgutils.c.

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

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

749 {
750  unsigned int size;
751 
752  if (att->attbyval)
753  size = sizeof(Datum);
754  else if (att->attlen > 0)
755  size = att->attlen;
756  else
757  size = VARSIZE_ANY(datum);
758 
759  return MAXALIGN(size);
760 }
uintptr_t Datum
Definition: postgres.h:411
#define VARSIZE_ANY(PTR)
Definition: postgres.h:348
#define MAXALIGN(LEN)
Definition: c.h:757

◆ SpGistGetLeafTupleSize()

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

Definition at line 787 of file spgutils.c.

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

Referenced by spgdoinsert().

789 {
790  Size size;
791  Size data_size;
792  bool needs_null_mask = false;
793  int natts = tupleDescriptor->natts;
794 
795  /*
796  * Decide whether we need a nulls bitmask.
797  *
798  * If there is only a key attribute (natts == 1), never use a bitmask, for
799  * compatibility with the pre-v14 layout of leaf tuples. Otherwise, we
800  * need one if any attribute is null.
801  */
802  if (natts > 1)
803  {
804  for (int i = 0; i < natts; i++)
805  {
806  if (isnulls[i])
807  {
808  needs_null_mask = true;
809  break;
810  }
811  }
812  }
813 
814  /*
815  * Calculate size of the data part; same as for heap tuples.
816  */
817  data_size = heap_compute_data_size(tupleDescriptor, datums, isnulls);
818 
819  /*
820  * Compute total size.
821  */
822  size = SGLTHDRSZ(needs_null_mask);
823  size += data_size;
824  size = MAXALIGN(size);
825 
826  /*
827  * Ensure that we can replace the tuple with a dead tuple later. This test
828  * is unnecessary when there are any non-null attributes, but be safe.
829  */
830  if (size < SGDTSIZE)
831  size = SGDTSIZE;
832 
833  return size;
834 }
#define SGDTSIZE
#define SGLTHDRSZ(hasnulls)
size_t Size
Definition: c.h:540
#define MAXALIGN(LEN)
Definition: c.h:757
Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:119
int i

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 690 of file spgutils.c.

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

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

691 {
692  Assert(BufferGetPageSize(b) == BLCKSZ);
694 }
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
#define Assert(condition)
Definition: c.h:804
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:676

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 700 of file spgutils.c.

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().

701 {
702  SpGistMetaPageData *metadata;
703  int i;
704 
706  metadata = SpGistPageGetMeta(page);
707  memset(metadata, 0, sizeof(SpGistMetaPageData));
708  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
709 
710  /* initialize last-used-page cache to empty */
711  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
713 
714  /*
715  * Set pd_lower just past the end of the metadata. This is essential,
716  * because without doing so, metadata will be lost if xlog.c compresses
717  * the page.
718  */
719  ((PageHeader) page)->pd_lower =
720  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
721 }
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
#define SPGIST_META
#define SPGIST_MAGIC_NUMBER
SpGistLUPCache lastUsedPages
#define InvalidBlockNumber
Definition: block.h:33
#define SPGIST_CACHED_PAGES
#define SpGistPageGetMeta(p)
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:676
int i

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 676 of file spgutils.c.

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

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

677 {
678  SpGistPageOpaque opaque;
679 
680  PageInit(page, BLCKSZ, sizeof(SpGistPageOpaqueData));
681  opaque = SpGistPageGetOpaque(page);
682  opaque->flags = f;
683  opaque->spgist_page_id = SPGIST_PAGE_ID;
684 }
#define SPGIST_PAGE_ID
#define SpGistPageGetOpaque(page)
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 353 of file spgutils.c.

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().

354 {
355  Buffer buffer;
356  bool needLock;
357 
358  /* First, try to get a page from FSM */
359  for (;;)
360  {
361  BlockNumber blkno = GetFreeIndexPage(index);
362 
363  if (blkno == InvalidBlockNumber)
364  break; /* nothing known to FSM */
365 
366  /*
367  * The fixed pages shouldn't ever be listed in FSM, but just in case
368  * one is, ignore it.
369  */
370  if (SpGistBlockIsFixed(blkno))
371  continue;
372 
373  buffer = ReadBuffer(index, blkno);
374 
375  /*
376  * We have to guard against the possibility that someone else already
377  * recycled this page; the buffer may be locked if so.
378  */
379  if (ConditionalLockBuffer(buffer))
380  {
381  Page page = BufferGetPage(buffer);
382 
383  if (PageIsNew(page))
384  return buffer; /* OK to use, if never initialized */
385 
386  if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
387  return buffer; /* OK to use */
388 
390  }
391 
392  /* Can't use it, so release buffer and try again */
393  ReleaseBuffer(buffer);
394  }
395 
396  /* Must extend the file */
397  needLock = !RELATION_IS_LOCAL(index);
398  if (needLock)
400 
401  buffer = ReadBuffer(index, P_NEW);
403 
404  if (needLock)
406 
407  return buffer;
408 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define PageIsEmpty(page)
Definition: bufpage.h:222
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:602
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3784
#define P_NEW
Definition: bufmgr.h:91
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:4049
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:403
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:453
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4023
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
#define SpGistPageIsDeleted(page)
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:697
#define InvalidBlockNumber
Definition: block.h:33
#define PageIsNew(page)
Definition: bufpage.h:229
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ SpGistPageAddNewItem()

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

Definition at line 1173 of file spgutils.c.

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().

1175 {
1176  SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
1177  OffsetNumber i,
1178  maxoff,
1179  offnum;
1180 
1181  if (opaque->nPlaceholder > 0 &&
1182  PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
1183  {
1184  /* Try to replace a placeholder */
1185  maxoff = PageGetMaxOffsetNumber(page);
1186  offnum = InvalidOffsetNumber;
1187 
1188  for (;;)
1189  {
1190  if (startOffset && *startOffset != InvalidOffsetNumber)
1191  i = *startOffset;
1192  else
1193  i = FirstOffsetNumber;
1194  for (; i <= maxoff; i++)
1195  {
1197  PageGetItemId(page, i));
1198 
1199  if (it->tupstate == SPGIST_PLACEHOLDER)
1200  {
1201  offnum = i;
1202  break;
1203  }
1204  }
1205 
1206  /* Done if we found a placeholder */
1207  if (offnum != InvalidOffsetNumber)
1208  break;
1209 
1210  if (startOffset && *startOffset != InvalidOffsetNumber)
1211  {
1212  /* Hint was no good, re-search from beginning */
1213  *startOffset = InvalidOffsetNumber;
1214  continue;
1215  }
1216 
1217  /* Hmm, no placeholder found? */
1218  opaque->nPlaceholder = 0;
1219  break;
1220  }
1221 
1222  if (offnum != InvalidOffsetNumber)
1223  {
1224  /* Replace the placeholder tuple */
1225  PageIndexTupleDelete(page, offnum);
1226 
1227  offnum = PageAddItem(page, item, size, offnum, false, false);
1228 
1229  /*
1230  * We should not have failed given the size check at the top of
1231  * the function, but test anyway. If we did fail, we must PANIC
1232  * because we've already deleted the placeholder tuple, and
1233  * there's no other way to keep the damage from getting to disk.
1234  */
1235  if (offnum != InvalidOffsetNumber)
1236  {
1237  Assert(opaque->nPlaceholder > 0);
1238  opaque->nPlaceholder--;
1239  if (startOffset)
1240  *startOffset = offnum + 1;
1241  }
1242  else
1243  elog(PANIC, "failed to add item of size %u to SPGiST index page",
1244  (int) size);
1245 
1246  return offnum;
1247  }
1248  }
1249 
1250  /* No luck in replacing a placeholder, so just add it to the page */
1251  offnum = PageAddItem(page, item, size,
1252  InvalidOffsetNumber, false, false);
1253 
1254  if (offnum == InvalidOffsetNumber && !errorOK)
1255  elog(ERROR, "failed to add item of size %u to SPGiST index page",
1256  (int) size);
1257 
1258  return offnum;
1259 }
#define SGDTSIZE
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1045
#define SPGIST_PLACEHOLDER
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
#define PANIC
Definition: elog.h:50
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define ERROR
Definition: elog.h:46
#define FirstOffsetNumber
Definition: off.h:27
SpGistDeadTupleData * SpGistDeadTuple
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
unsigned int tupstate
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:804
#define MAXALIGN(LEN)
Definition: c.h:757
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:951
#define SpGistPageGetOpaque(page)
#define elog(elevel,...)
Definition: elog.h:232
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 641 of file spgutils.c.

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().

642 {
643  SpGistCache *cache = spgGetCache(index);
644  SpGistLastUsedPage *lup;
645  int freeSpace;
646  Page page = BufferGetPage(buffer);
647  BlockNumber blkno = BufferGetBlockNumber(buffer);
648  int flags;
649 
650  /* Never enter fixed pages (root pages) in cache, though */
651  if (SpGistBlockIsFixed(blkno))
652  return;
653 
654  if (SpGistPageIsLeaf(page))
655  flags = GBUF_LEAF;
656  else
657  flags = GBUF_INNER_PARITY(blkno);
658  if (SpGistPageStoresNulls(page))
659  flags |= GBUF_NULLS;
660 
661  lup = GET_LUP(cache, flags);
662 
663  freeSpace = PageGetExactFreeSpace(page);
664  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
665  lup->freeSpace < freeSpace)
666  {
667  lup->blkno = blkno;
668  lup->freeSpace = freeSpace;
669  }
670 }
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:178
#define GET_LUP(c, f)
Definition: spgutils.c:458
uint32 BlockNumber
Definition: block.h:31
#define GBUF_INNER_PARITY(x)
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define GBUF_LEAF
#define SpGistPageStoresNulls(page)
#define InvalidBlockNumber
Definition: block.h:33
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:951
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2758
Pointer Page
Definition: bufpage.h:78

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 418 of file spgutils.c.

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

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

419 {
420  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
421 
422  if (cache != NULL)
423  {
424  Buffer metabuffer;
425 
426  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
427 
428  if (ConditionalLockBuffer(metabuffer))
429  {
430  Page metapage = BufferGetPage(metabuffer);
431  SpGistMetaPageData *metadata = SpGistPageGetMeta(metapage);
432 
433  metadata->lastUsedPages = cache->lastUsedPages;
434 
435  /*
436  * Set pd_lower just past the end of the metadata. This is
437  * essential, because without doing so, metadata will be lost if
438  * xlog.c compresses the page. (We must do this here because
439  * pre-v11 versions of PG did not set the metapage's pd_lower
440  * correctly, so a pg_upgraded index might contain the wrong
441  * value.)
442  */
443  ((PageHeader) metapage)->pd_lower =
444  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
445 
446  MarkBufferDirty(metabuffer);
447  UnlockReleaseBuffer(metabuffer);
448  }
449  else
450  {
451  ReleaseBuffer(metabuffer);
452  }
453  }
454 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1562
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3784
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3807
#define SPGIST_METAPAGE_BLKNO
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:4049
SpGistLUPCache lastUsedPages
PageHeaderData * PageHeader
Definition: bufpage.h:166
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:697
#define SpGistPageGetMeta(p)
void * rd_amcache
Definition: rel.h:224
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ spgoptions()

bytea* spgoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 727 of file spgutils.c.

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

Referenced by spghandler().

728 {
729  static const relopt_parse_elt tab[] = {
731  };
732 
733  return (bytea *) build_reloptions(reloptions, validate,
735  sizeof(SpGistOptions),
736  tab, lengthof(tab));
737 
738 }
#define lengthof(array)
Definition: c.h:734
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:1887
int fillfactor
Definition: pgbench.c:195
Definition: c.h:621
#define offsetof(type, field)
Definition: c.h:727

◆ spgproperty()

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

Definition at line 1268 of file spgutils.c.

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, SearchSysCacheList1, and catctup::tuple.

Referenced by spghandler().

1271 {
1272  Oid opclass,
1273  opfamily,
1274  opcintype;
1275  CatCList *catlist;
1276  int i;
1277 
1278  /* Only answer column-level inquiries */
1279  if (attno == 0)
1280  return false;
1281 
1282  switch (prop)
1283  {
1285  break;
1286  default:
1287  return false;
1288  }
1289 
1290  /*
1291  * Currently, SP-GiST distance-ordered scans require that there be a
1292  * distance operator in the opclass with the default types. So we assume
1293  * that if such a operator exists, then there's a reason for it.
1294  */
1295 
1296  /* First we need to know the column's opclass. */
1297  opclass = get_index_column_opclass(index_oid, attno);
1298  if (!OidIsValid(opclass))
1299  {
1300  *isnull = true;
1301  return true;
1302  }
1303 
1304  /* Now look up the opclass family and input datatype. */
1305  if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1306  {
1307  *isnull = true;
1308  return true;
1309  }
1310 
1311  /* And now we can check whether the operator is provided. */
1313  ObjectIdGetDatum(opfamily));
1314 
1315  *res = false;
1316 
1317  for (i = 0; i < catlist->n_members; i++)
1318  {
1319  HeapTuple amoptup = &catlist->members[i]->tuple;
1320  Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(amoptup);
1321 
1322  if (amopform->amoppurpose == AMOP_ORDER &&
1323  (amopform->amoplefttype == opcintype ||
1324  amopform->amoprighttype == opcintype) &&
1325  opfamily_can_sort_type(amopform->amopsortfamily,
1326  get_op_rettype(amopform->amopopr)))
1327  {
1328  *res = true;
1329  break;
1330  }
1331  }
1332 
1333  ReleaseSysCacheList(catlist);
1334 
1335  *isnull = false;
1336 
1337  return true;
1338 }
int n_members
Definition: catcache.h:176
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:271
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:710
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1304
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1228
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:211
#define ReleaseSysCacheList(x)
Definition: syscache.h:218
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
int i
HeapTupleData tuple
Definition: catcache.h:121