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 "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/float.h"
#include "utils/syscache.h"
#include "utils/snapmgr.h"
#include "utils/lsyscache.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)
 
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 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 771 of file gistutil.c.

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

772 {
773  Page page = BufferGetPage(buf);
774 
775  /*
776  * ReadBuffer verifies that every newly-read page passes
777  * PageHeaderIsValid, which means it either contains a reasonably sane
778  * page header or is all-zero. We have to defend against the all-zero
779  * case, however.
780  */
781  if (PageIsNew(page))
782  ereport(ERROR,
783  (errcode(ERRCODE_INDEX_CORRUPTED),
784  errmsg("index \"%s\" contains unexpected zero page at block %u",
787  errhint("Please REINDEX it.")));
788 
789  /*
790  * Additionally check that the special area looks sane.
791  */
792  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
793  ereport(ERROR,
794  (errcode(ERRCODE_INDEX_CORRUPTED),
795  errmsg("index \"%s\" contains corrupted page at block %u",
798  errhint("Please REINDEX it.")));
799 }
int errhint(const char *fmt,...)
Definition: elog.c:974
int errcode(int sqlerrcode)
Definition: elog.c:570
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:68
#define RelationGetRelationName(relation)
Definition: rel.h:453
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define ereport(elevel, rest)
Definition: elog.h:141
#define MAXALIGN(LEN)
Definition: c.h:685
#define PageGetSpecialSize(page)
Definition: bufpage.h:300
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
#define PageIsNew(page)
Definition: bufpage.h:229
int errmsg(const char *fmt,...)
Definition: elog.c:784
Pointer Page
Definition: bufpage.h:78

◆ gistchoose()

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

Definition at line 374 of file gistutil.c.

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

Referenced by gistdoinsert(), and gistProcessItup().

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  {
440  IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
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 = (random() <= (MAX_RANDOM_VALUE / 2)) ? 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 = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
534  }
535  if (keep_current_best == 1)
536  break;
537  }
538  }
539 
540  return result;
541 }
long random(void)
Definition: random.c:22
void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
Definition: gistutil.c:296
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
float gistpenalty(GISTSTATE *giststate, int attno, GISTENTRY *orig, bool isNullOrig, GISTENTRY *add, bool isNullAdd)
Definition: gistutil.c:716
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:547
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define MAX_RANDOM_VALUE
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:438
TupleDesc leafTupdesc
Definition: gist_private.h:80
#define GistPageIsLeaf(page)
Definition: gist.h:140
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:732
#define INDEX_MAX_KEYS
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

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

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

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

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 }
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:547
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:438
TupleDesc leafTupdesc
Definition: gist_private.h:80
uintptr_t Datum
Definition: postgres.h:367
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
int i

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

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

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 }
Relation rel
Definition: gist.h:132
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
#define PointerGetDatum(X)
Definition: postgres.h:556
#define OidIsValid(objectId)
Definition: c.h:638
Page page
Definition: gist.h:133
Datum key
Definition: gist.h:131
FmgrInfo decompressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:89
bool leafkey
Definition: gist.h:135
uintptr_t Datum
Definition: postgres.h:367
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1130
Oid fn_oid
Definition: fmgr.h:59
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:215
#define DatumGetPointer(X)
Definition: postgres.h:549
OffsetNumber offset
Definition: gist.h:134

◆ gistextractpage()

IndexTuple* gistextractpage ( Page  page,
int *  len 
)

Definition at line 95 of file gistutil.c.

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

Referenced by gistplacetopage().

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 }
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
void * palloc(Size size)
Definition: mcxt.c:949
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

◆ gistFetchAtt()

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

Definition at line 638 of file gistutil.c.

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

Referenced by gistFetchTuple().

639 {
640  GISTENTRY fentry;
641  GISTENTRY *fep;
642 
643  gistentryinit(fentry, k, r, NULL, (OffsetNumber) 0, false);
644 
645  fep = (GISTENTRY *)
646  DatumGetPointer(FunctionCall1Coll(&giststate->fetchFn[nkey],
647  giststate->supportCollation[nkey],
648  PointerGetDatum(&fentry)));
649 
650  /* fetchFn set 'key', return it to the caller */
651  return fep->key;
652 }
FmgrInfo fetchFn[INDEX_MAX_KEYS]
Definition: gist_private.h:94
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
#define PointerGetDatum(X)
Definition: postgres.h:556
uint16 OffsetNumber
Definition: off.h:24
Datum key
Definition: gist.h:131
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1130
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:215
#define DatumGetPointer(X)
Definition: postgres.h:549

◆ gistFetchTuple()

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

Definition at line 659 of file gistutil.c.

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

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

◆ gistfillbuffer()

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

Definition at line 34 of file gistutil.c.

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

Referenced by gistplacetopage(), and gistRedoPageSplitRecord().

35 {
37  int i;
38 
39  if (off == InvalidOffsetNumber)
40  off = (PageIsEmpty(page)) ? FirstOffsetNumber :
42 
43  for (i = 0; i < len; i++)
44  {
45  Size sz = IndexTupleSize(itup[i]);
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:222
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define ERROR
Definition: elog.h:43
#define FirstOffsetNumber
Definition: off.h:27
#define InvalidOffsetNumber
Definition: off.h:26
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
size_t Size
Definition: c.h:466
#define elog(elevel,...)
Definition: elog.h:226
int i
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gistfillitupvec()

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

Definition at line 127 of file gistutil.c.

References i, IndexTupleSize, and palloc().

Referenced by gistplacetopage(), and gistSplit().

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 }
void * palloc(Size size)
Definition: mcxt.c:949
int i
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gistfitpage()

bool gistfitpage ( IndexTuple itvec,
int  len 
)

Definition at line 79 of file gistutil.c.

References GiSTPageSize, i, and IndexTupleSize.

Referenced by gistSplit().

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 }
struct ItemIdData ItemIdData
#define GiSTPageSize
Definition: gist_private.h:468
size_t Size
Definition: c.h:466
int i
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gistFormTuple()

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

Definition at line 575 of file gistutil.c.

References GISTSTATE::compressFn, DatumGetPointer, FmgrInfo::fn_oid, FunctionCall1Coll(), gistentryinit, i, index_form_tuple(), INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, ItemPointerSetOffsetNumber, GISTENTRY::key, GISTSTATE::leafTupdesc, TupleDescData::natts, GISTSTATE::nonLeafTupdesc, OidIsValid, PointerGetDatum, RelationData::rd_att, GISTSTATE::supportCollation, and IndexTupleData::t_tid.

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

577 {
578  Datum compatt[INDEX_MAX_KEYS];
579  int i;
580  IndexTuple res;
581 
582  /*
583  * Call the compress method on each attribute.
584  */
585  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
586  {
587  if (isnull[i])
588  compatt[i] = (Datum) 0;
589  else
590  {
591  GISTENTRY centry;
592  GISTENTRY *cep;
593 
594  gistentryinit(centry, attdata[i], r, NULL, (OffsetNumber) 0,
595  isleaf);
596  /* there may not be a compress function in opclass */
597  if (OidIsValid(giststate->compressFn[i].fn_oid))
598  cep = (GISTENTRY *)
600  giststate->supportCollation[i],
601  PointerGetDatum(&centry)));
602  else
603  cep = &centry;
604  compatt[i] = cep->key;
605  }
606  }
607 
608  if (isleaf)
609  {
610  /*
611  * Emplace each included attribute if any.
612  */
613  for (; i < r->rd_att->natts; i++)
614  {
615  if (isnull[i])
616  compatt[i] = (Datum) 0;
617  else
618  compatt[i] = attdata[i];
619  }
620  }
621 
622  res = index_form_tuple(isleaf ? giststate->leafTupdesc :
623  giststate->nonLeafTupdesc,
624  compatt, isnull);
625 
626  /*
627  * The offset number on tuples on internal pages is unused. For historical
628  * reasons, it is set to 0xffff.
629  */
630  ItemPointerSetOffsetNumber(&(res->t_tid), 0xffff);
631  return res;
632 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
#define PointerGetDatum(X)
Definition: postgres.h:556
FmgrInfo compressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:88
ItemPointerData t_tid
Definition: itup.h:37
#define OidIsValid(objectId)
Definition: c.h:638
uint16 OffsetNumber
Definition: off.h:24
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:47
Datum key
Definition: gist.h:131
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:438
TupleDesc leafTupdesc
Definition: gist_private.h:80
uintptr_t Datum
Definition: postgres.h:367
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1130
TupleDesc rd_att
Definition: rel.h:84
TupleDesc nonLeafTupdesc
Definition: gist_private.h:81
Oid fn_oid
Definition: fmgr.h:59
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:215
#define INDEX_MAX_KEYS
#define DatumGetPointer(X)
Definition: postgres.h:549
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:148
int i

◆ gistgetadjusted()

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

Definition at line 316 of file gistutil.c.

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

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

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 }
void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
Definition: gistutil.c:296
ItemPointerData t_tid
Definition: itup.h:37
bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
Definition: gistutil.c:281
uint16 OffsetNumber
Definition: off.h:24
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:438
uintptr_t Datum
Definition: postgres.h:367
void gistMakeUnionKey(GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull)
Definition: gistutil.c:233
#define INDEX_MAX_KEYS
int i
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum attdata[], bool isnull[], bool isleaf)
Definition: gistutil.c:575

◆ gistGetFakeLSN()

XLogRecPtr gistGetFakeLSN ( Relation  rel)

Definition at line 1027 of file gistutil.c.

References Assert, FirstNormalUnloggedLSN, GetFakeLSNForUnloggedRel(), and RelationData::rd_rel.

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

1028 {
1029  static XLogRecPtr counter = FirstNormalUnloggedLSN;
1030 
1031  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
1032  {
1033  /*
1034  * Temporary relations are only accessible in our session, so a simple
1035  * backend-local counter will do.
1036  */
1037  return counter++;
1038  }
1039  else
1040  {
1041  /*
1042  * Unlogged relations are accessible from other backends, and survive
1043  * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
1044  */
1045  Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED);
1046  return GetFakeLSNForUnloggedRel();
1047  }
1048 }
Form_pg_class rd_rel
Definition: rel.h:83
XLogRecPtr GetFakeLSNForUnloggedRel(void)
Definition: xlog.c:4838
#define FirstNormalUnloggedLSN
Definition: xlogdefs.h:36
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:732

◆ GISTInitBuffer()

void GISTInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 749 of file gistutil.c.

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

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

750 {
751  GISTPageOpaque opaque;
752  Page page;
753  Size pageSize;
754 
755  pageSize = BufferGetPageSize(b);
756  page = BufferGetPage(b);
757  PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
758 
759  opaque = GistPageGetOpaque(page);
760  /* page was already zeroed by PageInit, so this is not needed: */
761  /* memset(&(opaque->nsn), 0, sizeof(GistNSN)); */
762  opaque->rightlink = InvalidBlockNumber;
763  opaque->flags = f;
764  opaque->gist_page_id = GIST_PAGE_ID;
765 }
uint16 gist_page_id
Definition: gist.h:71
uint16 flags
Definition: gist.h:70
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:146
#define GistPageGetOpaque(page)
Definition: gist.h:138
size_t Size
Definition: c.h:466
#define InvalidBlockNumber
Definition: block.h:33
BlockNumber rightlink
Definition: gist.h:69
#define GIST_PAGE_ID
Definition: gist.h:82
Pointer Page
Definition: bufpage.h:78
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42

◆ gistjoinvector()

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

Definition at line 114 of file gistutil.c.

References memmove, and repalloc().

Referenced by gistplacetopage().

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 }
#define memmove(d, s, c)
Definition: c.h:1238
IndexTupleData * IndexTuple
Definition: itup.h:53
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1069

◆ gistKeyIsEQ()

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

Definition at line 281 of file gistutil.c.

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

Referenced by gistgetadjusted(), and gistUserPicksplit().

282 {
283  bool result;
284 
285  FunctionCall3Coll(&giststate->equalFn[attno],
286  giststate->supportCollation[attno],
287  a, b,
288  PointerGetDatum(&result));
289  return result;
290 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
#define PointerGetDatum(X)
Definition: postgres.h:556
FmgrInfo equalFn[INDEX_MAX_KEYS]
Definition: gist_private.h:92
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1172

◆ gistMakeUnionItVec()

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

Definition at line 155 of file gistutil.c.

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

Referenced by gistunion(), and gistunionsubkeyvec().

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 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
#define PointerGetDatum(X)
Definition: postgres.h:556
int32 n
Definition: gist.h:206
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:207
#define GEVHDRSZ
Definition: gist.h:210
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:547
struct GISTENTRY GISTENTRY
TupleDesc leafTupdesc
Definition: gist_private.h:80
uintptr_t Datum
Definition: postgres.h:367
TupleDesc nonLeafTupdesc
Definition: gist_private.h:81
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
void * palloc(Size size)
Definition: mcxt.c:949
int i
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:87

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

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

Referenced by gistgetadjusted(), and supportSecondarySplit().

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 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
#define PointerGetDatum(X)
Definition: postgres.h:556
int32 n
Definition: gist.h:206
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:207
#define GEVHDRSZ
Definition: gist.h:210
struct GISTENTRY GISTENTRY
uintptr_t Datum
Definition: postgres.h:367
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:87

◆ gistNewBuffer()

Buffer gistNewBuffer ( Relation  r)

Definition at line 810 of file gistutil.c.

References DataPageDeleteStack::blkno, 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().

811 {
812  Buffer buffer;
813  bool needLock;
814 
815  /* First, try to get a page from FSM */
816  for (;;)
817  {
818  BlockNumber blkno = GetFreeIndexPage(r);
819 
820  if (blkno == InvalidBlockNumber)
821  break; /* nothing left in FSM */
822 
823  buffer = ReadBuffer(r, blkno);
824 
825  /*
826  * We have to guard against the possibility that someone else already
827  * recycled this page; the buffer may be locked if so.
828  */
829  if (ConditionalLockBuffer(buffer))
830  {
831  Page page = BufferGetPage(buffer);
832 
833  /*
834  * If the page was never initialized, it's OK to use.
835  */
836  if (PageIsNew(page))
837  return buffer;
838 
839  gistcheckpage(r, buffer);
840 
841  /*
842  * Otherwise, recycle it if deleted, and too old to have any
843  * processes interested in it.
844  */
845  if (gistPageRecyclable(page))
846  {
847  /*
848  * If we are generating WAL for Hot Standby then create a WAL
849  * record that will allow us to conflict with queries running
850  * on standby, in case they have snapshots older than the
851  * page's deleteXid.
852  */
854  gistXLogPageReuse(r, blkno, GistPageGetDeleteXid(page));
855 
856  return buffer;
857  }
858 
859  LockBuffer(buffer, GIST_UNLOCK);
860  }
861 
862  /* Can't use it, so release buffer and try again */
863  ReleaseBuffer(buffer);
864  }
865 
866  /* Must extend the file */
867  needLock = !RELATION_IS_LOCAL(r);
868 
869  if (needLock)
871 
872  buffer = ReadBuffer(r, P_NEW);
873  LockBuffer(buffer, GIST_EXCLUSIVE);
874 
875  if (needLock)
877 
878  return buffer;
879 }
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:539
#define GIST_UNLOCK
Definition: gist_private.h:44
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define P_NEW
Definition: bufmgr.h:81
void gistXLogPageReuse(Relation rel, BlockNumber blkno, FullTransactionId latestRemovedXid)
Definition: gistxlog.c:599
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3628
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:402
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:452
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define XLogStandbyInfoActive()
Definition: xlog.h:195
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:771
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:521
static FullTransactionId GistPageGetDeleteXid(Page page)
Definition: gist.h:186
bool gistPageRecyclable(Page page)
Definition: gistutil.c:883
#define PageIsNew(page)
Definition: bufpage.h:229
#define GIST_EXCLUSIVE
Definition: gist_private.h:43
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ gistnospace()

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

Definition at line 59 of file gistutil.c.

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

Referenced by gistplacetopage().

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:581
IndexTupleData * IndexTuple
Definition: itup.h:53
struct ItemIdData ItemIdData
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define InvalidOffsetNumber
Definition: off.h:26
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gistoptions()

bytea* gistoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 909 of file gistutil.c.

References allocateReloptStruct(), fillfactor, fillRelOptions(), lengthof, offsetof, options, parseRelOptions(), pfree(), RELOPT_KIND_GIST, RELOPT_TYPE_ENUM, and RELOPT_TYPE_INT.

Referenced by gisthandler().

910 {
912  GiSTOptions *rdopts;
913  int numoptions;
914  static const relopt_parse_elt tab[] = {
915  {"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
916  {"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)}
917  };
918 
919  options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIST,
920  &numoptions);
921 
922  /* if none set, we're done */
923  if (numoptions == 0)
924  return NULL;
925 
926  rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions);
927 
928  fillRelOptions((void *) rdopts, sizeof(GiSTOptions), options, numoptions,
929  validate, tab, lengthof(tab));
930 
931  pfree(options);
932 
933  return (bytea *) rdopts;
934 }
#define lengthof(array)
Definition: c.h:662
void pfree(void *pointer)
Definition: mcxt.c:1056
int fillfactor
Definition: pgbench.c:157
void * allocateReloptStruct(Size base, relopt_value *options, int numoptions)
Definition: reloptions.c:1369
static char ** options
void fillRelOptions(void *rdopts, Size basesize, relopt_value *options, int numoptions, bool validate, const relopt_parse_elt *elems, int numelems)
Definition: reloptions.c:1393
Definition: c.h:549
relopt_value * parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts)
Definition: reloptions.c:1144
#define offsetof(type, field)
Definition: c.h:655

◆ gistPageRecyclable()

bool gistPageRecyclable ( Page  page)

Definition at line 883 of file gistutil.c.

References FullTransactionIdPrecedes, GetFullRecentGlobalXmin(), GistPageGetDeleteXid(), GistPageIsDeleted, and PageIsNew.

Referenced by gistNewBuffer(), and gistvacuumpage().

884 {
885  if (PageIsNew(page))
886  return true;
887  if (GistPageIsDeleted(page))
888  {
889  /*
890  * The page was deleted, but when? If it was just deleted, a scan
891  * might have seen the downlink to it, and will read the page later.
892  * As long as that can happen, we must keep the deleted page around as
893  * a tombstone.
894  *
895  * Compare the deletion XID with RecentGlobalXmin. If deleteXid <
896  * RecentGlobalXmin, then no scan that's still in progress could have
897  * seen its downlink, and we can recycle it.
898  */
899  FullTransactionId deletexid_full = GistPageGetDeleteXid(page);
900  FullTransactionId recentxmin_full = GetFullRecentGlobalXmin();
901 
902  if (FullTransactionIdPrecedes(deletexid_full, recentxmin_full))
903  return true;
904  }
905  return false;
906 }
#define GistPageIsDeleted(page)
Definition: gist.h:143
static FullTransactionId GistPageGetDeleteXid(Page page)
Definition: gist.h:186
#define PageIsNew(page)
Definition: bufpage.h:229
#define FullTransactionIdPrecedes(a, b)
Definition: transam.h:50
FullTransactionId GetFullRecentGlobalXmin(void)
Definition: snapmgr.c:963

◆ gistpenalty()

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

Definition at line 716 of file gistutil.c.

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

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

719 {
720  float penalty = 0.0;
721 
722  if (giststate->penaltyFn[attno].fn_strict == false ||
723  (isNullOrig == false && isNullAdd == false))
724  {
725  FunctionCall3Coll(&giststate->penaltyFn[attno],
726  giststate->supportCollation[attno],
727  PointerGetDatum(orig),
728  PointerGetDatum(add),
729  PointerGetDatum(&penalty));
730  /* disallow negative or NaN penalty */
731  if (isnan(penalty) || penalty < 0.0)
732  penalty = 0.0;
733  }
734  else if (isNullOrig && isNullAdd)
735  penalty = 0.0;
736  else
737  {
738  /* try to prevent mixing null and non-null values */
739  penalty = get_float4_infinity();
740  }
741 
742  return penalty;
743 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:97
#define PointerGetDatum(X)
Definition: postgres.h:556
bool fn_strict
Definition: fmgr.h:61
FmgrInfo penaltyFn[INDEX_MAX_KEYS]
Definition: gist_private.h:90
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1172
static float4 get_float4_infinity(void)
Definition: float.h:70

◆ gistproperty()

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

Definition at line 944 of file gistutil.c.

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, and SearchSysCacheExists4.

Referenced by gisthandler().

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

◆ gistunion()

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

Definition at line 219 of file gistutil.c.

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

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 }
uintptr_t Datum
Definition: postgres.h:367
void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull)
Definition: gistutil.c:155
#define INDEX_MAX_KEYS
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum attdata[], bool isnull[], bool isleaf)
Definition: gistutil.c:575