PostgreSQL Source Code  git master
gininsert.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * gininsert.c
4  * insert routines for the postgres inverted index access method.
5  *
6  *
7  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/access/gin/gininsert.c
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "access/gin_private.h"
18 #include "access/tableam.h"
19 #include "access/xloginsert.h"
20 #include "miscadmin.h"
21 #include "nodes/execnodes.h"
22 #include "storage/bufmgr.h"
23 #include "storage/predicate.h"
24 #include "utils/memutils.h"
25 #include "utils/rel.h"
26 
27 typedef struct
28 {
30  double indtuples;
36 
37 
38 /*
39  * Adds array of item pointers to tuple's posting list, or
40  * creates posting tree and tuple pointing to tree in case
41  * of not enough space. Max size of tuple is defined in
42  * GinFormTuple(). Returns a new, modified index tuple.
43  * items[] must be in sorted order with no duplicates.
44  */
45 static IndexTuple
47  IndexTuple old,
48  ItemPointerData *items, uint32 nitem,
49  GinStatsData *buildStats, Buffer buffer)
50 {
52  Datum key;
53  GinNullCategory category;
55  ItemPointerData *newItems,
56  *oldItems;
57  int oldNPosting,
58  newNPosting;
59  GinPostingList *compressedList;
60 
61  Assert(!GinIsPostingTree(old));
62 
63  attnum = gintuple_get_attrnum(ginstate, old);
64  key = gintuple_get_key(ginstate, old, &category);
65 
66  /* merge the old and new posting lists */
67  oldItems = ginReadTuple(ginstate, attnum, old, &oldNPosting);
68 
69  newItems = ginMergeItemPointers(items, nitem,
70  oldItems, oldNPosting,
71  &newNPosting);
72 
73  /* Compress the posting list, and try to a build tuple with room for it */
74  res = NULL;
75  compressedList = ginCompressPostingList(newItems, newNPosting, GinMaxItemSize,
76  NULL);
77  pfree(newItems);
78  if (compressedList)
79  {
80  res = GinFormTuple(ginstate, attnum, key, category,
81  (char *) compressedList,
82  SizeOfGinPostingList(compressedList),
83  newNPosting,
84  false);
85  pfree(compressedList);
86  }
87  if (!res)
88  {
89  /* posting list would be too big, convert to posting tree */
90  BlockNumber postingRoot;
91 
92  /*
93  * Initialize posting tree with the old tuple's posting list. It's
94  * surely small enough to fit on one posting-tree page, and should
95  * already be in order with no duplicates.
96  */
97  postingRoot = createPostingTree(ginstate->index,
98  oldItems,
99  oldNPosting,
100  buildStats,
101  buffer);
102 
103  /* Now insert the TIDs-to-be-added into the posting tree */
104  ginInsertItemPointers(ginstate->index, postingRoot,
105  items, nitem,
106  buildStats);
107 
108  /* And build a new posting-tree-only result tuple */
109  res = GinFormTuple(ginstate, attnum, key, category, NULL, 0, 0, true);
110  GinSetPostingTree(res, postingRoot);
111  }
112  pfree(oldItems);
113 
114  return res;
115 }
116 
117 /*
118  * Build a fresh leaf tuple, either posting-list or posting-tree format
119  * depending on whether the given items list will fit.
120  * items[] must be in sorted order with no duplicates.
121  *
122  * This is basically the same logic as in addItemPointersToLeafTuple,
123  * but working from slightly different input.
124  */
125 static IndexTuple
128  ItemPointerData *items, uint32 nitem,
129  GinStatsData *buildStats, Buffer buffer)
130 {
131  IndexTuple res = NULL;
132  GinPostingList *compressedList;
133 
134  /* try to build a posting list tuple with all the items */
135  compressedList = ginCompressPostingList(items, nitem, GinMaxItemSize, NULL);
136  if (compressedList)
137  {
138  res = GinFormTuple(ginstate, attnum, key, category,
139  (char *) compressedList,
140  SizeOfGinPostingList(compressedList),
141  nitem, false);
142  pfree(compressedList);
143  }
144  if (!res)
145  {
146  /* posting list would be too big, build posting tree */
147  BlockNumber postingRoot;
148 
149  /*
150  * Build posting-tree-only result tuple. We do this first so as to
151  * fail quickly if the key is too big.
152  */
153  res = GinFormTuple(ginstate, attnum, key, category, NULL, 0, 0, true);
154 
155  /*
156  * Initialize a new posting tree with the TIDs.
157  */
158  postingRoot = createPostingTree(ginstate->index, items, nitem,
159  buildStats, buffer);
160 
161  /* And save the root link in the result tuple */
162  GinSetPostingTree(res, postingRoot);
163  }
164 
165  return res;
166 }
167 
168 /*
169  * Insert one or more heap TIDs associated with the given key value.
170  * This will either add a single key entry, or enlarge a pre-existing entry.
171  *
172  * During an index build, buildStats is non-null and the counters
173  * it contains should be incremented as needed.
174  */
175 void
178  ItemPointerData *items, uint32 nitem,
179  GinStatsData *buildStats)
180 {
181  GinBtreeData btree;
182  GinBtreeEntryInsertData insertdata;
183  GinBtreeStack *stack;
184  IndexTuple itup;
185  Page page;
186 
187  insertdata.isDelete = false;
188 
189  ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
190  btree.isBuild = (buildStats != NULL);
191 
192  stack = ginFindLeafPage(&btree, false, false);
193  page = BufferGetPage(stack->buffer);
194 
195  if (btree.findItem(&btree, stack))
196  {
197  /* found pre-existing entry */
198  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
199 
200  if (GinIsPostingTree(itup))
201  {
202  /* add entries to existing posting tree */
203  BlockNumber rootPostingTree = GinGetPostingTree(itup);
204 
205  /* release all stack */
206  LockBuffer(stack->buffer, GIN_UNLOCK);
207  freeGinBtreeStack(stack);
208 
209  /* insert into posting tree */
210  ginInsertItemPointers(ginstate->index, rootPostingTree,
211  items, nitem,
212  buildStats);
213  return;
214  }
215 
216  CheckForSerializableConflictIn(ginstate->index, NULL,
217  BufferGetBlockNumber(stack->buffer));
218  /* modify an existing leaf entry */
219  itup = addItemPointersToLeafTuple(ginstate, itup,
220  items, nitem, buildStats, stack->buffer);
221 
222  insertdata.isDelete = true;
223  }
224  else
225  {
226  CheckForSerializableConflictIn(ginstate->index, NULL,
227  BufferGetBlockNumber(stack->buffer));
228  /* no match, so construct a new leaf entry */
229  itup = buildFreshLeafTuple(ginstate, attnum, key, category,
230  items, nitem, buildStats, stack->buffer);
231 
232  /*
233  * nEntries counts leaf tuples, so increment it only when we make a
234  * new one.
235  */
236  if (buildStats)
237  buildStats->nEntries++;
238  }
239 
240  /* Insert the new or modified leaf tuple */
241  insertdata.entry = itup;
242  ginInsertValue(&btree, stack, &insertdata, buildStats);
243  pfree(itup);
244 }
245 
246 /*
247  * Extract index entries for a single indexable item, and add them to the
248  * BuildAccumulator's state.
249  *
250  * This function is used only during initial index creation.
251  */
252 static void
254  Datum value, bool isNull,
255  ItemPointer heapptr)
256 {
257  Datum *entries;
258  GinNullCategory *categories;
259  int32 nentries;
260  MemoryContext oldCtx;
261 
262  oldCtx = MemoryContextSwitchTo(buildstate->funcCtx);
263  entries = ginExtractEntries(buildstate->accum.ginstate, attnum,
264  value, isNull,
265  &nentries, &categories);
266  MemoryContextSwitchTo(oldCtx);
267 
268  ginInsertBAEntries(&buildstate->accum, heapptr, attnum,
269  entries, categories, nentries);
270 
271  buildstate->indtuples += nentries;
272 
273  MemoryContextReset(buildstate->funcCtx);
274 }
275 
276 static void
278  bool *isnull, bool tupleIsAlive, void *state)
279 {
280  GinBuildState *buildstate = (GinBuildState *) state;
281  MemoryContext oldCtx;
282  int i;
283 
284  oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
285 
286  for (i = 0; i < buildstate->ginstate.origTupdesc->natts; i++)
287  ginHeapTupleBulkInsert(buildstate, (OffsetNumber) (i + 1),
288  values[i], isnull[i], tid);
289 
290  /* If we've maxed out our available memory, dump everything to the index */
291  if (buildstate->accum.allocatedMemory >= (Size) maintenance_work_mem * 1024L)
292  {
294  Datum key;
295  GinNullCategory category;
296  uint32 nlist;
298 
299  ginBeginBAScan(&buildstate->accum);
300  while ((list = ginGetBAEntry(&buildstate->accum,
301  &attnum, &key, &category, &nlist)) != NULL)
302  {
303  /* there could be many entries, so be willing to abort here */
305  ginEntryInsert(&buildstate->ginstate, attnum, key, category,
306  list, nlist, &buildstate->buildStats);
307  }
308 
309  MemoryContextReset(buildstate->tmpCtx);
310  ginInitBA(&buildstate->accum);
311  }
312 
313  MemoryContextSwitchTo(oldCtx);
314 }
315 
318 {
319  IndexBuildResult *result;
320  double reltuples;
321  GinBuildState buildstate;
322  Buffer RootBuffer,
323  MetaBuffer;
325  Datum key;
326  GinNullCategory category;
327  uint32 nlist;
328  MemoryContext oldCtx;
330 
332  elog(ERROR, "index \"%s\" already contains data",
334 
335  initGinState(&buildstate.ginstate, index);
336  buildstate.indtuples = 0;
337  memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
338 
339  /* initialize the meta page */
340  MetaBuffer = GinNewBuffer(index);
341 
342  /* initialize the root page */
343  RootBuffer = GinNewBuffer(index);
344 
346  GinInitMetabuffer(MetaBuffer);
347  MarkBufferDirty(MetaBuffer);
348  GinInitBuffer(RootBuffer, GIN_LEAF);
349  MarkBufferDirty(RootBuffer);
350 
351 
352  UnlockReleaseBuffer(MetaBuffer);
353  UnlockReleaseBuffer(RootBuffer);
355 
356  /* count the root as first entry page */
357  buildstate.buildStats.nEntryPages++;
358 
359  /*
360  * create a temporary memory context that is used to hold data not yet
361  * dumped out to the index
362  */
364  "Gin build temporary context",
366 
367  /*
368  * create a temporary memory context that is used for calling
369  * ginExtractEntries(), and can be reset after each tuple
370  */
372  "Gin build temporary context for user-defined function",
374 
375  buildstate.accum.ginstate = &buildstate.ginstate;
376  ginInitBA(&buildstate.accum);
377 
378  /*
379  * Do the heap scan. We disallow sync scan here because dataPlaceToPage
380  * prefers to receive tuples in TID order.
381  */
382  reltuples = table_index_build_scan(heap, index, indexInfo, false, true,
383  ginBuildCallback, (void *) &buildstate,
384  NULL);
385 
386  /* dump remaining entries to the index */
387  oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
388  ginBeginBAScan(&buildstate.accum);
389  while ((list = ginGetBAEntry(&buildstate.accum,
390  &attnum, &key, &category, &nlist)) != NULL)
391  {
392  /* there could be many entries, so be willing to abort here */
394  ginEntryInsert(&buildstate.ginstate, attnum, key, category,
395  list, nlist, &buildstate.buildStats);
396  }
397  MemoryContextSwitchTo(oldCtx);
398 
399  MemoryContextDelete(buildstate.funcCtx);
400  MemoryContextDelete(buildstate.tmpCtx);
401 
402  /*
403  * Update metapage stats
404  */
406  ginUpdateStats(index, &buildstate.buildStats, true);
407 
408  /*
409  * We didn't write WAL records as we built the index, so if WAL-logging is
410  * required, write all pages to the WAL now.
411  */
412  if (RelationNeedsWAL(index))
413  {
416  true);
417  }
418 
419  /*
420  * Return statistics
421  */
422  result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
423 
424  result->heap_tuples = reltuples;
425  result->index_tuples = buildstate.indtuples;
426 
427  return result;
428 }
429 
430 /*
431  * ginbuildempty() -- build an empty gin index in the initialization fork
432  */
433 void
435 {
436  Buffer RootBuffer,
437  MetaBuffer;
438 
439  /* An empty GIN index has two pages. */
440  MetaBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
442  RootBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
444 
445  /* Initialize and xlog metabuffer and root buffer. */
447  GinInitMetabuffer(MetaBuffer);
448  MarkBufferDirty(MetaBuffer);
449  log_newpage_buffer(MetaBuffer, true);
450  GinInitBuffer(RootBuffer, GIN_LEAF);
451  MarkBufferDirty(RootBuffer);
452  log_newpage_buffer(RootBuffer, false);
454 
455  /* Unlock and release the buffers. */
456  UnlockReleaseBuffer(MetaBuffer);
457  UnlockReleaseBuffer(RootBuffer);
458 }
459 
460 /*
461  * Insert index entries for a single indexable item during "normal"
462  * (non-fast-update) insertion
463  */
464 static void
466  Datum value, bool isNull,
467  ItemPointer item)
468 {
469  Datum *entries;
470  GinNullCategory *categories;
471  int32 i,
472  nentries;
473 
474  entries = ginExtractEntries(ginstate, attnum, value, isNull,
475  &nentries, &categories);
476 
477  for (i = 0; i < nentries; i++)
478  ginEntryInsert(ginstate, attnum, entries[i], categories[i],
479  item, 1, NULL);
480 }
481 
482 bool
484  ItemPointer ht_ctid, Relation heapRel,
485  IndexUniqueCheck checkUnique,
486  bool indexUnchanged,
487  IndexInfo *indexInfo)
488 {
489  GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
490  MemoryContext oldCtx;
491  MemoryContext insertCtx;
492  int i;
493 
494  /* Initialize GinState cache if first call in this statement */
495  if (ginstate == NULL)
496  {
497  oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
498  ginstate = (GinState *) palloc(sizeof(GinState));
499  initGinState(ginstate, index);
500  indexInfo->ii_AmCache = (void *) ginstate;
501  MemoryContextSwitchTo(oldCtx);
502  }
503 
505  "Gin insert temporary context",
507 
508  oldCtx = MemoryContextSwitchTo(insertCtx);
509 
511  {
512  GinTupleCollector collector;
513 
514  memset(&collector, 0, sizeof(GinTupleCollector));
515 
516  for (i = 0; i < ginstate->origTupdesc->natts; i++)
517  ginHeapTupleFastCollect(ginstate, &collector,
518  (OffsetNumber) (i + 1),
519  values[i], isnull[i],
520  ht_ctid);
521 
522  ginHeapTupleFastInsert(ginstate, &collector);
523  }
524  else
525  {
526  for (i = 0; i < ginstate->origTupdesc->natts; i++)
527  ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
528  values[i], isnull[i],
529  ht_ctid);
530  }
531 
532  MemoryContextSwitchTo(oldCtx);
533  MemoryContextDelete(insertCtx);
534 
535  return false;
536 }
uint32 BlockNumber
Definition: block.h:31
static Datum values[MAXATTR]
Definition: bootstrap.c:152
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3377
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition: bufmgr.c:838
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4577
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2189
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4795
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:229
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
@ EB_SKIP_EXTENSION_LOCK
Definition: bufmgr.h:73
@ EB_LOCK_FIRST
Definition: bufmgr.h:85
#define BMR_REL(p_rel)
Definition: bufmgr.h:106
Pointer Page
Definition: bufpage.h:78
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
unsigned int uint32
Definition: c.h:493
signed int int32
Definition: c.h:481
size_t Size
Definition: c.h:592
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
IndexUniqueCheck
Definition: genam.h:116
#define GIN_UNLOCK
Definition: gin_private.h:49
#define GinGetUseFastUpdate(relation)
Definition: gin_private.h:34
#define GinIsPostingTree(itup)
Definition: ginblock.h:231
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:342
#define GIN_LEAF
Definition: ginblock.h:42
#define GinGetPostingTree(itup)
Definition: ginblock.h:233
signed char GinNullCategory
Definition: ginblock.h:206
#define GinSetPostingTree(itup, blkno)
Definition: ginblock.h:232
#define GinMaxItemSize
Definition: ginblock.h:248
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:198
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:816
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck)
Definition: ginbtree.c:83
void ginBeginBAScan(BuildAccumulator *accum)
Definition: ginbulk.c:257
void ginInsertBAEntries(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum *entries, GinNullCategory *categories, int32 nentries)
Definition: ginbulk.c:210
void ginInitBA(BuildAccumulator *accum)
Definition: ginbulk.c:109
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
Definition: ginbulk.c:268
BlockNumber createPostingTree(Relation index, ItemPointerData *items, uint32 nitems, GinStatsData *buildStats, Buffer entrybuffer)
Definition: gindatapage.c:1775
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1908
ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum, IndexTuple itup, int *nitems)
Definition: ginentrypage.c:162
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
Definition: ginentrypage.c:44
void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
Definition: ginentrypage.c:747
void ginHeapTupleFastCollect(GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
Definition: ginfast.c:483
void ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
Definition: ginfast.c:219
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:46
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:126
static void ginHeapTupleBulkInsert(GinBuildState *buildstate, OffsetNumber attnum, Datum value, bool isNull, ItemPointer heapptr)
Definition: gininsert.c:253
void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gininsert.c:176
IndexBuildResult * ginbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: gininsert.c:317
static void ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, ItemPointer item)
Definition: gininsert.c:465
void ginbuildempty(Relation index)
Definition: gininsert.c:434
bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: gininsert.c:483
static void ginBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gininsert.c:277
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
Datum * ginExtractEntries(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
Definition: ginutil.c:483
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:226
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:300
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:350
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:259
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:356
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:97
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:650
int maintenance_work_mem
Definition: globals.c:130
static struct @150 value
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
IndexTupleData * IndexTuple
Definition: itup.h:53
Assert(fmt[strlen(fmt) - 1] !='\n')
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:371
void pfree(void *pointer)
Definition: mcxt.c:1508
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:442
void * palloc(Size size)
Definition: mcxt.c:1304
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
uint16 OffsetNumber
Definition: off.h:24
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
int16 attnum
Definition: pg_attribute.h:74
uintptr_t Datum
Definition: postgres.h:64
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4316
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationNeedsWAL(relation)
Definition: rel.h:628
@ MAIN_FORKNUM
Definition: relpath.h:50
@ INIT_FORKNUM
Definition: relpath.h:53
GinState * ginstate
Definition: gin_private.h:433
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:156
OffsetNumber off
Definition: gin_private.h:133
double indtuples
Definition: gininsert.c:30
GinState ginstate
Definition: gininsert.c:29
MemoryContext tmpCtx
Definition: gininsert.c:32
GinStatsData buildStats
Definition: gininsert.c:31
MemoryContext funcCtx
Definition: gininsert.c:33
BuildAccumulator accum
Definition: gininsert.c:34
TupleDesc origTupdesc
Definition: gin_private.h:73
Relation index
Definition: gin_private.h:59
BlockNumber nEntryPages
Definition: gin.h:46
int64 nEntries
Definition: gin.h:48
BlockNumber nTotalPages
Definition: gin.h:45
double heap_tuples
Definition: genam.h:32
double index_tuples
Definition: genam.h:33
void * ii_AmCache
Definition: execnodes.h:207
MemoryContext ii_Context
Definition: execnodes.h:208
Definition: type.h:95
Definition: regguts.h:323
static double table_index_build_scan(Relation table_rel, Relation index_rel, struct IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition: tableam.h:1767
void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1270
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1237