PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 "utils/catcache.h"
#include "utils/fmgrprotos.h"
#include "utils/index_selfuncs.h"
#include "utils/lsyscache.h"
#include "utils/rel.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, const Datum *datums, const bool *isnulls)
 
SpGistLeafTuple spgFormLeafTuple (SpGistState *state, const ItemPointerData *heapPtr, const Datum *datums, const 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, const void *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 491 of file spgutils.c.

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

Definition at line 514 of file spgutils.c.

515{
516 SpGistCache *cache = spgGetCache(index);
517 uint16 pageflags = 0;
518
519 if (GBUF_REQ_LEAF(flags))
521 if (GBUF_REQ_NULLS(flags))
523
524 for (;;)
525 {
526 Buffer buffer;
527
528 buffer = SpGistNewBuffer(index);
530
532 {
533 /* Leaf pages have no parity concerns, so just use it */
534 return buffer;
535 }
536 else
537 {
538 BlockNumber blkno = BufferGetBlockNumber(buffer);
539 int blkFlags = GBUF_INNER_PARITY(blkno);
540
541 if ((flags & GBUF_PARITY_MASK) == blkFlags)
542 {
543 /* Page has right parity, use it */
544 return buffer;
545 }
546 else
547 {
548 /* Page has wrong parity, record it in cache and try again */
551 cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
554 UnlockReleaseBuffer(buffer);
555 }
556 }
557 }
558}
uint32 BlockNumber
Definition block.h:31
int Buffer
Definition buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4356
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5518
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:466
Size PageGetExactFreeSpace(const PageData *page)
Definition bufpage.c:957
uint16_t uint16
Definition c.h:545
static int fb(int x)
#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:395
SpGistCache * spgGetCache(Relation index)
Definition spgutils.c:189
void SpGistInitBuffer(Buffer b, uint16 f)
Definition spgutils.c:723
SpGistLUPCache lastUsedPages
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
Definition type.h:96

References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage(), SpGistLUPCache::cachedPage, fb(), 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 167 of file spgutils.c.

168{
169 HeapTuple tp;
171
172 desc->type = type;
174 if (!HeapTupleIsValid(tp))
175 elog(ERROR, "cache lookup failed for type %u", type);
177 desc->attlen = typtup->typlen;
178 desc->attbyval = typtup->typbyval;
179 desc->attalign = typtup->typalign;
180 desc->attstorage = typtup->typstorage;
181 ReleaseSysCache(tp);
182}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
FormData_pg_type * Form_pg_type
Definition pg_type.h:261
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
const char * type

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

Referenced by spgGetCache().

◆ GetIndexInputType()

static Oid GetIndexInputType ( Relation  index,
AttrNumber  indexcol 
)
static

Definition at line 122 of file spgutils.c.

123{
124 Oid opcintype;
126 List *indexprs;
128
129 Assert(index->rd_index != NULL);
130 Assert(indexcol > 0 && indexcol <= index->rd_index->indnkeyatts);
131 opcintype = index->rd_opcintype[indexcol - 1];
132 if (!IsPolymorphicType(opcintype))
133 return opcintype;
134 heapcol = index->rd_index->indkey.values[indexcol - 1];
135 if (heapcol != 0) /* Simple index column? */
136 return getBaseType(get_atttype(index->rd_index->indrelid, heapcol));
137
138 /*
139 * If the index expressions are already cached, skip calling
140 * RelationGetIndexExpressions, as it will make a copy which is overkill.
141 * We're not going to modify the trees, and we're not going to do anything
142 * that would invalidate the relcache entry before we're done.
143 */
144 if (index->rd_indexprs)
145 indexprs = index->rd_indexprs;
146 else
149 for (int i = 1; i <= index->rd_index->indnkeyatts; i++)
150 {
151 if (index->rd_index->indkey.values[i - 1] == 0)
152 {
153 /* expression column */
154 if (indexpr_item == NULL)
155 elog(ERROR, "wrong number of index expressions");
156 if (i == indexcol)
159 }
160 }
161 elog(ERROR, "wrong number of index expressions");
162 return InvalidOid; /* keep compiler quiet */
163}
int16 AttrNumber
Definition attnum.h:21
#define Assert(condition)
Definition c.h:873
int i
Definition isn.c:77
Oid getBaseType(Oid typid)
Definition lsyscache.c:2671
Oid get_atttype(Oid relid, AttrNumber attnum)
Definition lsyscache.c:989
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
#define lfirst(lc)
Definition pg_list.h:172
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
#define InvalidOid
unsigned int Oid
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5092
Definition pg_list.h:54
Definition nodes.h:135

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

Referenced by spgGetCache().

◆ getSpGistTupleDesc()

TupleDesc getSpGistTupleDesc ( Relation  index,
SpGistTypeDesc keyType 
)

Definition at line 316 of file spgutils.c.

317{
320
321 if (keyType->type ==
324 else
325 {
328 /* It's sufficient to update the type-dependent fields of the column */
329 att->atttypid = keyType->type;
330 att->atttypmod = -1;
331 att->attlen = keyType->attlen;
332 att->attbyval = keyType->attbyval;
333 att->attalign = keyType->attalign;
334 att->attstorage = keyType->attstorage;
335 /* We shouldn't need to bother with making these valid: */
336 att->attcompression = InvalidCompressionMethod;
337 att->attcollation = InvalidOid;
338 /* In case we changed typlen, we'd better reset following offsets */
339 for (int i = spgFirstIncludeColumn; i < outTupDesc->natts; i++)
341
343 }
344 return outTupDesc;
345}
FormData_pg_attribute * Form_pg_attribute
#define RelationGetDescr(relation)
Definition rel.h:540
#define spgFirstIncludeColumn
#define spgKeyColumn
int32 attcacheoff
Definition tupdesc.h:70
#define InvalidCompressionMethod
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition tupdesc.c:252
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition tupdesc.c:117
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:160
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:175

References CompactAttribute::attcacheoff, CreateTupleDescCopy(), fb(), i, InvalidCompressionMethod, InvalidOid, populate_compact_attribute(), RelationGetDescr, spgFirstIncludeColumn, spgKeyColumn, TupleDescAttr(), and TupleDescCompactAttr().

Referenced by initSpGistState(), and spgbeginscan().

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 349 of file spgutils.c.

350{
351 SpGistCache *cache;
352
353 state->index = index;
354
355 /* Get cached static information about index */
356 cache = spgGetCache(index);
357
358 state->config = cache->config;
359 state->attType = cache->attType;
360 state->attLeafType = cache->attLeafType;
361 state->attPrefixType = cache->attPrefixType;
362 state->attLabelType = cache->attLabelType;
363
364 /* Ensure we have a valid descriptor for leaf tuples */
365 state->leafTupDesc = getSpGistTupleDesc(state->index, &state->attLeafType);
366
367 /* Make workspace for constructing dead tuples */
368 state->deadTupleStorage = palloc0(SGDTSIZE);
369
370 /*
371 * Set horizon XID to use in redirection tuples. Use our own XID if we
372 * have one, else use InvalidTransactionId. The latter case can happen in
373 * VACUUM or REINDEX CONCURRENTLY, and in neither case would it be okay to
374 * force an XID to be assigned. VACUUM won't create any redirection
375 * tuples anyway, but REINDEX CONCURRENTLY can. Fortunately, REINDEX
376 * CONCURRENTLY doesn't mark the index valid until the end, so there could
377 * never be any concurrent scans "in flight" to a redirection tuple it has
378 * inserted. And it locks out VACUUM until the end, too. So it's okay
379 * for VACUUM to immediately expire a redirection tuple that contains an
380 * invalid xid.
381 */
382 state->redirectXid = GetTopTransactionIdIfAny();
383
384 /* Assume we're not in an index build (spgbuild will override) */
385 state->isBuild = false;
386}
void * palloc0(Size size)
Definition mcxt.c:1417
#define SGDTSIZE
TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType)
Definition spgutils.c:316
SpGistTypeDesc attPrefixType
SpGistTypeDesc attLeafType
SpGistTypeDesc attType
spgConfigOut config
SpGistTypeDesc attLabelType
TransactionId GetTopTransactionIdIfAny(void)
Definition xact.c:442

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

799{
800 unsigned int size;
801
802 if (att->attbyval)
803 {
804 memcpy(target, &datum, sizeof(Datum));
805 }
806 else
807 {
808 size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(DatumGetPointer(datum));
809 memcpy(target, DatumGetPointer(datum), size);
810 }
811}
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
static Size VARSIZE_ANY(const void *PTR)
Definition varatt.h:460

References DatumGetPointer(), fb(), and VARSIZE_ANY().

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

◆ spgDeformLeafTuple()

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

Definition at line 1116 of file spgutils.c.

1118{
1120 char *tp; /* ptr to tuple data */
1121 bits8 *bp; /* ptr to null bitmap in tuple */
1122
1123 if (keyColumnIsNull && tupleDescriptor->natts == 1)
1124 {
1125 /*
1126 * Trivial case: there is only the key attribute and we're in a nulls
1127 * tree. The hasNullsMask bit in the tuple header should not be set
1128 * (and thus we can't use index_deform_tuple_internal), but
1129 * nonetheless the result is NULL.
1130 *
1131 * Note: currently this is dead code, because noplace calls this when
1132 * there is only the key attribute. But we should cover the case.
1133 */
1135
1136 datums[spgKeyColumn] = (Datum) 0;
1137 isnulls[spgKeyColumn] = true;
1138 return;
1139 }
1140
1141 tp = (char *) tup + SGLTHDRSZ(hasNullsMask);
1142 bp = (bits8 *) ((char *) tup + sizeof(SpGistLeafTupleData));
1143
1145 datums, isnulls,
1146 tp, bp, hasNullsMask);
1147
1148 /*
1149 * Key column isnull value from the tuple should be consistent with
1150 * keyColumnIsNull flag from the caller.
1151 */
1153}
uint8 bits8
Definition c.h:553
void index_deform_tuple_internal(TupleDesc tupleDescriptor, Datum *values, bool *isnull, char *tp, bits8 *bp, int hasnulls)
Definition indextuple.c:479
#define SGLT_GET_HASNULLMASK(spgLeafTuple)
#define SGLTHDRSZ(hasnulls)

References Assert, fb(), index_deform_tuple_internal(), SGLT_GET_HASNULLMASK, SGLTHDRSZ, and spgKeyColumn.

Referenced by doPickSplit(), and storeGettuple().

◆ spgExtractNodeLabels()

Datum * spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 1161 of file spgutils.c.

1162{
1163 Datum *nodeLabels;
1164 int i;
1165 SpGistNodeTuple node;
1166
1167 /* Either all the labels must be NULL, or none. */
1168 node = SGITNODEPTR(innerTuple);
1169 if (IndexTupleHasNulls(node))
1170 {
1171 SGITITERATE(innerTuple, i, node)
1172 {
1173 if (!IndexTupleHasNulls(node))
1174 elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1175 }
1176 /* They're all null, so just return NULL */
1177 return NULL;
1178 }
1179 else
1180 {
1181 nodeLabels = palloc_array(Datum, innerTuple->nNodes);
1182 SGITITERATE(innerTuple, i, node)
1183 {
1184 if (IndexTupleHasNulls(node))
1185 elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1186 nodeLabels[i] = SGNTDATUM(node, state);
1187 }
1188 return nodeLabels;
1189 }
1190}
#define palloc_array(type, count)
Definition fe_memutils.h:76
static bool IndexTupleHasNulls(const IndexTupleData *itup)
Definition itup.h:77
#define SGITITERATE(x, i, nt)
#define SGNTDATUM(x, s)
#define SGITNODEPTR(x)

References elog, ERROR, fb(), i, IndexTupleHasNulls(), palloc_array, SGITITERATE, SGITNODEPTR, and SGNTDATUM.

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

◆ spgFormDeadTuple()

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

Definition at line 1086 of file spgutils.c.

1088{
1089 SpGistDeadTuple tuple = (SpGistDeadTuple) state->deadTupleStorage;
1090
1091 tuple->tupstate = tupstate;
1092 tuple->size = SGDTSIZE;
1094
1095 if (tupstate == SPGIST_REDIRECT)
1096 {
1097 ItemPointerSet(&tuple->pointer, blkno, offnum);
1098 tuple->xid = state->redirectXid;
1099 }
1100 else
1101 {
1102 ItemPointerSetInvalid(&tuple->pointer);
1103 tuple->xid = InvalidTransactionId;
1104 }
1105
1106 return tuple;
1107}
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition itemptr.h:135
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
#define InvalidOffsetNumber
Definition off.h:26
SpGistDeadTupleData * SpGistDeadTuple
#define SPGIST_REDIRECT
#define SGLT_SET_NEXTOFFSET(spgLeafTuple, offsetNumber)
#define InvalidTransactionId
Definition transam.h:31

References InvalidOffsetNumber, InvalidTransactionId, ItemPointerSet(), ItemPointerSetInvalid(), SpGistDeadTupleData::pointer, SGDTSIZE, SGLT_SET_NEXTOFFSET, SpGistDeadTupleData::size, SPGIST_REDIRECT, 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 1003 of file spgutils.c.

1005{
1007 unsigned int size;
1008 unsigned int prefixSize;
1009 int i;
1010 char *ptr;
1011
1012 /* Compute size needed */
1013 if (hasPrefix)
1014 prefixSize = SpGistGetInnerTypeSize(&state->attPrefixType, prefix);
1015 else
1016 prefixSize = 0;
1017
1018 size = SGITHDRSZ + prefixSize;
1019
1020 /* Note: we rely on node tuple sizes to be maxaligned already */
1021 for (i = 0; i < nNodes; i++)
1022 size += IndexTupleSize(nodes[i]);
1023
1024 /*
1025 * Ensure that we can replace the tuple with a dead tuple later. This
1026 * test is unnecessary given current tuple layouts, but let's be safe.
1027 */
1028 if (size < SGDTSIZE)
1029 size = SGDTSIZE;
1030
1031 /*
1032 * Inner tuple should be small enough to fit on a page
1033 */
1034 if (size > SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))
1035 ereport(ERROR,
1037 errmsg("SP-GiST inner tuple size %zu exceeds maximum %zu",
1038 (Size) size,
1040 errhint("Values larger than a buffer page cannot be indexed.")));
1041
1042 /*
1043 * Check for overflow of header fields --- probably can't fail if the
1044 * above succeeded, but let's be paranoid
1045 */
1046 if (size > SGITMAXSIZE ||
1047 prefixSize > SGITMAXPREFIXSIZE ||
1048 nNodes > SGITMAXNNODES)
1049 elog(ERROR, "SPGiST inner tuple header field is too small");
1050
1051 /* OK, form the tuple */
1052 tup = (SpGistInnerTuple) palloc0(size);
1053
1054 tup->nNodes = nNodes;
1055 tup->prefixSize = prefixSize;
1056 tup->size = size;
1057
1058 if (hasPrefix)
1059 memcpyInnerDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
1060
1061 ptr = (char *) SGITNODEPTR(tup);
1062
1063 for (i = 0; i < nNodes; i++)
1064 {
1065 SpGistNodeTuple node = nodes[i];
1066
1067 memcpy(ptr, node, IndexTupleSize(node));
1068 ptr += IndexTupleSize(node);
1069 }
1070
1071 return tup;
1072}
size_t Size
Definition c.h:619
int errhint(const char *fmt,...)
Definition elog.c:1330
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ereport(elevel,...)
Definition elog.h:150
static Size IndexTupleSize(const IndexTupleData *itup)
Definition itup.h:71
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:798
unsigned int SpGistGetInnerTypeSize(SpGistTypeDesc *att, Datum datum)
Definition spgutils.c:780

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

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

◆ spgFormLeafTuple()

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

Definition at line 872 of file spgutils.c.

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

References fb(), heap_compute_data_size(), heap_fill_tuple(), i, InvalidOffsetNumber, MAXALIGN, palloc0(), SGDTSIZE, SGLT_SET_HASNULLMASK, SGLT_SET_NEXTOFFSET, SGLTHDRSZ, and spgKeyColumn.

Referenced by doPickSplit(), and spgdoinsert().

◆ spgFormNodeTuple()

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

Definition at line 961 of file spgutils.c.

962{
964 unsigned int size;
965 unsigned short infomask = 0;
966
967 /* compute space needed (note result is already maxaligned) */
968 size = SGNTHDRSZ;
969 if (!isnull)
970 size += SpGistGetInnerTypeSize(&state->attLabelType, label);
971
972 /*
973 * Here we make sure that the size will fit in the field reserved for it
974 * in t_info.
975 */
976 if ((size & INDEX_SIZE_MASK) != size)
979 errmsg("index row requires %zu bytes, maximum size is %zu",
980 (Size) size, (Size) INDEX_SIZE_MASK)));
981
982 tup = (SpGistNodeTuple) palloc0(size);
983
984 if (isnull)
986 /* we don't bother setting the INDEX_VAR_MASK bit */
987 infomask |= size;
988 tup->t_info = infomask;
989
990 /* The TID field will be filled in later */
991 ItemPointerSetInvalid(&tup->t_tid);
992
993 if (!isnull)
994 memcpyInnerDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
995
996 return tup;
997}
#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

References ereport, errcode(), errmsg(), ERROR, fb(), INDEX_NULL_MASK, INDEX_SIZE_MASK, ItemPointerSetInvalid(), label, memcpyInnerDatum(), palloc0(), SGNTDATAPTR, SGNTHDRSZ, and SpGistGetInnerTypeSize().

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

◆ spgGetCache()

SpGistCache * spgGetCache ( Relation  index)

Definition at line 189 of file spgutils.c.

190{
191 SpGistCache *cache;
192
193 if (index->rd_amcache == NULL)
194 {
195 Oid atttype;
196 spgConfigIn in;
198
199 cache = MemoryContextAllocZero(index->rd_indexcxt,
200 sizeof(SpGistCache));
201
202 /* SPGiST must have one key column and can also have INCLUDE columns */
205
206 /*
207 * Get the actual (well, nominal) data type of the key column. We
208 * pass this to the opclass config function so that polymorphic
209 * opclasses are possible.
210 */
211 atttype = GetIndexInputType(index, spgKeyColumn + 1);
212
213 /* Call the config function to get config info for the opclass */
214 in.attType = atttype;
215
218 index->rd_indcollation[spgKeyColumn],
219 PointerGetDatum(&in),
220 PointerGetDatum(&cache->config));
221
222 /*
223 * If leafType isn't specified, use the declared index column type,
224 * which index.c will have derived from the opclass's opcintype.
225 * (Although we now make spgvalidate.c warn if these aren't the same,
226 * old user-defined opclasses may not set the STORAGE parameter
227 * correctly, so believe leafType if it's given.)
228 */
229 if (!OidIsValid(cache->config.leafType))
230 {
231 cache->config.leafType =
233
234 /*
235 * If index column type is binary-coercible to atttype (for
236 * example, it's a domain over atttype), treat it as plain atttype
237 * to avoid thinking we need to compress.
238 */
239 if (cache->config.leafType != atttype &&
240 IsBinaryCoercible(cache->config.leafType, atttype))
241 cache->config.leafType = atttype;
242 }
243
244 /* Get the information we need about each relevant datatype */
245 fillTypeDesc(&cache->attType, atttype);
246
247 if (cache->config.leafType != atttype)
248 {
252 errmsg("compress method must be defined when leaf type is different from input type")));
253
254 fillTypeDesc(&cache->attLeafType, cache->config.leafType);
255 }
256 else
257 {
258 /* Save lookups in this common case */
259 cache->attLeafType = cache->attType;
260 }
261
263 fillTypeDesc(&cache->attLabelType, cache->config.labelType);
264
265 /*
266 * Finally, if it's a real index (not a partitioned one), get the
267 * lastUsedPages data from the metapage
268 */
269 if (index->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
270 {
272 SpGistMetaPageData *metadata;
273
276
278
279 if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
280 elog(ERROR, "index \"%s\" is not an SP-GiST index",
282
283 cache->lastUsedPages = metadata->lastUsedPages;
284
286 }
287
288 index->rd_amcache = cache;
289 }
290 else
291 {
292 /* assume it's up to date */
293 cache = (SpGistCache *) index->rd_amcache;
294 }
295
296 return cache;
297}
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:864
@ BUFFER_LOCK_SHARE
Definition bufmgr.h:210
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:328
#define OidIsValid(objectId)
Definition c.h:788
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1150
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:917
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:883
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define INDEX_MAX_KEYS
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
#define RelationGetRelationName(relation)
Definition rel.h:548
#define IndexRelationGetNumberOfAttributes(relation)
Definition rel.h:526
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:533
#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:122
static void fillTypeDesc(SpGistTypeDesc *desc, Oid type)
Definition spgutils.c:167
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, fb(), 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{
46 static const IndexAmRoutine amroutine = {
48 .amstrategies = 0,
49 .amsupport = SPGISTNProc,
50 .amoptsprocnum = SPGIST_OPTIONS_PROC,
51 .amcanorder = false,
52 .amcanorderbyop = true,
53 .amcanhash = false,
54 .amconsistentequality = false,
55 .amconsistentordering = false,
56 .amcanbackward = false,
57 .amcanunique = false,
58 .amcanmulticol = false,
59 .amoptionalkey = true,
60 .amsearcharray = false,
61 .amsearchnulls = true,
62 .amstorage = true,
63 .amclusterable = false,
64 .ampredlocks = false,
65 .amcanparallel = false,
66 .amcanbuildparallel = false,
67 .amcaninclude = true,
68 .amusemaintenanceworkmem = false,
69 .amsummarizing = false,
70 .amparallelvacuumoptions =
72 .amkeytype = InvalidOid,
73
74 .ambuild = spgbuild,
75 .ambuildempty = spgbuildempty,
76 .aminsert = spginsert,
77 .aminsertcleanup = NULL,
78 .ambulkdelete = spgbulkdelete,
79 .amvacuumcleanup = spgvacuumcleanup,
80 .amcanreturn = spgcanreturn,
81 .amcostestimate = spgcostestimate,
82 .amgettreeheight = NULL,
83 .amoptions = spgoptions,
84 .amproperty = spgproperty,
85 .ambuildphasename = NULL,
86 .amvalidate = spgvalidate,
87 .amadjustmembers = spgadjustmembers,
88 .ambeginscan = spgbeginscan,
89 .amrescan = spgrescan,
90 .amgettuple = spggettuple,
91 .amgetbitmap = spggetbitmap,
92 .amendscan = spgendscan,
93 .ammarkpos = NULL,
94 .amrestrpos = NULL,
95 .amestimateparallelscan = NULL,
96 .aminitparallelscan = NULL,
97 .amparallelrescan = NULL,
98 .amtranslatestrategy = NULL,
99 .amtranslatecmptype = NULL,
100 };
101
103}
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
void spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition selfuncs.c:8246
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition spginsert.c:73
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition spginsert.c:183
void spgbuildempty(Relation index)
Definition spginsert.c:154
#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:305
bool spgcanreturn(Relation index, int attno)
Definition spgscan.c:1078
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition spgscan.c:1021
void spgendscan(IndexScanDesc scan)
Definition spgscan.c:424
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition spgscan.c:375
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition spgscan.c:937
bytea * spgoptions(Datum reloptions, bool validate)
Definition spgutils.c:760
bool spgproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
Definition spgutils.c:1299
IndexBulkDeleteResult * spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition spgvacuum.c:950
IndexBulkDeleteResult * spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition spgvacuum.c:981
bool spgvalidate(Oid opclassoid)
Definition spgvalidate.c:38
void spgadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
NodeTag type
Definition amapi.h:234
#define VACUUM_OPTION_PARALLEL_BULKDEL
Definition vacuum.h:48
#define VACUUM_OPTION_PARALLEL_COND_CLEANUP
Definition vacuum.h:55

References fb(), InvalidOid, PG_RETURN_POINTER, spgadjustmembers(), spgbeginscan(), spgbuild(), spgbuildempty(), spgbulkdelete(), spgcanreturn(), spgcostestimate(), spgendscan(), spggetbitmap(), spggettuple(), spginsert(), SPGIST_OPTIONS_PROC, SPGISTNProc, spgoptions(), spgproperty(), spgrescan(), spgvacuumcleanup(), spgvalidate(), IndexAmRoutine::type, VACUUM_OPTION_PARALLEL_BULKDEL, and VACUUM_OPTION_PARALLEL_COND_CLEANUP.

◆ SpGistGetBuffer()

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

Definition at line 570 of file spgutils.c.

571{
572 SpGistCache *cache = spgGetCache(index);
574
575 /* Bail out if even an empty page wouldn't meet the demand */
577 elog(ERROR, "desired SPGiST tuple size is too big");
578
579 /*
580 * If possible, increase the space request to include relation's
581 * fillfactor. This ensures that when we add unrelated tuples to a page,
582 * we try to keep 100-fillfactor% available for adding tuples that are
583 * related to the ones already on it. But fillfactor mustn't cause an
584 * error for requests that would otherwise be legal.
585 */
588
589 /* Get the cache entry for this flags setting */
590 lup = GET_LUP(cache, flags);
591
592 /* If we have nothing cached, just turn it over to allocNewBuffer */
593 if (lup->blkno == InvalidBlockNumber)
594 {
595 *isNew = true;
596 return allocNewBuffer(index, flags);
597 }
598
599 /* fixed pages should never be in cache */
600 Assert(!SpGistBlockIsFixed(lup->blkno));
601
602 /* If cached freeSpace isn't enough, don't bother looking at the page */
603 if (lup->freeSpace >= needSpace)
604 {
605 Buffer buffer;
606 Page page;
607
608 buffer = ReadBuffer(index, lup->blkno);
609
610 if (!ConditionalLockBuffer(buffer))
611 {
612 /*
613 * buffer is locked by another process, so return a new buffer
614 */
615 ReleaseBuffer(buffer);
616 *isNew = true;
617 return allocNewBuffer(index, flags);
618 }
619
620 page = BufferGetPage(buffer);
621
622 if (PageIsNew(page) || SpGistPageIsDeleted(page) || PageIsEmpty(page))
623 {
624 /* OK to initialize the page */
625 uint16 pageflags = 0;
626
627 if (GBUF_REQ_LEAF(flags))
629 if (GBUF_REQ_NULLS(flags))
632 lup->freeSpace = PageGetExactFreeSpace(page) - needSpace;
633 *isNew = true;
634 return buffer;
635 }
636
637 /*
638 * Check that page is of right type and has enough space. We must
639 * recheck this since our cache isn't necessarily up to date.
640 */
641 if ((GBUF_REQ_LEAF(flags) ? SpGistPageIsLeaf(page) : !SpGistPageIsLeaf(page)) &&
643 {
644 int freeSpace = PageGetExactFreeSpace(page);
645
646 if (freeSpace >= needSpace)
647 {
648 /* Success, update freespace info and return the buffer */
649 lup->freeSpace = freeSpace - needSpace;
650 *isNew = false;
651 return buffer;
652 }
653 }
654
655 /*
656 * fallback to allocation of new buffer
657 */
658 UnlockReleaseBuffer(buffer);
659 }
660
661 /* No success with cache, so return a new buffer */
662 *isNew = true;
663 return allocNewBuffer(index, flags);
664}
#define InvalidBlockNumber
Definition block.h:33
bool ConditionalLockBuffer(Buffer buffer)
Definition bufmgr.c:6474
void ReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5501
static bool PageIsEmpty(const PageData *page)
Definition bufpage.h:223
static bool PageIsNew(const PageData *page)
Definition bufpage.h:233
PageData * Page
Definition bufpage.h:81
#define Min(x, y)
Definition c.h:997
#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:514
#define GET_LUP(c, f)
Definition spgutils.c:491

References allocNewBuffer(), Assert, BufferGetPage(), ConditionalLockBuffer(), elog, ERROR, fb(), 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 780 of file spgutils.c.

781{
782 unsigned int size;
783
784 if (att->attbyval)
785 size = sizeof(Datum);
786 else if (att->attlen > 0)
787 size = att->attlen;
788 else
789 size = VARSIZE_ANY(DatumGetPointer(datum));
790
791 return MAXALIGN(size);
792}

References DatumGetPointer(), fb(), MAXALIGN, and VARSIZE_ANY().

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

◆ SpGistGetLeafTupleSize()

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

Definition at line 819 of file spgutils.c.

821{
822 Size size;
824 bool needs_null_mask = false;
825 int natts = tupleDescriptor->natts;
826
827 /*
828 * Decide whether we need a nulls bitmask.
829 *
830 * If there is only a key attribute (natts == 1), never use a bitmask, for
831 * compatibility with the pre-v14 layout of leaf tuples. Otherwise, we
832 * need one if any attribute is null.
833 */
834 if (natts > 1)
835 {
836 for (int i = 0; i < natts; i++)
837 {
838 if (isnulls[i])
839 {
840 needs_null_mask = true;
841 break;
842 }
843 }
844 }
845
846 /*
847 * Calculate size of the data part; same as for heap tuples.
848 */
850
851 /*
852 * Compute total size.
853 */
855 size += data_size;
856 size = MAXALIGN(size);
857
858 /*
859 * Ensure that we can replace the tuple with a dead tuple later. This test
860 * is unnecessary when there are any non-null attributes, but be safe.
861 */
862 if (size < SGDTSIZE)
863 size = SGDTSIZE;
864
865 return size;
866}

References fb(), heap_compute_data_size(), i, MAXALIGN, SGDTSIZE, and SGLTHDRSZ.

Referenced by spgdoinsert().

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 723 of file spgutils.c.

724{
727}
static Size BufferGetPageSize(Buffer buffer)
Definition bufmgr.h:455
int b
Definition isn.c:74
void SpGistInitPage(Page page, uint16 f)
Definition spgutils.c:709

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 733 of file spgutils.c.

734{
735 SpGistMetaPageData *metadata;
736 int i;
737
739 metadata = SpGistPageGetMeta(page);
740 memset(metadata, 0, sizeof(SpGistMetaPageData));
742
743 /* initialize last-used-page cache to empty */
744 for (i = 0; i < SPGIST_CACHED_PAGES; i++)
746
747 /*
748 * Set pd_lower just past the end of the metadata. This is essential,
749 * because without doing so, metadata will be lost if xlog.c compresses
750 * the page.
751 */
752 ((PageHeader) page)->pd_lower =
753 ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
754}
PageHeaderData * PageHeader
Definition bufpage.h:173
#define SPGIST_META
#define SPGIST_CACHED_PAGES

References SpGistLastUsedPage::blkno, SpGistLUPCache::cachedPage, fb(), 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 709 of file spgutils.c.

710{
711 SpGistPageOpaque opaque;
712
713 PageInit(page, BLCKSZ, sizeof(SpGistPageOpaqueData));
714 opaque = SpGistPageGetOpaque(page);
715 opaque->flags = f;
717}
void PageInit(Page page, Size pageSize, Size specialSize)
Definition bufpage.c:42
#define SpGistPageGetOpaque(page)
#define SPGIST_PAGE_ID

References fb(), 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 395 of file spgutils.c.

396{
397 Buffer buffer;
398
399 /* First, try to get a page from FSM */
400 for (;;)
401 {
403
404 if (blkno == InvalidBlockNumber)
405 break; /* nothing known to FSM */
406
407 /*
408 * The fixed pages shouldn't ever be listed in FSM, but just in case
409 * one is, ignore it.
410 */
411 if (SpGistBlockIsFixed(blkno))
412 continue;
413
414 buffer = ReadBuffer(index, blkno);
415
416 /*
417 * We have to guard against the possibility that someone else already
418 * recycled this page; the buffer may be locked if so.
419 */
420 if (ConditionalLockBuffer(buffer))
421 {
422 Page page = BufferGetPage(buffer);
423
424 if (PageIsNew(page))
425 return buffer; /* OK to use, if never initialized */
426
427 if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
428 return buffer; /* OK to use */
429
431 }
432
433 /* Can't use it, so release buffer and try again */
434 ReleaseBuffer(buffer);
435 }
436
439
440 return buffer;
441}
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition bufmgr.c:964
@ BUFFER_LOCK_UNLOCK
Definition bufmgr.h:205
@ EB_LOCK_FIRST
Definition bufmgr.h:87
#define BMR_REL(p_rel)
Definition bufmgr.h:114
BlockNumber GetFreeIndexPage(Relation rel)
Definition indexfsm.c:38
@ MAIN_FORKNUM
Definition relpath.h:58

References BMR_REL, BUFFER_LOCK_UNLOCK, BufferGetPage(), ConditionalLockBuffer(), EB_LOCK_FIRST, ExtendBufferedRel(), fb(), GetFreeIndexPage(), InvalidBlockNumber, LockBuffer(), MAIN_FORKNUM, PageIsEmpty(), PageIsNew(), ReadBuffer(), ReleaseBuffer(), SpGistBlockIsFixed, and SpGistPageIsDeleted.

Referenced by allocNewBuffer(), and spgbuild().

◆ SpGistPageAddNewItem()

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

Definition at line 1204 of file spgutils.c.

1206{
1209 maxoff,
1210 offnum;
1211
1212 if (opaque->nPlaceholder > 0 &&
1213 PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
1214 {
1215 /* Try to replace a placeholder */
1216 maxoff = PageGetMaxOffsetNumber(page);
1217 offnum = InvalidOffsetNumber;
1218
1219 for (;;)
1220 {
1221 if (startOffset && *startOffset != InvalidOffsetNumber)
1222 i = *startOffset;
1223 else
1225 for (; i <= maxoff; i++)
1226 {
1228 PageGetItemId(page, i));
1229
1230 if (it->tupstate == SPGIST_PLACEHOLDER)
1231 {
1232 offnum = i;
1233 break;
1234 }
1235 }
1236
1237 /* Done if we found a placeholder */
1238 if (offnum != InvalidOffsetNumber)
1239 break;
1240
1241 if (startOffset && *startOffset != InvalidOffsetNumber)
1242 {
1243 /* Hint was no good, re-search from beginning */
1244 *startOffset = InvalidOffsetNumber;
1245 continue;
1246 }
1247
1248 /* Hmm, no placeholder found? */
1249 opaque->nPlaceholder = 0;
1250 break;
1251 }
1252
1253 if (offnum != InvalidOffsetNumber)
1254 {
1255 /* Replace the placeholder tuple */
1256 PageIndexTupleDelete(page, offnum);
1257
1258 offnum = PageAddItem(page, item, size, offnum, false, false);
1259
1260 /*
1261 * We should not have failed given the size check at the top of
1262 * the function, but test anyway. If we did fail, we must PANIC
1263 * because we've already deleted the placeholder tuple, and
1264 * there's no other way to keep the damage from getting to disk.
1265 */
1266 if (offnum != InvalidOffsetNumber)
1267 {
1268 Assert(opaque->nPlaceholder > 0);
1269 opaque->nPlaceholder--;
1270 if (startOffset)
1271 *startOffset = offnum + 1;
1272 }
1273 else
1274 elog(PANIC, "failed to add item of size %zu to SPGiST index page",
1275 size);
1276
1277 return offnum;
1278 }
1279 }
1280
1281 /* No luck in replacing a placeholder, so just add it to the page */
1282 offnum = PageAddItem(page, item, size,
1283 InvalidOffsetNumber, false, false);
1284
1285 if (offnum == InvalidOffsetNumber && !errorOK)
1286 elog(ERROR, "failed to add item of size %zu to SPGiST index page",
1287 size);
1288
1289 return offnum;
1290}
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition bufpage.c:1051
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:243
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:353
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition bufpage.h:471
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:371
#define PANIC
Definition elog.h:42
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
#define SPGIST_PLACEHOLDER

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

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

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 674 of file spgutils.c.

675{
676 SpGistCache *cache = spgGetCache(index);
678 int freeSpace;
679 Page page = BufferGetPage(buffer);
680 BlockNumber blkno = BufferGetBlockNumber(buffer);
681 int flags;
682
683 /* Never enter fixed pages (root pages) in cache, though */
684 if (SpGistBlockIsFixed(blkno))
685 return;
686
687 if (SpGistPageIsLeaf(page))
688 flags = GBUF_LEAF;
689 else
690 flags = GBUF_INNER_PARITY(blkno);
691 if (SpGistPageStoresNulls(page))
692 flags |= GBUF_NULLS;
693
694 lup = GET_LUP(cache, flags);
695
696 freeSpace = PageGetExactFreeSpace(page);
697 if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
698 lup->freeSpace < freeSpace)
699 {
700 lup->blkno = blkno;
701 lup->freeSpace = freeSpace;
702 }
703}
#define GBUF_LEAF

References BufferGetBlockNumber(), BufferGetPage(), fb(), 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 451 of file spgutils.c.

452{
453 SpGistCache *cache = (SpGistCache *) index->rd_amcache;
454
455 if (cache != NULL)
456 {
458
460
462 {
465
466 metadata->lastUsedPages = cache->lastUsedPages;
467
468 /*
469 * Set pd_lower just past the end of the metadata. This is
470 * essential, because without doing so, metadata will be lost if
471 * xlog.c compresses the page. (We must do this here because
472 * pre-v11 versions of PG did not set the metapage's pd_lower
473 * correctly, so a pg_upgraded index might contain the wrong
474 * value.)
475 */
476 ((PageHeader) metapage)->pd_lower =
477 ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
478
481 }
482 else
483 {
485 }
486 }
487}
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3056

References BufferGetPage(), ConditionalLockBuffer(), fb(), 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 760 of file spgutils.c.

761{
762 static const relopt_parse_elt tab[] = {
764 };
765
766 return (bytea *) build_reloptions(reloptions, validate,
768 sizeof(SpGistOptions),
769 tab, lengthof(tab));
770}
static bool validate(Port *port, const char *auth)
Definition auth-oauth.c:638
#define lengthof(array)
Definition c.h:803
static int fillfactor
Definition pgbench.c:188
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
@ RELOPT_KIND_SPGIST
Definition reloptions.h:51
@ RELOPT_TYPE_INT
Definition reloptions.h:33
Definition c.h:706

References build_reloptions(), fb(), fillfactor, lengthof, RELOPT_KIND_SPGIST, RELOPT_TYPE_INT, and validate().

Referenced by spghandler().

◆ spgproperty()

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

Definition at line 1299 of file spgutils.c.

1302{
1303 Oid opclass,
1304 opfamily,
1305 opcintype;
1307 int i;
1308
1309 /* Only answer column-level inquiries */
1310 if (attno == 0)
1311 return false;
1312
1313 switch (prop)
1314 {
1316 break;
1317 default:
1318 return false;
1319 }
1320
1321 /*
1322 * Currently, SP-GiST distance-ordered scans require that there be a
1323 * distance operator in the opclass with the default types. So we assume
1324 * that if such an operator exists, then there's a reason for it.
1325 */
1326
1327 /* First we need to know the column's opclass. */
1328 opclass = get_index_column_opclass(index_oid, attno);
1329 if (!OidIsValid(opclass))
1330 {
1331 *isnull = true;
1332 return true;
1333 }
1334
1335 /* Now look up the opclass family and input datatype. */
1336 if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1337 {
1338 *isnull = true;
1339 return true;
1340 }
1341
1342 /* And now we can check whether the operator is provided. */
1344 ObjectIdGetDatum(opfamily));
1345
1346 *res = false;
1347
1348 for (i = 0; i < catlist->n_members; i++)
1349 {
1350 HeapTuple amoptup = &catlist->members[i]->tuple;
1352
1353 if (amopform->amoppurpose == AMOP_ORDER &&
1354 (amopform->amoplefttype == opcintype ||
1355 amopform->amoprighttype == opcintype) &&
1356 opfamily_can_sort_type(amopform->amopsortfamily,
1357 get_op_rettype(amopform->amopopr)))
1358 {
1359 *res = true;
1360 break;
1361 }
1362 }
1363
1365
1366 *isnull = false;
1367
1368 return true;
1369}
@ AMPROP_DISTANCE_ORDERABLE
Definition amapi.h:46
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:1337
Oid get_op_rettype(Oid opno)
Definition lsyscache.c:1483
Oid get_index_column_opclass(Oid index_oid, int attno)
Definition lsyscache.c:3662
FormData_pg_amop * Form_pg_amop
Definition pg_amop.h:88
#define ReleaseSysCacheList(x)
Definition syscache.h:134
#define SearchSysCacheList1(cacheId, key1)
Definition syscache.h:127

References AMPROP_DISTANCE_ORDERABLE, fb(), get_index_column_opclass(), get_op_rettype(), get_opclass_opfamily_and_input_type(), GETSTRUCT(), i, ObjectIdGetDatum(), OidIsValid, opfamily_can_sort_type(), ReleaseSysCacheList, and SearchSysCacheList1.

Referenced by spghandler().