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