PostgreSQL Source Code  git master
gistutil.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/gist_private.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "common/pg_prng.h"
#include "storage/indexfsm.h"
#include "utils/float.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for gistutil.c:

Go to the source code of this file.

Functions

void gistfillbuffer (Page page, IndexTuple *itup, int len, OffsetNumber off)
 
bool gistnospace (Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
 
bool gistfitpage (IndexTuple *itvec, int len)
 
IndexTuplegistextractpage (Page page, int *len)
 
IndexTuplegistjoinvector (IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
 
IndexTupleDatagistfillitupvec (IndexTuple *vec, int veclen, int *memlen)
 
void gistMakeUnionItVec (GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull)
 
IndexTuple gistunion (Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
 
void gistMakeUnionKey (GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull)
 
bool gistKeyIsEQ (GISTSTATE *giststate, int attno, Datum a, Datum b)
 
void gistDeCompressAtt (GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
 
IndexTuple gistgetadjusted (Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
 
OffsetNumber gistchoose (Relation r, Page p, IndexTuple it, GISTSTATE *giststate)
 
void gistdentryinit (GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
 
IndexTuple gistFormTuple (GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf)
 
void gistCompressValues (GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf, Datum *compatt)
 
static Datum gistFetchAtt (GISTSTATE *giststate, int nkey, Datum k, Relation r)
 
HeapTuple gistFetchTuple (GISTSTATE *giststate, Relation r, IndexTuple tuple)
 
float gistpenalty (GISTSTATE *giststate, int attno, GISTENTRY *orig, bool isNullOrig, GISTENTRY *add, bool isNullAdd)
 
void gistinitpage (Page page, uint32 f)
 
void GISTInitBuffer (Buffer b, uint32 f)
 
void gistcheckpage (Relation rel, Buffer buf)
 
Buffer gistNewBuffer (Relation r, Relation heaprel)
 
bool gistPageRecyclable (Page page)
 
byteagistoptions (Datum reloptions, bool validate)
 
bool gistproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
 
XLogRecPtr gistGetFakeLSN (Relation rel)
 

Function Documentation

◆ gistcheckpage()

void gistcheckpage ( Relation  rel,
Buffer  buf 
)

Definition at line 784 of file gistutil.c.

785 {
786  Page page = BufferGetPage(buf);
787 
788  /*
789  * ReadBuffer verifies that every newly-read page passes
790  * PageHeaderIsValid, which means it either contains a reasonably sane
791  * page header or is all-zero. We have to defend against the all-zero
792  * case, however.
793  */
794  if (PageIsNew(page))
795  ereport(ERROR,
796  (errcode(ERRCODE_INDEX_CORRUPTED),
797  errmsg("index \"%s\" contains unexpected zero page at block %u",
800  errhint("Please REINDEX it.")));
801 
802  /*
803  * Additionally check that the special area looks sane.
804  */
805  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
806  ereport(ERROR,
807  (errcode(ERRCODE_INDEX_CORRUPTED),
808  errmsg("index \"%s\" contains corrupted page at block %u",
811  errhint("Please REINDEX it.")));
812 }
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3736
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
Pointer Page
Definition: bufpage.h:81
static bool PageIsNew(Page page)
Definition: bufpage.h:233
static uint16 PageGetSpecialSize(Page page)
Definition: bufpage.h:316
#define MAXALIGN(LEN)
Definition: c.h:811
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
static char * buf
Definition: pg_test_fsync.c:73
#define RelationGetRelationName(relation)
Definition: rel.h:539

References buf, BufferGetBlockNumber(), BufferGetPage(), ereport, errcode(), errhint(), errmsg(), ERROR, MAXALIGN, PageGetSpecialSize(), PageIsNew(), and RelationGetRelationName.

Referenced by gistBufferingFindCorrectParent(), gistdoinsert(), gistFindCorrectParent(), gistFindPath(), gistkillitems(), gistNewBuffer(), gistScanPage(), gistvacuum_delete_empty_pages(), and pgstat_gist_page().

◆ gistchoose()

OffsetNumber gistchoose ( Relation  r,
Page  p,
IndexTuple  it,
GISTSTATE giststate 
)

Definition at line 373 of file gistutil.c.

375 {
376  OffsetNumber result;
377  OffsetNumber maxoff;
378  OffsetNumber i;
379  float best_penalty[INDEX_MAX_KEYS];
380  GISTENTRY entry,
381  identry[INDEX_MAX_KEYS];
382  bool isnull[INDEX_MAX_KEYS];
383  int keep_current_best;
384 
385  Assert(!GistPageIsLeaf(p));
386 
387  gistDeCompressAtt(giststate, r,
388  it, NULL, (OffsetNumber) 0,
389  identry, isnull);
390 
391  /* we'll return FirstOffsetNumber if page is empty (shouldn't happen) */
392  result = FirstOffsetNumber;
393 
394  /*
395  * The index may have multiple columns, and there's a penalty value for
396  * each column. The penalty associated with a column that appears earlier
397  * in the index definition is strictly more important than the penalty of
398  * a column that appears later in the index definition.
399  *
400  * best_penalty[j] is the best penalty we have seen so far for column j,
401  * or -1 when we haven't yet examined column j. Array entries to the
402  * right of the first -1 are undefined.
403  */
404  best_penalty[0] = -1;
405 
406  /*
407  * If we find a tuple that's exactly as good as the currently best one, we
408  * could use either one. When inserting a lot of tuples with the same or
409  * similar keys, it's preferable to descend down the same path when
410  * possible, as that's more cache-friendly. On the other hand, if all
411  * inserts land on the same leaf page after a split, we're never going to
412  * insert anything to the other half of the split, and will end up using
413  * only 50% of the available space. Distributing the inserts evenly would
414  * lead to better space usage, but that hurts cache-locality during
415  * insertion. To get the best of both worlds, when we find a tuple that's
416  * exactly as good as the previous best, choose randomly whether to stick
417  * to the old best, or use the new one. Once we decide to stick to the
418  * old best, we keep sticking to it for any subsequent equally good tuples
419  * we might find. This favors tuples with low offsets, but still allows
420  * some inserts to go to other equally-good subtrees.
421  *
422  * keep_current_best is -1 if we haven't yet had to make a random choice
423  * whether to keep the current best tuple. If we have done so, and
424  * decided to keep it, keep_current_best is 1; if we've decided to
425  * replace, keep_current_best is 0. (This state will be reset to -1 as
426  * soon as we've made the replacement, but sometimes we make the choice in
427  * advance of actually finding a replacement best tuple.)
428  */
429  keep_current_best = -1;
430 
431  /*
432  * Loop over tuples on page.
433  */
434  maxoff = PageGetMaxOffsetNumber(p);
435  Assert(maxoff >= FirstOffsetNumber);
436 
437  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
438  {
440  bool zero_penalty;
441  int j;
442 
443  zero_penalty = true;
444 
445  /* Loop over index attributes. */
446  for (j = 0; j < IndexRelationGetNumberOfKeyAttributes(r); j++)
447  {
448  Datum datum;
449  float usize;
450  bool IsNull;
451 
452  /* Compute penalty for this column. */
453  datum = index_getattr(itup, j + 1, giststate->leafTupdesc,
454  &IsNull);
455  gistdentryinit(giststate, j, &entry, datum, r, p, i,
456  false, IsNull);
457  usize = gistpenalty(giststate, j, &entry, IsNull,
458  &identry[j], isnull[j]);
459  if (usize > 0)
460  zero_penalty = false;
461 
462  if (best_penalty[j] < 0 || usize < best_penalty[j])
463  {
464  /*
465  * New best penalty for column. Tentatively select this tuple
466  * as the target, and record the best penalty. Then reset the
467  * next column's penalty to "unknown" (and indirectly, the
468  * same for all the ones to its right). This will force us to
469  * adopt this tuple's penalty values as the best for all the
470  * remaining columns during subsequent loop iterations.
471  */
472  result = i;
473  best_penalty[j] = usize;
474 
476  best_penalty[j + 1] = -1;
477 
478  /* we have new best, so reset keep-it decision */
479  keep_current_best = -1;
480  }
481  else if (best_penalty[j] == usize)
482  {
483  /*
484  * The current tuple is exactly as good for this column as the
485  * best tuple seen so far. The next iteration of this loop
486  * will compare the next column.
487  */
488  }
489  else
490  {
491  /*
492  * The current tuple is worse for this column than the best
493  * tuple seen so far. Skip the remaining columns and move on
494  * to the next tuple, if any.
495  */
496  zero_penalty = false; /* so outer loop won't exit */
497  break;
498  }
499  }
500 
501  /*
502  * If we looped past the last column, and did not update "result",
503  * then this tuple is exactly as good as the prior best tuple.
504  */
505  if (j == IndexRelationGetNumberOfKeyAttributes(r) && result != i)
506  {
507  if (keep_current_best == -1)
508  {
509  /* we didn't make the random choice yet for this old best */
510  keep_current_best = pg_prng_bool(&pg_global_prng_state) ? 1 : 0;
511  }
512  if (keep_current_best == 0)
513  {
514  /* we choose to use the new tuple */
515  result = i;
516  /* choose again if there are even more exactly-as-good ones */
517  keep_current_best = -1;
518  }
519  }
520 
521  /*
522  * If we find a tuple with zero penalty for all columns, and we've
523  * decided we don't want to search for another tuple with equal
524  * penalty, there's no need to examine remaining tuples; just break
525  * out of the loop and return it.
526  */
527  if (zero_penalty)
528  {
529  if (keep_current_best == -1)
530  {
531  /* we didn't make the random choice yet for this old best */
532  keep_current_best = pg_prng_bool(&pg_global_prng_state) ? 1 : 0;
533  }
534  if (keep_current_best == 1)
535  break;
536  }
537  }
538 
539  return result;
540 }
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:354
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
#define Assert(condition)
Definition: c.h:858
#define GistPageIsLeaf(page)
Definition: gist.h:167
void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
Definition: gistutil.c:295
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:546
float gistpenalty(GISTSTATE *giststate, int attno, GISTENTRY *orig, bool isNullOrig, GISTENTRY *add, bool isNullAdd)
Definition: gistutil.c:723
int j
Definition: isn.c:74
int i
Definition: isn.c:73
IndexTupleData * IndexTuple
Definition: itup.h:53
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: itup.h:117
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
#define INDEX_MAX_KEYS
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:34
bool pg_prng_bool(pg_prng_state *state)
Definition: pg_prng.c:313
uintptr_t Datum
Definition: postgres.h:64
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
TupleDesc leafTupdesc
Definition: gist_private.h:80

References Assert, FirstOffsetNumber, gistDeCompressAtt(), gistdentryinit(), GistPageIsLeaf, gistpenalty(), i, index_getattr(), INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, j, GISTSTATE::leafTupdesc, OffsetNumberNext, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), pg_global_prng_state, and pg_prng_bool().

Referenced by gistdoinsert(), and gistProcessItup().

◆ gistCompressValues()

void gistCompressValues ( GISTSTATE giststate,
Relation  r,
const Datum attdata,
const bool isnull,
bool  isleaf,
Datum compatt 
)

Definition at line 595 of file gistutil.c.

597 {
598  int i;
599 
600  /*
601  * Call the compress method on each attribute.
602  */
603  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
604  {
605  if (isnull[i])
606  compatt[i] = (Datum) 0;
607  else
608  {
609  GISTENTRY centry;
610  GISTENTRY *cep;
611 
612  gistentryinit(centry, attdata[i], r, NULL, (OffsetNumber) 0,
613  isleaf);
614  /* there may not be a compress function in opclass */
615  if (OidIsValid(giststate->compressFn[i].fn_oid))
616  cep = (GISTENTRY *)
618  giststate->supportCollation[i],
619  PointerGetDatum(&centry)));
620  else
621  cep = &centry;
622  compatt[i] = cep->key;
623  }
624  }
625 
626  if (isleaf)
627  {
628  /*
629  * Emplace each included attribute if any.
630  */
631  for (; i < r->rd_att->natts; i++)
632  {
633  if (isnull[i])
634  compatt[i] = (Datum) 0;
635  else
636  compatt[i] = attdata[i];
637  }
638  }
639 }
#define OidIsValid(objectId)
Definition: c.h:775
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1129
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:242
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
Oid fn_oid
Definition: fmgr.h:59
Datum key
Definition: gist.h:158
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
FmgrInfo compressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:88
TupleDesc rd_att
Definition: rel.h:112

References GISTSTATE::compressFn, DatumGetPointer(), FmgrInfo::fn_oid, FunctionCall1Coll(), gistentryinit, i, IndexRelationGetNumberOfKeyAttributes, GISTENTRY::key, TupleDescData::natts, OidIsValid, PointerGetDatum(), RelationData::rd_att, and GISTSTATE::supportCollation.

Referenced by gistFormTuple(), and gistSortedBuildCallback().

◆ gistDeCompressAtt()

void gistDeCompressAtt ( GISTSTATE giststate,
Relation  r,
IndexTuple  tuple,
Page  p,
OffsetNumber  o,
GISTENTRY attdata,
bool isnull 
)

Definition at line 295 of file gistutil.c.

297 {
298  int i;
299 
300  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
301  {
302  Datum datum;
303 
304  datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
305  gistdentryinit(giststate, i, &attdata[i],
306  datum, r, p, o,
307  false, isnull[i]);
308  }
309 }

References gistdentryinit(), i, index_getattr(), IndexRelationGetNumberOfKeyAttributes, and GISTSTATE::leafTupdesc.

Referenced by gistchoose(), gistgetadjusted(), gistRelocateBuildBuffersOnSplit(), and placeOne().

◆ gistdentryinit()

void gistdentryinit ( GISTSTATE giststate,
int  nkey,
GISTENTRY e,
Datum  k,
Relation  r,
Page  pg,
OffsetNumber  o,
bool  l,
bool  isNull 
)

Definition at line 546 of file gistutil.c.

549 {
550  if (!isNull)
551  {
552  GISTENTRY *dep;
553 
554  gistentryinit(*e, k, r, pg, o, l);
555 
556  /* there may not be a decompress function in opclass */
557  if (!OidIsValid(giststate->decompressFn[nkey].fn_oid))
558  return;
559 
560  dep = (GISTENTRY *)
562  giststate->supportCollation[nkey],
563  PointerGetDatum(e)));
564  /* decompressFn may just return the given pointer */
565  if (dep != e)
566  gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
567  dep->leafkey);
568  }
569  else
570  gistentryinit(*e, (Datum) 0, r, pg, o, l);
571 }
e
Definition: preproc-init.c:82
OffsetNumber offset
Definition: gist.h:161
Page page
Definition: gist.h:160
Relation rel
Definition: gist.h:159
bool leafkey
Definition: gist.h:162
FmgrInfo decompressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:89

References DatumGetPointer(), GISTSTATE::decompressFn, FmgrInfo::fn_oid, FunctionCall1Coll(), gistentryinit, GISTENTRY::key, GISTENTRY::leafkey, GISTENTRY::offset, OidIsValid, GISTENTRY::page, PointerGetDatum(), GISTENTRY::rel, and GISTSTATE::supportCollation.

Referenced by gistchoose(), gistDeCompressAtt(), gistindex_keytest(), gistMakeUnionItVec(), and gistSplitByKey().

◆ gistextractpage()

IndexTuple* gistextractpage ( Page  page,
int *  len 
)

Definition at line 94 of file gistutil.c.

95 {
97  maxoff;
98  IndexTuple *itvec;
99 
100  maxoff = PageGetMaxOffsetNumber(page);
101  *len = maxoff;
102  itvec = palloc(sizeof(IndexTuple) * maxoff);
103  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
104  itvec[i - FirstOffsetNumber] = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
105 
106  return itvec;
107 }
void * palloc(Size size)
Definition: mcxt.c:1317
const void size_t len

References FirstOffsetNumber, i, len, OffsetNumberNext, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), and palloc().

Referenced by gist_indexsortbuild_levelstate_flush(), and gistplacetopage().

◆ gistFetchAtt()

static Datum gistFetchAtt ( GISTSTATE giststate,
int  nkey,
Datum  k,
Relation  r 
)
static

Definition at line 645 of file gistutil.c.

646 {
647  GISTENTRY fentry;
648  GISTENTRY *fep;
649 
650  gistentryinit(fentry, k, r, NULL, (OffsetNumber) 0, false);
651 
652  fep = (GISTENTRY *)
653  DatumGetPointer(FunctionCall1Coll(&giststate->fetchFn[nkey],
654  giststate->supportCollation[nkey],
655  PointerGetDatum(&fentry)));
656 
657  /* fetchFn set 'key', return it to the caller */
658  return fep->key;
659 }
FmgrInfo fetchFn[INDEX_MAX_KEYS]
Definition: gist_private.h:94

References DatumGetPointer(), GISTSTATE::fetchFn, FunctionCall1Coll(), gistentryinit, GISTENTRY::key, PointerGetDatum(), and GISTSTATE::supportCollation.

Referenced by gistFetchTuple().

◆ gistFetchTuple()

HeapTuple gistFetchTuple ( GISTSTATE giststate,
Relation  r,
IndexTuple  tuple 
)

Definition at line 666 of file gistutil.c.

667 {
668  MemoryContext oldcxt = MemoryContextSwitchTo(giststate->tempCxt);
670  bool isnull[INDEX_MAX_KEYS];
671  int i;
672 
673  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
674  {
675  Datum datum;
676 
677  datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
678 
679  if (giststate->fetchFn[i].fn_oid != InvalidOid)
680  {
681  if (!isnull[i])
682  fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
683  else
684  fetchatt[i] = (Datum) 0;
685  }
686  else if (giststate->compressFn[i].fn_oid == InvalidOid)
687  {
688  /*
689  * If opclass does not provide compress method that could change
690  * original value, att is necessarily stored in original form.
691  */
692  if (!isnull[i])
693  fetchatt[i] = datum;
694  else
695  fetchatt[i] = (Datum) 0;
696  }
697  else
698  {
699  /*
700  * Index-only scans not supported for this column. Since the
701  * planner chose an index-only scan anyway, it is not interested
702  * in this column, and we can replace it with a NULL.
703  */
704  isnull[i] = true;
705  fetchatt[i] = (Datum) 0;
706  }
707  }
708 
709  /*
710  * Get each included attribute.
711  */
712  for (; i < r->rd_att->natts; i++)
713  {
714  fetchatt[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
715  &isnull[i]);
716  }
717  MemoryContextSwitchTo(oldcxt);
718 
719  return heap_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
720 }
static Datum gistFetchAtt(GISTSTATE *giststate, int nkey, Datum k, Relation r)
Definition: gistutil.c:645
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#define InvalidOid
Definition: postgres_ext.h:36
MemoryContextSwitchTo(old_ctx)
TupleDesc fetchTupdesc
Definition: gist_private.h:83
MemoryContext tempCxt
Definition: gist_private.h:78
#define fetchatt(A, T)
Definition: tupmacs.h:46

References GISTSTATE::compressFn, fetchatt, GISTSTATE::fetchFn, GISTSTATE::fetchTupdesc, FmgrInfo::fn_oid, gistFetchAtt(), heap_form_tuple(), i, index_getattr(), INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, InvalidOid, GISTSTATE::leafTupdesc, MemoryContextSwitchTo(), TupleDescData::natts, RelationData::rd_att, and GISTSTATE::tempCxt.

Referenced by gistScanPage().

◆ gistfillbuffer()

void gistfillbuffer ( Page  page,
IndexTuple itup,
int  len,
OffsetNumber  off 
)

Definition at line 33 of file gistutil.c.

34 {
35  int i;
36 
37  if (off == InvalidOffsetNumber)
38  off = (PageIsEmpty(page)) ? FirstOffsetNumber :
40 
41  for (i = 0; i < len; i++)
42  {
43  Size sz = IndexTupleSize(itup[i]);
44  OffsetNumber l;
45 
46  l = PageAddItem(page, (Item) itup[i], sz, off, false, false);
47  if (l == InvalidOffsetNumber)
48  elog(ERROR, "failed to add item to GiST index page, item %d out of %d, size %d bytes",
49  i, len, (int) sz);
50  off++;
51  }
52 }
static bool PageIsEmpty(Page page)
Definition: bufpage.h:223
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
size_t Size
Definition: c.h:605
#define elog(elevel,...)
Definition: elog.h:224
Pointer Item
Definition: item.h:17
#define IndexTupleSize(itup)
Definition: itup.h:70
#define InvalidOffsetNumber
Definition: off.h:26

References elog, ERROR, FirstOffsetNumber, i, IndexTupleSize, InvalidOffsetNumber, len, OffsetNumberNext, PageAddItem, PageGetMaxOffsetNumber(), and PageIsEmpty().

Referenced by gist_indexsortbuild_levelstate_add(), gistplacetopage(), and gistRedoPageSplitRecord().

◆ gistfillitupvec()

IndexTupleData* gistfillitupvec ( IndexTuple vec,
int  veclen,
int *  memlen 
)

Definition at line 126 of file gistutil.c.

127 {
128  char *ptr,
129  *ret;
130  int i;
131 
132  *memlen = 0;
133 
134  for (i = 0; i < veclen; i++)
135  *memlen += IndexTupleSize(vec[i]);
136 
137  ptr = ret = palloc(*memlen);
138 
139  for (i = 0; i < veclen; i++)
140  {
141  memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
142  ptr += IndexTupleSize(vec[i]);
143  }
144 
145  return (IndexTupleData *) ret;
146 }

References i, IndexTupleSize, and palloc().

Referenced by gist_indexsortbuild_levelstate_flush(), gistplacetopage(), and gistSplit().

◆ gistfitpage()

bool gistfitpage ( IndexTuple itvec,
int  len 
)

Definition at line 78 of file gistutil.c.

79 {
80  int i;
81  Size size = 0;
82 
83  for (i = 0; i < len; i++)
84  size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
85 
86  /* TODO: Consider fillfactor */
87  return (size <= GiSTPageSize);
88 }
#define GiSTPageSize
Definition: gist_private.h:476
struct ItemIdData ItemIdData
static pg_noinline void Size size
Definition: slab.c:607

References GiSTPageSize, i, IndexTupleSize, len, and size.

Referenced by gistSplit().

◆ gistFormTuple()

IndexTuple gistFormTuple ( GISTSTATE giststate,
Relation  r,
const Datum attdata,
const bool isnull,
bool  isleaf 
)

Definition at line 574 of file gistutil.c.

576 {
577  Datum compatt[INDEX_MAX_KEYS];
578  IndexTuple res;
579 
580  gistCompressValues(giststate, r, attdata, isnull, isleaf, compatt);
581 
582  res = index_form_tuple(isleaf ? giststate->leafTupdesc :
583  giststate->nonLeafTupdesc,
584  compatt, isnull);
585 
586  /*
587  * The offset number on tuples on internal pages is unused. For historical
588  * reasons, it is set to 0xffff.
589  */
590  ItemPointerSetOffsetNumber(&(res->t_tid), 0xffff);
591  return res;
592 }
void gistCompressValues(GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf, Datum *compatt)
Definition: gistutil.c:595
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: indextuple.c:44
static void ItemPointerSetOffsetNumber(ItemPointerData *pointer, OffsetNumber offsetNumber)
Definition: itemptr.h:158
TupleDesc nonLeafTupdesc
Definition: gist_private.h:81

References gistCompressValues(), index_form_tuple(), INDEX_MAX_KEYS, ItemPointerSetOffsetNumber(), GISTSTATE::leafTupdesc, GISTSTATE::nonLeafTupdesc, and res.

Referenced by gistBuildCallback(), gistgetadjusted(), gistinsert(), gistSplit(), and gistunion().

◆ gistgetadjusted()

IndexTuple gistgetadjusted ( Relation  r,
IndexTuple  oldtup,
IndexTuple  addtup,
GISTSTATE giststate 
)

Definition at line 315 of file gistutil.c.

316 {
317  bool neednew = false;
318  GISTENTRY oldentries[INDEX_MAX_KEYS],
319  addentries[INDEX_MAX_KEYS];
320  bool oldisnull[INDEX_MAX_KEYS],
321  addisnull[INDEX_MAX_KEYS];
322  Datum attr[INDEX_MAX_KEYS];
323  bool isnull[INDEX_MAX_KEYS];
324  IndexTuple newtup = NULL;
325  int i;
326 
327  gistDeCompressAtt(giststate, r, oldtup, NULL,
328  (OffsetNumber) 0, oldentries, oldisnull);
329 
330  gistDeCompressAtt(giststate, r, addtup, NULL,
331  (OffsetNumber) 0, addentries, addisnull);
332 
333  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
334  {
335  gistMakeUnionKey(giststate, i,
336  oldentries + i, oldisnull[i],
337  addentries + i, addisnull[i],
338  attr + i, isnull + i);
339 
340  if (neednew)
341  /* we already need new key, so we can skip check */
342  continue;
343 
344  if (isnull[i])
345  /* union of key may be NULL if and only if both keys are NULL */
346  continue;
347 
348  if (!addisnull[i])
349  {
350  if (oldisnull[i] ||
351  !gistKeyIsEQ(giststate, i, oldentries[i].key, attr[i]))
352  neednew = true;
353  }
354  }
355 
356  if (neednew)
357  {
358  /* need to update key */
359  newtup = gistFormTuple(giststate, r, attr, isnull, false);
360  newtup->t_tid = oldtup->t_tid;
361  }
362 
363  return newtup;
364 }
void gistMakeUnionKey(GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull)
Definition: gistutil.c:232
bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
Definition: gistutil.c:280
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf)
Definition: gistutil.c:574
ItemPointerData t_tid
Definition: itup.h:37

References gistDeCompressAtt(), gistFormTuple(), gistKeyIsEQ(), gistMakeUnionKey(), i, INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, sort-test::key, and IndexTupleData::t_tid.

Referenced by gistdoinsert(), gistformdownlink(), gistProcessItup(), and gistRelocateBuildBuffersOnSplit().

◆ gistGetFakeLSN()

XLogRecPtr gistGetFakeLSN ( Relation  rel)

Definition at line 1015 of file gistutil.c.

1016 {
1017  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
1018  {
1019  /*
1020  * Temporary relations are only accessible in our session, so a simple
1021  * backend-local counter will do.
1022  */
1023  static XLogRecPtr counter = FirstNormalUnloggedLSN;
1024 
1025  return counter++;
1026  }
1027  else if (RelationIsPermanent(rel))
1028  {
1029  /*
1030  * WAL-logging on this relation will start after commit, so its LSNs
1031  * must be distinct numbers smaller than the LSN at the next commit.
1032  * Emit a dummy WAL record if insert-LSN hasn't advanced after the
1033  * last call.
1034  */
1035  static XLogRecPtr lastlsn = InvalidXLogRecPtr;
1036  XLogRecPtr currlsn = GetXLogInsertRecPtr();
1037 
1038  /* Shouldn't be called for WAL-logging relations */
1039  Assert(!RelationNeedsWAL(rel));
1040 
1041  /* No need for an actual record if we already have a distinct LSN */
1042  if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
1043  currlsn = gistXLogAssignLSN();
1044 
1045  lastlsn = currlsn;
1046  return currlsn;
1047  }
1048  else
1049  {
1050  /*
1051  * Unlogged relations are accessible from other backends, and survive
1052  * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
1053  */
1054  Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED);
1055  return GetFakeLSNForUnloggedRel();
1056  }
1057 }
XLogRecPtr gistXLogAssignLSN(void)
Definition: gistxlog.c:576
#define RelationNeedsWAL(relation)
Definition: rel.h:628
#define RelationIsPermanent(relation)
Definition: rel.h:617
Form_pg_class rd_rel
Definition: rel.h:111
XLogRecPtr GetXLogInsertRecPtr(void)
Definition: xlog.c:9365
XLogRecPtr GetFakeLSNForUnloggedRel(void)
Definition: xlog.c:4569
#define FirstNormalUnloggedLSN
Definition: xlogdefs.h:36
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References Assert, FirstNormalUnloggedLSN, GetFakeLSNForUnloggedRel(), GetXLogInsertRecPtr(), gistXLogAssignLSN(), InvalidXLogRecPtr, RelationData::rd_rel, RelationIsPermanent, RelationNeedsWAL, and XLogRecPtrIsInvalid.

Referenced by gistdeletepage(), gistplacetopage(), gistprunepage(), gistvacuumpage(), and gistvacuumscan().

◆ GISTInitBuffer()

void GISTInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 772 of file gistutil.c.

773 {
774  Page page;
775 
776  page = BufferGetPage(b);
777  gistinitpage(page, f);
778 }
void gistinitpage(Page page, uint32 f)
Definition: gistutil.c:756
int b
Definition: isn.c:70

References b, BufferGetPage(), and gistinitpage().

Referenced by gistbuild(), gistbuildempty(), gistplacetopage(), and gistRedoPageSplitRecord().

◆ gistinitpage()

void gistinitpage ( Page  page,
uint32  f 
)

Definition at line 756 of file gistutil.c.

757 {
758  GISTPageOpaque opaque;
759 
760  PageInit(page, BLCKSZ, sizeof(GISTPageOpaqueData));
761 
762  opaque = GistPageGetOpaque(page);
763  opaque->rightlink = InvalidBlockNumber;
764  opaque->flags = f;
765  opaque->gist_page_id = GIST_PAGE_ID;
766 }
#define InvalidBlockNumber
Definition: block.h:33
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42
#define GIST_PAGE_ID
Definition: gist.h:109
#define GistPageGetOpaque(page)
Definition: gist.h:165
uint16 gist_page_id
Definition: gist.h:80
BlockNumber rightlink
Definition: gist.h:78
uint16 flags
Definition: gist.h:79

References GISTPageOpaqueData::flags, GISTPageOpaqueData::gist_page_id, GIST_PAGE_ID, GistPageGetOpaque, InvalidBlockNumber, PageInit(), and GISTPageOpaqueData::rightlink.

Referenced by gist_indexsortbuild(), gist_indexsortbuild_levelstate_add(), gist_indexsortbuild_levelstate_flush(), and GISTInitBuffer().

◆ gistjoinvector()

IndexTuple* gistjoinvector ( IndexTuple itvec,
int *  len,
IndexTuple additvec,
int  addlen 
)

Definition at line 113 of file gistutil.c.

114 {
115  itvec = (IndexTuple *) repalloc(itvec, sizeof(IndexTuple) * ((*len) + addlen));
116  memmove(&itvec[*len], additvec, sizeof(IndexTuple) * addlen);
117  *len += addlen;
118  return itvec;
119 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541

References len, and repalloc().

Referenced by gist_indexsortbuild_levelstate_flush(), and gistplacetopage().

◆ gistKeyIsEQ()

bool gistKeyIsEQ ( GISTSTATE giststate,
int  attno,
Datum  a,
Datum  b 
)

Definition at line 280 of file gistutil.c.

281 {
282  bool result = false; /* silence compiler warning */
283 
284  FunctionCall3Coll(&giststate->equalFn[attno],
285  giststate->supportCollation[attno],
286  a, b,
287  PointerGetDatum(&result));
288  return result;
289 }
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1171
int a
Definition: isn.c:69
FmgrInfo equalFn[INDEX_MAX_KEYS]
Definition: gist_private.h:92

References a, b, GISTSTATE::equalFn, FunctionCall3Coll(), PointerGetDatum(), and GISTSTATE::supportCollation.

Referenced by gistgetadjusted(), and gistUserPicksplit().

◆ gistMakeUnionItVec()

void gistMakeUnionItVec ( GISTSTATE giststate,
IndexTuple itvec,
int  len,
Datum attr,
bool isnull 
)

Definition at line 154 of file gistutil.c.

156 {
157  int i;
158  GistEntryVector *evec;
159  int attrsize;
160 
161  evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
162 
163  for (i = 0; i < giststate->nonLeafTupdesc->natts; i++)
164  {
165  int j;
166 
167  /* Collect non-null datums for this column */
168  evec->n = 0;
169  for (j = 0; j < len; j++)
170  {
171  Datum datum;
172  bool IsNull;
173 
174  datum = index_getattr(itvec[j], i + 1, giststate->leafTupdesc,
175  &IsNull);
176  if (IsNull)
177  continue;
178 
179  gistdentryinit(giststate, i,
180  evec->vector + evec->n,
181  datum,
182  NULL, NULL, (OffsetNumber) 0,
183  false, IsNull);
184  evec->n++;
185  }
186 
187  /* If this column was all NULLs, the union is NULL */
188  if (evec->n == 0)
189  {
190  attr[i] = (Datum) 0;
191  isnull[i] = true;
192  }
193  else
194  {
195  if (evec->n == 1)
196  {
197  /* unionFn may expect at least two inputs */
198  evec->n = 2;
199  evec->vector[1] = evec->vector[0];
200  }
201 
202  /* Make union and store in attr array */
203  attr[i] = FunctionCall2Coll(&giststate->unionFn[i],
204  giststate->supportCollation[i],
205  PointerGetDatum(evec),
206  PointerGetDatum(&attrsize));
207 
208  isnull[i] = false;
209  }
210  }
211 }
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
struct GISTENTRY GISTENTRY
#define GEVHDRSZ
Definition: gist.h:237
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:87
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:234
int32 n
Definition: gist.h:233

References FunctionCall2Coll(), GEVHDRSZ, gistdentryinit(), i, index_getattr(), j, GISTSTATE::leafTupdesc, len, GistEntryVector::n, TupleDescData::natts, GISTSTATE::nonLeafTupdesc, palloc(), PointerGetDatum(), GISTSTATE::supportCollation, GISTSTATE::unionFn, and GistEntryVector::vector.

Referenced by gistunion(), and gistunionsubkeyvec().

◆ gistMakeUnionKey()

void gistMakeUnionKey ( GISTSTATE giststate,
int  attno,
GISTENTRY entry1,
bool  isnull1,
GISTENTRY entry2,
bool  isnull2,
Datum dst,
bool dstisnull 
)

Definition at line 232 of file gistutil.c.

236 {
237  /* we need a GistEntryVector with room for exactly 2 elements */
238  union
239  {
240  GistEntryVector gev;
241  char padding[2 * sizeof(GISTENTRY) + GEVHDRSZ];
242  } storage;
243  GistEntryVector *evec = &storage.gev;
244  int dstsize;
245 
246  evec->n = 2;
247 
248  if (isnull1 && isnull2)
249  {
250  *dstisnull = true;
251  *dst = (Datum) 0;
252  }
253  else
254  {
255  if (isnull1 == false && isnull2 == false)
256  {
257  evec->vector[0] = *entry1;
258  evec->vector[1] = *entry2;
259  }
260  else if (isnull1 == false)
261  {
262  evec->vector[0] = *entry1;
263  evec->vector[1] = *entry1;
264  }
265  else
266  {
267  evec->vector[0] = *entry2;
268  evec->vector[1] = *entry2;
269  }
270 
271  *dstisnull = false;
272  *dst = FunctionCall2Coll(&giststate->unionFn[attno],
273  giststate->supportCollation[attno],
274  PointerGetDatum(evec),
275  PointerGetDatum(&dstsize));
276  }
277 }
#define storage
Definition: indent_codes.h:68

References FunctionCall2Coll(), GEVHDRSZ, GistEntryVector::n, PointerGetDatum(), storage, GISTSTATE::supportCollation, GISTSTATE::unionFn, and GistEntryVector::vector.

Referenced by gistgetadjusted(), and supportSecondarySplit().

◆ gistNewBuffer()

Buffer gistNewBuffer ( Relation  r,
Relation  heaprel 
)

Definition at line 823 of file gistutil.c.

824 {
825  Buffer buffer;
826 
827  /* First, try to get a page from FSM */
828  for (;;)
829  {
830  BlockNumber blkno = GetFreeIndexPage(r);
831 
832  if (blkno == InvalidBlockNumber)
833  break; /* nothing left in FSM */
834 
835  buffer = ReadBuffer(r, blkno);
836 
837  /*
838  * We have to guard against the possibility that someone else already
839  * recycled this page; the buffer may be locked if so.
840  */
841  if (ConditionalLockBuffer(buffer))
842  {
843  Page page = BufferGetPage(buffer);
844 
845  /*
846  * If the page was never initialized, it's OK to use.
847  */
848  if (PageIsNew(page))
849  return buffer;
850 
851  gistcheckpage(r, buffer);
852 
853  /*
854  * Otherwise, recycle it if deleted, and too old to have any
855  * processes interested in it.
856  */
857  if (gistPageRecyclable(page))
858  {
859  /*
860  * If we are generating WAL for Hot Standby then create a WAL
861  * record that will allow us to conflict with queries running
862  * on standby, in case they have snapshots older than the
863  * page's deleteXid.
864  */
866  gistXLogPageReuse(r, heaprel, blkno, GistPageGetDeleteXid(page));
867 
868  return buffer;
869  }
870 
871  LockBuffer(buffer, GIST_UNLOCK);
872  }
873 
874  /* Can't use it, so release buffer and try again */
875  ReleaseBuffer(buffer);
876  }
877 
878  /* Must extend the file */
879  buffer = ExtendBufferedRel(BMR_REL(r), MAIN_FORKNUM, NULL,
880  EB_LOCK_FIRST);
881 
882  return buffer;
883 }
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition: bufmgr.c:873
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:5197
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4936
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5171
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:773
@ EB_LOCK_FIRST
Definition: bufmgr.h:86
#define BMR_REL(p_rel)
Definition: bufmgr.h:107
static FullTransactionId GistPageGetDeleteXid(Page page)
Definition: gist.h:213
#define GIST_UNLOCK
Definition: gist_private.h:44
bool gistPageRecyclable(Page page)
Definition: gistutil.c:887
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:784
void gistXLogPageReuse(Relation rel, Relation heaprel, BlockNumber blkno, FullTransactionId deleteXid)
Definition: gistxlog.c:594
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
@ MAIN_FORKNUM
Definition: relpath.h:50
#define XLogStandbyInfoActive()
Definition: xlog.h:123

References BMR_REL, BufferGetPage(), ConditionalLockBuffer(), EB_LOCK_FIRST, ExtendBufferedRel(), GetFreeIndexPage(), GIST_UNLOCK, gistcheckpage(), GistPageGetDeleteXid(), gistPageRecyclable(), gistXLogPageReuse(), InvalidBlockNumber, LockBuffer(), MAIN_FORKNUM, PageIsNew(), ReadBuffer(), RelationNeedsWAL, ReleaseBuffer(), and XLogStandbyInfoActive.

Referenced by gistbuild(), and gistplacetopage().

◆ gistnospace()

bool gistnospace ( Page  page,
IndexTuple itvec,
int  len,
OffsetNumber  todelete,
Size  freespace 
)

Definition at line 58 of file gistutil.c.

59 {
60  unsigned int size = freespace,
61  deleted = 0;
62  int i;
63 
64  for (i = 0; i < len; i++)
65  size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
66 
67  if (todelete != InvalidOffsetNumber)
68  {
69  IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
70 
71  deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
72  }
73 
74  return (PageGetFreeSpace(page) + deleted < size);
75 }
Size PageGetFreeSpace(Page page)
Definition: bufpage.c:907

References i, IndexTupleSize, InvalidOffsetNumber, len, PageGetFreeSpace(), PageGetItem(), PageGetItemId(), and size.

Referenced by gistplacetopage().

◆ gistoptions()

bytea* gistoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 911 of file gistutil.c.

912 {
913  static const relopt_parse_elt tab[] = {
914  {"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
915  {"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)}
916  };
917 
918  return (bytea *) build_reloptions(reloptions, validate,
920  sizeof(GiSTOptions),
921  tab, lengthof(tab));
922 }
#define lengthof(array)
Definition: c.h:788
static int fillfactor
Definition: pgbench.c:187
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1908
@ RELOPT_KIND_GIST
Definition: reloptions.h:47
@ RELOPT_TYPE_ENUM
Definition: reloptions.h:34
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
Definition: c.h:687

References build_reloptions(), fillfactor, lengthof, RELOPT_KIND_GIST, RELOPT_TYPE_ENUM, and RELOPT_TYPE_INT.

Referenced by gisthandler().

◆ gistPageRecyclable()

bool gistPageRecyclable ( Page  page)

Definition at line 887 of file gistutil.c.

888 {
889  if (PageIsNew(page))
890  return true;
891  if (GistPageIsDeleted(page))
892  {
893  /*
894  * The page was deleted, but when? If it was just deleted, a scan
895  * might have seen the downlink to it, and will read the page later.
896  * As long as that can happen, we must keep the deleted page around as
897  * a tombstone.
898  *
899  * For that check if the deletion XID could still be visible to
900  * anyone. If not, then no scan that's still in progress could have
901  * seen its downlink, and we can recycle it.
902  */
903  FullTransactionId deletexid_full = GistPageGetDeleteXid(page);
904 
905  return GlobalVisCheckRemovableFullXid(NULL, deletexid_full);
906  }
907  return false;
908 }
#define GistPageIsDeleted(page)
Definition: gist.h:170
bool GlobalVisCheckRemovableFullXid(Relation rel, FullTransactionId fxid)
Definition: procarray.c:4290

References GistPageGetDeleteXid(), GistPageIsDeleted, GlobalVisCheckRemovableFullXid(), and PageIsNew().

Referenced by gistNewBuffer(), and gistvacuumpage().

◆ gistpenalty()

float gistpenalty ( GISTSTATE giststate,
int  attno,
GISTENTRY orig,
bool  isNullOrig,
GISTENTRY add,
bool  isNullAdd 
)

Definition at line 723 of file gistutil.c.

726 {
727  float penalty = 0.0;
728 
729  if (giststate->penaltyFn[attno].fn_strict == false ||
730  (isNullOrig == false && isNullAdd == false))
731  {
732  FunctionCall3Coll(&giststate->penaltyFn[attno],
733  giststate->supportCollation[attno],
734  PointerGetDatum(orig),
735  PointerGetDatum(add),
736  PointerGetDatum(&penalty));
737  /* disallow negative or NaN penalty */
738  if (isnan(penalty) || penalty < 0.0)
739  penalty = 0.0;
740  }
741  else if (isNullOrig && isNullAdd)
742  penalty = 0.0;
743  else
744  {
745  /* try to prevent mixing null and non-null values */
746  penalty = get_float4_infinity();
747  }
748 
749  return penalty;
750 }
static float4 get_float4_infinity(void)
Definition: float.h:74
bool fn_strict
Definition: fmgr.h:61
FmgrInfo penaltyFn[INDEX_MAX_KEYS]
Definition: gist_private.h:90

References FmgrInfo::fn_strict, FunctionCall3Coll(), get_float4_infinity(), GISTSTATE::penaltyFn, PointerGetDatum(), and GISTSTATE::supportCollation.

Referenced by findDontCares(), gistchoose(), gistRelocateBuildBuffersOnSplit(), placeOne(), and supportSecondarySplit().

◆ gistproperty()

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

Definition at line 932 of file gistutil.c.

935 {
936  Oid opclass,
937  opfamily,
938  opcintype;
939  int16 procno;
940 
941  /* Only answer column-level inquiries */
942  if (attno == 0)
943  return false;
944 
945  /*
946  * Currently, GiST distance-ordered scans require that there be a distance
947  * function in the opclass with the default types (i.e. the one loaded
948  * into the relcache entry, see initGISTstate). So we assume that if such
949  * a function exists, then there's a reason for it (rather than grubbing
950  * through all the opfamily's operators to find an ordered one).
951  *
952  * Essentially the same code can test whether we support returning the
953  * column data, since that's true if the opclass provides a fetch proc.
954  */
955 
956  switch (prop)
957  {
959  procno = GIST_DISTANCE_PROC;
960  break;
961  case AMPROP_RETURNABLE:
962  procno = GIST_FETCH_PROC;
963  break;
964  default:
965  return false;
966  }
967 
968  /* First we need to know the column's opclass. */
969  opclass = get_index_column_opclass(index_oid, attno);
970  if (!OidIsValid(opclass))
971  {
972  *isnull = true;
973  return true;
974  }
975 
976  /* Now look up the opclass family and input datatype. */
977  if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
978  {
979  *isnull = true;
980  return true;
981  }
982 
983  /* And now we can check whether the function is provided. */
984 
985  *res = SearchSysCacheExists4(AMPROCNUM,
986  ObjectIdGetDatum(opfamily),
987  ObjectIdGetDatum(opcintype),
988  ObjectIdGetDatum(opcintype),
989  Int16GetDatum(procno));
990 
991  /*
992  * Special case: even without a fetch function, AMPROP_RETURNABLE is true
993  * if the opclass has no compress function.
994  */
995  if (prop == AMPROP_RETURNABLE && !*res)
996  {
997  *res = !SearchSysCacheExists4(AMPROCNUM,
998  ObjectIdGetDatum(opfamily),
999  ObjectIdGetDatum(opcintype),
1000  ObjectIdGetDatum(opcintype),
1002  }
1003 
1004  *isnull = false;
1005 
1006  return true;
1007 }
@ AMPROP_DISTANCE_ORDERABLE
Definition: amapi.h:42
@ AMPROP_RETURNABLE
Definition: amapi.h:43
signed short int16
Definition: c.h:493
#define GIST_FETCH_PROC
Definition: gist.h:38
#define GIST_COMPRESS_PROC
Definition: gist.h:32
#define GIST_DISTANCE_PROC
Definition: gist.h:37
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1235
Oid get_index_column_opclass(Oid index_oid, int attno)
Definition: lsyscache.c:3512
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:101

References AMPROP_DISTANCE_ORDERABLE, AMPROP_RETURNABLE, get_index_column_opclass(), get_opclass_opfamily_and_input_type(), GIST_COMPRESS_PROC, GIST_DISTANCE_PROC, GIST_FETCH_PROC, Int16GetDatum(), ObjectIdGetDatum(), OidIsValid, res, and SearchSysCacheExists4.

Referenced by gisthandler().

◆ gistunion()

IndexTuple gistunion ( Relation  r,
IndexTuple itvec,
int  len,
GISTSTATE giststate 
)

Definition at line 218 of file gistutil.c.

219 {
220  Datum attr[INDEX_MAX_KEYS];
221  bool isnull[INDEX_MAX_KEYS];
222 
223  gistMakeUnionItVec(giststate, itvec, len, attr, isnull);
224 
225  return gistFormTuple(giststate, r, attr, isnull, false);
226 }
void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull)
Definition: gistutil.c:154

References gistFormTuple(), gistMakeUnionItVec(), INDEX_MAX_KEYS, and len.

Referenced by gist_indexsortbuild_levelstate_flush().