PostgreSQL Source Code  git master
spgist_private.h File Reference
#include "access/itup.h"
#include "access/spgist.h"
#include "catalog/pg_am_d.h"
#include "nodes/tidbitmap.h"
#include "storage/buf.h"
#include "utils/geo_decls.h"
#include "utils/relcache.h"
Include dependency graph for spgist_private.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  SpGistOptions
 
struct  SpGistPageOpaqueData
 
struct  SpGistLastUsedPage
 
struct  SpGistLUPCache
 
struct  SpGistMetaPageData
 
struct  SpGistTypeDesc
 
struct  SpGistState
 
struct  SpGistSearchItem
 
struct  SpGistScanOpaqueData
 
struct  SpGistCache
 
struct  SpGistInnerTupleData
 
struct  SpGistLeafTupleData
 
struct  SpGistDeadTupleData
 

Macros

#define SpGistGetFillFactor(relation)
 
#define SpGistGetTargetPageFreeSpace(relation)    (BLCKSZ * (100 - SpGistGetFillFactor(relation)) / 100)
 
#define spgKeyColumn   0
 
#define spgFirstIncludeColumn   1
 
#define SPGIST_METAPAGE_BLKNO   (0) /* metapage */
 
#define SPGIST_ROOT_BLKNO   (1) /* root for normal entries */
 
#define SPGIST_NULL_BLKNO   (2) /* root for null-value entries */
 
#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO
 
#define SpGistBlockIsRoot(blkno)    ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO)
 
#define SpGistBlockIsFixed(blkno)    ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO)
 
#define SPGIST_META   (1<<0)
 
#define SPGIST_DELETED
 
#define SPGIST_LEAF   (1<<2)
 
#define SPGIST_NULLS   (1<<3)
 
#define SpGistPageGetOpaque(page)   ((SpGistPageOpaque) PageGetSpecialPointer(page))
 
#define SpGistPageIsMeta(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_META)
 
#define SpGistPageIsDeleted(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED)
 
#define SpGistPageIsLeaf(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF)
 
#define SpGistPageStoresNulls(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)
 
#define SPGIST_PAGE_ID   0xFF82
 
#define SPGIST_CACHED_PAGES   8
 
#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)
 
#define SpGistPageGetMeta(p)    ((SpGistMetaPageData *) PageGetContents(p))
 
#define SizeOfSpGistSearchItem(n_distances)    (offsetof(SpGistSearchItem, distances) + sizeof(double) * (n_distances))
 
#define SPGIST_LIVE   0 /* normal live tuple (either inner or leaf) */
 
#define SPGIST_REDIRECT   1 /* temporary redirection placeholder */
 
#define SPGIST_DEAD   2 /* dead, cannot be removed because of links */
 
#define SPGIST_PLACEHOLDER   3 /* placeholder, used to preserve offsets */
 
#define SGITMAXNNODES   0x1FFF
 
#define SGITMAXPREFIXSIZE   0xFFFF
 
#define SGITMAXSIZE   0xFFFF
 
#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))
 
#define _SGITDATA(x)   (((char *) (x)) + SGITHDRSZ)
 
#define SGITDATAPTR(x)   ((x)->prefixSize ? _SGITDATA(x) : NULL)
 
#define SGITDATUM(x, s)
 
#define SGITNODEPTR(x)   ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize))
 
#define SGITITERATE(x, i, nt)
 
#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))
 
#define SGNTDATAPTR(x)   (((char *) (x)) + SGNTHDRSZ)
 
#define SGNTDATUM(x, s)
 
#define SGLT_GET_NEXTOFFSET(spgLeafTuple)    ((spgLeafTuple)->t_info & 0x3FFF)
 
#define SGLT_GET_HASNULLMASK(spgLeafTuple)    (((spgLeafTuple)->t_info & 0x8000) ? true : false)
 
#define SGLT_SET_NEXTOFFSET(spgLeafTuple, offsetNumber)
 
#define SGLT_SET_HASNULLMASK(spgLeafTuple, hasnulls)
 
#define SGLTHDRSZ(hasnulls)
 
#define SGLTDATAPTR(x)   (((char *) (x)) + SGLTHDRSZ(SGLT_GET_HASNULLMASK(x)))
 
#define SGLTDATUM(x, s)
 
#define SGDTSIZE   MAXALIGN(sizeof(SpGistDeadTupleData))
 
#define SPGIST_PAGE_CAPACITY
 
#define SpGistPageGetFreeSpace(p, n)
 
#define STORE_STATE(s, d)
 
#define GBUF_LEAF   0x03
 
#define GBUF_INNER_PARITY(x)   ((x) % 3)
 
#define GBUF_NULLS   0x04
 
#define GBUF_PARITY_MASK   0x03
 
#define GBUF_REQ_LEAF(flags)   (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF)
 
#define GBUF_REQ_NULLS(flags)   ((flags) & GBUF_NULLS)
 
#define SPGIST_MIN_FILLFACTOR   10
 
#define SPGIST_DEFAULT_FILLFACTOR   80
 

Typedefs

typedef struct SpGistOptions SpGistOptions
 
typedef struct SpGistPageOpaqueData SpGistPageOpaqueData
 
typedef SpGistPageOpaqueDataSpGistPageOpaque
 
typedef struct SpGistLastUsedPage SpGistLastUsedPage
 
typedef struct SpGistLUPCache SpGistLUPCache
 
typedef struct SpGistMetaPageData SpGistMetaPageData
 
typedef struct SpGistLeafTupleDataSpGistLeafTuple
 
typedef struct SpGistTypeDesc SpGistTypeDesc
 
typedef struct SpGistState SpGistState
 
typedef struct SpGistSearchItem SpGistSearchItem
 
typedef struct SpGistScanOpaqueData SpGistScanOpaqueData
 
typedef SpGistScanOpaqueDataSpGistScanOpaque
 
typedef struct SpGistCache SpGistCache
 
typedef struct SpGistInnerTupleData SpGistInnerTupleData
 
typedef SpGistInnerTupleDataSpGistInnerTuple
 
typedef IndexTupleData SpGistNodeTupleData
 
typedef SpGistNodeTupleDataSpGistNodeTuple
 
typedef struct SpGistLeafTupleData SpGistLeafTupleData
 
typedef struct SpGistDeadTupleData SpGistDeadTupleData
 
typedef SpGistDeadTupleDataSpGistDeadTuple
 

Functions

SpGistCachespgGetCache (Relation index)
 
TupleDesc getSpGistTupleDesc (Relation index, SpGistTypeDesc *keyType)
 
void initSpGistState (SpGistState *state, Relation index)
 
Buffer SpGistNewBuffer (Relation index)
 
void SpGistUpdateMetaPage (Relation index)
 
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)
 
unsigned int SpGistGetInnerTypeSize (SpGistTypeDesc *att, Datum datum)
 
Size SpGistGetLeafTupleSize (TupleDesc tupleDescriptor, Datum *datums, bool *isnulls)
 
SpGistLeafTuple spgFormLeafTuple (SpGistState *state, ItemPointer heapPtr, Datum *datums, bool *isnulls)
 
SpGistNodeTuple spgFormNodeTuple (SpGistState *state, Datum label, bool isnull)
 
SpGistInnerTuple spgFormInnerTuple (SpGistState *state, bool hasPrefix, Datum prefix, int nNodes, SpGistNodeTuple *nodes)
 
SpGistDeadTuple spgFormDeadTuple (SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
 
void spgDeformLeafTuple (SpGistLeafTuple tup, TupleDesc tupleDescriptor, Datum *datums, bool *isnulls, bool keyColumnIsNull)
 
DatumspgExtractNodeLabels (SpGistState *state, SpGistInnerTuple innerTuple)
 
OffsetNumber SpGistPageAddNewItem (SpGistState *state, Page page, Item item, Size size, OffsetNumber *startOffset, bool errorOK)
 
bool spgproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
 
void spgUpdateNodeLink (SpGistInnerTuple tup, int nodeN, BlockNumber blkno, OffsetNumber offset)
 
void spgPageIndexMultiDelete (SpGistState *state, Page page, OffsetNumber *itemnos, int nitems, int firststate, int reststate, BlockNumber blkno, OffsetNumber offnum)
 
bool spgdoinsert (Relation index, SpGistState *state, ItemPointer heapPtr, Datum *datums, bool *isnulls)
 
double * spg_key_orderbys_distances (Datum key, bool isLeaf, ScanKey orderbys, int norderbys)
 
BOXbox_copy (BOX *orig)
 

Macro Definition Documentation

◆ _SGITDATA

#define _SGITDATA (   x)    (((char *) (x)) + SGITHDRSZ)

Definition at line 311 of file spgist_private.h.

◆ GBUF_INNER_PARITY

#define GBUF_INNER_PARITY (   x)    ((x) % 3)

Definition at line 482 of file spgist_private.h.

◆ GBUF_LEAF

#define GBUF_LEAF   0x03

Definition at line 481 of file spgist_private.h.

◆ GBUF_NULLS

#define GBUF_NULLS   0x04

Definition at line 483 of file spgist_private.h.

◆ GBUF_PARITY_MASK

#define GBUF_PARITY_MASK   0x03

Definition at line 485 of file spgist_private.h.

◆ GBUF_REQ_LEAF

#define GBUF_REQ_LEAF (   flags)    (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF)

Definition at line 486 of file spgist_private.h.

◆ GBUF_REQ_NULLS

#define GBUF_REQ_NULLS (   flags)    ((flags) & GBUF_NULLS)

Definition at line 487 of file spgist_private.h.

◆ SGDTSIZE

#define SGDTSIZE   MAXALIGN(sizeof(SpGistDeadTupleData))

Definition at line 436 of file spgist_private.h.

◆ SGITDATAPTR

#define SGITDATAPTR (   x)    ((x)->prefixSize ? _SGITDATA(x) : NULL)

Definition at line 312 of file spgist_private.h.

◆ SGITDATUM

#define SGITDATUM (   x,
 
)
Value:
((x)->prefixSize ? \
((s)->attPrefixType.attbyval ? \
*(Datum *) _SGITDATA(x) : \
PointerGetDatum(_SGITDATA(x))) \
: (Datum) 0)
int x
Definition: isn.c:71
uintptr_t Datum
Definition: postgres.h:412
#define _SGITDATA(x)

Definition at line 313 of file spgist_private.h.

◆ SGITHDRSZ

#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))

Definition at line 310 of file spgist_private.h.

◆ SGITITERATE

#define SGITITERATE (   x,
  i,
  nt 
)
Value:
for ((i) = 0, (nt) = SGITNODEPTR(x); \
(i) < (x)->nNodes; \
(i)++, (nt) = (SpGistNodeTuple) (((char *) (nt)) + IndexTupleSize(nt)))
int i
Definition: isn.c:73
#define IndexTupleSize(itup)
Definition: itup.h:70
SpGistNodeTupleData * SpGistNodeTuple
#define SGITNODEPTR(x)

Definition at line 321 of file spgist_private.h.

◆ SGITMAXNNODES

#define SGITMAXNNODES   0x1FFF

Definition at line 306 of file spgist_private.h.

◆ SGITMAXPREFIXSIZE

#define SGITMAXPREFIXSIZE   0xFFFF

Definition at line 307 of file spgist_private.h.

◆ SGITMAXSIZE

#define SGITMAXSIZE   0xFFFF

Definition at line 308 of file spgist_private.h.

◆ SGITNODEPTR

#define SGITNODEPTR (   x)    ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize))

Definition at line 318 of file spgist_private.h.

◆ SGLT_GET_HASNULLMASK

#define SGLT_GET_HASNULLMASK (   spgLeafTuple)     (((spgLeafTuple)->t_info & 0x8000) ? true : false)

Definition at line 396 of file spgist_private.h.

◆ SGLT_GET_NEXTOFFSET

#define SGLT_GET_NEXTOFFSET (   spgLeafTuple)     ((spgLeafTuple)->t_info & 0x3FFF)

Definition at line 394 of file spgist_private.h.

◆ SGLT_SET_HASNULLMASK

#define SGLT_SET_HASNULLMASK (   spgLeafTuple,
  hasnulls 
)
Value:
((spgLeafTuple)->t_info = \
((spgLeafTuple)->t_info & 0x7FFF) | ((hasnulls) ? 0x8000 : 0))

Definition at line 401 of file spgist_private.h.

◆ SGLT_SET_NEXTOFFSET

#define SGLT_SET_NEXTOFFSET (   spgLeafTuple,
  offsetNumber 
)
Value:
((spgLeafTuple)->t_info = \
((spgLeafTuple)->t_info & 0xC000) | ((offsetNumber) & 0x3FFF))

Definition at line 398 of file spgist_private.h.

◆ SGLTDATAPTR

#define SGLTDATAPTR (   x)    (((char *) (x)) + SGLTHDRSZ(SGLT_GET_HASNULLMASK(x)))

Definition at line 409 of file spgist_private.h.

◆ SGLTDATUM

#define SGLTDATUM (   x,
 
)
Value:
(s)->attLeafType.attbyval, \
(s)->attLeafType.attlen)
#define SGLTDATAPTR(x)
static Datum fetch_att(const void *T, bool attbyval, int attlen)
Definition: tupmacs.h:52

Definition at line 410 of file spgist_private.h.

◆ SGLTHDRSZ

#define SGLTHDRSZ (   hasnulls)
Value:
((hasnulls) ? MAXALIGN(sizeof(SpGistLeafTupleData) + \
#define MAXALIGN(LEN)
Definition: c.h:747

Definition at line 405 of file spgist_private.h.

◆ SGNTDATAPTR

#define SGNTDATAPTR (   x)    (((char *) (x)) + SGNTHDRSZ)

Definition at line 340 of file spgist_private.h.

◆ SGNTDATUM

#define SGNTDATUM (   x,
 
)
Value:
((s)->attLabelType.attbyval ? \
*(Datum *) SGNTDATAPTR(x) : \
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
#define SGNTDATAPTR(x)

Definition at line 341 of file spgist_private.h.

◆ SGNTHDRSZ

#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))

Definition at line 339 of file spgist_private.h.

◆ SizeOfSpGistSearchItem

#define SizeOfSpGistSearchItem (   n_distances)     (offsetof(SpGistSearchItem, distances) + sizeof(double) * (n_distances))

Definition at line 182 of file spgist_private.h.

◆ spgFirstIncludeColumn

#define spgFirstIncludeColumn   1

Definition at line 44 of file spgist_private.h.

◆ SPGIST_CACHED_PAGES

#define SPGIST_CACHED_PAGES   8

Definition at line 105 of file spgist_private.h.

◆ SPGIST_DEAD

#define SPGIST_DEAD   2 /* dead, cannot be removed because of links */

Definition at line 273 of file spgist_private.h.

◆ SPGIST_DEFAULT_FILLFACTOR

#define SPGIST_DEFAULT_FILLFACTOR   80

Definition at line 493 of file spgist_private.h.

◆ SPGIST_DELETED

#define SPGIST_DELETED
Value:
(1<<1) /* never set, but keep for backwards
* compatibility */

Definition at line 73 of file spgist_private.h.

◆ SPGIST_LAST_FIXED_BLKNO

#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO

Definition at line 50 of file spgist_private.h.

◆ SPGIST_LEAF

#define SPGIST_LEAF   (1<<2)

Definition at line 74 of file spgist_private.h.

◆ SPGIST_LIVE

#define SPGIST_LIVE   0 /* normal live tuple (either inner or leaf) */

Definition at line 271 of file spgist_private.h.

◆ SPGIST_MAGIC_NUMBER

#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)

Definition at line 121 of file spgist_private.h.

◆ SPGIST_META

#define SPGIST_META   (1<<0)

Definition at line 72 of file spgist_private.h.

◆ SPGIST_METAPAGE_BLKNO

#define SPGIST_METAPAGE_BLKNO   (0) /* metapage */

Definition at line 47 of file spgist_private.h.

◆ SPGIST_MIN_FILLFACTOR

#define SPGIST_MIN_FILLFACTOR   10

Definition at line 492 of file spgist_private.h.

◆ SPGIST_NULL_BLKNO

#define SPGIST_NULL_BLKNO   (2) /* root for null-value entries */

Definition at line 49 of file spgist_private.h.

◆ SPGIST_NULLS

#define SPGIST_NULLS   (1<<3)

Definition at line 75 of file spgist_private.h.

◆ SPGIST_PAGE_CAPACITY

#define SPGIST_PAGE_CAPACITY
Value:
MAXALIGN_DOWN(BLCKSZ - \
#define SizeOfPageHeaderData
Definition: bufpage.h:213
#define MAXALIGN_DOWN(LEN)
Definition: c.h:759

Definition at line 446 of file spgist_private.h.

◆ SPGIST_PAGE_ID

#define SPGIST_PAGE_ID   0xFF82

Definition at line 91 of file spgist_private.h.

◆ SPGIST_PLACEHOLDER

#define SPGIST_PLACEHOLDER   3 /* placeholder, used to preserve offsets */

Definition at line 274 of file spgist_private.h.

◆ SPGIST_REDIRECT

#define SPGIST_REDIRECT   1 /* temporary redirection placeholder */

Definition at line 272 of file spgist_private.h.

◆ SPGIST_ROOT_BLKNO

#define SPGIST_ROOT_BLKNO   (1) /* root for normal entries */

Definition at line 48 of file spgist_private.h.

◆ SpGistBlockIsFixed

#define SpGistBlockIsFixed (   blkno)     ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO)

Definition at line 54 of file spgist_private.h.

◆ SpGistBlockIsRoot

#define SpGistBlockIsRoot (   blkno)     ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO)

Definition at line 52 of file spgist_private.h.

◆ SpGistGetFillFactor

#define SpGistGetFillFactor (   relation)
Value:
(AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
relation->rd_rel->relam == SPGIST_AM_OID), \
(relation)->rd_options ? \
((SpGistOptions *) (relation)->rd_options)->fillfactor : \
SPGIST_DEFAULT_FILLFACTOR)
#define AssertMacro(condition)
Definition: c.h:795

Definition at line 32 of file spgist_private.h.

◆ SpGistGetTargetPageFreeSpace

#define SpGistGetTargetPageFreeSpace (   relation)     (BLCKSZ * (100 - SpGistGetFillFactor(relation)) / 100)

Definition at line 38 of file spgist_private.h.

◆ SpGistPageGetFreeSpace

#define SpGistPageGetFreeSpace (   p,
 
)
Value:
Min(SpGistPageGetOpaque(p)->nPlaceholder, n) * \
(SGDTSIZE + sizeof(ItemIdData)))
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:958
struct ItemIdData ItemIdData
#define SGDTSIZE
#define SpGistPageGetOpaque(page)

Definition at line 455 of file spgist_private.h.

◆ SpGistPageGetMeta

#define SpGistPageGetMeta (   p)     ((SpGistMetaPageData *) PageGetContents(p))

Definition at line 123 of file spgist_private.h.

◆ SpGistPageGetOpaque

#define SpGistPageGetOpaque (   page)    ((SpGistPageOpaque) PageGetSpecialPointer(page))

Definition at line 77 of file spgist_private.h.

◆ SpGistPageIsDeleted

#define SpGistPageIsDeleted (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED)

Definition at line 79 of file spgist_private.h.

◆ SpGistPageIsLeaf

#define SpGistPageIsLeaf (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF)

Definition at line 80 of file spgist_private.h.

◆ SpGistPageIsMeta

#define SpGistPageIsMeta (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_META)

Definition at line 78 of file spgist_private.h.

◆ SpGistPageStoresNulls

#define SpGistPageStoresNulls (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)

Definition at line 81 of file spgist_private.h.

◆ spgKeyColumn

#define spgKeyColumn   0

Definition at line 43 of file spgist_private.h.

◆ STORE_STATE

#define STORE_STATE (   s,
 
)
Value:
do { \
(d).myXid = (s)->myXid; \
(d).isBuild = (s)->isBuild; \
} while(0)

Definition at line 464 of file spgist_private.h.

Typedef Documentation

◆ SpGistCache

typedef struct SpGistCache SpGistCache

◆ SpGistDeadTuple

Definition at line 434 of file spgist_private.h.

◆ SpGistDeadTupleData

◆ SpGistInnerTuple

Definition at line 303 of file spgist_private.h.

◆ SpGistInnerTupleData

◆ SpGistLastUsedPage

◆ SpGistLeafTuple

Definition at line 131 of file spgist_private.h.

◆ SpGistLeafTupleData

◆ SpGistLUPCache

◆ SpGistMetaPageData

◆ SpGistNodeTuple

Definition at line 337 of file spgist_private.h.

◆ SpGistNodeTupleData

Definition at line 335 of file spgist_private.h.

◆ SpGistOptions

typedef struct SpGistOptions SpGistOptions

◆ SpGistPageOpaque

Definition at line 69 of file spgist_private.h.

◆ SpGistPageOpaqueData

◆ SpGistScanOpaque

Definition at line 244 of file spgist_private.h.

◆ SpGistScanOpaqueData

◆ SpGistSearchItem

◆ SpGistState

typedef struct SpGistState SpGistState

◆ SpGistTypeDesc

Function Documentation

◆ box_copy()

BOX* box_copy ( BOX orig)

Definition at line 82 of file spgproc.c.

83 {
84  BOX *result = palloc(sizeof(BOX));
85 
86  *result = *orig;
87  return result;
88 }
void * palloc(Size size)
Definition: mcxt.c:1199
Definition: geo_decls.h:141

References palloc().

Referenced by spg_kd_inner_consistent(), and spg_quad_inner_consistent().

◆ getSpGistTupleDesc()

TupleDesc getSpGistTupleDesc ( Relation  index,
SpGistTypeDesc keyType 
)

Definition at line 299 of file spgutils.c.

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

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

Referenced by initSpGistState(), and spgbeginscan().

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 330 of file spgutils.c.

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

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

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

◆ spg_key_orderbys_distances()

double* spg_key_orderbys_distances ( Datum  key,
bool  isLeaf,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 63 of file spgproc.c.

65 {
66  int sk_num;
67  double *distances = (double *) palloc(norderbys * sizeof(double)),
68  *distance = distances;
69 
70  for (sk_num = 0; sk_num < norderbys; ++sk_num, ++orderbys, ++distance)
71  {
72  Point *point = DatumGetPointP(orderbys->sk_argument);
73 
74  *distance = isLeaf ? point_point_distance(point, DatumGetPointP(key))
76  }
77 
78  return distances;
79 }
static Point * DatumGetPointP(Datum X)
Definition: geo_decls.h:176
static BOX * DatumGetBoxP(Datum X)
Definition: geo_decls.h:234
#define point_point_distance(p1, p2)
Definition: spgproc.c:25
static double point_box_distance(Point *point, BOX *box)
Definition: spgproc.c:31

References DatumGetBoxP(), DatumGetPointP(), sort-test::key, palloc(), point_box_distance(), point_point_distance, and ScanKeyData::sk_argument.

Referenced by spg_box_quad_leaf_consistent(), spg_kd_inner_consistent(), spg_quad_inner_consistent(), and spg_quad_leaf_consistent().

◆ spgDeformLeafTuple()

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

Definition at line 1096 of file spgutils.c.

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

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

Referenced by doPickSplit(), and storeGettuple().

◆ spgdoinsert()

bool spgdoinsert ( Relation  index,
SpGistState state,
ItemPointer  heapPtr,
Datum datums,
bool isnulls 
)

Definition at line 1915 of file spgdoinsert.c.

1917 {
1918  bool result = true;
1919  TupleDesc leafDescriptor = state->leafTupDesc;
1920  bool isnull = isnulls[spgKeyColumn];
1921  int level = 0;
1922  Datum leafDatums[INDEX_MAX_KEYS];
1923  int leafSize;
1924  int bestLeafSize;
1925  int numNoProgressCycles = 0;
1926  SPPageDesc current,
1927  parent;
1928  FmgrInfo *procinfo = NULL;
1929 
1930  /*
1931  * Look up FmgrInfo of the user-defined choose function once, to save
1932  * cycles in the loop below.
1933  */
1934  if (!isnull)
1935  procinfo = index_getprocinfo(index, 1, SPGIST_CHOOSE_PROC);
1936 
1937  /*
1938  * Prepare the leaf datum to insert.
1939  *
1940  * If an optional "compress" method is provided, then call it to form the
1941  * leaf key datum from the input datum. Otherwise, store the input datum
1942  * as is. Since we don't use index_form_tuple in this AM, we have to make
1943  * sure value to be inserted is not toasted; FormIndexDatum doesn't
1944  * guarantee that. But we assume the "compress" method to return an
1945  * untoasted value.
1946  */
1947  if (!isnull)
1948  {
1950  {
1951  FmgrInfo *compressProcinfo = NULL;
1952 
1953  compressProcinfo = index_getprocinfo(index, 1, SPGIST_COMPRESS_PROC);
1954  leafDatums[spgKeyColumn] =
1955  FunctionCall1Coll(compressProcinfo,
1956  index->rd_indcollation[spgKeyColumn],
1957  datums[spgKeyColumn]);
1958  }
1959  else
1960  {
1961  Assert(state->attLeafType.type == state->attType.type);
1962 
1963  if (state->attType.attlen == -1)
1964  leafDatums[spgKeyColumn] =
1966  else
1967  leafDatums[spgKeyColumn] = datums[spgKeyColumn];
1968  }
1969  }
1970  else
1971  leafDatums[spgKeyColumn] = (Datum) 0;
1972 
1973  /* Likewise, ensure that any INCLUDE values are not toasted */
1974  for (int i = spgFirstIncludeColumn; i < leafDescriptor->natts; i++)
1975  {
1976  if (!isnulls[i])
1977  {
1978  if (TupleDescAttr(leafDescriptor, i)->attlen == -1)
1979  leafDatums[i] = PointerGetDatum(PG_DETOAST_DATUM(datums[i]));
1980  else
1981  leafDatums[i] = datums[i];
1982  }
1983  else
1984  leafDatums[i] = (Datum) 0;
1985  }
1986 
1987  /*
1988  * Compute space needed for a leaf tuple containing the given data.
1989  */
1990  leafSize = SpGistGetLeafTupleSize(leafDescriptor, leafDatums, isnulls);
1991  /* Account for an item pointer, too */
1992  leafSize += sizeof(ItemIdData);
1993 
1994  /*
1995  * If it isn't gonna fit, and the opclass can't reduce the datum size by
1996  * suffixing, bail out now rather than doing a lot of useless work.
1997  */
1998  if (leafSize > SPGIST_PAGE_CAPACITY &&
1999  (isnull || !state->config.longValuesOK))
2000  ereport(ERROR,
2001  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2002  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
2003  leafSize - sizeof(ItemIdData),
2004  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData),
2006  errhint("Values larger than a buffer page cannot be indexed.")));
2007  bestLeafSize = leafSize;
2008 
2009  /* Initialize "current" to the appropriate root page */
2010  current.blkno = isnull ? SPGIST_NULL_BLKNO : SPGIST_ROOT_BLKNO;
2011  current.buffer = InvalidBuffer;
2012  current.page = NULL;
2013  current.offnum = FirstOffsetNumber;
2014  current.node = -1;
2015 
2016  /* "parent" is invalid for the moment */
2017  parent.blkno = InvalidBlockNumber;
2018  parent.buffer = InvalidBuffer;
2019  parent.page = NULL;
2020  parent.offnum = InvalidOffsetNumber;
2021  parent.node = -1;
2022 
2023  /*
2024  * Before entering the loop, try to clear any pending interrupt condition.
2025  * If a query cancel is pending, we might as well accept it now not later;
2026  * while if a non-canceling condition is pending, servicing it here avoids
2027  * having to restart the insertion and redo all the work so far.
2028  */
2030 
2031  for (;;)
2032  {
2033  bool isNew = false;
2034 
2035  /*
2036  * Bail out if query cancel is pending. We must have this somewhere
2037  * in the loop since a broken opclass could produce an infinite
2038  * picksplit loop. However, because we'll be holding buffer lock(s)
2039  * after the first iteration, ProcessInterrupts() wouldn't be able to
2040  * throw a cancel error here. Hence, if we see that an interrupt is
2041  * pending, break out of the loop and deal with the situation below.
2042  * Set result = false because we must restart the insertion if the
2043  * interrupt isn't a query-cancel-or-die case.
2044  */
2046  {
2047  result = false;
2048  break;
2049  }
2050 
2051  if (current.blkno == InvalidBlockNumber)
2052  {
2053  /*
2054  * Create a leaf page. If leafSize is too large to fit on a page,
2055  * we won't actually use the page yet, but it simplifies the API
2056  * for doPickSplit to always have a leaf page at hand; so just
2057  * quietly limit our request to a page size.
2058  */
2059  current.buffer =
2061  GBUF_LEAF | (isnull ? GBUF_NULLS : 0),
2062  Min(leafSize, SPGIST_PAGE_CAPACITY),
2063  &isNew);
2064  current.blkno = BufferGetBlockNumber(current.buffer);
2065  }
2066  else if (parent.buffer == InvalidBuffer)
2067  {
2068  /* we hold no parent-page lock, so no deadlock is possible */
2069  current.buffer = ReadBuffer(index, current.blkno);
2071  }
2072  else if (current.blkno != parent.blkno)
2073  {
2074  /* descend to a new child page */
2075  current.buffer = ReadBuffer(index, current.blkno);
2076 
2077  /*
2078  * Attempt to acquire lock on child page. We must beware of
2079  * deadlock against another insertion process descending from that
2080  * page to our parent page (see README). If we fail to get lock,
2081  * abandon the insertion and tell our caller to start over.
2082  *
2083  * XXX this could be improved, because failing to get lock on a
2084  * buffer is not proof of a deadlock situation; the lock might be
2085  * held by a reader, or even just background writer/checkpointer
2086  * process. Perhaps it'd be worth retrying after sleeping a bit?
2087  */
2088  if (!ConditionalLockBuffer(current.buffer))
2089  {
2090  ReleaseBuffer(current.buffer);
2091  UnlockReleaseBuffer(parent.buffer);
2092  return false;
2093  }
2094  }
2095  else
2096  {
2097  /* inner tuple can be stored on the same page as parent one */
2098  current.buffer = parent.buffer;
2099  }
2100  current.page = BufferGetPage(current.buffer);
2101 
2102  /* should not arrive at a page of the wrong type */
2103  if (isnull ? !SpGistPageStoresNulls(current.page) :
2104  SpGistPageStoresNulls(current.page))
2105  elog(ERROR, "SPGiST index page %u has wrong nulls flag",
2106  current.blkno);
2107 
2108  if (SpGistPageIsLeaf(current.page))
2109  {
2110  SpGistLeafTuple leafTuple;
2111  int nToSplit,
2112  sizeToSplit;
2113 
2114  leafTuple = spgFormLeafTuple(state, heapPtr, leafDatums, isnulls);
2115  if (leafTuple->size + sizeof(ItemIdData) <=
2116  SpGistPageGetFreeSpace(current.page, 1))
2117  {
2118  /* it fits on page, so insert it and we're done */
2119  addLeafTuple(index, state, leafTuple,
2120  &current, &parent, isnull, isNew);
2121  break;
2122  }
2123  else if ((sizeToSplit =
2124  checkSplitConditions(index, state, &current,
2125  &nToSplit)) < SPGIST_PAGE_CAPACITY / 2 &&
2126  nToSplit < 64 &&
2127  leafTuple->size + sizeof(ItemIdData) + sizeToSplit <= SPGIST_PAGE_CAPACITY)
2128  {
2129  /*
2130  * the amount of data is pretty small, so just move the whole
2131  * chain to another leaf page rather than splitting it.
2132  */
2133  Assert(!isNew);
2134  moveLeafs(index, state, &current, &parent, leafTuple, isnull);
2135  break; /* we're done */
2136  }
2137  else
2138  {
2139  /* picksplit */
2140  if (doPickSplit(index, state, &current, &parent,
2141  leafTuple, level, isnull, isNew))
2142  break; /* doPickSplit installed new tuples */
2143 
2144  /* leaf tuple will not be inserted yet */
2145  pfree(leafTuple);
2146 
2147  /*
2148  * current now describes new inner tuple, go insert into it
2149  */
2150  Assert(!SpGistPageIsLeaf(current.page));
2151  goto process_inner_tuple;
2152  }
2153  }
2154  else /* non-leaf page */
2155  {
2156  /*
2157  * Apply the opclass choose function to figure out how to insert
2158  * the given datum into the current inner tuple.
2159  */
2160  SpGistInnerTuple innerTuple;
2161  spgChooseIn in;
2162  spgChooseOut out;
2163 
2164  /*
2165  * spgAddNode and spgSplitTuple cases will loop back to here to
2166  * complete the insertion operation. Just in case the choose
2167  * function is broken and produces add or split requests
2168  * repeatedly, check for query cancel (see comments above).
2169  */
2170  process_inner_tuple:
2172  {
2173  result = false;
2174  break;
2175  }
2176 
2177  innerTuple = (SpGistInnerTuple) PageGetItem(current.page,
2178  PageGetItemId(current.page, current.offnum));
2179 
2180  in.datum = datums[spgKeyColumn];
2181  in.leafDatum = leafDatums[spgKeyColumn];
2182  in.level = level;
2183  in.allTheSame = innerTuple->allTheSame;
2184  in.hasPrefix = (innerTuple->prefixSize > 0);
2185  in.prefixDatum = SGITDATUM(innerTuple, state);
2186  in.nNodes = innerTuple->nNodes;
2187  in.nodeLabels = spgExtractNodeLabels(state, innerTuple);
2188 
2189  memset(&out, 0, sizeof(out));
2190 
2191  if (!isnull)
2192  {
2193  /* use user-defined choose method */
2194  FunctionCall2Coll(procinfo,
2195  index->rd_indcollation[0],
2196  PointerGetDatum(&in),
2197  PointerGetDatum(&out));
2198  }
2199  else
2200  {
2201  /* force "match" action (to insert to random subnode) */
2202  out.resultType = spgMatchNode;
2203  }
2204 
2205  if (innerTuple->allTheSame)
2206  {
2207  /*
2208  * It's not allowed to do an AddNode at an allTheSame tuple.
2209  * Opclass must say "match", in which case we choose a random
2210  * one of the nodes to descend into, or "split".
2211  */
2212  if (out.resultType == spgAddNode)
2213  elog(ERROR, "cannot add a node to an allTheSame inner tuple");
2214  else if (out.resultType == spgMatchNode)
2215  out.result.matchNode.nodeN =
2217  0, innerTuple->nNodes - 1);
2218  }
2219 
2220  switch (out.resultType)
2221  {
2222  case spgMatchNode:
2223  /* Descend to N'th child node */
2224  spgMatchNodeAction(index, state, innerTuple,
2225  &current, &parent,
2226  out.result.matchNode.nodeN);
2227  /* Adjust level as per opclass request */
2228  level += out.result.matchNode.levelAdd;
2229  /* Replace leafDatum and recompute leafSize */
2230  if (!isnull)
2231  {
2232  leafDatums[spgKeyColumn] = out.result.matchNode.restDatum;
2233  leafSize = SpGistGetLeafTupleSize(leafDescriptor,
2234  leafDatums, isnulls);
2235  leafSize += sizeof(ItemIdData);
2236  }
2237 
2238  /*
2239  * Check new tuple size; fail if it can't fit, unless the
2240  * opclass says it can handle the situation by suffixing.
2241  *
2242  * However, the opclass can only shorten the leaf datum,
2243  * which may not be enough to ever make the tuple fit,
2244  * since INCLUDE columns might alone use more than a page.
2245  * Depending on the opclass' behavior, that could lead to
2246  * an infinite loop --- spgtextproc.c, for example, will
2247  * just repeatedly generate an empty-string leaf datum
2248  * once it runs out of data. Actual bugs in opclasses
2249  * might cause infinite looping, too. To detect such a
2250  * loop, check to see if we are making progress by
2251  * reducing the leafSize in each pass. This is a bit
2252  * tricky though. Because of alignment considerations,
2253  * the total tuple size might not decrease on every pass.
2254  * Also, there are edge cases where the choose method
2255  * might seem to not make progress for a cycle or two.
2256  * Somewhat arbitrarily, we allow up to 10 no-progress
2257  * iterations before failing. (This limit should be more
2258  * than MAXALIGN, to accommodate opclasses that trim one
2259  * byte from the leaf datum per pass.)
2260  */
2261  if (leafSize > SPGIST_PAGE_CAPACITY)
2262  {
2263  bool ok = false;
2264 
2265  if (state->config.longValuesOK && !isnull)
2266  {
2267  if (leafSize < bestLeafSize)
2268  {
2269  ok = true;
2270  bestLeafSize = leafSize;
2271  numNoProgressCycles = 0;
2272  }
2273  else if (++numNoProgressCycles < 10)
2274  ok = true;
2275  }
2276  if (!ok)
2277  ereport(ERROR,
2278  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2279  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
2280  leafSize - sizeof(ItemIdData),
2281  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData),
2283  errhint("Values larger than a buffer page cannot be indexed.")));
2284  }
2285 
2286  /*
2287  * Loop around and attempt to insert the new leafDatum at
2288  * "current" (which might reference an existing child
2289  * tuple, or might be invalid to force us to find a new
2290  * page for the tuple).
2291  */
2292  break;
2293  case spgAddNode:
2294  /* AddNode is not sensible if nodes don't have labels */
2295  if (in.nodeLabels == NULL)
2296  elog(ERROR, "cannot add a node to an inner tuple without node labels");
2297  /* Add node to inner tuple, per request */
2298  spgAddNodeAction(index, state, innerTuple,
2299  &current, &parent,
2300  out.result.addNode.nodeN,
2301  out.result.addNode.nodeLabel);
2302 
2303  /*
2304  * Retry insertion into the enlarged node. We assume that
2305  * we'll get a MatchNode result this time.
2306  */
2307  goto process_inner_tuple;
2308  break;
2309  case spgSplitTuple:
2310  /* Split inner tuple, per request */
2311  spgSplitNodeAction(index, state, innerTuple,
2312  &current, &out);
2313 
2314  /* Retry insertion into the split node */
2315  goto process_inner_tuple;
2316  break;
2317  default:
2318  elog(ERROR, "unrecognized SPGiST choose result: %d",
2319  (int) out.resultType);
2320  break;
2321  }
2322  }
2323  } /* end loop */
2324 
2325  /*
2326  * Release any buffers we're still holding. Beware of possibility that
2327  * current and parent reference same buffer.
2328  */
2329  if (current.buffer != InvalidBuffer)
2330  {
2332  UnlockReleaseBuffer(current.buffer);
2333  }
2334  if (parent.buffer != InvalidBuffer &&
2335  parent.buffer != current.buffer)
2336  {
2338  UnlockReleaseBuffer(parent.buffer);
2339  }
2340 
2341  /*
2342  * We do not support being called while some outer function is holding a
2343  * buffer lock (or any other reason to postpone query cancels). If that
2344  * were the case, telling the caller to retry would create an infinite
2345  * loop.
2346  */
2348 
2349  /*
2350  * Finally, check for interrupts again. If there was a query cancel,
2351  * ProcessInterrupts() will be able to throw the error here. If it was
2352  * some other kind of interrupt that can just be cleared, return false to
2353  * tell our caller to retry.
2354  */
2356 
2357  return result;
2358 }
#define InvalidBlockNumber
Definition: block.h:33
#define InvalidBuffer
Definition: buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2763
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:4198
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3931
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3954
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4172
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:712
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:280
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:107
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
#define Min(x, y)
Definition: c.h:937
#define OidIsValid(objectId)
Definition: c.h:711
int errhint(const char *fmt,...)
Definition: elog.c:1153
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1134
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1114
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:240
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:803
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:769
void pfree(void *pointer)
Definition: mcxt.c:1306
#define INTERRUPTS_CAN_BE_PROCESSED()
Definition: miscadmin.h:128
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
#define INTERRUPTS_PENDING_CONDITION()
Definition: miscadmin.h:112
#define InvalidOffsetNumber
Definition: off.h:26
#define FirstOffsetNumber
Definition: off.h:27
#define INDEX_MAX_KEYS
uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
Definition: pg_prng.c:138
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:28
#define RelationGetRelationName(relation)
Definition: rel.h:535
static void spgAddNodeAction(Relation index, SpGistState *state, SpGistInnerTuple innerTuple, SPPageDesc *current, SPPageDesc *parent, int nodeN, Datum nodeLabel)
Definition: spgdoinsert.c:1514
static void spgSplitNodeAction(Relation index, SpGistState *state, SpGistInnerTuple innerTuple, SPPageDesc *current, spgChooseOut *out)
Definition: spgdoinsert.c:1716
static void spgMatchNodeAction(Relation index, SpGistState *state, SpGistInnerTuple innerTuple, SPPageDesc *current, SPPageDesc *parent, int nodeN)
Definition: spgdoinsert.c:1460
static bool doPickSplit(Relation index, SpGistState *state, SPPageDesc *current, SPPageDesc *parent, SpGistLeafTuple newLeafTuple, int level, bool isNulls, bool isNew)
Definition: spgdoinsert.c:678
static void moveLeafs(Relation index, SpGistState *state, SPPageDesc *current, SPPageDesc *parent, SpGistLeafTuple newLeafTuple, bool isNulls)
Definition: spgdoinsert.c:388
static int checkSplitConditions(Relation index, SpGistState *state, SPPageDesc *current, int *nToSplit)
Definition: spgdoinsert.c:334
static void addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple, SPPageDesc *current, SPPageDesc *parent, bool isNulls, bool isNew)
Definition: spgdoinsert.c:204
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:28
#define SPGIST_CHOOSE_PROC
Definition: spgist.h:24
@ spgMatchNode
Definition: spgist.h:69
@ spgAddNode
Definition: spgist.h:70
@ spgSplitTuple
Definition: spgist.h:71
#define SPGIST_NULL_BLKNO
#define GBUF_NULLS
SpGistInnerTupleData * SpGistInnerTuple
#define SpGistPageStoresNulls(page)
#define SGITDATUM(x, s)
#define GBUF_LEAF
#define SpGistPageIsLeaf(page)
#define SPGIST_PAGE_CAPACITY
#define SPGIST_ROOT_BLKNO
#define SpGistPageGetFreeSpace(p, n)
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:1141
SpGistLeafTuple spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr, Datum *datums, bool *isnulls)
Definition: spgutils.c:851
Buffer SpGistGetBuffer(Relation index, int flags, int needSpace, bool *isNew)
Definition: spgutils.c:549
Size SpGistGetLeafTupleSize(TupleDesc tupleDescriptor, Datum *datums, bool *isnulls)
Definition: spgutils.c:798
void SpGistSetLastUsedPage(Relation index, Buffer buffer)
Definition: spgutils.c:653
Definition: fmgr.h:57
Buffer buffer
Definition: spgdoinsert.c:38
OffsetNumber offnum
Definition: spgdoinsert.c:40
BlockNumber blkno
Definition: spgdoinsert.c:37
unsigned int prefixSize
unsigned int allTheSame
Datum * nodeLabels
Definition: spgist.h:64
bool hasPrefix
Definition: spgist.h:61
Datum prefixDatum
Definition: spgist.h:62
int nNodes
Definition: spgist.h:63
Datum datum
Definition: spgist.h:55
int level
Definition: spgist.h:57
Datum leafDatum
Definition: spgist.h:56
bool allTheSame
Definition: spgist.h:60
spgChooseResultType resultType
Definition: spgist.h:76
struct spgChooseOut::@46::@48 addNode
union spgChooseOut::@46 result
struct spgChooseOut::@46::@47 matchNode

References addLeafTuple(), spgChooseOut::addNode, spgChooseIn::allTheSame, SpGistInnerTupleData::allTheSame, Assert(), SPPageDesc::blkno, SPPageDesc::buffer, BUFFER_LOCK_EXCLUSIVE, BufferGetBlockNumber(), BufferGetPage(), CHECK_FOR_INTERRUPTS, checkSplitConditions(), ConditionalLockBuffer(), spgChooseIn::datum, doPickSplit(), elog(), ereport, errcode(), errhint(), errmsg(), ERROR, FirstOffsetNumber, FunctionCall1Coll(), FunctionCall2Coll(), GBUF_LEAF, GBUF_NULLS, spgChooseIn::hasPrefix, i, index_getprocid(), index_getprocinfo(), INDEX_MAX_KEYS, INTERRUPTS_CAN_BE_PROCESSED, INTERRUPTS_PENDING_CONDITION, InvalidBlockNumber, InvalidBuffer, InvalidOffsetNumber, spgChooseIn::leafDatum, spgChooseIn::level, LockBuffer(), spgChooseOut::matchNode, Min, moveLeafs(), TupleDescData::natts, spgChooseIn::nNodes, SpGistInnerTupleData::nNodes, SPPageDesc::node, spgChooseIn::nodeLabels, SPPageDesc::offnum, OidIsValid, SPPageDesc::page, PageGetItem(), PageGetItemId(), pfree(), PG_DETOAST_DATUM, pg_global_prng_state, pg_prng_uint64_range(), PointerGetDatum(), spgChooseIn::prefixDatum, SpGistInnerTupleData::prefixSize, ReadBuffer(), RelationGetRelationName, ReleaseBuffer(), spgChooseOut::result, spgChooseOut::resultType, SGITDATUM, SpGistLeafTupleData::size, spgAddNode, spgAddNodeAction(), spgExtractNodeLabels(), spgFirstIncludeColumn, spgFormLeafTuple(), SPGIST_CHOOSE_PROC, SPGIST_COMPRESS_PROC, SPGIST_NULL_BLKNO, SPGIST_PAGE_CAPACITY, SPGIST_ROOT_BLKNO, SpGistGetBuffer(), SpGistGetLeafTupleSize(), SpGistPageGetFreeSpace, SpGistPageIsLeaf, SpGistPageStoresNulls, SpGistSetLastUsedPage(), spgKeyColumn, spgMatchNode, spgMatchNodeAction(), spgSplitNodeAction(), spgSplitTuple, TupleDescAttr, and UnlockReleaseBuffer().

Referenced by spginsert(), and spgistBuildCallback().

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 1141 of file spgutils.c.

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

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

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

◆ spgFormDeadTuple()

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

Definition at line 1065 of file spgutils.c.

1067 {
1068  SpGistDeadTuple tuple = (SpGistDeadTuple) state->deadTupleStorage;
1069 
1070  tuple->tupstate = tupstate;
1071  tuple->size = SGDTSIZE;
1073 
1074  if (tupstate == SPGIST_REDIRECT)
1075  {
1076  ItemPointerSet(&tuple->pointer, blkno, offnum);
1078  tuple->xid = state->myXid;
1079  }
1080  else
1081  {
1082  ItemPointerSetInvalid(&tuple->pointer);
1083  tuple->xid = InvalidTransactionId;
1084  }
1085 
1086  return tuple;
1087 }
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition: itemptr.h:135
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
SpGistDeadTupleData * SpGistDeadTuple
#define SPGIST_REDIRECT
#define SGLT_SET_NEXTOFFSET(spgLeafTuple, offsetNumber)
unsigned int tupstate
ItemPointerData pointer
#define InvalidTransactionId
Definition: transam.h:31
#define TransactionIdIsValid(xid)
Definition: transam.h:41

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

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

◆ spgFormInnerTuple()

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

Definition at line 982 of file spgutils.c.

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

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

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

◆ spgFormLeafTuple()

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

Definition at line 851 of file spgutils.c.

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

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

Referenced by doPickSplit(), and spgdoinsert().

◆ spgFormNodeTuple()

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

Definition at line 940 of file spgutils.c.

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

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

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

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 179 of file spgutils.c.

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

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

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

◆ SpGistGetBuffer()

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

Definition at line 549 of file spgutils.c.

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

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

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

◆ SpGistGetInnerTypeSize()

unsigned int SpGistGetInnerTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 759 of file spgutils.c.

760 {
761  unsigned int size;
762 
763  if (att->attbyval)
764  size = sizeof(Datum);
765  else if (att->attlen > 0)
766  size = att->attlen;
767  else
768  size = VARSIZE_ANY(datum);
769 
770  return MAXALIGN(size);
771 }
#define VARSIZE_ANY(PTR)
Definition: postgres.h:349

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

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

◆ SpGistGetLeafTupleSize()

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

Definition at line 798 of file spgutils.c.

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

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

Referenced by spgdoinsert().

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 702 of file spgutils.c.

703 {
704  Assert(BufferGetPageSize(b) == BLCKSZ);
706 }
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:266
int b
Definition: isn.c:70
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:688

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 712 of file spgutils.c.

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

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

Referenced by spgbuild(), and spgbuildempty().

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 688 of file spgutils.c.

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

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

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

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 365 of file spgutils.c.

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

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

Referenced by allocNewBuffer(), and spgbuild().

◆ SpGistPageAddNewItem()

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

Definition at line 1184 of file spgutils.c.

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

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

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

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 653 of file spgutils.c.

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

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

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

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 430 of file spgutils.c.

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

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

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

◆ spgPageIndexMultiDelete()

void spgPageIndexMultiDelete ( SpGistState state,
Page  page,
OffsetNumber itemnos,
int  nitems,
int  firststate,
int  reststate,
BlockNumber  blkno,
OffsetNumber  offnum 
)

Definition at line 132 of file spgdoinsert.c.

136 {
137  OffsetNumber firstItem;
139  SpGistDeadTuple tuple = NULL;
140  int i;
141 
142  if (nitems == 0)
143  return; /* nothing to do */
144 
145  /*
146  * For efficiency we want to use PageIndexMultiDelete, which requires the
147  * targets to be listed in sorted order, so we have to sort the itemnos
148  * array. (This also greatly simplifies the math for reinserting the
149  * replacement tuples.) However, we must not scribble on the caller's
150  * array, so we have to make a copy.
151  */
152  memcpy(sortednos, itemnos, sizeof(OffsetNumber) * nitems);
153  if (nitems > 1)
154  qsort(sortednos, nitems, sizeof(OffsetNumber), cmpOffsetNumbers);
155 
156  PageIndexMultiDelete(page, sortednos, nitems);
157 
158  firstItem = itemnos[0];
159 
160  for (i = 0; i < nitems; i++)
161  {
162  OffsetNumber itemno = sortednos[i];
163  int tupstate;
164 
165  tupstate = (itemno == firstItem) ? firststate : reststate;
166  if (tuple == NULL || tuple->tupstate != tupstate)
167  tuple = spgFormDeadTuple(state, tupstate, blkno, offnum);
168 
169  if (PageAddItem(page, (Item) tuple, tuple->size,
170  itemno, false, false) != itemno)
171  elog(ERROR, "failed to add item of size %u to SPGiST index page",
172  tuple->size);
173 
174  if (tupstate == SPGIST_REDIRECT)
175  SpGistPageGetOpaque(page)->nRedirection++;
176  else if (tupstate == SPGIST_PLACEHOLDER)
177  SpGistPageGetOpaque(page)->nPlaceholder++;
178  }
179 }
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1161
Pointer Item
Definition: item.h:17
#define MaxIndexTuplesPerPage
Definition: itup.h:165
#define qsort(a, b, c, d)
Definition: port.h:445
static int cmpOffsetNumbers(const void *a, const void *b)
Definition: spgdoinsert.c:111
SpGistDeadTuple spgFormDeadTuple(SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
Definition: spgutils.c:1065

References cmpOffsetNumbers(), elog(), ERROR, i, MaxIndexTuplesPerPage, PageAddItem, PageIndexMultiDelete(), qsort, SpGistDeadTupleData::size, spgFormDeadTuple(), SPGIST_PLACEHOLDER, SPGIST_REDIRECT, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.

Referenced by doPickSplit(), moveLeafs(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoVacuumLeaf(), and vacuumLeafPage().

◆ spgproperty()

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

Definition at line 1279 of file spgutils.c.

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

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

Referenced by spghandler().

◆ spgUpdateNodeLink()

void spgUpdateNodeLink ( SpGistInnerTuple  tup,
int  nodeN,
BlockNumber  blkno,
OffsetNumber  offset 
)

Definition at line 51 of file spgdoinsert.c.

53 {
54  int i;
55  SpGistNodeTuple node;
56 
57  SGITITERATE(tup, i, node)
58  {
59  if (i == nodeN)
60  {
61  ItemPointerSet(&node->t_tid, blkno, offset);
62  return;
63  }
64  }
65 
66  elog(ERROR, "failed to find requested node %d in SPGiST inner tuple",
67  nodeN);
68 }

References elog(), ERROR, i, ItemPointerSet(), SGITITERATE, and IndexTupleData::t_tid.

Referenced by saveNodeLink(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), and spgSplitNodeAction().