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

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

◆ gistchoose()

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

Definition at line 373 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().

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

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

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

297 {
298  int i;
299 
300  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
301  {
302  Datum datum;
303 
304  datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
305  gistdentryinit(giststate, i, &attdata[i],
306  datum, r, p, o,
307  false, isnull[i]);
308  }
309 }
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:546
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:441
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 546 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().

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

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

Referenced by gistplacetopage().

95 {
97  maxoff;
98  IndexTuple *itvec;
99 
100  maxoff = PageGetMaxOffsetNumber(page);
101  *len = maxoff;
102  itvec = palloc(sizeof(IndexTuple) * maxoff);
103  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
104  itvec[i - FirstOffsetNumber] = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
105 
106  return itvec;
107 }
#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 637 of file gistutil.c.

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

Referenced by gistFetchTuple().

638 {
639  GISTENTRY fentry;
640  GISTENTRY *fep;
641 
642  gistentryinit(fentry, k, r, NULL, (OffsetNumber) 0, false);
643 
644  fep = (GISTENTRY *)
645  DatumGetPointer(FunctionCall1Coll(&giststate->fetchFn[nkey],
646  giststate->supportCollation[nkey],
647  PointerGetDatum(&fentry)));
648 
649  /* fetchFn set 'key', return it to the caller */
650  return fep->key;
651 }
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 658 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().

659 {
660  MemoryContext oldcxt = MemoryContextSwitchTo(giststate->tempCxt);
662  bool isnull[INDEX_MAX_KEYS];
663  int i;
664 
665  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
666  {
667  Datum datum;
668 
669  datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
670 
671  if (giststate->fetchFn[i].fn_oid != InvalidOid)
672  {
673  if (!isnull[i])
674  fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
675  else
676  fetchatt[i] = (Datum) 0;
677  }
678  else if (giststate->compressFn[i].fn_oid == InvalidOid)
679  {
680  /*
681  * If opclass does not provide compress method that could change
682  * original value, att is necessarily stored in original form.
683  */
684  if (!isnull[i])
685  fetchatt[i] = datum;
686  else
687  fetchatt[i] = (Datum) 0;
688  }
689  else
690  {
691  /*
692  * Index-only scans not supported for this column. Since the
693  * planner chose an index-only scan anyway, it is not interested
694  * in this column, and we can replace it with a NULL.
695  */
696  isnull[i] = true;
697  fetchatt[i] = (Datum) 0;
698  }
699  }
700 
701  /*
702  * Get each included attribute.
703  */
704  for (; i < r->rd_att->natts; i++)
705  {
706  fetchatt[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
707  &isnull[i]);
708  }
709  MemoryContextSwitchTo(oldcxt);
710 
711  return heap_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
712 }
static Datum gistFetchAtt(GISTSTATE *giststate, int nkey, Datum k, Relation r)
Definition: gistutil.c:637
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:441
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 33 of file gistutil.c.

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

Referenced by gistplacetopage(), and gistRedoPageSplitRecord().

34 {
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 
46  l = PageAddItem(page, (Item) itup[i], sz, off, false, false);
47  if (l == InvalidOffsetNumber)
48  elog(ERROR, "failed to add item to GiST index page, item %d out of %d, size %d bytes",
49  i, len, (int) sz);
50  off++;
51  }
52 }
#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:467
#define elog(elevel,...)
Definition: elog.h:228
int i
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gistfillitupvec()

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

Definition at line 126 of file gistutil.c.

References i, IndexTupleSize, and palloc().

Referenced by gistplacetopage(), and gistSplit().

127 {
128  char *ptr,
129  *ret;
130  int i;
131 
132  *memlen = 0;
133 
134  for (i = 0; i < veclen; i++)
135  *memlen += IndexTupleSize(vec[i]);
136 
137  ptr = ret = palloc(*memlen);
138 
139  for (i = 0; i < veclen; i++)
140  {
141  memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
142  ptr += IndexTupleSize(vec[i]);
143  }
144 
145  return (IndexTupleData *) ret;
146 }
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 78 of file gistutil.c.

References GiSTPageSize, i, and IndexTupleSize.

Referenced by gistSplit().

79 {
80  int i;
81  Size size = 0;
82 
83  for (i = 0; i < len; i++)
84  size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
85 
86  /* TODO: Consider fillfactor */
87  return (size <= GiSTPageSize);
88 }
struct ItemIdData ItemIdData
#define GiSTPageSize
Definition: gist_private.h:468
size_t Size
Definition: c.h:467
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 574 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().

576 {
577  Datum compatt[INDEX_MAX_KEYS];
578  int i;
579  IndexTuple res;
580 
581  /*
582  * Call the compress method on each attribute.
583  */
584  for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
585  {
586  if (isnull[i])
587  compatt[i] = (Datum) 0;
588  else
589  {
590  GISTENTRY centry;
591  GISTENTRY *cep;
592 
593  gistentryinit(centry, attdata[i], r, NULL, (OffsetNumber) 0,
594  isleaf);
595  /* there may not be a compress function in opclass */
596  if (OidIsValid(giststate->compressFn[i].fn_oid))
597  cep = (GISTENTRY *)
599  giststate->supportCollation[i],
600  PointerGetDatum(&centry)));
601  else
602  cep = &centry;
603  compatt[i] = cep->key;
604  }
605  }
606 
607  if (isleaf)
608  {
609  /*
610  * Emplace each included attribute if any.
611  */
612  for (; i < r->rd_att->natts; i++)
613  {
614  if (isnull[i])
615  compatt[i] = (Datum) 0;
616  else
617  compatt[i] = attdata[i];
618  }
619  }
620 
621  res = index_form_tuple(isleaf ? giststate->leafTupdesc :
622  giststate->nonLeafTupdesc,
623  compatt, isnull);
624 
625  /*
626  * The offset number on tuples on internal pages is unused. For historical
627  * reasons, it is set to 0xffff.
628  */
629  ItemPointerSetOffsetNumber(&(res->t_tid), 0xffff);
630  return res;
631 }
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:645
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:441
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 315 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().

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

◆ gistGetFakeLSN()

XLogRecPtr gistGetFakeLSN ( Relation  rel)

Definition at line 1012 of file gistutil.c.

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

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

1013 {
1014  static XLogRecPtr counter = FirstNormalUnloggedLSN;
1015 
1016  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
1017  {
1018  /*
1019  * Temporary relations are only accessible in our session, so a simple
1020  * backend-local counter will do.
1021  */
1022  return counter++;
1023  }
1024  else
1025  {
1026  /*
1027  * Unlogged relations are accessible from other backends, and survive
1028  * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
1029  */
1030  Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED);
1031  return GetFakeLSNForUnloggedRel();
1032  }
1033 }
Form_pg_class rd_rel
Definition: rel.h:83
XLogRecPtr GetFakeLSNForUnloggedRel(void)
Definition: xlog.c:4835
#define FirstNormalUnloggedLSN
Definition: xlogdefs.h:36
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:739

◆ GISTInitBuffer()

void GISTInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 748 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().

749 {
750  GISTPageOpaque opaque;
751  Page page;
752  Size pageSize;
753 
754  pageSize = BufferGetPageSize(b);
755  page = BufferGetPage(b);
756  PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
757 
758  opaque = GistPageGetOpaque(page);
759  /* page was already zeroed by PageInit, so this is not needed: */
760  /* memset(&(opaque->nsn), 0, sizeof(GistNSN)); */
761  opaque->rightlink = InvalidBlockNumber;
762  opaque->flags = f;
763  opaque->gist_page_id = GIST_PAGE_ID;
764 }
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:467
#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 113 of file gistutil.c.

References memmove, and repalloc().

Referenced by gistplacetopage().

114 {
115  itvec = (IndexTuple *) repalloc((void *) itvec, sizeof(IndexTuple) * ((*len) + addlen));
116  memmove(&itvec[*len], additvec, sizeof(IndexTuple) * addlen);
117  *len += addlen;
118  return itvec;
119 }
#define memmove(d, s, c)
Definition: c.h:1267
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 280 of file gistutil.c.

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

Referenced by gistgetadjusted(), and gistUserPicksplit().

281 {
282  bool result;
283 
284  FunctionCall3Coll(&giststate->equalFn[attno],
285  giststate->supportCollation[attno],
286  a, b,
287  PointerGetDatum(&result));
288  return result;
289 }
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 154 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().

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

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

Referenced by gistgetadjusted(), and supportSecondarySplit().

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

810 {
811  Buffer buffer;
812  bool needLock;
813 
814  /* First, try to get a page from FSM */
815  for (;;)
816  {
817  BlockNumber blkno = GetFreeIndexPage(r);
818 
819  if (blkno == InvalidBlockNumber)
820  break; /* nothing left in FSM */
821 
822  buffer = ReadBuffer(r, blkno);
823 
824  /*
825  * We have to guard against the possibility that someone else already
826  * recycled this page; the buffer may be locked if so.
827  */
828  if (ConditionalLockBuffer(buffer))
829  {
830  Page page = BufferGetPage(buffer);
831 
832  /*
833  * If the page was never initialized, it's OK to use.
834  */
835  if (PageIsNew(page))
836  return buffer;
837 
838  gistcheckpage(r, buffer);
839 
840  /*
841  * Otherwise, recycle it if deleted, and too old to have any
842  * processes interested in it.
843  */
844  if (gistPageRecyclable(page))
845  {
846  /*
847  * If we are generating WAL for Hot Standby then create a WAL
848  * record that will allow us to conflict with queries running
849  * on standby, in case they have snapshots older than the
850  * page's deleteXid.
851  */
853  gistXLogPageReuse(r, blkno, GistPageGetDeleteXid(page));
854 
855  return buffer;
856  }
857 
858  LockBuffer(buffer, GIST_UNLOCK);
859  }
860 
861  /* Can't use it, so release buffer and try again */
862  ReleaseBuffer(buffer);
863  }
864 
865  /* Must extend the file */
866  needLock = !RELATION_IS_LOCAL(r);
867 
868  if (needLock)
870 
871  buffer = ReadBuffer(r, P_NEW);
872  LockBuffer(buffer, GIST_EXCLUSIVE);
873 
874  if (needLock)
876 
877  return buffer;
878 }
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:542
#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:770
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define InvalidBlockNumber
Definition: block.h:33
#define RelationNeedsWAL(relation)
Definition: rel.h:524
static FullTransactionId GistPageGetDeleteXid(Page page)
Definition: gist.h:186
bool gistPageRecyclable(Page page)
Definition: gistutil.c:882
#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 58 of file gistutil.c.

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

Referenced by gistplacetopage().

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

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

Referenced by gisthandler().

909 {
910  static const relopt_parse_elt tab[] = {
911  {"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
912  {"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)}
913  };
914 
915  return (bytea *) build_reloptions(reloptions, validate,
917  sizeof(GiSTOptions),
918  tab, lengthof(tab));
919 }
#define lengthof(array)
Definition: c.h:669
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:1552
int fillfactor
Definition: pgbench.c:160
Definition: c.h:556
#define offsetof(type, field)
Definition: c.h:662

◆ gistPageRecyclable()

bool gistPageRecyclable ( Page  page)

Definition at line 882 of file gistutil.c.

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

Referenced by gistNewBuffer(), and gistvacuumpage().

883 {
884  if (PageIsNew(page))
885  return true;
886  if (GistPageIsDeleted(page))
887  {
888  /*
889  * The page was deleted, but when? If it was just deleted, a scan
890  * might have seen the downlink to it, and will read the page later.
891  * As long as that can happen, we must keep the deleted page around as
892  * a tombstone.
893  *
894  * Compare the deletion XID with RecentGlobalXmin. If deleteXid <
895  * RecentGlobalXmin, then no scan that's still in progress could have
896  * seen its downlink, and we can recycle it.
897  */
898  FullTransactionId deletexid_full = GistPageGetDeleteXid(page);
899  FullTransactionId recentxmin_full = GetFullRecentGlobalXmin();
900 
901  if (FullTransactionIdPrecedes(deletexid_full, recentxmin_full))
902  return true;
903  }
904  return false;
905 }
#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 715 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().

718 {
719  float penalty = 0.0;
720 
721  if (giststate->penaltyFn[attno].fn_strict == false ||
722  (isNullOrig == false && isNullAdd == false))
723  {
724  FunctionCall3Coll(&giststate->penaltyFn[attno],
725  giststate->supportCollation[attno],
726  PointerGetDatum(orig),
727  PointerGetDatum(add),
728  PointerGetDatum(&penalty));
729  /* disallow negative or NaN penalty */
730  if (isnan(penalty) || penalty < 0.0)
731  penalty = 0.0;
732  }
733  else if (isNullOrig && isNullAdd)
734  penalty = 0.0;
735  else
736  {
737  /* try to prevent mixing null and non-null values */
738  penalty = get_float4_infinity();
739  }
740 
741  return penalty;
742 }
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 929 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().

932 {
933  Oid opclass,
934  opfamily,
935  opcintype;
936  int16 procno;
937 
938  /* Only answer column-level inquiries */
939  if (attno == 0)
940  return false;
941 
942  /*
943  * Currently, GiST distance-ordered scans require that there be a distance
944  * function in the opclass with the default types (i.e. the one loaded
945  * into the relcache entry, see initGISTstate). So we assume that if such
946  * a function exists, then there's a reason for it (rather than grubbing
947  * through all the opfamily's operators to find an ordered one).
948  *
949  * Essentially the same code can test whether we support returning the
950  * column data, since that's true if the opclass provides a fetch proc.
951  */
952 
953  switch (prop)
954  {
956  procno = GIST_DISTANCE_PROC;
957  break;
958  case AMPROP_RETURNABLE:
959  procno = GIST_FETCH_PROC;
960  break;
961  default:
962  return false;
963  }
964 
965  /* First we need to know the column's opclass. */
966  opclass = get_index_column_opclass(index_oid, attno);
967  if (!OidIsValid(opclass))
968  {
969  *isnull = true;
970  return true;
971  }
972 
973  /* Now look up the opclass family and input datatype. */
974  if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
975  {
976  *isnull = true;
977  return true;
978  }
979 
980  /* And now we can check whether the function is provided. */
981 
983  ObjectIdGetDatum(opfamily),
984  ObjectIdGetDatum(opcintype),
985  ObjectIdGetDatum(opcintype),
986  Int16GetDatum(procno));
987 
988  /*
989  * Special case: even without a fetch function, AMPROP_RETURNABLE is true
990  * if the opclass has no compress function.
991  */
992  if (prop == AMPROP_RETURNABLE && !*res)
993  {
995  ObjectIdGetDatum(opfamily),
996  ObjectIdGetDatum(opcintype),
997  ObjectIdGetDatum(opcintype),
999  }
1000 
1001  *isnull = false;
1002 
1003  return true;
1004 }
signed short int16
Definition: c.h:346
#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:645
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 218 of file gistutil.c.

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

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