PostgreSQL Source Code  git master
spgist.h File Reference
#include "access/amapi.h"
#include "access/xlogreader.h"
#include "lib/stringinfo.h"
Include dependency graph for spgist.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  spgConfigIn
 
struct  spgConfigOut
 
struct  spgChooseIn
 
struct  spgChooseOut
 
struct  spgPickSplitIn
 
struct  spgPickSplitOut
 
struct  spgInnerConsistentIn
 
struct  spgInnerConsistentOut
 
struct  spgLeafConsistentIn
 
struct  spgLeafConsistentOut
 

Macros

#define SPGIST_CONFIG_PROC   1
 
#define SPGIST_CHOOSE_PROC   2
 
#define SPGIST_PICKSPLIT_PROC   3
 
#define SPGIST_INNER_CONSISTENT_PROC   4
 
#define SPGIST_LEAF_CONSISTENT_PROC   5
 
#define SPGIST_COMPRESS_PROC   6
 
#define SPGIST_OPTIONS_PROC   7
 
#define SPGISTNRequiredProc   5
 
#define SPGISTNProc   7
 

Typedefs

typedef struct spgConfigIn spgConfigIn
 
typedef struct spgConfigOut spgConfigOut
 
typedef struct spgChooseIn spgChooseIn
 
typedef enum spgChooseResultType spgChooseResultType
 
typedef struct spgChooseOut spgChooseOut
 
typedef struct spgPickSplitIn spgPickSplitIn
 
typedef struct spgPickSplitOut spgPickSplitOut
 
typedef struct spgInnerConsistentIn spgInnerConsistentIn
 
typedef struct spgInnerConsistentOut spgInnerConsistentOut
 
typedef struct spgLeafConsistentIn spgLeafConsistentIn
 
typedef struct spgLeafConsistentOut spgLeafConsistentOut
 

Enumerations

enum  spgChooseResultType { spgMatchNode = 1, spgAddNode, spgSplitTuple }
 

Functions

byteaspgoptions (Datum reloptions, bool validate)
 
IndexBuildResultspgbuild (Relation heap, Relation index, struct IndexInfo *indexInfo)
 
void spgbuildempty (Relation index)
 
bool spginsert (Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, struct IndexInfo *indexInfo)
 
IndexScanDesc spgbeginscan (Relation rel, int keysz, int orderbysz)
 
void spgendscan (IndexScanDesc scan)
 
void spgrescan (IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
 
int64 spggetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
bool spggettuple (IndexScanDesc scan, ScanDirection dir)
 
bool spgcanreturn (Relation index, int attno)
 
IndexBulkDeleteResultspgbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 
IndexBulkDeleteResultspgvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
bool spgvalidate (Oid opclassoid)
 
void spgadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 

Macro Definition Documentation

◆ SPGIST_CHOOSE_PROC

#define SPGIST_CHOOSE_PROC   2

Definition at line 24 of file spgist.h.

Referenced by spgadjustmembers(), spgdoinsert(), and spgvalidate().

◆ SPGIST_COMPRESS_PROC

#define SPGIST_COMPRESS_PROC   6

Definition at line 28 of file spgist.h.

Referenced by spgadjustmembers(), spgdoinsert(), spgGetCache(), and spgvalidate().

◆ SPGIST_CONFIG_PROC

#define SPGIST_CONFIG_PROC   1

Definition at line 23 of file spgist.h.

Referenced by spgadjustmembers(), spgGetCache(), and spgvalidate().

◆ SPGIST_INNER_CONSISTENT_PROC

#define SPGIST_INNER_CONSISTENT_PROC   4

Definition at line 26 of file spgist.h.

Referenced by spgadjustmembers(), spgbeginscan(), and spgvalidate().

◆ SPGIST_LEAF_CONSISTENT_PROC

#define SPGIST_LEAF_CONSISTENT_PROC   5

Definition at line 27 of file spgist.h.

Referenced by spgadjustmembers(), spgbeginscan(), and spgvalidate().

◆ SPGIST_OPTIONS_PROC

#define SPGIST_OPTIONS_PROC   7

Definition at line 29 of file spgist.h.

Referenced by spgadjustmembers(), spghandler(), and spgvalidate().

◆ SPGIST_PICKSPLIT_PROC

#define SPGIST_PICKSPLIT_PROC   3

Definition at line 25 of file spgist.h.

Referenced by doPickSplit(), spgadjustmembers(), and spgvalidate().

◆ SPGISTNProc

#define SPGISTNProc   7

Definition at line 31 of file spgist.h.

Referenced by spghandler(), and spgvalidate().

◆ SPGISTNRequiredProc

#define SPGISTNRequiredProc   5

Definition at line 30 of file spgist.h.

Typedef Documentation

◆ spgChooseIn

typedef struct spgChooseIn spgChooseIn

◆ spgChooseOut

typedef struct spgChooseOut spgChooseOut

◆ spgChooseResultType

◆ spgConfigIn

typedef struct spgConfigIn spgConfigIn

◆ spgConfigOut

typedef struct spgConfigOut spgConfigOut

◆ spgInnerConsistentIn

◆ spgInnerConsistentOut

◆ spgLeafConsistentIn

◆ spgLeafConsistentOut

◆ spgPickSplitIn

◆ spgPickSplitOut

Enumeration Type Documentation

◆ spgChooseResultType

Enumerator
spgMatchNode 
spgAddNode 
spgSplitTuple 

Definition at line 67 of file spgist.h.

68 {
69  spgMatchNode = 1, /* descend into existing node */
70  spgAddNode, /* add a node to the inner tuple */
71  spgSplitTuple /* split inner tuple (change its prefix) */
spgChooseResultType
Definition: spgist.h:67

Function Documentation

◆ spgadjustmembers()

void spgadjustmembers ( Oid  opfamilyoid,
Oid  opclassoid,
List operators,
List functions 
)

Definition at line 332 of file spgvalidate.c.

References ereport, errcode(), errmsg(), ERROR, lfirst, OpFamilyMember::number, OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, SPGIST_CHOOSE_PROC, SPGIST_COMPRESS_PROC, SPGIST_CONFIG_PROC, SPGIST_INNER_CONSISTENT_PROC, SPGIST_LEAF_CONSISTENT_PROC, SPGIST_OPTIONS_PROC, and SPGIST_PICKSPLIT_PROC.

Referenced by spghandler().

336 {
337  ListCell *lc;
338 
339  /*
340  * Operator members of an SP-GiST opfamily should never have hard
341  * dependencies, since their connection to the opfamily depends only on
342  * what the support functions think, and that can be altered. For
343  * consistency, we make all soft dependencies point to the opfamily,
344  * though a soft dependency on the opclass would work as well in the
345  * CREATE OPERATOR CLASS case.
346  */
347  foreach(lc, operators)
348  {
349  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
350 
351  op->ref_is_hard = false;
352  op->ref_is_family = true;
353  op->refobjid = opfamilyoid;
354  }
355 
356  /*
357  * Required support functions should have hard dependencies. Preferably
358  * those are just dependencies on the opclass, but if we're in ALTER
359  * OPERATOR FAMILY, we leave the dependency pointing at the whole
360  * opfamily. (Given that SP-GiST opclasses generally don't share
361  * opfamilies, it seems unlikely to be worth working harder.)
362  */
363  foreach(lc, functions)
364  {
365  OpFamilyMember *op = (OpFamilyMember *) lfirst(lc);
366 
367  switch (op->number)
368  {
369  case SPGIST_CONFIG_PROC:
370  case SPGIST_CHOOSE_PROC:
374  /* Required support function */
375  op->ref_is_hard = true;
376  break;
378  case SPGIST_OPTIONS_PROC:
379  /* Optional, so force it to be a soft family dependency */
380  op->ref_is_hard = false;
381  op->ref_is_family = true;
382  op->refobjid = opfamilyoid;
383  break;
384  default:
385  ereport(ERROR,
386  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
387  errmsg("support function number %d is invalid for access method %s",
388  op->number, "spgist")));
389  break;
390  }
391  }
392 }
bool ref_is_hard
Definition: amapi.h:88
#define SPGIST_OPTIONS_PROC
Definition: spgist.h:29
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:27
int number
Definition: amapi.h:84
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ERROR
Definition: elog.h:46
#define ereport(elevel,...)
Definition: elog.h:157
#define lfirst(lc)
Definition: pg_list.h:169
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:28
#define SPGIST_CONFIG_PROC
Definition: spgist.h:23
bool ref_is_family
Definition: amapi.h:89
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:26
Oid refobjid
Definition: amapi.h:90
#define SPGIST_CHOOSE_PROC
Definition: spgist.h:24
#define SPGIST_PICKSPLIT_PROC
Definition: spgist.h:25

◆ spgbeginscan()

IndexScanDesc spgbeginscan ( Relation  rel,
int  keysz,
int  orderbysz 
)

Definition at line 303 of file spgscan.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, SpGistState::attType, CurrentMemoryContext, fmgr_info_copy(), get_float8_infinity(), getSpGistTupleDesc(), i, index_getprocinfo(), SpGistScanOpaqueData::indexCollation, IndexScanDescData::indexRelation, SpGistScanOpaqueData::infDistances, initSpGistState(), SpGistScanOpaqueData::innerConsistentFn, SpGistScanOpaqueData::keyData, SpGistScanOpaqueData::leafConsistentFn, SpGistScanOpaqueData::nonNullOrderByOffsets, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, SpGistScanOpaqueData::orderByTypes, palloc(), palloc0(), RelationData::rd_indcollation, SpGistScanOpaqueData::reconTupDesc, RelationGetIndexScan(), SPGIST_INNER_CONSISTENT_PROC, SPGIST_LEAF_CONSISTENT_PROC, SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, SpGistScanOpaqueData::traversalCxt, IndexScanDescData::xs_hitupdesc, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, and SpGistScanOpaqueData::zeroDistances.

Referenced by spghandler().

304 {
305  IndexScanDesc scan;
306  SpGistScanOpaque so;
307  int i;
308 
309  scan = RelationGetIndexScan(rel, keysz, orderbysz);
310 
312  if (keysz > 0)
313  so->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * keysz);
314  else
315  so->keyData = NULL;
316  initSpGistState(&so->state, scan->indexRelation);
317 
319  "SP-GiST search temporary context",
322  "SP-GiST traversal-value context",
324 
325  /*
326  * Set up reconTupDesc and xs_hitupdesc in case it's an index-only scan,
327  * making sure that the key column is shown as being of type attType.
328  * (It's rather annoying to do this work when it might be wasted, but for
329  * most opclasses we can re-use the index reldesc instead of making one.)
330  */
331  so->reconTupDesc = scan->xs_hitupdesc =
332  getSpGistTupleDesc(rel, &so->state.attType);
333 
334  /* Allocate various arrays needed for order-by scans */
335  if (scan->numberOfOrderBys > 0)
336  {
337  /* This will be filled in spgrescan, but allocate the space here */
338  so->orderByTypes = (Oid *)
339  palloc(sizeof(Oid) * scan->numberOfOrderBys);
340  so->nonNullOrderByOffsets = (int *)
341  palloc(sizeof(int) * scan->numberOfOrderBys);
342 
343  /* These arrays have constant contents, so we can fill them now */
344  so->zeroDistances = (double *)
345  palloc(sizeof(double) * scan->numberOfOrderBys);
346  so->infDistances = (double *)
347  palloc(sizeof(double) * scan->numberOfOrderBys);
348 
349  for (i = 0; i < scan->numberOfOrderBys; i++)
350  {
351  so->zeroDistances[i] = 0.0;
353  }
354 
355  scan->xs_orderbyvals = (Datum *)
356  palloc0(sizeof(Datum) * scan->numberOfOrderBys);
357  scan->xs_orderbynulls = (bool *)
358  palloc(sizeof(bool) * scan->numberOfOrderBys);
359  memset(scan->xs_orderbynulls, true,
360  sizeof(bool) * scan->numberOfOrderBys);
361  }
362 
366 
370 
371  so->indexCollation = rel->rd_indcollation[0];
372 
373  scan->opaque = so;
374 
375  return scan;
376 }
#define AllocSetContextCreate
Definition: memutils.h:173
static float8 get_float8_infinity(void)
Definition: float.h:93
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:27
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:803
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:145
SpGistTypeDesc attType
MemoryContext tempCxt
Datum * xs_orderbyvals
Definition: relscan.h:161
unsigned int Oid
Definition: postgres_ext.h:31
Relation indexRelation
Definition: relscan.h:118
bool * xs_orderbynulls
Definition: relscan.h:162
Oid * rd_indcollation
Definition: rel.h:200
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:608
ScanKeyData * ScanKey
Definition: skey.h:75
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:318
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void * palloc0(Size size)
Definition: mcxt.c:1093
uintptr_t Datum
Definition: postgres.h:411
SpGistScanOpaqueData * SpGistScanOpaque
MemoryContext traversalCxt
void * palloc(Size size)
Definition: mcxt.c:1062
TupleDesc getSpGistTupleDesc(Relation index, SpGistTypeDesc *keyType)
Definition: spgutils.c:287
int i
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:26
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:81
int numberOfOrderBys
Definition: relscan.h:121

◆ spgbuild()

IndexBuildResult* spgbuild ( Relation  heap,
Relation  index,
struct IndexInfo indexInfo 
)

Definition at line 75 of file spginsert.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, BufferGetBlockNumber(), BufferGetPage, CurrentMemoryContext, elog, END_CRIT_SECTION, ERROR, IndexBuildResult::heap_tuples, IndexBuildResult::index_tuples, SpGistBuildState::indtuples, initSpGistState(), SpGistState::isBuild, log_newpage_range(), MAIN_FORKNUM, MarkBufferDirty(), MemoryContextDelete(), palloc0(), RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, SPGIST_LEAF, SPGIST_METAPAGE_BLKNO, SPGIST_NULL_BLKNO, SPGIST_NULLS, SPGIST_ROOT_BLKNO, spgistBuildCallback(), SpGistInitBuffer(), SpGistInitMetapage(), SpGistNewBuffer(), SpGistUpdateMetaPage(), SpGistBuildState::spgstate, START_CRIT_SECTION, table_index_build_scan(), SpGistBuildState::tmpCtx, and UnlockReleaseBuffer().

Referenced by spghandler().

76 {
77  IndexBuildResult *result;
78  double reltuples;
79  SpGistBuildState buildstate;
80  Buffer metabuffer,
81  rootbuffer,
82  nullbuffer;
83 
84  if (RelationGetNumberOfBlocks(index) != 0)
85  elog(ERROR, "index \"%s\" already contains data",
87 
88  /*
89  * Initialize the meta page and root pages
90  */
91  metabuffer = SpGistNewBuffer(index);
92  rootbuffer = SpGistNewBuffer(index);
93  nullbuffer = SpGistNewBuffer(index);
94 
98 
100 
101  SpGistInitMetapage(BufferGetPage(metabuffer));
102  MarkBufferDirty(metabuffer);
103  SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
104  MarkBufferDirty(rootbuffer);
106  MarkBufferDirty(nullbuffer);
107 
108 
110 
111  UnlockReleaseBuffer(metabuffer);
112  UnlockReleaseBuffer(rootbuffer);
113  UnlockReleaseBuffer(nullbuffer);
114 
115  /*
116  * Now insert all the heap data into the index
117  */
118  initSpGistState(&buildstate.spgstate, index);
119  buildstate.spgstate.isBuild = true;
120  buildstate.indtuples = 0;
121 
123  "SP-GiST build temporary context",
125 
126  reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
127  spgistBuildCallback, (void *) &buildstate,
128  NULL);
129 
130  MemoryContextDelete(buildstate.tmpCtx);
131 
132  SpGistUpdateMetaPage(index);
133 
134  /*
135  * We didn't write WAL records as we built the index, so if WAL-logging is
136  * required, write all pages to the WAL now.
137  */
138  if (RelationNeedsWAL(index))
139  {
141  0, RelationGetNumberOfBlocks(index),
142  true);
143  }
144 
145  result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
146  result->heap_tuples = reltuples;
147  result->index_tuples = buildstate.indtuples;
148 
149  return result;
150 }
static void spgistBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: spginsert.c:43
void SpGistUpdateMetaPage(Relation index)
Definition: spgutils.c:418
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
#define AllocSetContextCreate
Definition: memutils.h:173
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1562
#define END_CRIT_SECTION()
Definition: miscadmin.h:137
#define SPGIST_NULLS
#define START_CRIT_SECTION()
Definition: miscadmin.h:135
SpGistState spgstate
Definition: spginsert.c:35
#define SPGIST_ROOT_BLKNO
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3807
#define ERROR
Definition: elog.h:46
static double table_index_build_scan(Relation table_rel, Relation index_rel, struct IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition: tableam.h:1745
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
#define SPGIST_NULL_BLKNO
#define SPGIST_METAPAGE_BLKNO
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:318
#define RelationGetRelationName(relation)
Definition: rel.h:491
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:690
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
void * palloc0(Size size)
Definition: mcxt.c:1093
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:213
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:353
#define Assert(condition)
Definition: c.h:804
void SpGistInitMetapage(Page page)
Definition: spgutils.c:700
#define RelationNeedsWAL(relation)
Definition: rel.h:570
void log_newpage_range(Relation rel, ForkNumber forkNum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1123
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2758
#define elog(elevel,...)
Definition: elog.h:232
MemoryContext tmpCtx
Definition: spginsert.c:37
#define SPGIST_LEAF
int Buffer
Definition: buf.h:23
double index_tuples
Definition: genam.h:33
double heap_tuples
Definition: genam.h:32

◆ spgbuildempty()

void spgbuildempty ( Relation  index)

Definition at line 156 of file spginsert.c.

References INIT_FORKNUM, log_newpage(), RelFileNodeBackend::node, PageSetChecksumInplace(), palloc(), RelationData::rd_smgr, SMgrRelationData::smgr_rnode, smgrimmedsync(), smgrwrite(), SPGIST_LEAF, SPGIST_METAPAGE_BLKNO, SPGIST_NULL_BLKNO, SPGIST_NULLS, SPGIST_ROOT_BLKNO, SpGistInitMetapage(), and SpGistInitPage().

Referenced by spghandler().

157 {
158  Page page;
159 
160  /* Construct metapage. */
161  page = (Page) palloc(BLCKSZ);
162  SpGistInitMetapage(page);
163 
164  /*
165  * Write the page and log it unconditionally. This is important
166  * particularly for indexes created on tablespaces and databases whose
167  * creation happened after the last redo pointer as recovery removes any
168  * of their existing content when the corresponding create records are
169  * replayed.
170  */
173  (char *) page, true);
175  SPGIST_METAPAGE_BLKNO, page, true);
176 
177  /* Likewise for the root page. */
179 
182  (char *) page, true);
184  SPGIST_ROOT_BLKNO, page, true);
185 
186  /* Likewise for the null-tuples root page. */
188 
191  (char *) page, true);
193  SPGIST_NULL_BLKNO, page, true);
194 
195  /*
196  * An immediate sync is required even if we xlog'd the pages, because the
197  * writes did not go through shared buffers and therefore a concurrent
198  * checkpoint may have moved the redo pointer past our xlog record.
199  */
201 }
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
#define SPGIST_NULLS
#define SPGIST_ROOT_BLKNO
RelFileNodeBackend smgr_rnode
Definition: smgr.h:42
#define SPGIST_NULL_BLKNO
void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:523
#define SPGIST_METAPAGE_BLKNO
RelFileNode node
Definition: relfilenode.h:74
void SpGistInitMetapage(Page page)
Definition: spgutils.c:700
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1532
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:676
void * palloc(Size size)
Definition: mcxt.c:1062
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:996
#define SPGIST_LEAF
void smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:660
Pointer Page
Definition: bufpage.h:78

◆ spgbulkdelete()

IndexBulkDeleteResult* spgbulkdelete ( IndexVacuumInfo info,
IndexBulkDeleteResult stats,
IndexBulkDeleteCallback  callback,
void *  callback_state 
)

Definition at line 906 of file spgvacuum.c.

References spgBulkDeleteState::callback, callback(), spgBulkDeleteState::callback_state, spgBulkDeleteState::info, palloc0(), spgvacuumscan(), and spgBulkDeleteState::stats.

Referenced by spghandler().

908 {
909  spgBulkDeleteState bds;
910 
911  /* allocate stats if first time through, else re-use existing struct */
912  if (stats == NULL)
914  bds.info = info;
915  bds.stats = stats;
916  bds.callback = callback;
917  bds.callback_state = callback_state;
918 
919  spgvacuumscan(&bds);
920 
921  return stats;
922 }
IndexVacuumInfo * info
Definition: spgvacuum.c:44
static void spgvacuumscan(spgBulkDeleteState *bds)
Definition: spgvacuum.c:794
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
IndexBulkDeleteCallback callback
Definition: spgvacuum.c:46
void * palloc0(Size size)
Definition: mcxt.c:1093
void * callback_state
Definition: spgvacuum.c:47
IndexBulkDeleteResult * stats
Definition: spgvacuum.c:45

◆ spgcanreturn()

bool spgcanreturn ( Relation  index,
int  attno 
)

Definition at line 1081 of file spgscan.c.

References spgConfigOut::canReturnData, SpGistCache::config, and spgGetCache().

Referenced by spghandler().

1082 {
1083  SpGistCache *cache;
1084 
1085  /* INCLUDE attributes can always be fetched for index-only scans */
1086  if (attno > 1)
1087  return true;
1088 
1089  /* We can do it if the opclass config function says so */
1090  cache = spgGetCache(index);
1091 
1092  return cache->config.canReturnData;
1093 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:178
bool canReturnData
Definition: spgist.h:46
spgConfigOut config

◆ spgendscan()

void spgendscan ( IndexScanDesc  scan)

Definition at line 425 of file spgscan.c.

References SpGistState::deadTupleStorage, FreeTupleDesc(), SpGistState::index, SpGistScanOpaqueData::infDistances, SpGistScanOpaqueData::keyData, SpGistState::leafTupDesc, MemoryContextDelete(), SpGistScanOpaqueData::nonNullOrderByOffsets, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, SpGistScanOpaqueData::orderByTypes, pfree(), RelationGetDescr, SpGistScanOpaqueData::state, SpGistScanOpaqueData::tempCxt, SpGistScanOpaqueData::traversalCxt, IndexScanDescData::xs_orderbynulls, IndexScanDescData::xs_orderbyvals, and SpGistScanOpaqueData::zeroDistances.

Referenced by spghandler().

426 {
428 
431 
432  if (so->keyData)
433  pfree(so->keyData);
434 
435  if (so->state.leafTupDesc &&
438 
439  if (so->state.deadTupleStorage)
441 
442  if (scan->numberOfOrderBys > 0)
443  {
444  pfree(so->orderByTypes);
446  pfree(so->zeroDistances);
447  pfree(so->infDistances);
448  pfree(scan->xs_orderbyvals);
449  pfree(scan->xs_orderbynulls);
450  }
451 
452  pfree(so);
453 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
#define RelationGetDescr(relation)
Definition: rel.h:483
MemoryContext tempCxt
Datum * xs_orderbyvals
Definition: relscan.h:161
bool * xs_orderbynulls
Definition: relscan.h:162
void pfree(void *pointer)
Definition: mcxt.c:1169
char * deadTupleStorage
SpGistScanOpaqueData * SpGistScanOpaque
TupleDesc leafTupDesc
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:309
MemoryContext traversalCxt
Relation index
int numberOfOrderBys
Definition: relscan.h:121

◆ spggetbitmap()

int64 spggetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 939 of file spgscan.c.

References IndexScanDescData::indexRelation, SpGistScanOpaqueData::ntids, IndexScanDescData::opaque, spgWalk(), storeBitmap(), SpGistScanOpaqueData::tbm, SpGistScanOpaqueData::want_itup, and IndexScanDescData::xs_snapshot.

Referenced by spghandler().

940 {
942 
943  /* Copy want_itup to *so so we don't need to pass it around separately */
944  so->want_itup = false;
945 
946  so->tbm = tbm;
947  so->ntids = 0;
948 
949  spgWalk(scan->indexRelation, so, true, storeBitmap, scan->xs_snapshot);
950 
951  return so->ntids;
952 }
static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, SpGistLeafTuple leafTuple, bool recheck, bool recheckDistances, double *distances)
Definition: spgscan.c:928
struct SnapshotData * xs_snapshot
Definition: relscan.h:119
Relation indexRelation
Definition: relscan.h:118
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:813

◆ spggettuple()

bool spggettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 1023 of file spgscan.c.

References SpGistScanOpaqueData::distances, elog, ERROR, ForwardScanDirection, SpGistScanOpaqueData::heapPtrs, i, index_store_float8_orderby_distances(), IndexScanDescData::indexRelation, SpGistScanOpaqueData::iPtr, SpGistScanOpaqueData::nPtrs, SpGistScanOpaqueData::numberOfOrderBys, IndexScanDescData::opaque, SpGistScanOpaqueData::orderByTypes, pfree(), SpGistScanOpaqueData::recheck, SpGistScanOpaqueData::recheckDistances, SpGistScanOpaqueData::reconTups, spgWalk(), storeGettuple(), SpGistScanOpaqueData::want_itup, IndexScanDescData::xs_heaptid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, IndexScanDescData::xs_snapshot, and IndexScanDescData::xs_want_itup.

Referenced by spghandler().

1024 {
1026 
1027  if (dir != ForwardScanDirection)
1028  elog(ERROR, "SP-GiST only supports forward scan direction");
1029 
1030  /* Copy want_itup to *so so we don't need to pass it around separately */
1031  so->want_itup = scan->xs_want_itup;
1032 
1033  for (;;)
1034  {
1035  if (so->iPtr < so->nPtrs)
1036  {
1037  /* continuing to return reported tuples */
1038  scan->xs_heaptid = so->heapPtrs[so->iPtr];
1039  scan->xs_recheck = so->recheck[so->iPtr];
1040  scan->xs_hitup = so->reconTups[so->iPtr];
1041 
1042  if (so->numberOfOrderBys > 0)
1044  so->distances[so->iPtr],
1045  so->recheckDistances[so->iPtr]);
1046  so->iPtr++;
1047  return true;
1048  }
1049 
1050  if (so->numberOfOrderBys > 0)
1051  {
1052  /* Must pfree distances to avoid memory leak */
1053  int i;
1054 
1055  for (i = 0; i < so->nPtrs; i++)
1056  if (so->distances[i])
1057  pfree(so->distances[i]);
1058  }
1059 
1060  if (so->want_itup)
1061  {
1062  /* Must pfree reconstructed tuples to avoid memory leak */
1063  int i;
1064 
1065  for (i = 0; i < so->nPtrs; i++)
1066  pfree(so->reconTups[i]);
1067  }
1068  so->iPtr = so->nPtrs = 0;
1069 
1070  spgWalk(scan->indexRelation, so, false, storeGettuple,
1071  scan->xs_snapshot);
1072 
1073  if (so->nPtrs == 0)
1074  break; /* must have completed scan */
1075  }
1076 
1077  return false;
1078 }
IndexOrderByDistance * distances[MaxIndexTuplesPerPage]
bool recheckDistances[MaxIndexTuplesPerPage]
ItemPointerData heapPtrs[MaxIndexTuplesPerPage]
struct SnapshotData * xs_snapshot
Definition: relscan.h:119
HeapTuple reconTups[MaxIndexTuplesPerPage]
Relation indexRelation
Definition: relscan.h:118
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
ItemPointerData xs_heaptid
Definition: relscan.h:147
bool recheck[MaxIndexTuplesPerPage]
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:871
SpGistScanOpaqueData * SpGistScanOpaque
static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, storeRes_func storeRes, Snapshot snapshot)
Definition: spgscan.c:813
HeapTuple xs_hitup
Definition: relscan.h:144
static void storeGettuple(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, SpGistLeafTuple leafTuple, bool recheck, bool recheckDistances, double *nonNullDistances)
Definition: spgscan.c:956
#define elog(elevel,...)
Definition: elog.h:232
int i

◆ spginsert()

bool spginsert ( Relation  index,
Datum values,
bool isnull,
ItemPointer  ht_ctid,
Relation  heapRel,
IndexUniqueCheck  checkUnique,
bool  indexUnchanged,
struct IndexInfo indexInfo 
)

Definition at line 207 of file spginsert.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CurrentMemoryContext, initSpGistState(), MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), spgdoinsert(), and SpGistUpdateMetaPage().

Referenced by spghandler().

212 {
213  SpGistState spgstate;
214  MemoryContext oldCtx;
215  MemoryContext insertCtx;
216 
218  "SP-GiST insert temporary context",
220  oldCtx = MemoryContextSwitchTo(insertCtx);
221 
222  initSpGistState(&spgstate, index);
223 
224  /*
225  * We might have to repeat spgdoinsert() multiple times, if conflicts
226  * occur with concurrent insertions. If so, reset the insertCtx each time
227  * to avoid cumulative memory consumption. That means we also have to
228  * redo initSpGistState(), but it's cheap enough not to matter.
229  */
230  while (!spgdoinsert(index, &spgstate, ht_ctid, values, isnull))
231  {
232  MemoryContextReset(insertCtx);
233  initSpGistState(&spgstate, index);
234  }
235 
236  SpGistUpdateMetaPage(index);
237 
238  MemoryContextSwitchTo(oldCtx);
239  MemoryContextDelete(insertCtx);
240 
241  /* return false since we've not done any unique check */
242  return false;
243 }
void SpGistUpdateMetaPage(Relation index)
Definition: spgutils.c:418
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
#define AllocSetContextCreate
Definition: memutils.h:173
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:143
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:318
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
bool spgdoinsert(Relation index, SpGistState *state, ItemPointer heapPtr, Datum *datums, bool *isnulls)
Definition: spgdoinsert.c:1912
static Datum values[MAXATTR]
Definition: bootstrap.c:166

◆ 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

◆ spgrescan()

void spgrescan ( IndexScanDesc  scan,
ScanKey  scankey,
int  nscankeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 379 of file spgscan.c.

References FmgrInfo::fn_oid, get_func_rettype(), i, IndexScanDescData::keyData, IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, IndexScanDescData::orderByData, SpGistScanOpaqueData::orderByTypes, resetSpGistScanOpaque(), ScanKeyData::sk_func, and spgPrepareScanKeys().

Referenced by spghandler().

381 {
383 
384  /* copy scankeys into local storage */
385  if (scankey && scan->numberOfKeys > 0)
386  memmove(scan->keyData, scankey,
387  scan->numberOfKeys * sizeof(ScanKeyData));
388 
389  /* initialize order-by data if needed */
390  if (orderbys && scan->numberOfOrderBys > 0)
391  {
392  int i;
393 
394  memmove(scan->orderByData, orderbys,
395  scan->numberOfOrderBys * sizeof(ScanKeyData));
396 
397  for (i = 0; i < scan->numberOfOrderBys; i++)
398  {
399  ScanKey skey = &scan->orderByData[i];
400 
401  /*
402  * Look up the datatype returned by the original ordering
403  * operator. SP-GiST always uses a float8 for the distance
404  * function, but the ordering operator could be anything else.
405  *
406  * XXX: The distance function is only allowed to be lossy if the
407  * ordering operator's result type is float4 or float8. Otherwise
408  * we don't know how to return the distance to the executor. But
409  * we cannot check that here, as we won't know if the distance
410  * function is lossy until it returns *recheck = true for the
411  * first time.
412  */
414  }
415  }
416 
417  /* preprocess scankeys, set up the representation in *so */
418  spgPrepareScanKeys(scan);
419 
420  /* set up starting queue entries */
422 }
struct ScanKeyData * orderByData
Definition: relscan.h:123
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1626
static void spgPrepareScanKeys(IndexScanDesc scan)
Definition: spgscan.c:207
FmgrInfo sk_func
Definition: skey.h:71
SpGistScanOpaqueData * SpGistScanOpaque
Oid fn_oid
Definition: fmgr.h:59
static void resetSpGistScanOpaque(SpGistScanOpaque so)
Definition: spgscan.c:153
struct ScanKeyData * keyData
Definition: relscan.h:122
int i
int numberOfOrderBys
Definition: relscan.h:121

◆ spgvacuumcleanup()

IndexBulkDeleteResult* spgvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 937 of file spgvacuum.c.

References IndexVacuumInfo::analyze_only, spgBulkDeleteState::callback, spgBulkDeleteState::callback_state, dummy_callback(), IndexVacuumInfo::estimated_count, spgBulkDeleteState::info, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, palloc0(), spgvacuumscan(), and spgBulkDeleteState::stats.

Referenced by spghandler().

938 {
939  spgBulkDeleteState bds;
940 
941  /* No-op in ANALYZE ONLY mode */
942  if (info->analyze_only)
943  return stats;
944 
945  /*
946  * We don't need to scan the index if there was a preceding bulkdelete
947  * pass. Otherwise, make a pass that won't delete any live tuples, but
948  * might still accomplish useful stuff with redirect/placeholder cleanup
949  * and/or FSM housekeeping, and in any case will provide stats.
950  */
951  if (stats == NULL)
952  {
954  bds.info = info;
955  bds.stats = stats;
956  bds.callback = dummy_callback;
957  bds.callback_state = NULL;
958 
959  spgvacuumscan(&bds);
960  }
961 
962  /*
963  * It's quite possible for us to be fooled by concurrent tuple moves into
964  * double-counting some index tuples, so disbelieve any total that exceeds
965  * the underlying heap's count ... if we know that accurately. Otherwise
966  * this might just make matters worse.
967  */
968  if (!info->estimated_count)
969  {
970  if (stats->num_index_tuples > info->num_heap_tuples)
971  stats->num_index_tuples = info->num_heap_tuples;
972  }
973 
974  return stats;
975 }
IndexVacuumInfo * info
Definition: spgvacuum.c:44
bool analyze_only
Definition: genam.h:47
static void spgvacuumscan(spgBulkDeleteState *bds)
Definition: spgvacuum.c:794
IndexBulkDeleteCallback callback
Definition: spgvacuum.c:46
void * palloc0(Size size)
Definition: mcxt.c:1093
static bool dummy_callback(ItemPointer itemptr, void *state)
Definition: spgvacuum.c:926
double num_heap_tuples
Definition: genam.h:51
void * callback_state
Definition: spgvacuum.c:47
IndexBulkDeleteResult * stats
Definition: spgvacuum.c:45
double num_index_tuples
Definition: genam.h:78
bool estimated_count
Definition: genam.h:49

◆ spgvalidate()

bool spgvalidate ( Oid  opclassoid)

Definition at line 39 of file spgvalidate.c.

References AMOPSTRATEGY, AMPROCNUM, spgConfigIn::attType, check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), CLAOID, elog, ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), format_type_be(), OpFamilyOpFuncGroup::functionset, get_op_rettype(), GETSTRUCT, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, InvalidOid, spgConfigOut::leafType, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum, OidFunctionCall2, OidIsValid, OpFamilyOpFuncGroup::operatorset, opfamily_can_sort_type(), OPFAMILYOID, PointerGetDatum, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, SPGIST_CHOOSE_PROC, SPGIST_COMPRESS_PROC, SPGIST_CONFIG_PROC, SPGIST_INNER_CONSISTENT_PROC, SPGIST_LEAF_CONSISTENT_PROC, SPGIST_OPTIONS_PROC, SPGIST_PICKSPLIT_PROC, SPGISTNProc, and catctup::tuple.

Referenced by spghandler().

40 {
41  bool result = true;
42  HeapTuple classtup;
43  Form_pg_opclass classform;
44  Oid opfamilyoid;
45  Oid opcintype;
46  Oid opckeytype;
47  char *opclassname;
48  HeapTuple familytup;
49  Form_pg_opfamily familyform;
50  char *opfamilyname;
51  CatCList *proclist,
52  *oprlist;
53  List *grouplist;
54  OpFamilyOpFuncGroup *opclassgroup;
55  int i;
56  ListCell *lc;
57  spgConfigIn configIn;
58  spgConfigOut configOut;
59  Oid configOutLefttype = InvalidOid;
60  Oid configOutRighttype = InvalidOid;
61  Oid configOutLeafType = InvalidOid;
62 
63  /* Fetch opclass information */
64  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
65  if (!HeapTupleIsValid(classtup))
66  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
67  classform = (Form_pg_opclass) GETSTRUCT(classtup);
68 
69  opfamilyoid = classform->opcfamily;
70  opcintype = classform->opcintype;
71  opckeytype = classform->opckeytype;
72  opclassname = NameStr(classform->opcname);
73 
74  /* Fetch opfamily information */
75  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
76  if (!HeapTupleIsValid(familytup))
77  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
78  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
79 
80  opfamilyname = NameStr(familyform->opfname);
81 
82  /* Fetch all operators and support functions of the opfamily */
83  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
84  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
85  grouplist = identify_opfamily_groups(oprlist, proclist);
86 
87  /* Check individual support functions */
88  for (i = 0; i < proclist->n_members; i++)
89  {
90  HeapTuple proctup = &proclist->members[i]->tuple;
91  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
92  bool ok;
93 
94  /*
95  * All SP-GiST support functions should be registered with matching
96  * left/right types
97  */
98  if (procform->amproclefttype != procform->amprocrighttype)
99  {
100  ereport(INFO,
101  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
102  errmsg("operator family \"%s\" of access method %s contains support function %s with different left and right input types",
103  opfamilyname, "spgist",
104  format_procedure(procform->amproc))));
105  result = false;
106  }
107 
108  /* Check procedure numbers and function signatures */
109  switch (procform->amprocnum)
110  {
111  case SPGIST_CONFIG_PROC:
112  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
113  2, 2, INTERNALOID, INTERNALOID);
114  configIn.attType = procform->amproclefttype;
115  memset(&configOut, 0, sizeof(configOut));
116 
117  OidFunctionCall2(procform->amproc,
118  PointerGetDatum(&configIn),
119  PointerGetDatum(&configOut));
120 
121  configOutLefttype = procform->amproclefttype;
122  configOutRighttype = procform->amprocrighttype;
123 
124  /* Default leaf type is opckeytype or input type */
125  if (OidIsValid(opckeytype))
126  configOutLeafType = opckeytype;
127  else
128  configOutLeafType = procform->amproclefttype;
129 
130  /* If some other leaf datum type is specified, warn */
131  if (OidIsValid(configOut.leafType) &&
132  configOutLeafType != configOut.leafType)
133  {
134  ereport(INFO,
135  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
136  errmsg("SP-GiST leaf data type %s does not match declared type %s",
137  format_type_be(configOut.leafType),
138  format_type_be(configOutLeafType))));
139  result = false;
140  configOutLeafType = configOut.leafType;
141  }
142 
143  /*
144  * When leaf and attribute types are the same, compress
145  * function is not required and we set corresponding bit in
146  * functionset for later group consistency check.
147  */
148  if (configOutLeafType == configIn.attType)
149  {
150  foreach(lc, grouplist)
151  {
152  OpFamilyOpFuncGroup *group = lfirst(lc);
153 
154  if (group->lefttype == procform->amproclefttype &&
155  group->righttype == procform->amprocrighttype)
156  {
157  group->functionset |=
158  ((uint64) 1) << SPGIST_COMPRESS_PROC;
159  break;
160  }
161  }
162  }
163  break;
164  case SPGIST_CHOOSE_PROC:
167  ok = check_amproc_signature(procform->amproc, VOIDOID, true,
168  2, 2, INTERNALOID, INTERNALOID);
169  break;
171  ok = check_amproc_signature(procform->amproc, BOOLOID, true,
172  2, 2, INTERNALOID, INTERNALOID);
173  break;
175  if (configOutLefttype != procform->amproclefttype ||
176  configOutRighttype != procform->amprocrighttype)
177  ok = false;
178  else
179  ok = check_amproc_signature(procform->amproc,
180  configOutLeafType, true,
181  1, 1, procform->amproclefttype);
182  break;
183  case SPGIST_OPTIONS_PROC:
184  ok = check_amoptsproc_signature(procform->amproc);
185  break;
186  default:
187  ereport(INFO,
188  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
189  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
190  opfamilyname, "spgist",
191  format_procedure(procform->amproc),
192  procform->amprocnum)));
193  result = false;
194  continue; /* don't want additional message */
195  }
196 
197  if (!ok)
198  {
199  ereport(INFO,
200  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
201  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
202  opfamilyname, "spgist",
203  format_procedure(procform->amproc),
204  procform->amprocnum)));
205  result = false;
206  }
207  }
208 
209  /* Check individual operators */
210  for (i = 0; i < oprlist->n_members; i++)
211  {
212  HeapTuple oprtup = &oprlist->members[i]->tuple;
213  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
214  Oid op_rettype;
215 
216  /* TODO: Check that only allowed strategy numbers exist */
217  if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
218  {
219  ereport(INFO,
220  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
221  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
222  opfamilyname, "spgist",
223  format_operator(oprform->amopopr),
224  oprform->amopstrategy)));
225  result = false;
226  }
227 
228  /* spgist supports ORDER BY operators */
229  if (oprform->amoppurpose != AMOP_SEARCH)
230  {
231  /* ... and operator result must match the claimed btree opfamily */
232  op_rettype = get_op_rettype(oprform->amopopr);
233  if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
234  {
235  ereport(INFO,
236  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
237  errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
238  opfamilyname, "spgist",
239  format_operator(oprform->amopopr))));
240  result = false;
241  }
242  }
243  else
244  op_rettype = BOOLOID;
245 
246  /* Check operator signature --- same for all spgist strategies */
247  if (!check_amop_signature(oprform->amopopr, op_rettype,
248  oprform->amoplefttype,
249  oprform->amoprighttype))
250  {
251  ereport(INFO,
252  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
253  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
254  opfamilyname, "spgist",
255  format_operator(oprform->amopopr))));
256  result = false;
257  }
258  }
259 
260  /* Now check for inconsistent groups of operators/functions */
261  opclassgroup = NULL;
262  foreach(lc, grouplist)
263  {
264  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
265 
266  /* Remember the group exactly matching the test opclass */
267  if (thisgroup->lefttype == opcintype &&
268  thisgroup->righttype == opcintype)
269  opclassgroup = thisgroup;
270 
271  /*
272  * Complain if there are any datatype pairs with functions but no
273  * operators. This is about the best we can do for now to detect
274  * missing operators.
275  */
276  if (thisgroup->operatorset == 0)
277  {
278  ereport(INFO,
279  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
280  errmsg("operator family \"%s\" of access method %s is missing operator(s) for types %s and %s",
281  opfamilyname, "spgist",
282  format_type_be(thisgroup->lefttype),
283  format_type_be(thisgroup->righttype))));
284  result = false;
285  }
286 
287  /*
288  * Complain if we're missing functions for any datatype, remembering
289  * that SP-GiST doesn't use cross-type support functions.
290  */
291  if (thisgroup->lefttype != thisgroup->righttype)
292  continue;
293 
294  for (i = 1; i <= SPGISTNProc; i++)
295  {
296  if ((thisgroup->functionset & (((uint64) 1) << i)) != 0)
297  continue; /* got it */
298  if (i == SPGIST_OPTIONS_PROC)
299  continue; /* optional method */
300  ereport(INFO,
301  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
302  errmsg("operator family \"%s\" of access method %s is missing support function %d for type %s",
303  opfamilyname, "spgist", i,
304  format_type_be(thisgroup->lefttype))));
305  result = false;
306  }
307  }
308 
309  /* Check that the originally-named opclass is supported */
310  /* (if group is there, we already checked it adequately above) */
311  if (!opclassgroup)
312  {
313  ereport(INFO,
314  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
315  errmsg("operator class \"%s\" of access method %s is missing operator(s)",
316  opclassname, "spgist")));
317  result = false;
318  }
319 
320  ReleaseCatCacheList(proclist);
321  ReleaseCatCacheList(oprlist);
322  ReleaseSysCache(familytup);
323  ReleaseSysCache(classtup);
324 
325  return result;
326 }
int n_members
Definition: catcache.h:176
#define SPGIST_OPTIONS_PROC
Definition: spgist.h:29
#define GETSTRUCT(TUP)
Definition: htup_details.h:654
#define SPGIST_LEAF_CONSISTENT_PROC
Definition: spgist.h:27
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:271
#define PointerGetDatum(X)
Definition: postgres.h:600
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:68
int errcode(int sqlerrcode)
Definition: elog.c:698
#define INFO
Definition: elog.h:33
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
char * format_operator(Oid operator_oid)
Definition: regproc.c:851
Oid attType
Definition: spgist.h:38
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
bool check_amoptsproc_signature(Oid funcid)
Definition: amvalidate.c:192
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1784
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:152
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:43
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:211
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:322
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:169
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:28
#define SPGIST_CONFIG_PROC
Definition: spgist.h:23
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:206
#define OidFunctionCall2(functionId, arg1, arg2)
Definition: fmgr.h:666
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define SPGISTNProc
Definition: spgist.h:31
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
#define elog(elevel,...)
Definition: elog.h:232
int i
#define NameStr(name)
Definition: c.h:681
Oid leafType
Definition: spgist.h:45
#define SPGIST_INNER_CONSISTENT_PROC
Definition: spgist.h:26
HeapTupleData tuple
Definition: catcache.h:121
#define SPGIST_CHOOSE_PROC
Definition: spgist.h:24
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define SPGIST_PICKSPLIT_PROC
Definition: spgist.h:25
Definition: pg_list.h:50