PostgreSQL Source Code  git master
ginutil.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ginutil.c
4  * Utility routines for the Postgres inverted index access method.
5  *
6  *
7  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/access/gin/ginutil.c
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "access/gin_private.h"
18 #include "access/ginxlog.h"
19 #include "access/reloptions.h"
20 #include "access/xloginsert.h"
21 #include "catalog/pg_collation.h"
22 #include "catalog/pg_type.h"
23 #include "commands/vacuum.h"
24 #include "miscadmin.h"
25 #include "storage/indexfsm.h"
26 #include "utils/builtins.h"
27 #include "utils/index_selfuncs.h"
28 #include "utils/rel.h"
29 #include "utils/typcache.h"
30 
31 
32 /*
33  * GIN handler function: return IndexAmRoutine with access method parameters
34  * and callbacks.
35  */
36 Datum
38 {
40 
41  amroutine->amstrategies = 0;
42  amroutine->amsupport = GINNProcs;
43  amroutine->amoptsprocnum = GIN_OPTIONS_PROC;
44  amroutine->amcanorder = false;
45  amroutine->amcanorderbyop = false;
46  amroutine->amcanbackward = false;
47  amroutine->amcanunique = false;
48  amroutine->amcanmulticol = true;
49  amroutine->amoptionalkey = true;
50  amroutine->amsearcharray = false;
51  amroutine->amsearchnulls = false;
52  amroutine->amstorage = true;
53  amroutine->amclusterable = false;
54  amroutine->ampredlocks = true;
55  amroutine->amcanparallel = false;
56  amroutine->amcanbuildparallel = false;
57  amroutine->amcaninclude = false;
58  amroutine->amusemaintenanceworkmem = true;
59  amroutine->amsummarizing = false;
60  amroutine->amparallelvacuumoptions =
62  amroutine->amkeytype = InvalidOid;
63 
64  amroutine->ambuild = ginbuild;
65  amroutine->ambuildempty = ginbuildempty;
66  amroutine->aminsert = gininsert;
67  amroutine->aminsertcleanup = NULL;
68  amroutine->ambulkdelete = ginbulkdelete;
69  amroutine->amvacuumcleanup = ginvacuumcleanup;
70  amroutine->amcanreturn = NULL;
71  amroutine->amcostestimate = gincostestimate;
72  amroutine->amgettreeheight = NULL;
73  amroutine->amoptions = ginoptions;
74  amroutine->amproperty = NULL;
75  amroutine->ambuildphasename = NULL;
76  amroutine->amvalidate = ginvalidate;
77  amroutine->amadjustmembers = ginadjustmembers;
78  amroutine->ambeginscan = ginbeginscan;
79  amroutine->amrescan = ginrescan;
80  amroutine->amgettuple = NULL;
81  amroutine->amgetbitmap = gingetbitmap;
82  amroutine->amendscan = ginendscan;
83  amroutine->ammarkpos = NULL;
84  amroutine->amrestrpos = NULL;
85  amroutine->amestimateparallelscan = NULL;
86  amroutine->aminitparallelscan = NULL;
87  amroutine->amparallelrescan = NULL;
88 
89  PG_RETURN_POINTER(amroutine);
90 }
91 
92 /*
93  * initGinState: fill in an empty GinState struct to describe the index
94  *
95  * Note: assorted subsidiary data is allocated in the CurrentMemoryContext.
96  */
97 void
99 {
100  TupleDesc origTupdesc = RelationGetDescr(index);
101  int i;
102 
103  MemSet(state, 0, sizeof(GinState));
104 
105  state->index = index;
106  state->oneCol = (origTupdesc->natts == 1);
107  state->origTupdesc = origTupdesc;
108 
109  for (i = 0; i < origTupdesc->natts; i++)
110  {
111  Form_pg_attribute attr = TupleDescAttr(origTupdesc, i);
112 
113  if (state->oneCol)
114  state->tupdesc[i] = state->origTupdesc;
115  else
116  {
117  state->tupdesc[i] = CreateTemplateTupleDesc(2);
118 
119  TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL,
120  INT2OID, -1, 0);
121  TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 2, NULL,
122  attr->atttypid,
123  attr->atttypmod,
124  attr->attndims);
126  attr->attcollation);
127  }
128 
129  /*
130  * If the compare proc isn't specified in the opclass definition, look
131  * up the index key type's default btree comparator.
132  */
134  {
135  fmgr_info_copy(&(state->compareFn[i]),
138  }
139  else
140  {
141  TypeCacheEntry *typentry;
142 
143  typentry = lookup_type_cache(attr->atttypid,
145  if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
146  ereport(ERROR,
147  (errcode(ERRCODE_UNDEFINED_FUNCTION),
148  errmsg("could not identify a comparison function for type %s",
149  format_type_be(attr->atttypid))));
150  fmgr_info_copy(&(state->compareFn[i]),
151  &(typentry->cmp_proc_finfo),
153  }
154 
155  /* Opclass must always provide extract procs */
156  fmgr_info_copy(&(state->extractValueFn[i]),
159  fmgr_info_copy(&(state->extractQueryFn[i]),
162 
163  /*
164  * Check opclass capability to do tri-state or binary logic consistent
165  * check.
166  */
168  {
169  fmgr_info_copy(&(state->triConsistentFn[i]),
172  }
173 
175  {
176  fmgr_info_copy(&(state->consistentFn[i]),
179  }
180 
181  if (state->consistentFn[i].fn_oid == InvalidOid &&
182  state->triConsistentFn[i].fn_oid == InvalidOid)
183  {
184  elog(ERROR, "missing GIN support function (%d or %d) for attribute %d of index \"%s\"",
187  }
188 
189  /*
190  * Check opclass capability to do partial match.
191  */
193  {
194  fmgr_info_copy(&(state->comparePartialFn[i]),
197  state->canPartialMatch[i] = true;
198  }
199  else
200  {
201  state->canPartialMatch[i] = false;
202  }
203 
204  /*
205  * If the index column has a specified collation, we should honor that
206  * while doing comparisons. However, we may have a collatable storage
207  * type for a noncollatable indexed data type (for instance, hstore
208  * uses text index entries). If there's no index collation then
209  * specify default collation in case the support functions need
210  * collation. This is harmless if the support functions don't care
211  * about collation, so we just do it unconditionally. (We could
212  * alternatively call get_typcollation, but that seems like expensive
213  * overkill --- there aren't going to be any cases where a GIN storage
214  * type has a nondefault collation.)
215  */
216  if (OidIsValid(index->rd_indcollation[i]))
217  state->supportCollation[i] = index->rd_indcollation[i];
218  else
219  state->supportCollation[i] = DEFAULT_COLLATION_OID;
220  }
221 }
222 
223 /*
224  * Extract attribute (column) number of stored entry from GIN tuple
225  */
228 {
229  OffsetNumber colN;
230 
231  if (ginstate->oneCol)
232  {
233  /* column number is not stored explicitly */
234  colN = FirstOffsetNumber;
235  }
236  else
237  {
238  Datum res;
239  bool isnull;
240 
241  /*
242  * First attribute is always int16, so we can safely use any tuple
243  * descriptor to obtain first attribute of tuple
244  */
245  res = index_getattr(tuple, FirstOffsetNumber, ginstate->tupdesc[0],
246  &isnull);
247  Assert(!isnull);
248 
249  colN = DatumGetUInt16(res);
250  Assert(colN >= FirstOffsetNumber && colN <= ginstate->origTupdesc->natts);
251  }
252 
253  return colN;
254 }
255 
256 /*
257  * Extract stored datum (and possible null category) from GIN tuple
258  */
259 Datum
261  GinNullCategory *category)
262 {
263  Datum res;
264  bool isnull;
265 
266  if (ginstate->oneCol)
267  {
268  /*
269  * Single column index doesn't store attribute numbers in tuples
270  */
271  res = index_getattr(tuple, FirstOffsetNumber, ginstate->origTupdesc,
272  &isnull);
273  }
274  else
275  {
276  /*
277  * Since the datum type depends on which index column it's from, we
278  * must be careful to use the right tuple descriptor here.
279  */
280  OffsetNumber colN = gintuple_get_attrnum(ginstate, tuple);
281 
283  ginstate->tupdesc[colN - 1],
284  &isnull);
285  }
286 
287  if (isnull)
288  *category = GinGetNullCategory(tuple, ginstate);
289  else
290  *category = GIN_CAT_NORM_KEY;
291 
292  return res;
293 }
294 
295 /*
296  * Allocate a new page (either by recycling, or by extending the index file)
297  * The returned buffer is already pinned and exclusive-locked
298  * Caller is responsible for initializing the page by calling GinInitBuffer
299  */
300 Buffer
302 {
303  Buffer buffer;
304 
305  /* First, try to get a page from FSM */
306  for (;;)
307  {
309 
310  if (blkno == InvalidBlockNumber)
311  break;
312 
313  buffer = ReadBuffer(index, blkno);
314 
315  /*
316  * We have to guard against the possibility that someone else already
317  * recycled this page; the buffer may be locked if so.
318  */
319  if (ConditionalLockBuffer(buffer))
320  {
321  if (GinPageIsRecyclable(BufferGetPage(buffer)))
322  return buffer; /* OK to use */
323 
324  LockBuffer(buffer, GIN_UNLOCK);
325  }
326 
327  /* Can't use it, so release buffer and try again */
328  ReleaseBuffer(buffer);
329  }
330 
331  /* Must extend the file */
332  buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM, NULL,
333  EB_LOCK_FIRST);
334 
335  return buffer;
336 }
337 
338 void
339 GinInitPage(Page page, uint32 f, Size pageSize)
340 {
341  GinPageOpaque opaque;
342 
343  PageInit(page, pageSize, sizeof(GinPageOpaqueData));
344 
345  opaque = GinPageGetOpaque(page);
346  opaque->flags = f;
347  opaque->rightlink = InvalidBlockNumber;
348 }
349 
350 void
352 {
354 }
355 
356 void
358 {
359  GinMetaPageData *metadata;
360  Page page = BufferGetPage(b);
361 
363 
364  metadata = GinPageGetMeta(page);
365 
366  metadata->head = metadata->tail = InvalidBlockNumber;
367  metadata->tailFreeSize = 0;
368  metadata->nPendingPages = 0;
369  metadata->nPendingHeapTuples = 0;
370  metadata->nTotalPages = 0;
371  metadata->nEntryPages = 0;
372  metadata->nDataPages = 0;
373  metadata->nEntries = 0;
374  metadata->ginVersion = GIN_CURRENT_VERSION;
375 
376  /*
377  * Set pd_lower just past the end of the metadata. This is essential,
378  * because without doing so, metadata will be lost if xlog.c compresses
379  * the page.
380  */
381  ((PageHeader) page)->pd_lower =
382  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) page;
383 }
384 
385 /*
386  * Compare two keys of the same index column
387  */
388 int
390  Datum a, GinNullCategory categorya,
391  Datum b, GinNullCategory categoryb)
392 {
393  /* if not of same null category, sort by that first */
394  if (categorya != categoryb)
395  return (categorya < categoryb) ? -1 : 1;
396 
397  /* all null items in same category are equal */
398  if (categorya != GIN_CAT_NORM_KEY)
399  return 0;
400 
401  /* both not null, so safe to call the compareFn */
402  return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
403  ginstate->supportCollation[attnum - 1],
404  a, b));
405 }
406 
407 /*
408  * Compare two keys of possibly different index columns
409  */
410 int
412  OffsetNumber attnuma, Datum a, GinNullCategory categorya,
413  OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
414 {
415  /* attribute number is the first sort key */
416  if (attnuma != attnumb)
417  return (attnuma < attnumb) ? -1 : 1;
418 
419  return ginCompareEntries(ginstate, attnuma, a, categorya, b, categoryb);
420 }
421 
422 
423 /*
424  * Support for sorting key datums in ginExtractEntries
425  *
426  * Note: we only have to worry about null and not-null keys here;
427  * ginExtractEntries never generates more than one placeholder null,
428  * so it doesn't have to sort those.
429  */
430 typedef struct
431 {
433  bool isnull;
434 } keyEntryData;
435 
436 typedef struct
437 {
440  bool haveDups;
441 } cmpEntriesArg;
442 
443 static int
444 cmpEntries(const void *a, const void *b, void *arg)
445 {
446  const keyEntryData *aa = (const keyEntryData *) a;
447  const keyEntryData *bb = (const keyEntryData *) b;
449  int res;
450 
451  if (aa->isnull)
452  {
453  if (bb->isnull)
454  res = 0; /* NULL "=" NULL */
455  else
456  res = 1; /* NULL ">" not-NULL */
457  }
458  else if (bb->isnull)
459  res = -1; /* not-NULL "<" NULL */
460  else
461  res = DatumGetInt32(FunctionCall2Coll(data->cmpDatumFunc,
462  data->collation,
463  aa->datum, bb->datum));
464 
465  /*
466  * Detect if we have any duplicates. If there are equal keys, qsort must
467  * compare them at some point, else it wouldn't know whether one should go
468  * before or after the other.
469  */
470  if (res == 0)
471  data->haveDups = true;
472 
473  return res;
474 }
475 
476 
477 /*
478  * Extract the index key values from an indexable item
479  *
480  * The resulting key values are sorted, and any duplicates are removed.
481  * This avoids generating redundant index entries.
482  */
483 Datum *
485  Datum value, bool isNull,
486  int32 *nentries, GinNullCategory **categories)
487 {
488  Datum *entries;
489  bool *nullFlags;
490  int32 i;
491 
492  /*
493  * We don't call the extractValueFn on a null item. Instead generate a
494  * placeholder.
495  */
496  if (isNull)
497  {
498  *nentries = 1;
499  entries = (Datum *) palloc(sizeof(Datum));
500  entries[0] = (Datum) 0;
501  *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
502  (*categories)[0] = GIN_CAT_NULL_ITEM;
503  return entries;
504  }
505 
506  /* OK, call the opclass's extractValueFn */
507  nullFlags = NULL; /* in case extractValue doesn't set it */
508  entries = (Datum *)
510  ginstate->supportCollation[attnum - 1],
511  value,
512  PointerGetDatum(nentries),
513  PointerGetDatum(&nullFlags)));
514 
515  /*
516  * Generate a placeholder if the item contained no keys.
517  */
518  if (entries == NULL || *nentries <= 0)
519  {
520  *nentries = 1;
521  entries = (Datum *) palloc(sizeof(Datum));
522  entries[0] = (Datum) 0;
523  *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory));
524  (*categories)[0] = GIN_CAT_EMPTY_ITEM;
525  return entries;
526  }
527 
528  /*
529  * If the extractValueFn didn't create a nullFlags array, create one,
530  * assuming that everything's non-null.
531  */
532  if (nullFlags == NULL)
533  nullFlags = (bool *) palloc0(*nentries * sizeof(bool));
534 
535  /*
536  * If there's more than one key, sort and unique-ify.
537  *
538  * XXX Using qsort here is notationally painful, and the overhead is
539  * pretty bad too. For small numbers of keys it'd likely be better to use
540  * a simple insertion sort.
541  */
542  if (*nentries > 1)
543  {
544  keyEntryData *keydata;
546 
547  keydata = (keyEntryData *) palloc(*nentries * sizeof(keyEntryData));
548  for (i = 0; i < *nentries; i++)
549  {
550  keydata[i].datum = entries[i];
551  keydata[i].isnull = nullFlags[i];
552  }
553 
554  arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1];
555  arg.collation = ginstate->supportCollation[attnum - 1];
556  arg.haveDups = false;
557  qsort_arg(keydata, *nentries, sizeof(keyEntryData),
558  cmpEntries, &arg);
559 
560  if (arg.haveDups)
561  {
562  /* there are duplicates, must get rid of 'em */
563  int32 j;
564 
565  entries[0] = keydata[0].datum;
566  nullFlags[0] = keydata[0].isnull;
567  j = 1;
568  for (i = 1; i < *nentries; i++)
569  {
570  if (cmpEntries(&keydata[i - 1], &keydata[i], &arg) != 0)
571  {
572  entries[j] = keydata[i].datum;
573  nullFlags[j] = keydata[i].isnull;
574  j++;
575  }
576  }
577  *nentries = j;
578  }
579  else
580  {
581  /* easy, no duplicates */
582  for (i = 0; i < *nentries; i++)
583  {
584  entries[i] = keydata[i].datum;
585  nullFlags[i] = keydata[i].isnull;
586  }
587  }
588 
589  pfree(keydata);
590  }
591 
592  /*
593  * Create GinNullCategory representation from nullFlags.
594  */
595  *categories = (GinNullCategory *) palloc0(*nentries * sizeof(GinNullCategory));
596  for (i = 0; i < *nentries; i++)
597  (*categories)[i] = (nullFlags[i] ? GIN_CAT_NULL_KEY : GIN_CAT_NORM_KEY);
598 
599  return entries;
600 }
601 
602 bytea *
603 ginoptions(Datum reloptions, bool validate)
604 {
605  static const relopt_parse_elt tab[] = {
606  {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
607  {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
608  pendingListCleanupSize)}
609  };
610 
611  return (bytea *) build_reloptions(reloptions, validate,
613  sizeof(GinOptions),
614  tab, lengthof(tab));
615 }
616 
617 /*
618  * Fetch index's statistical data into *stats
619  *
620  * Note: in the result, nPendingPages can be trusted to be up-to-date,
621  * as can ginVersion; but the other fields are as of the last VACUUM.
622  */
623 void
625 {
626  Buffer metabuffer;
627  Page metapage;
628  GinMetaPageData *metadata;
629 
630  metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
631  LockBuffer(metabuffer, GIN_SHARE);
632  metapage = BufferGetPage(metabuffer);
633  metadata = GinPageGetMeta(metapage);
634 
635  stats->nPendingPages = metadata->nPendingPages;
636  stats->nTotalPages = metadata->nTotalPages;
637  stats->nEntryPages = metadata->nEntryPages;
638  stats->nDataPages = metadata->nDataPages;
639  stats->nEntries = metadata->nEntries;
640  stats->ginVersion = metadata->ginVersion;
641 
642  UnlockReleaseBuffer(metabuffer);
643 }
644 
645 /*
646  * Write the given statistics to the index's metapage
647  *
648  * Note: nPendingPages and ginVersion are *not* copied over
649  */
650 void
651 ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
652 {
653  Buffer metabuffer;
654  Page metapage;
655  GinMetaPageData *metadata;
656 
657  metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
658  LockBuffer(metabuffer, GIN_EXCLUSIVE);
659  metapage = BufferGetPage(metabuffer);
660  metadata = GinPageGetMeta(metapage);
661 
663 
664  metadata->nTotalPages = stats->nTotalPages;
665  metadata->nEntryPages = stats->nEntryPages;
666  metadata->nDataPages = stats->nDataPages;
667  metadata->nEntries = stats->nEntries;
668 
669  /*
670  * Set pd_lower just past the end of the metadata. This is essential,
671  * because without doing so, metadata will be lost if xlog.c compresses
672  * the page. (We must do this here because pre-v11 versions of PG did not
673  * set the metapage's pd_lower correctly, so a pg_upgraded index might
674  * contain the wrong value.)
675  */
676  ((PageHeader) metapage)->pd_lower =
677  ((char *) metadata + sizeof(GinMetaPageData)) - (char *) metapage;
678 
679  MarkBufferDirty(metabuffer);
680 
681  if (RelationNeedsWAL(index) && !is_build)
682  {
683  XLogRecPtr recptr;
685 
686  data.locator = index->rd_locator;
687  data.ntuples = 0;
688  data.newRightlink = data.prevTail = InvalidBlockNumber;
689  memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
690 
691  XLogBeginInsert();
692  XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
694 
695  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
696  PageSetLSN(metapage, recptr);
697  }
698 
699  UnlockReleaseBuffer(metabuffer);
700 
702 }
int16 AttrNumber
Definition: attnum.h:21
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition: bufmgr.c:846
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:5184
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4924
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4941
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5158
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:746
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:389
@ EB_LOCK_FIRST
Definition: bufmgr.h:86
#define BMR_REL(p_rel)
Definition: bufmgr.h:107
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42
PageHeaderData * PageHeader
Definition: bufpage.h:173
Pointer Page
Definition: bufpage.h:81
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
#define Assert(condition)
Definition: c.h:812
int32_t int32
Definition: c.h:481
uint32_t uint32
Definition: c.h:485
#define lengthof(array)
Definition: c.h:742
#define MemSet(start, val, len)
Definition: c.h:974
#define OidIsValid(objectId)
Definition: c.h:729
size_t Size
Definition: c.h:559
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1171
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:580
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
#define GIN_COMPARE_PROC
Definition: gin.h:22
#define GIN_CONSISTENT_PROC
Definition: gin.h:25
#define GIN_EXTRACTQUERY_PROC
Definition: gin.h:24
#define GIN_EXTRACTVALUE_PROC
Definition: gin.h:23
#define GINNProcs
Definition: gin.h:29
#define GIN_TRICONSISTENT_PROC
Definition: gin.h:27
#define GIN_COMPARE_PARTIAL_PROC
Definition: gin.h:26
#define GIN_OPTIONS_PROC
Definition: gin.h:28
#define GIN_UNLOCK
Definition: gin_private.h:49
#define GIN_EXCLUSIVE
Definition: gin_private.h:51
#define GIN_SHARE
Definition: gin_private.h:50
#define GIN_CURRENT_VERSION
Definition: ginblock.h:102
#define GIN_METAPAGE_BLKNO
Definition: ginblock.h:51
#define GinGetNullCategory(itup, ginstate)
Definition: ginblock.h:220
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:208
#define GIN_CAT_EMPTY_ITEM
Definition: ginblock.h:210
#define GIN_META
Definition: ginblock.h:44
signed char GinNullCategory
Definition: ginblock.h:206
#define GIN_CAT_NULL_ITEM
Definition: ginblock.h:211
#define GIN_CAT_NULL_KEY
Definition: ginblock.h:209
#define GinPageGetMeta(p)
Definition: ginblock.h:104
int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: ginget.c:1914
IndexBuildResult * ginbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: gininsert.c:317
void ginbuildempty(Relation index)
Definition: gininsert.c:433
bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: gininsert.c:482
IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys)
Definition: ginscan.c:25
void ginendscan(IndexScanDesc scan)
Definition: ginscan.c:455
void ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: ginscan.c:442
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:339
Datum ginhandler(PG_FUNCTION_ARGS)
Definition: ginutil.c:37
void ginGetStats(Relation index, GinStatsData *stats)
Definition: ginutil.c:624
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
Definition: ginutil.c:484
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:227
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:301
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:351
int ginCompareAttEntries(GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
Definition: ginutil.c:411
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:260
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:357
static int cmpEntries(const void *a, const void *b, void *arg)
Definition: ginutil.c:444
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:98
bytea * ginoptions(Datum reloptions, bool validate)
Definition: ginutil.c:603
int ginCompareEntries(GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
Definition: ginutil.c:389
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:651
IndexBulkDeleteResult * ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: ginvacuum.c:564
bool GinPageIsRecyclable(Page page)
Definition: ginvacuum.c:801
IndexBulkDeleteResult * ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: ginvacuum.c:687
bool ginvalidate(Oid opclassoid)
Definition: ginvalidate.c:31
void ginadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
Definition: ginvalidate.c:277
#define XLOG_GIN_UPDATE_META_PAGE
Definition: ginxlog.h:162
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:862
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:828
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
static struct @160 value
int b
Definition: isn.c:69
int a
Definition: isn.c:68
int j
Definition: isn.c:73
int i
Definition: isn.c:72
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: itup.h:117
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * palloc(Size size)
Definition: mcxt.c:1317
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
#define makeNode(_type_)
Definition: nodes.h:155
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
void * arg
const void * data
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static uint16 DatumGetUInt16(Datum X)
Definition: postgres.h:182
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationNeedsWAL(relation)
Definition: rel.h:628
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1908
@ RELOPT_KIND_GIN
Definition: reloptions.h:46
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
@ RELOPT_TYPE_BOOL
Definition: reloptions.h:31
@ MAIN_FORKNUM
Definition: relpath.h:58
void gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition: selfuncs.c:7594
Definition: fmgr.h:57
Oid fn_oid
Definition: fmgr.h:59
int64 nEntries
Definition: ginblock.h:82
int32 ginVersion
Definition: ginblock.h:99
BlockNumber tail
Definition: ginblock.h:62
BlockNumber nEntryPages
Definition: ginblock.h:80
uint32 tailFreeSize
Definition: ginblock.h:67
BlockNumber nPendingPages
Definition: ginblock.h:73
int64 nPendingHeapTuples
Definition: ginblock.h:74
BlockNumber nTotalPages
Definition: ginblock.h:79
BlockNumber nDataPages
Definition: ginblock.h:81
BlockNumber head
Definition: ginblock.h:61
BlockNumber rightlink
Definition: ginblock.h:32
bool oneCol
Definition: gin_private.h:60
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:74
TupleDesc origTupdesc
Definition: gin_private.h:73
FmgrInfo extractValueFn[INDEX_MAX_KEYS]
Definition: gin_private.h:80
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gin_private.h:88
FmgrInfo compareFn[INDEX_MAX_KEYS]
Definition: gin_private.h:79
BlockNumber nDataPages
Definition: gin.h:47
BlockNumber nPendingPages
Definition: gin.h:44
BlockNumber nEntryPages
Definition: gin.h:46
int64 nEntries
Definition: gin.h:48
BlockNumber nTotalPages
Definition: gin.h:45
int32 ginVersion
Definition: gin.h:49
ambuildphasename_function ambuildphasename
Definition: amapi.h:289
ambuildempty_function ambuildempty
Definition: amapi.h:279
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:283
bool amclusterable
Definition: amapi.h:253
amoptions_function amoptions
Definition: amapi.h:287
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:301
amrestrpos_function amrestrpos
Definition: amapi.h:298
aminsert_function aminsert
Definition: amapi.h:280
amendscan_function amendscan
Definition: amapi.h:296
uint16 amoptsprocnum
Definition: amapi.h:233
amparallelrescan_function amparallelrescan
Definition: amapi.h:303
Oid amkeytype
Definition: amapi.h:269
bool ampredlocks
Definition: amapi.h:255
uint16 amsupport
Definition: amapi.h:231
amcostestimate_function amcostestimate
Definition: amapi.h:285
bool amcanorderbyop
Definition: amapi.h:237
amadjustmembers_function amadjustmembers
Definition: amapi.h:291
ambuild_function ambuild
Definition: amapi.h:278
bool amstorage
Definition: amapi.h:251
uint16 amstrategies
Definition: amapi.h:229
bool amoptionalkey
Definition: amapi.h:245
amgettuple_function amgettuple
Definition: amapi.h:294
amcanreturn_function amcanreturn
Definition: amapi.h:284
bool amcanunique
Definition: amapi.h:241
amgetbitmap_function amgetbitmap
Definition: amapi.h:295
amproperty_function amproperty
Definition: amapi.h:288
ambulkdelete_function ambulkdelete
Definition: amapi.h:282
bool amsearcharray
Definition: amapi.h:247
bool amsummarizing
Definition: amapi.h:265
amvalidate_function amvalidate
Definition: amapi.h:290
ammarkpos_function ammarkpos
Definition: amapi.h:297
bool amcanmulticol
Definition: amapi.h:243
bool amusemaintenanceworkmem
Definition: amapi.h:263
ambeginscan_function ambeginscan
Definition: amapi.h:292
bool amcanparallel
Definition: amapi.h:257
amrescan_function amrescan
Definition: amapi.h:293
bool amcanorder
Definition: amapi.h:235
bool amcanbuildparallel
Definition: amapi.h:259
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:302
uint8 amparallelvacuumoptions
Definition: amapi.h:267
aminsertcleanup_function aminsertcleanup
Definition: amapi.h:281
bool amcanbackward
Definition: amapi.h:239
amgettreeheight_function amgettreeheight
Definition: amapi.h:286
bool amcaninclude
Definition: amapi.h:261
bool amsearchnulls
Definition: amapi.h:249
FmgrInfo cmp_proc_finfo
Definition: typcache.h:76
FmgrInfo * cmpDatumFunc
Definition: ginutil.c:438
Oid collation
Definition: ginutil.c:439
bool haveDups
Definition: ginutil.c:440
Definition: type.h:96
bool isnull
Definition: ginutil.c:433
Datum datum
Definition: ginutil.c:432
Definition: regguts.h:323
Definition: c.h:641
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:833
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_CMP_PROC_FINFO
Definition: typcache.h:143
#define VACUUM_OPTION_PARALLEL_CLEANUP
Definition: vacuum.h:63
#define VACUUM_OPTION_PARALLEL_BULKDEL
Definition: vacuum.h:48
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33