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 "catalog/pg_opclass.h"
#include "common/pg_prng.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/float.h"
#include "utils/lsyscache.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, Datum *attdata, bool *isnull, bool isleaf)
 
void gistCompressValues (GISTSTATE *giststate, Relation r, Datum *attdata, 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)
 
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 785 of file gistutil.c.

786 {
787  Page page = BufferGetPage(buf);
788 
789  /*
790  * ReadBuffer verifies that every newly-read page passes
791  * PageHeaderIsValid, which means it either contains a reasonably sane
792  * page header or is all-zero. We have to defend against the all-zero
793  * case, however.
794  */
795  if (PageIsNew(page))
796  ereport(ERROR,
797  (errcode(ERRCODE_INDEX_CORRUPTED),
798  errmsg("index \"%s\" contains unexpected zero page at block %u",
801  errhint("Please REINDEX it.")));
802 
803  /*
804  * Additionally check that the special area looks sane.
805  */
806  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
807  ereport(ERROR,
808  (errcode(ERRCODE_INDEX_CORRUPTED),
809  errmsg("index \"%s\" contains corrupted page at block %u",
812  errhint("Please REINDEX it.")));
813 }
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2748
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
Pointer Page
Definition: bufpage.h:78
#define PageGetSpecialSize(page)
Definition: bufpage.h:299
#define PageIsNew(page)
Definition: bufpage.h:228
#define MAXALIGN(LEN)
Definition: c.h:757
int errhint(const char *fmt,...)
Definition: elog.c:1156
int errcode(int sqlerrcode)
Definition: elog.c:698
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
static char * buf
Definition: pg_test_fsync.c:70
#define RelationGetRelationName(relation)
Definition: rel.h:512

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 374 of file gistutil.c.

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

Definition at line 596 of file gistutil.c.

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

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 296 of file gistutil.c.

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

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 547 of file gistutil.c.

550 {
551  if (!isNull)
552  {
553  GISTENTRY *dep;
554 
555  gistentryinit(*e, k, r, pg, o, l);
556 
557  /* there may not be a decompress function in opclass */
558  if (!OidIsValid(giststate->decompressFn[nkey].fn_oid))
559  return;
560 
561  dep = (GISTENTRY *)
563  giststate->supportCollation[nkey],
564  PointerGetDatum(e)));
565  /* decompressFn may just return the given pointer */
566  if (dep != e)
567  gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
568  dep->leafkey);
569  }
570  else
571  gistentryinit(*e, (Datum) 0, r, pg, o, l);
572 }
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 95 of file gistutil.c.

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

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

Referenced by gist_indexsortbuild_pagestate_flush(), and gistplacetopage().

◆ gistFetchAtt()

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

Definition at line 646 of file gistutil.c.

647 {
648  GISTENTRY fentry;
649  GISTENTRY *fep;
650 
651  gistentryinit(fentry, k, r, NULL, (OffsetNumber) 0, false);
652 
653  fep = (GISTENTRY *)
654  DatumGetPointer(FunctionCall1Coll(&giststate->fetchFn[nkey],
655  giststate->supportCollation[nkey],
656  PointerGetDatum(&fentry)));
657 
658  /* fetchFn set 'key', return it to the caller */
659  return fep->key;
660 }
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 667 of file gistutil.c.

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

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 34 of file gistutil.c.

35 {
36  int i;
37 
38  if (off == InvalidOffsetNumber)
39  off = (PageIsEmpty(page)) ? FirstOffsetNumber :
41 
42  for (i = 0; i < len; i++)
43  {
44  Size sz = IndexTupleSize(itup[i]);
45  OffsetNumber l;
46 
47  l = PageAddItem(page, (Item) itup[i], sz, off, false, false);
48  if (l == InvalidOffsetNumber)
49  elog(ERROR, "failed to add item to GiST index page, item %d out of %d, size %d bytes",
50  i, len, (int) sz);
51  off++;
52  }
53 }
#define PageIsEmpty(page)
Definition: bufpage.h:221
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:415
size_t Size
Definition: c.h:540
#define elog(elevel,...)
Definition: elog.h:218
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_pagestate_add(), gistplacetopage(), and gistRedoPageSplitRecord().

◆ gistfillitupvec()

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

Definition at line 127 of file gistutil.c.

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

References i, IndexTupleSize, and palloc().

Referenced by gistplacetopage(), and gistSplit().

◆ gistfitpage()

bool gistfitpage ( IndexTuple itvec,
int  len 
)

Definition at line 79 of file gistutil.c.

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

References GiSTPageSize, i, IndexTupleSize, and len.

Referenced by gistSplit().

◆ gistFormTuple()

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

Definition at line 575 of file gistutil.c.

577 {
578  Datum compatt[INDEX_MAX_KEYS];
579  IndexTuple res;
580 
581  gistCompressValues(giststate, r, attdata, isnull, isleaf, compatt);
582 
583  res = index_form_tuple(isleaf ? giststate->leafTupdesc :
584  giststate->nonLeafTupdesc,
585  compatt, isnull);
586 
587  /*
588  * The offset number on tuples on internal pages is unused. For historical
589  * reasons, it is set to 0xffff.
590  */
591  ItemPointerSetOffsetNumber(&(res->t_tid), 0xffff);
592  return res;
593 }
void gistCompressValues(GISTSTATE *giststate, Relation r, Datum *attdata, bool *isnull, bool isleaf, Datum *compatt)
Definition: gistutil.c:596
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:47
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:148
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 316 of file gistutil.c.

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

1026 {
1027  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
1028  {
1029  /*
1030  * Temporary relations are only accessible in our session, so a simple
1031  * backend-local counter will do.
1032  */
1033  static XLogRecPtr counter = FirstNormalUnloggedLSN;
1034 
1035  return counter++;
1036  }
1037  else if (RelationIsPermanent(rel))
1038  {
1039  /*
1040  * WAL-logging on this relation will start after commit, so its LSNs
1041  * must be distinct numbers smaller than the LSN at the next commit.
1042  * Emit a dummy WAL record if insert-LSN hasn't advanced after the
1043  * last call.
1044  */
1045  static XLogRecPtr lastlsn = InvalidXLogRecPtr;
1046  XLogRecPtr currlsn = GetXLogInsertRecPtr();
1047 
1048  /* Shouldn't be called for WAL-logging relations */
1049  Assert(!RelationNeedsWAL(rel));
1050 
1051  /* No need for an actual record if we already have a distinct LSN */
1052  if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
1053  currlsn = gistXLogAssignLSN();
1054 
1055  lastlsn = currlsn;
1056  return currlsn;
1057  }
1058  else
1059  {
1060  /*
1061  * Unlogged relations are accessible from other backends, and survive
1062  * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
1063  */
1064  Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED);
1065  return GetFakeLSNForUnloggedRel();
1066  }
1067 }
XLogRecPtr gistXLogAssignLSN(void)
Definition: gistxlog.c:581
#define RelationNeedsWAL(relation)
Definition: rel.h:602
#define RelationIsPermanent(relation)
Definition: rel.h:591
Form_pg_class rd_rel
Definition: rel.h:109
XLogRecPtr GetXLogInsertRecPtr(void)
Definition: xlog.c:12017
XLogRecPtr GetFakeLSNForUnloggedRel(void)
Definition: xlog.c:5086
#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 773 of file gistutil.c.

774 {
775  Page page;
776 
777  page = BufferGetPage(b);
778  gistinitpage(page, f);
779 }
void gistinitpage(Page page, uint32 f)
Definition: gistutil.c:757
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 757 of file gistutil.c.

758 {
759  GISTPageOpaque opaque;
760 
761  PageInit(page, BLCKSZ, sizeof(GISTPageOpaqueData));
762 
763  opaque = GistPageGetOpaque(page);
764  opaque->rightlink = InvalidBlockNumber;
765  opaque->flags = f;
766  opaque->gist_page_id = GIST_PAGE_ID;
767 }
#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_pagestate_flush(), and GISTInitBuffer().

◆ gistjoinvector()

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

Definition at line 114 of file gistutil.c.

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

References len, and repalloc().

Referenced by gistplacetopage().

◆ gistKeyIsEQ()

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

Definition at line 281 of file gistutil.c.

282 {
283  bool result;
284 
285  FunctionCall3Coll(&giststate->equalFn[attno],
286  giststate->supportCollation[attno],
287  a, b,
288  PointerGetDatum(&result));
289  return result;
290 }
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1170
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 155 of file gistutil.c.

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

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

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

Referenced by gistgetadjusted(), and supportSecondarySplit().

◆ gistNewBuffer()

Buffer gistNewBuffer ( Relation  r)

Definition at line 824 of file gistutil.c.

825 {
826  Buffer buffer;
827  bool needLock;
828 
829  /* First, try to get a page from FSM */
830  for (;;)
831  {
832  BlockNumber blkno = GetFreeIndexPage(r);
833 
834  if (blkno == InvalidBlockNumber)
835  break; /* nothing left in FSM */
836 
837  buffer = ReadBuffer(r, blkno);
838 
839  /*
840  * We have to guard against the possibility that someone else already
841  * recycled this page; the buffer may be locked if so.
842  */
843  if (ConditionalLockBuffer(buffer))
844  {
845  Page page = BufferGetPage(buffer);
846 
847  /*
848  * If the page was never initialized, it's OK to use.
849  */
850  if (PageIsNew(page))
851  return buffer;
852 
853  gistcheckpage(r, buffer);
854 
855  /*
856  * Otherwise, recycle it if deleted, and too old to have any
857  * processes interested in it.
858  */
859  if (gistPageRecyclable(page))
860  {
861  /*
862  * If we are generating WAL for Hot Standby then create a WAL
863  * record that will allow us to conflict with queries running
864  * on standby, in case they have snapshots older than the
865  * page's deleteXid.
866  */
868  gistXLogPageReuse(r, blkno, GistPageGetDeleteXid(page));
869 
870  return buffer;
871  }
872 
873  LockBuffer(buffer, GIST_UNLOCK);
874  }
875 
876  /* Can't use it, so release buffer and try again */
877  ReleaseBuffer(buffer);
878  }
879 
880  /* Must extend the file */
881  needLock = !RELATION_IS_LOCAL(r);
882 
883  if (needLock)
885 
886  buffer = ReadBuffer(r, P_NEW);
887  LockBuffer(buffer, GIST_EXCLUSIVE);
888 
889  if (needLock)
891 
892  return buffer;
893 }
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:4033
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3768
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4007
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:694
#define P_NEW
Definition: bufmgr.h:91
static FullTransactionId GistPageGetDeleteXid(Page page)
Definition: gist.h:213
#define GIST_UNLOCK
Definition: gist_private.h:44
#define GIST_EXCLUSIVE
Definition: gist_private.h:43
bool gistPageRecyclable(Page page)
Definition: gistutil.c:897
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:785
void gistXLogPageReuse(Relation rel, BlockNumber blkno, FullTransactionId latestRemovedXid)
Definition: gistxlog.c:599
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:403
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:453
#define ExclusiveLock
Definition: lockdefs.h:42
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:622
#define XLogStandbyInfoActive()
Definition: xlog.h:178

References BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), GIST_EXCLUSIVE, GIST_UNLOCK, gistcheckpage(), GistPageGetDeleteXid(), gistPageRecyclable(), gistXLogPageReuse(), InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, RelationNeedsWAL, ReleaseBuffer(), UnlockRelationForExtension(), and XLogStandbyInfoActive.

Referenced by gistbuild(), and gistplacetopage().

◆ gistnospace()

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

Definition at line 59 of file gistutil.c.

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

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

Referenced by gistplacetopage().

◆ gistoptions()

bytea* gistoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 921 of file gistutil.c.

922 {
923  static const relopt_parse_elt tab[] = {
924  {"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
925  {"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)}
926  };
927 
928  return (bytea *) build_reloptions(reloptions, validate,
930  sizeof(GiSTOptions),
931  tab, lengthof(tab));
932 }
#define offsetof(type, field)
Definition: c.h:727
#define lengthof(array)
Definition: c.h:734
int fillfactor
Definition: pgbench.c:198
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:1904
@ RELOPT_KIND_GIST
Definition: reloptions.h:47
@ RELOPT_TYPE_ENUM
Definition: reloptions.h:34
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
Definition: c.h:622

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

Referenced by gisthandler().

◆ gistPageRecyclable()

bool gistPageRecyclable ( Page  page)

Definition at line 897 of file gistutil.c.

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

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 724 of file gistutil.c.

727 {
728  float penalty = 0.0;
729 
730  if (giststate->penaltyFn[attno].fn_strict == false ||
731  (isNullOrig == false && isNullAdd == false))
732  {
733  FunctionCall3Coll(&giststate->penaltyFn[attno],
734  giststate->supportCollation[attno],
735  PointerGetDatum(orig),
736  PointerGetDatum(add),
737  PointerGetDatum(&penalty));
738  /* disallow negative or NaN penalty */
739  if (isnan(penalty) || penalty < 0.0)
740  penalty = 0.0;
741  }
742  else if (isNullOrig && isNullAdd)
743  penalty = 0.0;
744  else
745  {
746  /* try to prevent mixing null and non-null values */
747  penalty = get_float4_infinity();
748  }
749 
750  return penalty;
751 }
static float4 get_float4_infinity(void)
Definition: float.h:73
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 942 of file gistutil.c.

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

References AMPROCNUM, 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 219 of file gistutil.c.

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

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

Referenced by gist_indexsortbuild_pagestate_flush().