PostgreSQL Source Code  git master
gistutil.c File Reference
#include "postgres.h"
#include <float.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/builtins.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)
 
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 743 of file gistutil.c.

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

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

744 {
745  Page page = BufferGetPage(buf);
746 
747  /*
748  * ReadBuffer verifies that every newly-read page passes
749  * PageHeaderIsValid, which means it either contains a reasonably sane
750  * page header or is all-zero. We have to defend against the all-zero
751  * case, however.
752  */
753  if (PageIsNew(page))
754  ereport(ERROR,
755  (errcode(ERRCODE_INDEX_CORRUPTED),
756  errmsg("index \"%s\" contains unexpected zero page at block %u",
759  errhint("Please REINDEX it.")));
760 
761  /*
762  * Additionally check that the special area looks sane.
763  */
764  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
765  ereport(ERROR,
766  (errcode(ERRCODE_INDEX_CORRUPTED),
767  errmsg("index \"%s\" contains corrupted page at block %u",
770  errhint("Please REINDEX it.")));
771 }
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define MAXALIGN(LEN)
Definition: c.h:633
#define PageGetSpecialSize(page)
Definition: bufpage.h:296
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define PageIsNew(page)
Definition: bufpage.h:225
int errmsg(const char *fmt,...)
Definition: elog.c:797
Pointer Page
Definition: bufpage.h:74

◆ gistchoose()

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

Definition at line 372 of file gistutil.c.

References Assert, FirstOffsetNumber, gistDeCompressAtt(), gistdentryinit(), GistPageIsLeaf, gistpenalty(), i, index_getattr, INDEX_MAX_KEYS, MAX_RANDOM_VALUE, tupleDesc::natts, OffsetNumberNext, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, random(), RelationData::rd_att, and GISTSTATE::tupdesc.

Referenced by gistdoinsert(), and gistProcessItup().

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

◆ gistDeCompressAtt()

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

Definition at line 294 of file gistutil.c.

References gistdentryinit(), i, index_getattr, tupleDesc::natts, RelationData::rd_att, and GISTSTATE::tupdesc.

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

296 {
297  int i;
298 
299  for (i = 0; i < r->rd_att->natts; i++)
300  {
301  Datum datum;
302 
303  datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
304  gistdentryinit(giststate, i, &attdata[i],
305  datum, r, p, o,
306  false, isnull[i]);
307  }
308 }
TupleDesc tupdesc
Definition: gist_private.h:81
int natts
Definition: tupdesc.h:79
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:544
uintptr_t Datum
Definition: postgres.h:372
TupleDesc rd_att
Definition: rel.h:115
#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 544 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().

547 {
548  if (!isNull)
549  {
550  GISTENTRY *dep;
551 
552  gistentryinit(*e, k, r, pg, o, l);
553 
554  /* there may not be a decompress function in opclass */
555  if (!OidIsValid(giststate->decompressFn[nkey].fn_oid))
556  return;
557 
558  dep = (GISTENTRY *)
560  giststate->supportCollation[nkey],
561  PointerGetDatum(e)));
562  /* decompressFn may just return the given pointer */
563  if (dep != e)
564  gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
565  dep->leafkey);
566  }
567  else
568  gistentryinit(*e, (Datum) 0, r, pg, o, l);
569 }
Relation rel
Definition: gist.h:124
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:562
#define OidIsValid(objectId)
Definition: c.h:586
Page page
Definition: gist.h:125
Datum key
Definition: gist.h:123
FmgrInfo decompressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:88
bool leafkey
Definition: gist.h:127
uintptr_t Datum
Definition: postgres.h:372
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1022
Oid fn_oid
Definition: fmgr.h:59
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:169
#define DatumGetPointer(X)
Definition: postgres.h:555
OffsetNumber offset
Definition: gist.h:126

◆ 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:353
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
void * palloc(Size size)
Definition: mcxt.c:835
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:336

◆ gistFetchAtt()

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

Definition at line 619 of file gistutil.c.

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

Referenced by gistFetchTuple().

620 {
621  GISTENTRY fentry;
622  GISTENTRY *fep;
623 
624  gistentryinit(fentry, k, r, NULL, (OffsetNumber) 0, false);
625 
626  fep = (GISTENTRY *)
627  DatumGetPointer(FunctionCall1Coll(&giststate->fetchFn[nkey],
628  giststate->supportCollation[nkey],
629  PointerGetDatum(&fentry)));
630 
631  /* fetchFn set 'key', return it to the caller */
632  return fep->key;
633 }
FmgrInfo fetchFn[INDEX_MAX_KEYS]
Definition: gist_private.h:93
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:562
uint16 OffsetNumber
Definition: off.h:24
Datum key
Definition: gist.h:123
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1022
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:169
#define DatumGetPointer(X)
Definition: postgres.h:555

◆ gistFetchTuple()

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

Definition at line 640 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, InvalidOid, MemoryContextSwitchTo(), tupleDesc::natts, RelationData::rd_att, GISTSTATE::tempCxt, and GISTSTATE::tupdesc.

Referenced by gistScanPage().

641 {
642  MemoryContext oldcxt = MemoryContextSwitchTo(giststate->tempCxt);
644  bool isnull[INDEX_MAX_KEYS];
645  int i;
646 
647  for (i = 0; i < r->rd_att->natts; i++)
648  {
649  Datum datum;
650 
651  datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
652 
653  if (giststate->fetchFn[i].fn_oid != InvalidOid)
654  {
655  if (!isnull[i])
656  fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
657  else
658  fetchatt[i] = (Datum) 0;
659  }
660  else if (giststate->compressFn[i].fn_oid == InvalidOid)
661  {
662  /*
663  * If opclass does not provide compress method that could change
664  * original value, att is necessarily stored in original form.
665  */
666  if (!isnull[i])
667  fetchatt[i] = datum;
668  else
669  fetchatt[i] = (Datum) 0;
670  }
671  else
672  {
673  /*
674  * Index-only scans not supported for this column. Since the
675  * planner chose an index-only scan anyway, it is not interested
676  * in this column, and we can replace it with a NULL.
677  */
678  isnull[i] = true;
679  fetchatt[i] = (Datum) 0;
680  }
681  }
682  MemoryContextSwitchTo(oldcxt);
683 
684  return heap_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
685 }
TupleDesc tupdesc
Definition: gist_private.h:81
static Datum gistFetchAtt(GISTSTATE *giststate, int nkey, Datum k, Relation r)
Definition: gistutil.c:619
FmgrInfo fetchFn[INDEX_MAX_KEYS]
Definition: gist_private.h:93
FmgrInfo compressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:87
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
int natts
Definition: tupdesc.h:79
#define fetchatt(A, T)
Definition: tupmacs.h:37
MemoryContext tempCxt
Definition: gist_private.h:79
uintptr_t Datum
Definition: postgres.h:372
TupleDesc rd_att
Definition: rel.h:115
#define InvalidOid
Definition: postgres_ext.h:36
Oid fn_oid
Definition: fmgr.h:59
TupleDesc fetchTupdesc
Definition: gist_private.h:82
#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:218
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
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:53
size_t Size
Definition: c.h:414
int i
#define elog
Definition: elog.h:219
#define IndexTupleSize(itup)
Definition: itup.h:70

◆ 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:835
int i
#define IndexTupleSize(itup)
Definition: itup.h:70

◆ 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:432
size_t Size
Definition: c.h:414
int i
#define IndexTupleSize(itup)
Definition: itup.h:70

◆ gistFormTuple()

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

Definition at line 572 of file gistutil.c.

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

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

574 {
575  Datum compatt[INDEX_MAX_KEYS];
576  int i;
577  IndexTuple res;
578 
579  /*
580  * Call the compress method on each attribute.
581  */
582  for (i = 0; i < r->rd_att->natts; i++)
583  {
584  if (isnull[i])
585  compatt[i] = (Datum) 0;
586  else
587  {
588  GISTENTRY centry;
589  GISTENTRY *cep;
590 
591  gistentryinit(centry, attdata[i], r, NULL, (OffsetNumber) 0,
592  isleaf);
593  /* there may not be a compress function in opclass */
594  if (OidIsValid(giststate->compressFn[i].fn_oid))
595  cep = (GISTENTRY *)
597  giststate->supportCollation[i],
598  PointerGetDatum(&centry)));
599  else
600  cep = &centry;
601  compatt[i] = cep->key;
602  }
603  }
604 
605  res = index_form_tuple(giststate->tupdesc, compatt, isnull);
606 
607  /*
608  * The offset number on tuples on internal pages is unused. For historical
609  * reasons, it is set to 0xffff.
610  */
611  ItemPointerSetOffsetNumber(&(res->t_tid), 0xffff);
612  return res;
613 }
TupleDesc tupdesc
Definition: gist_private.h:81
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:562
FmgrInfo compressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:87
ItemPointerData t_tid
Definition: itup.h:37
#define OidIsValid(objectId)
Definition: c.h:586
int natts
Definition: tupdesc.h:79
uint16 OffsetNumber
Definition: off.h:24
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:37
Datum key
Definition: gist.h:123
uintptr_t Datum
Definition: postgres.h:372
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1022
TupleDesc rd_att
Definition: rel.h:115
Oid fn_oid
Definition: fmgr.h:59
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:169
#define INDEX_MAX_KEYS
#define DatumGetPointer(X)
Definition: postgres.h:555
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:126
int i

◆ gistgetadjusted()

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

Definition at line 314 of file gistutil.c.

References gistDeCompressAtt(), gistFormTuple(), gistKeyIsEQ(), gistMakeUnionKey(), i, INDEX_MAX_KEYS, tupleDesc::natts, RelationData::rd_att, and IndexTupleData::t_tid.

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

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

◆ gistGetFakeLSN()

XLogRecPtr gistGetFakeLSN ( Relation  rel)

Definition at line 980 of file gistutil.c.

References Assert, GetFakeLSNForUnloggedRel(), RelationData::rd_rel, RELPERSISTENCE_TEMP, and RELPERSISTENCE_UNLOGGED.

Referenced by gistbuild(), gistbulkdelete(), gistplacetopage(), and gistvacuumpage().

981 {
982  static XLogRecPtr counter = 1;
983 
984  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
985  {
986  /*
987  * Temporary relations are only accessible in our session, so a simple
988  * backend-local counter will do.
989  */
990  return counter++;
991  }
992  else
993  {
994  /*
995  * Unlogged relations are accessible from other backends, and survive
996  * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
997  */
998  Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED);
999  return GetFakeLSNForUnloggedRel();
1000  }
1001 }
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:171
Form_pg_class rd_rel
Definition: rel.h:114
XLogRecPtr GetFakeLSNForUnloggedRel(void)
Definition: xlog.c:4747
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:680
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172

◆ GISTInitBuffer()

void GISTInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 721 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(), gistRedoCreateIndex(), and gistRedoPageSplitRecord().

722 {
723  GISTPageOpaque opaque;
724  Page page;
725  Size pageSize;
726 
727  pageSize = BufferGetPageSize(b);
728  page = BufferGetPage(b);
729  PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
730 
731  opaque = GistPageGetOpaque(page);
732  /* page was already zeroed by PageInit, so this is not needed: */
733  /* memset(&(opaque->nsn), 0, sizeof(GistNSN)); */
734  opaque->rightlink = InvalidBlockNumber;
735  opaque->flags = f;
736  opaque->gist_page_id = GIST_PAGE_ID;
737 }
uint16 gist_page_id
Definition: gist.h:63
uint16 flags
Definition: gist.h:62
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
#define GistPageGetOpaque(page)
Definition: gist.h:130
size_t Size
Definition: c.h:414
#define InvalidBlockNumber
Definition: block.h:33
BlockNumber rightlink
Definition: gist.h:61
#define GIST_PAGE_ID
Definition: gist.h:74
Pointer Page
Definition: bufpage.h:74
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41

◆ 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:1055
IndexTupleData * IndexTuple
Definition: itup.h:53
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:949

◆ gistKeyIsEQ()

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

Definition at line 279 of file gistutil.c.

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

Referenced by gistgetadjusted(), and gistUserPicksplit().

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

◆ 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, GistEntryVector::n, tupleDesc::natts, palloc(), PointerGetDatum, GISTSTATE::supportCollation, GISTSTATE::tupdesc, 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->tupdesc->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->tupdesc, &IsNull);
175  if (IsNull)
176  continue;
177 
178  gistdentryinit(giststate, i,
179  evec->vector + evec->n,
180  datum,
181  NULL, NULL, (OffsetNumber) 0,
182  false, IsNull);
183  evec->n++;
184  }
185 
186  /* If this column was all NULLs, the union is NULL */
187  if (evec->n == 0)
188  {
189  attr[i] = (Datum) 0;
190  isnull[i] = true;
191  }
192  else
193  {
194  if (evec->n == 1)
195  {
196  /* unionFn may expect at least two inputs */
197  evec->n = 2;
198  evec->vector[1] = evec->vector[0];
199  }
200 
201  /* Make union and store in attr array */
202  attr[i] = FunctionCall2Coll(&giststate->unionFn[i],
203  giststate->supportCollation[i],
204  PointerGetDatum(evec),
205  PointerGetDatum(&attrsize));
206 
207  isnull[i] = false;
208  }
209  }
210 }
TupleDesc tupdesc
Definition: gist_private.h:81
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:562
int32 n
Definition: gist.h:160
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
int natts
Definition: tupdesc.h:79
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define GEVHDRSZ
Definition: gist.h:164
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:544
struct GISTENTRY GISTENTRY
uintptr_t Datum
Definition: postgres.h:372
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
void * palloc(Size size)
Definition: mcxt.c:835
int i
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:86

◆ gistMakeUnionKey()

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

Definition at line 231 of file gistutil.c.

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

Referenced by gistgetadjusted(), and supportSecondarySplit().

235 {
236  /* we need a GistEntryVector with room for exactly 2 elements */
237  union
238  {
239  GistEntryVector gev;
240  char padding[2 * sizeof(GISTENTRY) + GEVHDRSZ];
241  } storage;
242  GistEntryVector *evec = &storage.gev;
243  int dstsize;
244 
245  evec->n = 2;
246 
247  if (isnull1 && isnull2)
248  {
249  *dstisnull = true;
250  *dst = (Datum) 0;
251  }
252  else
253  {
254  if (isnull1 == false && isnull2 == false)
255  {
256  evec->vector[0] = *entry1;
257  evec->vector[1] = *entry2;
258  }
259  else if (isnull1 == false)
260  {
261  evec->vector[0] = *entry1;
262  evec->vector[1] = *entry1;
263  }
264  else
265  {
266  evec->vector[0] = *entry2;
267  evec->vector[1] = *entry2;
268  }
269 
270  *dstisnull = false;
271  *dst = FunctionCall2Coll(&giststate->unionFn[attno],
272  giststate->supportCollation[attno],
273  PointerGetDatum(evec),
274  PointerGetDatum(&dstsize));
275  }
276 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:562
int32 n
Definition: gist.h:160
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define GEVHDRSZ
Definition: gist.h:164
struct GISTENTRY GISTENTRY
uintptr_t Datum
Definition: postgres.h:372
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:86

◆ gistNewBuffer()

Buffer gistNewBuffer ( Relation  r)

Definition at line 782 of file gistutil.c.

References DataPageDeleteStack::blkno, buffer, BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), GIST_EXCLUSIVE, GIST_UNLOCK, gistcheckpage(), GistPageIsDeleted, InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), and UnlockRelationForExtension().

Referenced by gistbuild(), and gistplacetopage().

783 {
784  Buffer buffer;
785  bool needLock;
786 
787  /* First, try to get a page from FSM */
788  for (;;)
789  {
790  BlockNumber blkno = GetFreeIndexPage(r);
791 
792  if (blkno == InvalidBlockNumber)
793  break; /* nothing left in FSM */
794 
795  buffer = ReadBuffer(r, blkno);
796 
797  /*
798  * We have to guard against the possibility that someone else already
799  * recycled this page; the buffer may be locked if so.
800  */
801  if (ConditionalLockBuffer(buffer))
802  {
803  Page page = BufferGetPage(buffer);
804 
805  if (PageIsNew(page))
806  return buffer; /* OK to use, if never initialized */
807 
808  gistcheckpage(r, buffer);
809 
810  if (GistPageIsDeleted(page))
811  return buffer; /* OK to use */
812 
813  LockBuffer(buffer, GIST_UNLOCK);
814  }
815 
816  /* Can't use it, so release buffer and try again */
817  ReleaseBuffer(buffer);
818  }
819 
820  /* Must extend the file */
821  needLock = !RELATION_IS_LOCAL(r);
822 
823  if (needLock)
825 
826  buffer = ReadBuffer(r, P_NEW);
827  LockBuffer(buffer, GIST_EXCLUSIVE);
828 
829  if (needLock)
831 
832  return buffer;
833 }
#define GistPageIsDeleted(page)
Definition: gist.h:135
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:532
#define GIST_UNLOCK
Definition: gist_private.h:45
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define P_NEW
Definition: bufmgr.h:82
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:743
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
#define PageIsNew(page)
Definition: bufpage.h:225
#define GIST_EXCLUSIVE
Definition: gist_private.h:44
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

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

◆ gistoptions()

bytea* gistoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 836 of file gistutil.c.

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

Referenced by gisthandler().

837 {
839  GiSTOptions *rdopts;
840  int numoptions;
841  static const relopt_parse_elt tab[] = {
842  {"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
843  {"buffering", RELOPT_TYPE_STRING, offsetof(GiSTOptions, bufferingModeOffset)}
844  };
845 
846  options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIST,
847  &numoptions);
848 
849  /* if none set, we're done */
850  if (numoptions == 0)
851  return NULL;
852 
853  rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions);
854 
855  fillRelOptions((void *) rdopts, sizeof(GiSTOptions), options, numoptions,
856  validate, tab, lengthof(tab));
857 
858  pfree(options);
859 
860  return (bytea *) rdopts;
861 }
#define lengthof(array)
Definition: c.h:610
void pfree(void *pointer)
Definition: mcxt.c:936
int fillfactor
Definition: pgbench.c:117
void * allocateReloptStruct(Size base, relopt_value *options, int numoptions)
Definition: reloptions.c:1225
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:1249
Definition: c.h:497
relopt_value * parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts)
Definition: reloptions.c:1030
#define offsetof(type, field)
Definition: c.h:603

◆ gistpenalty()

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

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

691 {
692  float penalty = 0.0;
693 
694  if (giststate->penaltyFn[attno].fn_strict == false ||
695  (isNullOrig == false && isNullAdd == false))
696  {
697  FunctionCall3Coll(&giststate->penaltyFn[attno],
698  giststate->supportCollation[attno],
699  PointerGetDatum(orig),
700  PointerGetDatum(add),
701  PointerGetDatum(&penalty));
702  /* disallow negative or NaN penalty */
703  if (isnan(penalty) || penalty < 0.0)
704  penalty = 0.0;
705  }
706  else if (isNullOrig && isNullAdd)
707  penalty = 0.0;
708  else
709  {
710  /* try to prevent mixing null and non-null values */
711  penalty = get_float4_infinity();
712  }
713 
714  return penalty;
715 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:562
float get_float4_infinity(void)
Definition: float.c:147
bool fn_strict
Definition: fmgr.h:61
FmgrInfo penaltyFn[INDEX_MAX_KEYS]
Definition: gist_private.h:89
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1064

◆ gistproperty()

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

Definition at line 871 of file gistutil.c.

References AMPROCNUM, AMPROP_DISTANCE_ORDERABLE, AMPROP_RETURNABLE, Anum_pg_index_indclass, Assert, CLAOID, DatumGetPointer, GETSTRUCT, GIST_COMPRESS_PROC, GIST_DISTANCE_PROC, GIST_FETCH_PROC, HeapTupleIsValid, INDEXRELID, Int16GetDatum, ObjectIdGetDatum, PG_USED_FOR_ASSERTS_ONLY, ReleaseSysCache(), SearchSysCache1(), SearchSysCacheExists4, SysCacheGetAttr(), and oidvector::values.

Referenced by gisthandler().

874 {
875  HeapTuple tuple;
877  Form_pg_opclass rd_opclass;
878  Datum datum;
879  bool disnull;
880  oidvector *indclass;
881  Oid opclass,
882  opfamily,
883  opcintype;
884  int16 procno;
885 
886  /* Only answer column-level inquiries */
887  if (attno == 0)
888  return false;
889 
890  /*
891  * Currently, GiST distance-ordered scans require that there be a distance
892  * function in the opclass with the default types (i.e. the one loaded
893  * into the relcache entry, see initGISTstate). So we assume that if such
894  * a function exists, then there's a reason for it (rather than grubbing
895  * through all the opfamily's operators to find an ordered one).
896  *
897  * Essentially the same code can test whether we support returning the
898  * column data, since that's true if the opclass provides a fetch proc.
899  */
900 
901  switch (prop)
902  {
904  procno = GIST_DISTANCE_PROC;
905  break;
906  case AMPROP_RETURNABLE:
907  procno = GIST_FETCH_PROC;
908  break;
909  default:
910  return false;
911  }
912 
913  /* First we need to know the column's opclass. */
914 
915  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
916  if (!HeapTupleIsValid(tuple))
917  {
918  *isnull = true;
919  return true;
920  }
921  rd_index = (Form_pg_index) GETSTRUCT(tuple);
922 
923  /* caller is supposed to guarantee this */
924  Assert(attno > 0 && attno <= rd_index->indnatts);
925 
926  datum = SysCacheGetAttr(INDEXRELID, tuple,
927  Anum_pg_index_indclass, &disnull);
928  Assert(!disnull);
929 
930  indclass = ((oidvector *) DatumGetPointer(datum));
931  opclass = indclass->values[attno - 1];
932 
933  ReleaseSysCache(tuple);
934 
935  /* Now look up the opclass family and input datatype. */
936 
937  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
938  if (!HeapTupleIsValid(tuple))
939  {
940  *isnull = true;
941  return true;
942  }
943  rd_opclass = (Form_pg_opclass) GETSTRUCT(tuple);
944 
945  opfamily = rd_opclass->opcfamily;
946  opcintype = rd_opclass->opcintype;
947 
948  ReleaseSysCache(tuple);
949 
950  /* And now we can check whether the function is provided. */
951 
953  ObjectIdGetDatum(opfamily),
954  ObjectIdGetDatum(opcintype),
955  ObjectIdGetDatum(opcintype),
956  Int16GetDatum(procno));
957 
958  /*
959  * Special case: even without a fetch function, AMPROP_RETURNABLE is true
960  * if the opclass has no compress function.
961  */
962  if (prop == AMPROP_RETURNABLE && !*res)
963  {
965  ObjectIdGetDatum(opfamily),
966  ObjectIdGetDatum(opcintype),
967  ObjectIdGetDatum(opcintype),
969  }
970 
971  return true;
972 }
signed short int16
Definition: c.h:293
Definition: c.h:536
#define GIST_FETCH_PROC
Definition: gist.h:36
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define Int16GetDatum(X)
Definition: postgres.h:457
#define Anum_pg_index_indclass
Definition: pg_index.h:89
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:188
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define GIST_COMPRESS_PROC
Definition: gist.h:30
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:544
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:680
#define GIST_DISTANCE_PROC
Definition: gist.h:35
#define DatumGetPointer(X)
Definition: postgres.h:555
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:122
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68

◆ gistunion()

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

Definition at line 217 of file gistutil.c.

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

218 {
219  Datum attr[INDEX_MAX_KEYS];
220  bool isnull[INDEX_MAX_KEYS];
221 
222  gistMakeUnionItVec(giststate, itvec, len, attr, isnull);
223 
224  return gistFormTuple(giststate, r, attr, isnull, false);
225 }
uintptr_t Datum
Definition: postgres.h:372
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:572