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 312 of file spgist_private.h.

◆ GBUF_INNER_PARITY

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

◆ GBUF_LEAF

#define GBUF_LEAF   0x03

Definition at line 482 of file spgist_private.h.

Referenced by doPickSplit(), moveLeafs(), spgdoinsert(), and SpGistSetLastUsedPage().

◆ GBUF_NULLS

#define GBUF_NULLS   0x04

◆ GBUF_PARITY_MASK

#define GBUF_PARITY_MASK   0x03

Definition at line 486 of file spgist_private.h.

Referenced by allocNewBuffer().

◆ GBUF_REQ_LEAF

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

Definition at line 487 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

◆ GBUF_REQ_NULLS

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

Definition at line 488 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

◆ SGDTSIZE

◆ SGITDATAPTR

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

Definition at line 313 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITDATUM

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

Definition at line 314 of file spgist_private.h.

Referenced by addNode(), spgdoinsert(), and spgInitInnerConsistentIn().

◆ SGITHDRSZ

#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))

Definition at line 311 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITITERATE

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

Definition at line 322 of file spgist_private.h.

Referenced by addNode(), doPickSplit(), spgExtractNodeLabels(), spgInnerTest(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), and spgUpdateNodeLink().

◆ SGITMAXNNODES

#define SGITMAXNNODES   0x1FFF

Definition at line 307 of file spgist_private.h.

Referenced by spgFormInnerTuple(), and spgSplitNodeAction().

◆ SGITMAXPREFIXSIZE

#define SGITMAXPREFIXSIZE   0xFFFF

Definition at line 308 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITMAXSIZE

#define SGITMAXSIZE   0xFFFF

Definition at line 309 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITNODEPTR

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

Definition at line 319 of file spgist_private.h.

Referenced by spgExtractNodeLabels(), and spgFormInnerTuple().

◆ SGLT_GET_HASNULLMASK

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

Definition at line 397 of file spgist_private.h.

Referenced by spgDeformLeafTuple().

◆ SGLT_GET_NEXTOFFSET

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

◆ SGLT_SET_HASNULLMASK

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

Definition at line 402 of file spgist_private.h.

Referenced by spgFormLeafTuple().

◆ SGLT_SET_NEXTOFFSET

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

Definition at line 399 of file spgist_private.h.

Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgFormDeadTuple(), spgFormLeafTuple(), spgRedoAddLeaf(), spgRedoVacuumLeaf(), and vacuumLeafPage().

◆ SGLTDATAPTR

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

Definition at line 410 of file spgist_private.h.

◆ SGLTDATUM

#define SGLTDATUM (   x,
 
)
Value:
(s)->attLeafType.attbyval, \
(s)->attLeafType.attlen)
#define SGLTDATAPTR(x)
#define fetch_att(T, attbyval, attlen)
Definition: tupmacs.h:75

Definition at line 411 of file spgist_private.h.

Referenced by doPickSplit(), and spgLeafTest().

◆ SGLTHDRSZ

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

Definition at line 406 of file spgist_private.h.

Referenced by spgDeformLeafTuple(), spgFormLeafTuple(), and SpGistGetLeafTupleSize().

◆ SGNTDATAPTR

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

Definition at line 341 of file spgist_private.h.

Referenced by spgFormNodeTuple().

◆ SGNTDATUM

#define SGNTDATUM (   x,
 
)
Value:
((s)->attLabelType.attbyval ? \
*(Datum *) SGNTDATAPTR(x) : \
#define PointerGetDatum(X)
Definition: postgres.h:600
uintptr_t Datum
Definition: postgres.h:411
#define SGNTDATAPTR(x)

Definition at line 342 of file spgist_private.h.

Referenced by spgExtractNodeLabels().

◆ SGNTHDRSZ

#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))

Definition at line 340 of file spgist_private.h.

Referenced by spgFormNodeTuple().

◆ SizeOfSpGistSearchItem

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

Definition at line 183 of file spgist_private.h.

Referenced by spgAllocSearchItem().

◆ spgFirstIncludeColumn

#define spgFirstIncludeColumn   1

Definition at line 44 of file spgist_private.h.

Referenced by getSpGistTupleDesc(), and spgdoinsert().

◆ SPGIST_CACHED_PAGES

#define SPGIST_CACHED_PAGES   8

Definition at line 106 of file spgist_private.h.

Referenced by SpGistInitMetapage().

◆ SPGIST_DEAD

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

◆ 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.

Referenced by spgvacuumscan().

◆ SPGIST_LEAF

#define SPGIST_LEAF   (1<<2)

◆ SPGIST_LIVE

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

◆ SPGIST_MAGIC_NUMBER

#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)

Definition at line 122 of file spgist_private.h.

Referenced by spgGetCache(), and SpGistInitMetapage().

◆ SPGIST_META

#define SPGIST_META   (1<<0)

Definition at line 72 of file spgist_private.h.

Referenced by SpGistInitMetapage().

◆ SPGIST_METAPAGE_BLKNO

#define SPGIST_METAPAGE_BLKNO   (0) /* metapage */

◆ 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.

Referenced by spgAddStartItem(), spgbuild(), spgbuildempty(), and spgdoinsert().

◆ SPGIST_NULLS

#define SPGIST_NULLS   (1<<3)

◆ SPGIST_PAGE_CAPACITY

#define SPGIST_PAGE_CAPACITY
Value:
MAXALIGN_DOWN(BLCKSZ - \
#define SizeOfPageHeaderData
Definition: bufpage.h:216
#define MAXALIGN(LEN)
Definition: c.h:757
#define MAXALIGN_DOWN(LEN)
Definition: c.h:769

Definition at line 447 of file spgist_private.h.

Referenced by doPickSplit(), spgdoinsert(), spgFormInnerTuple(), and SpGistGetBuffer().

◆ SPGIST_PAGE_ID

#define SPGIST_PAGE_ID   0xFF82

Definition at line 92 of file spgist_private.h.

Referenced by SpGistInitPage().

◆ SPGIST_PLACEHOLDER

◆ SPGIST_REDIRECT

◆ SPGIST_ROOT_BLKNO

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

Definition at line 48 of file spgist_private.h.

Referenced by spgAddStartItem(), spgbuild(), spgbuildempty(), and spgdoinsert().

◆ SpGistBlockIsFixed

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

Definition at line 54 of file spgist_private.h.

Referenced by SpGistGetBuffer(), SpGistNewBuffer(), and SpGistSetLastUsedPage().

◆ SpGistBlockIsRoot

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

◆ 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:805

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.

Referenced by SpGistGetBuffer().

◆ SpGistPageGetFreeSpace

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

Definition at line 456 of file spgist_private.h.

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

◆ SpGistPageGetMeta

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

Definition at line 124 of file spgist_private.h.

Referenced by spgGetCache(), SpGistInitMetapage(), and SpGistUpdateMetaPage().

◆ SpGistPageGetOpaque

◆ SpGistPageIsDeleted

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

Definition at line 80 of file spgist_private.h.

Referenced by SpGistGetBuffer(), SpGistNewBuffer(), and spgprocesspending().

◆ SpGistPageIsLeaf

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

◆ SpGistPageIsMeta

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

Definition at line 79 of file spgist_private.h.

◆ SpGistPageStoresNulls

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

◆ spgKeyColumn

#define spgKeyColumn   0

◆ STORE_STATE

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

Definition at line 465 of file spgist_private.h.

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), vacuumLeafPage(), and vacuumLeafRoot().

Typedef Documentation

◆ SpGistCache

typedef struct SpGistCache SpGistCache

◆ SpGistDeadTuple

Definition at line 435 of file spgist_private.h.

◆ SpGistDeadTupleData

◆ SpGistInnerTuple

Definition at line 304 of file spgist_private.h.

◆ SpGistInnerTupleData

◆ SpGistLastUsedPage

◆ SpGistLeafTuple

Definition at line 132 of file spgist_private.h.

◆ SpGistLeafTupleData

◆ SpGistLUPCache

◆ SpGistMetaPageData

◆ SpGistNodeTuple

Definition at line 338 of file spgist_private.h.

◆ SpGistNodeTupleData

Definition at line 336 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 245 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.

References palloc().

Referenced by spg_kd_inner_consistent(), and spg_quad_inner_consistent().

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

◆ getSpGistTupleDesc()

TupleDesc getSpGistTupleDesc ( Relation  index,
SpGistTypeDesc keyType 
)

Definition at line 287 of file spgutils.c.

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

Referenced by initSpGistState(), and spgbeginscan().

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

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 318 of file spgutils.c.

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

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

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

◆ 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.

References DatumGetBoxP, DatumGetPointP, palloc(), point_box_distance(), and point_point_distance.

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

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 }
#define point_point_distance(p1, p2)
Definition: spgproc.c:25
#define DatumGetPointP(X)
Definition: geo_decls.h:175
#define DatumGetBoxP(X)
Definition: geo_decls.h:197
void * palloc(Size size)
Definition: mcxt.c:1062
static double point_box_distance(Point *point, BOX *box)
Definition: spgproc.c:31

◆ spgDeformLeafTuple()

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

Definition at line 1085 of file spgutils.c.

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

Referenced by doPickSplit(), and storeGettuple().

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

◆ spgdoinsert()

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

Definition at line 1913 of file spgdoinsert.c.

References addLeafTuple(), spgChooseOut::addNode, spgChooseIn::allTheSame, SpGistInnerTupleData::allTheSame, Assert, SpGistState::attLeafType, SpGistTypeDesc::attlen, SpGistState::attType, SPPageDesc::blkno, SPPageDesc::buffer, BUFFER_LOCK_EXCLUSIVE, BufferGetBlockNumber(), BufferGetPage, CHECK_FOR_INTERRUPTS, checkSplitConditions(), ConditionalLockBuffer(), SpGistState::config, 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, SpGistState::leafTupDesc, spgChooseIn::level, LockBuffer(), spgConfigOut::longValuesOK, 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, PointerGetDatum, spgChooseIn::prefixDatum, SpGistInnerTupleData::prefixSize, random(), RelationData::rd_indcollation, 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, SpGistTypeDesc::type, and UnlockReleaseBuffer().

Referenced by spginsert(), and spgistBuildCallback().

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

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 1130 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

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

◆ spgFormDeadTuple()

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

Definition at line 1054 of file spgutils.c.

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

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

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

◆ spgFormInnerTuple()

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

Definition at line 971 of file spgutils.c.

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

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

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

◆ spgFormLeafTuple()

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

Definition at line 840 of file spgutils.c.

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

Referenced by doPickSplit(), and spgdoinsert().

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

◆ spgFormNodeTuple()

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

Definition at line 929 of file spgutils.c.

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

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

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

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 178 of file spgutils.c.

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

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

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

◆ SpGistGetBuffer()

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

Definition at line 537 of file spgutils.c.

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

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

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

◆ SpGistGetInnerTypeSize()

unsigned int SpGistGetInnerTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 748 of file spgutils.c.

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

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

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

◆ SpGistGetLeafTupleSize()

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

Definition at line 787 of file spgutils.c.

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

Referenced by spgdoinsert().

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

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 690 of file spgutils.c.

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

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 700 of file spgutils.c.

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

Referenced by spgbuild(), and spgbuildempty().

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

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 676 of file spgutils.c.

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

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

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

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 353 of file spgutils.c.

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

Referenced by allocNewBuffer(), and spgbuild().

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

◆ SpGistPageAddNewItem()

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

Definition at line 1173 of file spgutils.c.

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

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

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

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 641 of file spgutils.c.

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

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

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

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 418 of file spgutils.c.

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

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

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

◆ 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.

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

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 }
SpGistDeadTuple spgFormDeadTuple(SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
Definition: spgutils.c:1054
#define SPGIST_REDIRECT
#define SPGIST_PLACEHOLDER
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
uint16 OffsetNumber
Definition: off.h:24
#define ERROR
Definition: elog.h:46
unsigned int tupstate
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1154
#define SpGistPageGetOpaque(page)
#define MaxIndexTuplesPerPage
Definition: itup.h:145
#define elog(elevel,...)
Definition: elog.h:232
int i
#define qsort(a, b, c, d)
Definition: port.h:504
static int cmpOffsetNumbers(const void *a, const void *b)
Definition: spgdoinsert.c:110

◆ spgproperty()

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

Definition at line 1268 of file spgutils.c.

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

Referenced by spghandler().

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

◆ spgUpdateNodeLink()

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

Definition at line 50 of file spgdoinsert.c.

References elog, ERROR, i, ItemPointerSet, SPPageDesc::node, SGITITERATE, and IndexTupleData::t_tid.

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

52 {
53  int i;
54  SpGistNodeTuple node;
55 
56  SGITITERATE(tup, i, node)
57  {
58  if (i == nodeN)
59  {
60  ItemPointerSet(&node->t_tid, blkno, offset);
61  return;
62  }
63  }
64 
65  elog(ERROR, "failed to find requested node %d in SPGiST inner tuple",
66  nodeN);
67 }
#define SGITITERATE(x, i, nt)
ItemPointerData t_tid
Definition: itup.h:37
#define ERROR
Definition: elog.h:46
#define elog(elevel,...)
Definition: elog.h:232
int i
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127