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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Functions

SpGistCachespgGetCache (Relation index)
 
TupleDesc getSpGistTupleDesc (Relation index, SpGistTypeDesc *keyType)
 
void initSpGistState (SpGistState *state, Relation index)
 
Buffer SpGistNewBuffer (Relation index)
 
void SpGistUpdateMetaPage (Relation index)
 
Buffer SpGistGetBuffer (Relation index, int flags, int needSpace, bool *isNew)
 
void SpGistSetLastUsedPage (Relation index, Buffer buffer)
 
void SpGistInitPage (Page page, uint16 f)
 
void SpGistInitBuffer (Buffer b, uint16 f)
 
void SpGistInitMetapage (Page page)
 
unsigned int SpGistGetInnerTypeSize (SpGistTypeDesc *att, Datum datum)
 
Size SpGistGetLeafTupleSize (TupleDesc tupleDescriptor, const Datum *datums, const bool *isnulls)
 
SpGistLeafTuple spgFormLeafTuple (SpGistState *state, const ItemPointerData *heapPtr, const Datum *datums, const bool *isnulls)
 
SpGistNodeTuple spgFormNodeTuple (SpGistState *state, Datum label, bool isnull)
 
SpGistInnerTuple spgFormInnerTuple (SpGistState *state, bool hasPrefix, Datum prefix, int nNodes, SpGistNodeTuple *nodes)
 
SpGistDeadTuple spgFormDeadTuple (SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
 
void spgDeformLeafTuple (SpGistLeafTuple tup, TupleDesc tupleDescriptor, Datum *datums, bool *isnulls, bool keyColumnIsNull)
 
DatumspgExtractNodeLabels (SpGistState *state, SpGistInnerTuple innerTuple)
 
OffsetNumber SpGistPageAddNewItem (SpGistState *state, Page page, const void *item, Size size, OffsetNumber *startOffset, bool errorOK)
 
bool spgproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
 
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, const ItemPointerData *heapPtr, const Datum *datums, const 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 313 of file spgist_private.h.

◆ GBUF_INNER_PARITY

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

Definition at line 485 of file spgist_private.h.

◆ GBUF_LEAF

#define GBUF_LEAF   0x03

Definition at line 484 of file spgist_private.h.

◆ GBUF_NULLS

#define GBUF_NULLS   0x04

Definition at line 486 of file spgist_private.h.

◆ GBUF_PARITY_MASK

#define GBUF_PARITY_MASK   0x03

Definition at line 488 of file spgist_private.h.

◆ GBUF_REQ_LEAF

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

Definition at line 489 of file spgist_private.h.

◆ GBUF_REQ_NULLS

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

Definition at line 490 of file spgist_private.h.

◆ SGDTSIZE

#define SGDTSIZE   MAXALIGN(sizeof(SpGistDeadTupleData))

Definition at line 439 of file spgist_private.h.

◆ SGITDATAPTR

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

Definition at line 314 of file spgist_private.h.

◆ SGITDATUM

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

Definition at line 315 of file spgist_private.h.

◆ SGITHDRSZ

#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))

Definition at line 312 of file spgist_private.h.

◆ SGITITERATE

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

Definition at line 323 of file spgist_private.h.

◆ SGITMAXNNODES

#define SGITMAXNNODES   0x1FFF

Definition at line 308 of file spgist_private.h.

◆ SGITMAXPREFIXSIZE

#define SGITMAXPREFIXSIZE   0xFFFF

Definition at line 309 of file spgist_private.h.

◆ SGITMAXSIZE

#define SGITMAXSIZE   0xFFFF

Definition at line 310 of file spgist_private.h.

◆ SGITNODEPTR

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

Definition at line 320 of file spgist_private.h.

◆ SGLT_GET_HASNULLMASK

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

Definition at line 398 of file spgist_private.h.

◆ SGLT_GET_NEXTOFFSET

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

Definition at line 396 of file spgist_private.h.

◆ SGLT_SET_HASNULLMASK

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

Definition at line 403 of file spgist_private.h.

◆ SGLT_SET_NEXTOFFSET

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

Definition at line 400 of file spgist_private.h.

◆ SGLTDATAPTR

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

Definition at line 411 of file spgist_private.h.

◆ SGLTDATUM

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

Definition at line 412 of file spgist_private.h.

◆ SGLTHDRSZ

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

Definition at line 407 of file spgist_private.h.

◆ SGNTDATAPTR

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

Definition at line 342 of file spgist_private.h.

◆ SGNTDATUM

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

Definition at line 343 of file spgist_private.h.

◆ SGNTHDRSZ

#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))

Definition at line 341 of file spgist_private.h.

◆ SizeOfSpGistSearchItem

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

Definition at line 182 of file spgist_private.h.

◆ spgFirstIncludeColumn

#define spgFirstIncludeColumn   1

Definition at line 44 of file spgist_private.h.

◆ SPGIST_CACHED_PAGES

#define SPGIST_CACHED_PAGES   8

Definition at line 105 of file spgist_private.h.

◆ SPGIST_DEAD

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

Definition at line 273 of file spgist_private.h.

◆ SPGIST_DEFAULT_FILLFACTOR

#define SPGIST_DEFAULT_FILLFACTOR   80

Definition at line 496 of file spgist_private.h.

◆ SPGIST_DELETED

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

Definition at line 73 of file spgist_private.h.

◆ SPGIST_LAST_FIXED_BLKNO

#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO

Definition at line 50 of file spgist_private.h.

◆ SPGIST_LEAF

#define SPGIST_LEAF   (1<<2)

Definition at line 74 of file spgist_private.h.

◆ SPGIST_LIVE

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

Definition at line 271 of file spgist_private.h.

◆ SPGIST_MAGIC_NUMBER

#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)

Definition at line 121 of file spgist_private.h.

◆ SPGIST_META

#define SPGIST_META   (1<<0)

Definition at line 72 of file spgist_private.h.

◆ SPGIST_METAPAGE_BLKNO

#define SPGIST_METAPAGE_BLKNO   (0) /* metapage */

Definition at line 47 of file spgist_private.h.

◆ SPGIST_MIN_FILLFACTOR

#define SPGIST_MIN_FILLFACTOR   10

Definition at line 495 of file spgist_private.h.

◆ SPGIST_NULL_BLKNO

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

Definition at line 49 of file spgist_private.h.

◆ SPGIST_NULLS

#define SPGIST_NULLS   (1<<3)

Definition at line 75 of file spgist_private.h.

◆ SPGIST_PAGE_CAPACITY

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

Definition at line 449 of file spgist_private.h.

◆ SPGIST_PAGE_ID

#define SPGIST_PAGE_ID   0xFF82

Definition at line 91 of file spgist_private.h.

◆ SPGIST_PLACEHOLDER

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

Definition at line 274 of file spgist_private.h.

◆ SPGIST_REDIRECT

#define SPGIST_REDIRECT   1 /* temporary redirection placeholder */

Definition at line 272 of file spgist_private.h.

◆ SPGIST_ROOT_BLKNO

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

Definition at line 48 of file spgist_private.h.

◆ SpGistBlockIsFixed

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

Definition at line 54 of file spgist_private.h.

◆ SpGistBlockIsRoot

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

Definition at line 52 of file spgist_private.h.

◆ SpGistGetFillFactor

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

Definition at line 32 of file spgist_private.h.

◆ SpGistGetTargetPageFreeSpace

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

Definition at line 38 of file spgist_private.h.

◆ SpGistPageGetFreeSpace

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

Definition at line 458 of file spgist_private.h.

◆ SpGistPageGetMeta

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

Definition at line 123 of file spgist_private.h.

◆ SpGistPageGetOpaque

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

Definition at line 77 of file spgist_private.h.

◆ SpGistPageIsDeleted

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

Definition at line 79 of file spgist_private.h.

◆ SpGistPageIsLeaf

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

Definition at line 80 of file spgist_private.h.

◆ SpGistPageIsMeta

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

Definition at line 78 of file spgist_private.h.

◆ SpGistPageStoresNulls

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

Definition at line 81 of file spgist_private.h.

◆ spgKeyColumn

#define spgKeyColumn   0

Definition at line 43 of file spgist_private.h.

◆ STORE_STATE

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

Definition at line 467 of file spgist_private.h.

Typedef Documentation

◆ SpGistCache

typedef struct SpGistCache SpGistCache

◆ SpGistDeadTuple

Definition at line 437 of file spgist_private.h.

◆ SpGistDeadTupleData

◆ SpGistInnerTuple

Definition at line 305 of file spgist_private.h.

◆ SpGistInnerTupleData

◆ SpGistLastUsedPage

◆ SpGistLeafTuple

Definition at line 131 of file spgist_private.h.

◆ SpGistLeafTupleData

◆ SpGistLUPCache

◆ SpGistMetaPageData

◆ SpGistNodeTuple

Definition at line 339 of file spgist_private.h.

◆ SpGistNodeTupleData

Definition at line 337 of file spgist_private.h.

◆ SpGistOptions

typedef struct SpGistOptions SpGistOptions

◆ SpGistPageOpaque

Definition at line 69 of file spgist_private.h.

◆ SpGistPageOpaqueData

◆ SpGistScanOpaque

Definition at line 244 of file spgist_private.h.

◆ SpGistScanOpaqueData

◆ SpGistSearchItem

◆ SpGistState

typedef struct SpGistState SpGistState

◆ SpGistTypeDesc

Function Documentation

◆ box_copy()

BOX * box_copy ( BOX orig)

Definition at line 82 of file spgproc.c.

83{
84 BOX *result = palloc_object(BOX);
85
86 *result = *orig;
87 return result;
88}
#define palloc_object(type)
Definition: fe_memutils.h:74
Definition: geo_decls.h:140

References palloc_object.

Referenced by spg_kd_inner_consistent(), and spg_quad_inner_consistent().

◆ getSpGistTupleDesc()

TupleDesc getSpGistTupleDesc ( Relation  index,
SpGistTypeDesc keyType 
)

Definition at line 316 of file spgutils.c.

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

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

Referenced by initSpGistState(), and spgbeginscan().

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 349 of file spgutils.c.

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

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

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

◆ spg_key_orderbys_distances()

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

Definition at line 63 of file spgproc.c.

65{
66 int sk_num;
67 double *distances = palloc_array(double, norderbys),
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 palloc_array(type, count)
Definition: fe_memutils.h:76
static Point * DatumGetPointP(Datum X)
Definition: geo_decls.h:175
static BOX * DatumGetBoxP(Datum X)
Definition: geo_decls.h:233
#define point_point_distance(p1, p2)
Definition: spgproc.c:25
static double point_box_distance(Point *point, BOX *box)
Definition: spgproc.c:31

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

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

◆ spgDeformLeafTuple()

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

Definition at line 1116 of file spgutils.c.

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

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

Referenced by doPickSplit(), and storeGettuple().

◆ spgdoinsert()

bool spgdoinsert ( Relation  index,
SpGistState state,
const ItemPointerData heapPtr,
const Datum datums,
const bool *  isnulls 
)

Definition at line 1909 of file spgdoinsert.c.

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

References addLeafTuple(), spgChooseOut::addNode, spgChooseIn::allTheSame, SpGistInnerTupleData::allTheSame, Assert(), CompactAttribute::attlen, SPPageDesc::blkno, SPPageDesc::buffer, BUFFER_LOCK_EXCLUSIVE, BufferGetBlockNumber(), BufferGetPage(), CHECK_FOR_INTERRUPTS, checkSplitConditions(), ConditionalLockBuffer(), spgChooseIn::datum, doPickSplit(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, FirstOffsetNumber, FunctionCall1Coll(), FunctionCall2Coll(), GBUF_LEAF, GBUF_NULLS, spgChooseIn::hasPrefix, i, index_getprocid(), index_getprocinfo(), INDEX_MAX_KEYS, INTERRUPTS_CAN_BE_PROCESSED, INTERRUPTS_PENDING_CONDITION, InvalidBlockNumber, InvalidBuffer, InvalidOffsetNumber, spgChooseIn::leafDatum, spgChooseIn::level, spgChooseOut::levelAdd, LockBuffer(), spgChooseOut::matchNode, Min, moveLeafs(), TupleDescData::natts, spgChooseIn::nNodes, SpGistInnerTupleData::nNodes, SPPageDesc::node, spgChooseOut::nodeLabel, spgChooseIn::nodeLabels, spgChooseOut::nodeN, SPPageDesc::offnum, OidIsValid, SPPageDesc::page, PageGetItem(), PageGetItemId(), pfree(), PG_DETOAST_DATUM, pg_global_prng_state, pg_prng_uint64_range(), PointerGetDatum(), spgChooseIn::prefixDatum, SpGistInnerTupleData::prefixSize, ReadBuffer(), RelationGetRelationName, ReleaseBuffer(), spgChooseOut::restDatum, 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, TupleDescCompactAttr(), and UnlockReleaseBuffer().

Referenced by spginsert(), and spgistBuildCallback().

◆ spgExtractNodeLabels()

Datum * spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 1161 of file spgutils.c.

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

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

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

◆ spgFormDeadTuple()

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

Definition at line 1086 of file spgutils.c.

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

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

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

◆ spgFormInnerTuple()

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

Definition at line 1003 of file spgutils.c.

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

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

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

◆ spgFormLeafTuple()

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

Definition at line 872 of file spgutils.c.

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

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

Referenced by doPickSplit(), and spgdoinsert().

◆ spgFormNodeTuple()

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

Definition at line 961 of file spgutils.c.

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

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

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

◆ spgGetCache()

SpGistCache * spgGetCache ( Relation  index)

Definition at line 189 of file spgutils.c.

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

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

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

◆ SpGistGetBuffer()

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

Definition at line 570 of file spgutils.c.

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

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

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

◆ SpGistGetInnerTypeSize()

unsigned int SpGistGetInnerTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 780 of file spgutils.c.

781{
782 unsigned int size;
783
784 if (att->attbyval)
785 size = sizeof(Datum);
786 else if (att->attlen > 0)
787 size = att->attlen;
788 else
789 size = VARSIZE_ANY(DatumGetPointer(datum));
790
791 return MAXALIGN(size);
792}
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:342
static Size VARSIZE_ANY(const void *PTR)
Definition: varatt.h:460

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, DatumGetPointer(), MAXALIGN, and VARSIZE_ANY().

Referenced by spgFormInnerTuple(), and spgFormNodeTuple().

◆ SpGistGetLeafTupleSize()

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

Definition at line 819 of file spgutils.c.

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

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

Referenced by spgdoinsert().

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 723 of file spgutils.c.

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

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 733 of file spgutils.c.

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

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

Referenced by spgbuild(), and spgbuildempty().

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 709 of file spgutils.c.

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

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

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

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 395 of file spgutils.c.

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

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

Referenced by allocNewBuffer(), and spgbuild().

◆ SpGistPageAddNewItem()

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

Definition at line 1204 of file spgutils.c.

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

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

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

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 674 of file spgutils.c.

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

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

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

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 451 of file spgutils.c.

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

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

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

◆ spgPageIndexMultiDelete()

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

Definition at line 131 of file spgdoinsert.c.

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

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

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

◆ spgproperty()

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

Definition at line 1299 of file spgutils.c.

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

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

Referenced by spghandler().

◆ spgUpdateNodeLink()

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

Definition at line 52 of file spgdoinsert.c.

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

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

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