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