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