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, const Datum *datums, const bool *isnulls)
 
SpGistLeafTuple spgFormLeafTuple (SpGistState *state, ItemPointer heapPtr, const Datum *datums, const bool *isnulls)
 
SpGistNodeTuple spgFormNodeTuple (SpGistState *state, Datum label, bool isnull)
 
SpGistInnerTuple spgFormInnerTuple (SpGistState *state, bool hasPrefix, Datum prefix, int nNodes, SpGistNodeTuple *nodes)
 
SpGistDeadTuple spgFormDeadTuple (SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
 
void spgDeformLeafTuple (SpGistLeafTuple tup, TupleDesc tupleDescriptor, Datum *datums, bool *isnulls, bool keyColumnIsNull)
 
DatumspgExtractNodeLabels (SpGistState *state, SpGistInnerTuple innerTuple)
 
OffsetNumber SpGistPageAddNewItem (SpGistState *state, Page page, 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 483 of file spgist_private.h.

◆ GBUF_LEAF

#define GBUF_LEAF   0x03

Definition at line 482 of file spgist_private.h.

◆ GBUF_NULLS

#define GBUF_NULLS   0x04

Definition at line 484 of file spgist_private.h.

◆ GBUF_PARITY_MASK

#define GBUF_PARITY_MASK   0x03

Definition at line 486 of file spgist_private.h.

◆ GBUF_REQ_LEAF

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

Definition at line 487 of file spgist_private.h.

◆ GBUF_REQ_NULLS

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

Definition at line 488 of file spgist_private.h.

◆ SGDTSIZE

#define SGDTSIZE   MAXALIGN(sizeof(SpGistDeadTupleData))

Definition at line 437 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:64
#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:811

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:322
#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 494 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 493 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:216
#define MAXALIGN_DOWN(LEN)
Definition: c.h:823

Definition at line 447 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:859

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 456 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).redirectXid = (s)->redirectXid; \
(d).isBuild = (s)->isBuild; \
} while(0)

Definition at line 465 of file spgist_private.h.

Typedef Documentation

◆ SpGistCache

typedef struct SpGistCache SpGistCache

◆ SpGistDeadTuple

Definition at line 435 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:1317
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 310 of file spgutils.c.

311 {
312  TupleDesc outTupDesc;
313  Form_pg_attribute att;
314 
315  if (keyType->type ==
317  outTupDesc = RelationGetDescr(index);
318  else
319  {
321  att = TupleDescAttr(outTupDesc, spgKeyColumn);
322  /* It's sufficient to update the type-dependent fields of the column */
323  att->atttypid = keyType->type;
324  att->atttypmod = -1;
325  att->attlen = keyType->attlen;
326  att->attbyval = keyType->attbyval;
327  att->attalign = keyType->attalign;
328  att->attstorage = keyType->attstorage;
329  /* We shouldn't need to bother with making these valid: */
330  att->attcompression = InvalidCompressionMethod;
331  att->attcollation = InvalidOid;
332  /* In case we changed typlen, we'd better reset following offsets */
333  for (int i = spgFirstIncludeColumn; i < outTupDesc->natts; i++)
334  TupleDescAttr(outTupDesc, i)->attcacheoff = -1;
335  }
336  return outTupDesc;
337 }
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define InvalidOid
Definition: postgres_ext.h:36
#define RelationGetDescr(relation)
Definition: rel.h:531
#define spgFirstIncludeColumn
#define spgKeyColumn
Definition: type.h:95
#define InvalidCompressionMethod
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:133
#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 341 of file spgutils.c.

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

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

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

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

1154 {
1155  Datum *nodeLabels;
1156  int i;
1157  SpGistNodeTuple node;
1158 
1159  /* Either all the labels must be NULL, or none. */
1160  node = SGITNODEPTR(innerTuple);
1161  if (IndexTupleHasNulls(node))
1162  {
1163  SGITITERATE(innerTuple, i, node)
1164  {
1165  if (!IndexTupleHasNulls(node))
1166  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1167  }
1168  /* They're all null, so just return NULL */
1169  return NULL;
1170  }
1171  else
1172  {
1173  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
1174  SGITITERATE(innerTuple, i, node)
1175  {
1176  if (IndexTupleHasNulls(node))
1177  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
1178  nodeLabels[i] = SGNTDATUM(node, state);
1179  }
1180  return nodeLabels;
1181  }
1182 }
#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 1078 of file spgutils.c.

1080 {
1081  SpGistDeadTuple tuple = (SpGistDeadTuple) state->deadTupleStorage;
1082 
1083  tuple->tupstate = tupstate;
1084  tuple->size = SGDTSIZE;
1086 
1087  if (tupstate == SPGIST_REDIRECT)
1088  {
1089  ItemPointerSet(&tuple->pointer, blkno, offnum);
1090  tuple->xid = state->redirectXid;
1091  }
1092  else
1093  {
1094  ItemPointerSetInvalid(&tuple->pointer);
1095  tuple->xid = InvalidTransactionId;
1096  }
1097 
1098  return tuple;
1099 }
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

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

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

◆ spgFormInnerTuple()

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

Definition at line 995 of file spgutils.c.

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

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

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

◆ spgFormLeafTuple()

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

Definition at line 864 of file spgutils.c.

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

Referenced by doPickSplit(), and spgdoinsert().

◆ spgFormNodeTuple()

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

Definition at line 953 of file spgutils.c.

954 {
955  SpGistNodeTuple tup;
956  unsigned int size;
957  unsigned short infomask = 0;
958 
959  /* compute space needed (note result is already maxaligned) */
960  size = SGNTHDRSZ;
961  if (!isnull)
962  size += SpGistGetInnerTypeSize(&state->attLabelType, label);
963 
964  /*
965  * Here we make sure that the size will fit in the field reserved for it
966  * in t_info.
967  */
968  if ((size & INDEX_SIZE_MASK) != size)
969  ereport(ERROR,
970  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
971  errmsg("index row requires %zu bytes, maximum size is %zu",
972  (Size) size, (Size) INDEX_SIZE_MASK)));
973 
974  tup = (SpGistNodeTuple) palloc0(size);
975 
976  if (isnull)
977  infomask |= INDEX_NULL_MASK;
978  /* we don't bother setting the INDEX_VAR_MASK bit */
979  infomask |= size;
980  tup->t_info = infomask;
981 
982  /* The TID field will be filled in later */
984 
985  if (!isnull)
986  memcpyInnerDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
987 
988  return tup;
989 }
#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, size, SpGistGetInnerTypeSize(), IndexTupleData::t_info, and IndexTupleData::t_tid.

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

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 183 of file spgutils.c.

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

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

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

773 {
774  unsigned int size;
775 
776  if (att->attbyval)
777  size = sizeof(Datum);
778  else if (att->attlen > 0)
779  size = att->attlen;
780  else
781  size = VARSIZE_ANY(datum);
782 
783  return MAXALIGN(size);
784 }
#define VARSIZE_ANY(PTR)
Definition: varatt.h:311

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

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

◆ SpGistGetLeafTupleSize()

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

Definition at line 811 of file spgutils.c.

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

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

Referenced by spgdoinsert().

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 715 of file spgutils.c.

716 {
717  Assert(BufferGetPageSize(b) == BLCKSZ);
719 }
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:389
int b
Definition: isn.c:70
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:701

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

726 {
727  SpGistMetaPageData *metadata;
728  int i;
729 
731  metadata = SpGistPageGetMeta(page);
732  memset(metadata, 0, sizeof(SpGistMetaPageData));
733  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
734 
735  /* initialize last-used-page cache to empty */
736  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
738 
739  /*
740  * Set pd_lower just past the end of the metadata. This is essential,
741  * because without doing so, metadata will be lost if xlog.c compresses
742  * the page.
743  */
744  ((PageHeader) page)->pd_lower =
745  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
746 }
#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 701 of file spgutils.c.

702 {
703  SpGistPageOpaque opaque;
704 
705  PageInit(page, BLCKSZ, sizeof(SpGistPageOpaqueData));
706  opaque = SpGistPageGetOpaque(page);
707  opaque->flags = f;
708  opaque->spgist_page_id = SPGIST_PAGE_ID;
709 }
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 387 of file spgutils.c.

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

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

Referenced by allocNewBuffer(), and spgbuild().

◆ SpGistPageAddNewItem()

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

Definition at line 1196 of file spgutils.c.

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

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

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 666 of file spgutils.c.

667 {
668  SpGistCache *cache = spgGetCache(index);
669  SpGistLastUsedPage *lup;
670  int freeSpace;
671  Page page = BufferGetPage(buffer);
672  BlockNumber blkno = BufferGetBlockNumber(buffer);
673  int flags;
674 
675  /* Never enter fixed pages (root pages) in cache, though */
676  if (SpGistBlockIsFixed(blkno))
677  return;
678 
679  if (SpGistPageIsLeaf(page))
680  flags = GBUF_LEAF;
681  else
682  flags = GBUF_INNER_PARITY(blkno);
683  if (SpGistPageStoresNulls(page))
684  flags |= GBUF_NULLS;
685 
686  lup = GET_LUP(cache, flags);
687 
688  freeSpace = PageGetExactFreeSpace(page);
689  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
690  lup->freeSpace < freeSpace)
691  {
692  lup->blkno = blkno;
693  lup->freeSpace = freeSpace;
694  }
695 }
#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 443 of file spgutils.c.

444 {
445  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
446 
447  if (cache != NULL)
448  {
449  Buffer metabuffer;
450 
451  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
452 
453  if (ConditionalLockBuffer(metabuffer))
454  {
455  Page metapage = BufferGetPage(metabuffer);
456  SpGistMetaPageData *metadata = SpGistPageGetMeta(metapage);
457 
458  metadata->lastUsedPages = cache->lastUsedPages;
459 
460  /*
461  * Set pd_lower just past the end of the metadata. This is
462  * essential, because without doing so, metadata will be lost if
463  * xlog.c compresses the page. (We must do this here because
464  * pre-v11 versions of PG did not set the metapage's pd_lower
465  * correctly, so a pg_upgraded index might contain the wrong
466  * value.)
467  */
468  ((PageHeader) metapage)->pd_lower =
469  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
470 
471  MarkBufferDirty(metabuffer);
472  UnlockReleaseBuffer(metabuffer);
473  }
474  else
475  {
476  ReleaseBuffer(metabuffer);
477  }
478  }
479 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2514
PageHeaderData * PageHeader
Definition: bufpage.h:173
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 131 of file spgdoinsert.c.

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

References cmpOffsetNumbers(), elog, ERROR, i, MaxIndexTuplesPerPage, nitems, 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 1291 of file spgutils.c.

1294 {
1295  Oid opclass,
1296  opfamily,
1297  opcintype;
1298  CatCList *catlist;
1299  int i;
1300 
1301  /* Only answer column-level inquiries */
1302  if (attno == 0)
1303  return false;
1304 
1305  switch (prop)
1306  {
1308  break;
1309  default:
1310  return false;
1311  }
1312 
1313  /*
1314  * Currently, SP-GiST distance-ordered scans require that there be a
1315  * distance operator in the opclass with the default types. So we assume
1316  * that if such an operator exists, then there's a reason for it.
1317  */
1318 
1319  /* First we need to know the column's opclass. */
1320  opclass = get_index_column_opclass(index_oid, attno);
1321  if (!OidIsValid(opclass))
1322  {
1323  *isnull = true;
1324  return true;
1325  }
1326 
1327  /* Now look up the opclass family and input datatype. */
1328  if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1329  {
1330  *isnull = true;
1331  return true;
1332  }
1333 
1334  /* And now we can check whether the operator is provided. */
1335  catlist = SearchSysCacheList1(AMOPSTRATEGY,
1336  ObjectIdGetDatum(opfamily));
1337 
1338  *res = false;
1339 
1340  for (i = 0; i < catlist->n_members; i++)
1341  {
1342  HeapTuple amoptup = &catlist->members[i]->tuple;
1343  Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(amoptup);
1344 
1345  if (amopform->amoppurpose == AMOP_ORDER &&
1346  (amopform->amoplefttype == opcintype ||
1347  amopform->amoprighttype == opcintype) &&
1348  opfamily_can_sort_type(amopform->amopsortfamily,
1349  get_op_rettype(amopform->amopopr)))
1350  {
1351  *res = true;
1352  break;
1353  }
1354  }
1355 
1356  ReleaseSysCacheList(catlist);
1357 
1358  *isnull = false;
1359 
1360  return true;
1361 }
@ 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:653
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1235
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1333
Oid get_index_column_opclass(Oid index_oid, int attno)
Definition: lsyscache.c:3512
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
int n_members
Definition: catcache.h:178
HeapTupleData tuple
Definition: catcache.h:123
#define ReleaseSysCacheList(x)
Definition: syscache.h:129
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:122

References 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 52 of file spgdoinsert.c.

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

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

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