PostgreSQL Source Code  git master
ginentrypage.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ginentrypage.c
4  * routines for handling GIN entry tree pages.
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/ginentrypage.c
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "access/gin_private.h"
18 #include "access/ginxlog.h"
19 #include "access/xloginsert.h"
20 #include "utils/rel.h"
21 
22 static void entrySplitPage(GinBtree btree, Buffer origbuf,
23  GinBtreeStack *stack,
24  GinBtreeEntryInsertData *insertData,
25  BlockNumber updateblkno,
26  Page *newlpage, Page *newrpage);
27 
28 /*
29  * Form a tuple for entry tree.
30  *
31  * If the tuple would be too big to be stored, function throws a suitable
32  * error if errorTooBig is true, or returns NULL if errorTooBig is false.
33  *
34  * See src/backend/access/gin/README for a description of the index tuple
35  * format that is being built here. We build on the assumption that we
36  * are making a leaf-level key entry containing a posting list of nipd items.
37  * If the caller is actually trying to make a posting-tree entry, non-leaf
38  * entry, or pending-list entry, it should pass dataSize = 0 and then overwrite
39  * the t_tid fields as necessary. In any case, 'data' can be NULL to skip
40  * filling in the posting list; the caller is responsible for filling it
41  * afterwards if data = NULL and nipd > 0.
42  */
46  Pointer data, Size dataSize, int nipd,
47  bool errorTooBig)
48 {
49  Datum datums[2];
50  bool isnull[2];
51  IndexTuple itup;
52  uint32 newsize;
53 
54  /* Build the basic tuple: optional column number, plus key datum */
55  if (ginstate->oneCol)
56  {
57  datums[0] = key;
58  isnull[0] = (category != GIN_CAT_NORM_KEY);
59  }
60  else
61  {
62  datums[0] = UInt16GetDatum(attnum);
63  isnull[0] = false;
64  datums[1] = key;
65  isnull[1] = (category != GIN_CAT_NORM_KEY);
66  }
67 
68  itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull);
69 
70  /*
71  * Determine and store offset to the posting list, making sure there is
72  * room for the category byte if needed.
73  *
74  * Note: because index_form_tuple MAXALIGNs the tuple size, there may well
75  * be some wasted pad space. Is it worth recomputing the data length to
76  * prevent that? That would also allow us to Assert that the real data
77  * doesn't overlap the GinNullCategory byte, which this code currently
78  * takes on faith.
79  */
80  newsize = IndexTupleSize(itup);
81 
82  if (IndexTupleHasNulls(itup))
83  {
84  uint32 minsize;
85 
86  Assert(category != GIN_CAT_NORM_KEY);
87  minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory);
88  newsize = Max(newsize, minsize);
89  }
90 
91  newsize = SHORTALIGN(newsize);
92 
93  GinSetPostingOffset(itup, newsize);
94  GinSetNPosting(itup, nipd);
95 
96  /*
97  * Add space needed for posting list, if any. Then check that the tuple
98  * won't be too big to store.
99  */
100  newsize += dataSize;
101 
102  newsize = MAXALIGN(newsize);
103 
104  if (newsize > GinMaxItemSize)
105  {
106  if (errorTooBig)
107  ereport(ERROR,
108  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
109  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
110  (Size) newsize, (Size) GinMaxItemSize,
111  RelationGetRelationName(ginstate->index))));
112  pfree(itup);
113  return NULL;
114  }
115 
116  /*
117  * Resize tuple if needed
118  */
119  if (newsize != IndexTupleSize(itup))
120  {
121  itup = repalloc(itup, newsize);
122 
123  /*
124  * PostgreSQL 9.3 and earlier did not clear this new space, so we
125  * might find uninitialized padding when reading tuples from disk.
126  */
127  memset((char *) itup + IndexTupleSize(itup),
128  0, newsize - IndexTupleSize(itup));
129  /* set new size in tuple header */
130  itup->t_info &= ~INDEX_SIZE_MASK;
131  itup->t_info |= newsize;
132  }
133 
134  /*
135  * Copy in the posting list, if provided
136  */
137  if (data)
138  {
139  char *ptr = GinGetPosting(itup);
140 
141  memcpy(ptr, data, dataSize);
142  }
143 
144  /*
145  * Insert category byte, if needed
146  */
147  if (category != GIN_CAT_NORM_KEY)
148  {
149  Assert(IndexTupleHasNulls(itup));
150  GinSetNullCategory(itup, ginstate, category);
151  }
152  return itup;
153 }
154 
155 /*
156  * Read item pointers from leaf entry tuple.
157  *
158  * Returns a palloc'd array of ItemPointers. The number of items is returned
159  * in *nitems.
160  */
163  int *nitems)
164 {
165  Pointer ptr = GinGetPosting(itup);
166  int nipd = GinGetNPosting(itup);
167  ItemPointer ipd;
168  int ndecoded;
169 
170  if (GinItupIsCompressed(itup))
171  {
172  if (nipd > 0)
173  {
174  ipd = ginPostingListDecode((GinPostingList *) ptr, &ndecoded);
175  if (nipd != ndecoded)
176  elog(ERROR, "number of items mismatch in GIN entry tuple, %d in tuple header, %d decoded",
177  nipd, ndecoded);
178  }
179  else
180  {
181  ipd = palloc(0);
182  }
183  }
184  else
185  {
186  ipd = (ItemPointer) palloc(sizeof(ItemPointerData) * nipd);
187  memcpy(ipd, ptr, sizeof(ItemPointerData) * nipd);
188  }
189  *nitems = nipd;
190  return ipd;
191 }
192 
193 /*
194  * Form a non-leaf entry tuple by copying the key data from the given tuple,
195  * which can be either a leaf or non-leaf entry tuple.
196  *
197  * Any posting list in the source tuple is not copied. The specified child
198  * block number is inserted into t_tid.
199  */
200 static IndexTuple
202 {
203  IndexTuple nitup;
204 
205  if (GinPageIsLeaf(page) && !GinIsPostingTree(itup))
206  {
207  /* Tuple contains a posting list, just copy stuff before that */
208  uint32 origsize = GinGetPostingOffset(itup);
209 
210  origsize = MAXALIGN(origsize);
211  nitup = (IndexTuple) palloc(origsize);
212  memcpy(nitup, itup, origsize);
213  /* ... be sure to fix the size header field ... */
214  nitup->t_info &= ~INDEX_SIZE_MASK;
215  nitup->t_info |= origsize;
216  }
217  else
218  {
219  /* Copy the tuple as-is */
220  nitup = (IndexTuple) palloc(IndexTupleSize(itup));
221  memcpy(nitup, itup, IndexTupleSize(itup));
222  }
223 
224  /* Now insert the correct downlink */
225  GinSetDownlink(nitup, childblk);
226 
227  return nitup;
228 }
229 
230 /*
231  * Entry tree is a "static", ie tuple never deletes from it,
232  * so we don't use right bound, we use rightmost key instead.
233  */
234 static IndexTuple
236 {
237  OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
238 
239  return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff));
240 }
241 
242 static bool
244 {
245  IndexTuple itup;
247  Datum key;
248  GinNullCategory category;
249 
250  if (GinPageRightMost(page))
251  return false;
252 
253  itup = getRightMostTuple(page);
254  attnum = gintuple_get_attrnum(btree->ginstate, itup);
255  key = gintuple_get_key(btree->ginstate, itup, &category);
256 
257  if (ginCompareAttEntries(btree->ginstate,
258  btree->entryAttnum, btree->entryKey, btree->entryCategory,
259  attnum, key, category) > 0)
260  return true;
261 
262  return false;
263 }
264 
265 /*
266  * Find correct tuple in non-leaf page. It supposed that
267  * page correctly chosen and searching value SHOULD be on page
268  */
269 static BlockNumber
271 {
272  OffsetNumber low,
273  high,
274  maxoff;
275  IndexTuple itup = NULL;
276  int result;
277  Page page = BufferGetPage(stack->buffer);
278 
279  Assert(!GinPageIsLeaf(page));
280  Assert(!GinPageIsData(page));
281 
282  if (btree->fullScan)
283  {
284  stack->off = FirstOffsetNumber;
285  stack->predictNumber *= PageGetMaxOffsetNumber(page);
286  return btree->getLeftMostChild(btree, page);
287  }
288 
289  low = FirstOffsetNumber;
290  maxoff = high = PageGetMaxOffsetNumber(page);
291  Assert(high >= low);
292 
293  high++;
294 
295  while (high > low)
296  {
297  OffsetNumber mid = low + ((high - low) / 2);
298 
299  if (mid == maxoff && GinPageRightMost(page))
300  {
301  /* Right infinity */
302  result = -1;
303  }
304  else
305  {
307  Datum key;
308  GinNullCategory category;
309 
310  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
311  attnum = gintuple_get_attrnum(btree->ginstate, itup);
312  key = gintuple_get_key(btree->ginstate, itup, &category);
313  result = ginCompareAttEntries(btree->ginstate,
314  btree->entryAttnum,
315  btree->entryKey,
316  btree->entryCategory,
317  attnum, key, category);
318  }
319 
320  if (result == 0)
321  {
322  stack->off = mid;
324  return GinGetDownlink(itup);
325  }
326  else if (result > 0)
327  low = mid + 1;
328  else
329  high = mid;
330  }
331 
332  Assert(high >= FirstOffsetNumber && high <= maxoff);
333 
334  stack->off = high;
335  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, high));
337  return GinGetDownlink(itup);
338 }
339 
340 /*
341  * Searches correct position for value on leaf page.
342  * Page should be correctly chosen.
343  * Returns true if value found on page.
344  */
345 static bool
347 {
348  Page page = BufferGetPage(stack->buffer);
349  OffsetNumber low,
350  high;
351 
352  Assert(GinPageIsLeaf(page));
353  Assert(!GinPageIsData(page));
354 
355  if (btree->fullScan)
356  {
357  stack->off = FirstOffsetNumber;
358  return true;
359  }
360 
361  low = FirstOffsetNumber;
362  high = PageGetMaxOffsetNumber(page);
363 
364  if (high < low)
365  {
366  stack->off = FirstOffsetNumber;
367  return false;
368  }
369 
370  high++;
371 
372  while (high > low)
373  {
374  OffsetNumber mid = low + ((high - low) / 2);
375  IndexTuple itup;
377  Datum key;
378  GinNullCategory category;
379  int result;
380 
381  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
382  attnum = gintuple_get_attrnum(btree->ginstate, itup);
383  key = gintuple_get_key(btree->ginstate, itup, &category);
384  result = ginCompareAttEntries(btree->ginstate,
385  btree->entryAttnum,
386  btree->entryKey,
387  btree->entryCategory,
388  attnum, key, category);
389  if (result == 0)
390  {
391  stack->off = mid;
392  return true;
393  }
394  else if (result > 0)
395  low = mid + 1;
396  else
397  high = mid;
398  }
399 
400  stack->off = high;
401  return false;
402 }
403 
404 static OffsetNumber
406 {
407  OffsetNumber i,
408  maxoff = PageGetMaxOffsetNumber(page);
409  IndexTuple itup;
410 
411  Assert(!GinPageIsLeaf(page));
412  Assert(!GinPageIsData(page));
413 
414  /* if page isn't changed, we returns storedOff */
415  if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
416  {
417  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, storedOff));
418  if (GinGetDownlink(itup) == blkno)
419  return storedOff;
420 
421  /*
422  * we hope, that needed pointer goes to right. It's true if there
423  * wasn't a deletion
424  */
425  for (i = storedOff + 1; i <= maxoff; i++)
426  {
427  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
428  if (GinGetDownlink(itup) == blkno)
429  return i;
430  }
431  maxoff = storedOff - 1;
432  }
433 
434  /* last chance */
435  for (i = FirstOffsetNumber; i <= maxoff; i++)
436  {
437  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
438  if (GinGetDownlink(itup) == blkno)
439  return i;
440  }
441 
442  return InvalidOffsetNumber;
443 }
444 
445 static BlockNumber
447 {
448  IndexTuple itup;
449 
450  Assert(!GinPageIsLeaf(page));
451  Assert(!GinPageIsData(page));
453 
454  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
455  return GinGetDownlink(itup);
456 }
457 
458 static bool
460  GinBtreeEntryInsertData *insertData)
461 {
462  Size releasedsz = 0;
463  Size addedsz;
464  Page page = BufferGetPage(buf);
465 
466  Assert(insertData->entry);
467  Assert(!GinPageIsData(page));
468 
469  if (insertData->isDelete)
470  {
471  IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
472 
473  releasedsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
474  }
475 
476  addedsz = MAXALIGN(IndexTupleSize(insertData->entry)) + sizeof(ItemIdData);
477 
478  if (PageGetFreeSpace(page) + releasedsz >= addedsz)
479  return true;
480 
481  return false;
482 }
483 
484 /*
485  * Delete tuple on leaf page if tuples existed and we
486  * should update it, update old child blkno to new right page
487  * if child split occurred
488  */
489 static void
491  GinBtreeEntryInsertData *insertData, BlockNumber updateblkno)
492 {
493  Assert(insertData->entry);
494  Assert(!GinPageIsData(page));
495 
496  if (insertData->isDelete)
497  {
498  Assert(GinPageIsLeaf(page));
499  PageIndexTupleDelete(page, off);
500  }
501 
502  if (!GinPageIsLeaf(page) && updateblkno != InvalidBlockNumber)
503  {
504  IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
505 
506  GinSetDownlink(itup, updateblkno);
507  }
508 }
509 
510 /*
511  * Prepare to insert data on an entry page.
512  *
513  * If it will fit, return GPTP_INSERT after doing whatever setup is needed
514  * before we enter the insertion critical section. *ptp_workspace can be
515  * set to pass information along to the execPlaceToPage function.
516  *
517  * If it won't fit, perform a page split and return two temporary page
518  * images into *newlpage and *newrpage, with result GPTP_SPLIT.
519  *
520  * In neither case should the given page buffer be modified here.
521  *
522  * Note: on insertion to an internal node, in addition to inserting the given
523  * item, the downlink of the existing item at stack->off will be updated to
524  * point to updateblkno.
525  */
526 static GinPlaceToPageRC
528  void *insertPayload, BlockNumber updateblkno,
529  void **ptp_workspace,
530  Page *newlpage, Page *newrpage)
531 {
532  GinBtreeEntryInsertData *insertData = insertPayload;
533  OffsetNumber off = stack->off;
534 
535  /* If it doesn't fit, deal with split case */
536  if (!entryIsEnoughSpace(btree, buf, off, insertData))
537  {
538  entrySplitPage(btree, buf, stack, insertData, updateblkno,
539  newlpage, newrpage);
540  return GPTP_SPLIT;
541  }
542 
543  /* Else, we're ready to proceed with insertion */
544  return GPTP_INSERT;
545 }
546 
547 /*
548  * Perform data insertion after beginPlaceToPage has decided it will fit.
549  *
550  * This is invoked within a critical section, and XLOG record creation (if
551  * needed) is already started. The target buffer is registered in slot 0.
552  */
553 static void
555  void *insertPayload, BlockNumber updateblkno,
556  void *ptp_workspace)
557 {
558  GinBtreeEntryInsertData *insertData = insertPayload;
559  Page page = BufferGetPage(buf);
560  OffsetNumber off = stack->off;
561  OffsetNumber placed;
562 
563  entryPreparePage(btree, page, off, insertData, updateblkno);
564 
565  placed = PageAddItem(page,
566  (Item) insertData->entry,
567  IndexTupleSize(insertData->entry),
568  off, false, false);
569  if (placed != off)
570  elog(ERROR, "failed to add item to index page in \"%s\"",
572 
574 
575  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
576  {
577  /*
578  * This must be static, because it has to survive until XLogInsert,
579  * and we can't palloc here. Ugly, but the XLogInsert infrastructure
580  * isn't reentrant anyway.
581  */
582  static ginxlogInsertEntry data;
583 
584  data.isDelete = insertData->isDelete;
585  data.offset = off;
586 
588  XLogRegisterBufData(0, (char *) &data,
589  offsetof(ginxlogInsertEntry, tuple));
590  XLogRegisterBufData(0, (char *) insertData->entry,
591  IndexTupleSize(insertData->entry));
592  }
593 }
594 
595 /*
596  * Split entry page and insert new data.
597  *
598  * Returns new temp pages to *newlpage and *newrpage.
599  * The original buffer is left untouched.
600  */
601 static void
603  GinBtreeStack *stack,
604  GinBtreeEntryInsertData *insertData,
605  BlockNumber updateblkno,
606  Page *newlpage, Page *newrpage)
607 {
608  OffsetNumber off = stack->off;
609  OffsetNumber i,
610  maxoff,
612  Size totalsize = 0;
613  Size lsize = 0,
614  size;
615  char *ptr;
616  IndexTuple itup;
617  Page page;
618  Page lpage = PageGetTempPageCopy(BufferGetPage(origbuf));
619  Page rpage = PageGetTempPageCopy(BufferGetPage(origbuf));
620  Size pageSize = PageGetPageSize(lpage);
621  PGAlignedBlock tupstore[2]; /* could need 2 pages' worth of tuples */
622 
623  entryPreparePage(btree, lpage, off, insertData, updateblkno);
624 
625  /*
626  * First, append all the existing tuples and the new tuple we're inserting
627  * one after another in a temporary workspace.
628  */
629  maxoff = PageGetMaxOffsetNumber(lpage);
630  ptr = tupstore[0].data;
631  for (i = FirstOffsetNumber; i <= maxoff; i++)
632  {
633  if (i == off)
634  {
635  size = MAXALIGN(IndexTupleSize(insertData->entry));
636  memcpy(ptr, insertData->entry, size);
637  ptr += size;
638  totalsize += size + sizeof(ItemIdData);
639  }
640 
641  itup = (IndexTuple) PageGetItem(lpage, PageGetItemId(lpage, i));
642  size = MAXALIGN(IndexTupleSize(itup));
643  memcpy(ptr, itup, size);
644  ptr += size;
645  totalsize += size + sizeof(ItemIdData);
646  }
647 
648  if (off == maxoff + 1)
649  {
650  size = MAXALIGN(IndexTupleSize(insertData->entry));
651  memcpy(ptr, insertData->entry, size);
652  ptr += size;
653  totalsize += size + sizeof(ItemIdData);
654  }
655 
656  /*
657  * Initialize the left and right pages, and copy all the tuples back to
658  * them.
659  */
660  GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
661  GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
662 
663  ptr = tupstore[0].data;
664  maxoff++;
665  lsize = 0;
666 
667  page = lpage;
668  for (i = FirstOffsetNumber; i <= maxoff; i++)
669  {
670  itup = (IndexTuple) ptr;
671 
672  /*
673  * Decide where to split. We try to equalize the pages' total data
674  * size, not number of tuples.
675  */
676  if (lsize > totalsize / 2)
677  {
679  separator = i - 1;
680  page = rpage;
681  }
682  else
683  {
684  lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
685  }
686 
687  if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
688  elog(ERROR, "failed to add item to index page in \"%s\"",
690  ptr += MAXALIGN(IndexTupleSize(itup));
691  }
692 
693  /* return temp pages to caller */
694  *newlpage = lpage;
695  *newrpage = rpage;
696 }
697 
698 /*
699  * Construct insertion payload for inserting the downlink for given buffer.
700  */
701 static void *
703 {
704  GinBtreeEntryInsertData *insertData;
705  Page lpage = BufferGetPage(lbuf);
706  BlockNumber lblkno = BufferGetBlockNumber(lbuf);
707  IndexTuple itup;
708 
709  itup = getRightMostTuple(lpage);
710 
711  insertData = palloc(sizeof(GinBtreeEntryInsertData));
712  insertData->entry = GinFormInteriorTuple(itup, lpage, lblkno);
713  insertData->isDelete = false;
714 
715  return insertData;
716 }
717 
718 /*
719  * Fills new root by rightest values from child.
720  * Also called from ginxlog, should not use btree
721  */
722 void
724  BlockNumber lblkno, Page lpage,
725  BlockNumber rblkno, Page rpage)
726 {
727  IndexTuple itup;
728 
729  itup = GinFormInteriorTuple(getRightMostTuple(lpage), lpage, lblkno);
730  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
731  elog(ERROR, "failed to add item to index root page");
732  pfree(itup);
733 
734  itup = GinFormInteriorTuple(getRightMostTuple(rpage), rpage, rblkno);
735  if (PageAddItem(root, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
736  elog(ERROR, "failed to add item to index root page");
737  pfree(itup);
738 }
739 
740 /*
741  * Set up GinBtree for entry page access
742  *
743  * Note: during WAL recovery, there may be no valid data in ginstate
744  * other than a faked-up Relation pointer; the key datum is bogus too.
745  */
746 void
748  Datum key, GinNullCategory category,
749  GinState *ginstate)
750 {
751  memset(btree, 0, sizeof(GinBtreeData));
752 
753  btree->index = ginstate->index;
754  btree->rootBlkno = GIN_ROOT_BLKNO;
755  btree->ginstate = ginstate;
756 
759  btree->isMoveRight = entryIsMoveRight;
764  btree->fillRoot = ginEntryFillRoot;
766 
767  btree->isData = false;
768  btree->fullScan = false;
769  btree->isBuild = false;
770 
771  btree->entryAttnum = attnum;
772  btree->entryKey = key;
773  btree->entryCategory = category;
774 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3667
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2474
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:404
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1052
Page PageGetTempPageCopy(Page page)
Definition: bufpage.c:382
Size PageGetFreeSpace(Page page)
Definition: bufpage.c:907
Pointer Page
Definition: bufpage.h:78
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static Size PageGetPageSize(Page page)
Definition: bufpage.h:273
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:468
unsigned int uint32
Definition: c.h:506
#define MAXALIGN(LEN)
Definition: c.h:811
#define Max(x, y)
Definition: c.h:998
char * Pointer
Definition: c.h:483
#define Assert(condition)
Definition: c.h:858
#define SHORTALIGN(LEN)
Definition: c.h:807
size_t Size
Definition: c.h:605
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
GinPlaceToPageRC
Definition: gin_private.h:144
@ GPTP_INSERT
Definition: gin_private.h:146
@ GPTP_SPLIT
Definition: gin_private.h:147
#define GinIsPostingTree(itup)
Definition: ginblock.h:231
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GinCategoryOffset(itup, ginstate)
Definition: ginblock.h:217
#define GinGetPosting(itup)
Definition: ginblock.h:238
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:208
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
#define GinGetDownlink(itup)
Definition: ginblock.h:257
#define GinSetNPosting(itup, n)
Definition: ginblock.h:229
#define GinItupIsCompressed(itup)
Definition: ginblock.h:239
#define GinSetPostingOffset(itup, n)
Definition: ginblock.h:237
#define GinSetDownlink(itup, blkno)
Definition: ginblock.h:258
#define GinGetNPosting(itup)
Definition: ginblock.h:228
#define GinGetPostingOffset(itup)
Definition: ginblock.h:236
#define GinPageIsData(page)
Definition: ginblock.h:115
signed char GinNullCategory
Definition: ginblock.h:206
#define GinPageRightMost(page)
Definition: ginblock.h:129
#define GinSetNullCategory(itup, ginstate, c)
Definition: ginblock.h:222
#define GinMaxItemSize
Definition: ginblock.h:248
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
Definition: ginentrypage.c:723
static void entryPreparePage(GinBtree btree, Page page, OffsetNumber off, GinBtreeEntryInsertData *insertData, BlockNumber updateblkno)
Definition: ginentrypage.c:490
static bool entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:346
static bool entryIsMoveRight(GinBtree btree, Page page)
Definition: ginentrypage.c:243
static BlockNumber entryGetLeftMostPage(GinBtree btree, Page page)
Definition: ginentrypage.c:446
static void entrySplitPage(GinBtree btree, Buffer origbuf, GinBtreeStack *stack, GinBtreeEntryInsertData *insertData, BlockNumber updateblkno, Page *newlpage, Page *newrpage)
Definition: ginentrypage.c:602
static IndexTuple getRightMostTuple(Page page)
Definition: ginentrypage.c:235
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: ginentrypage.c:702
static IndexTuple GinFormInteriorTuple(IndexTuple itup, Page page, BlockNumber childblk)
Definition: ginentrypage.c:201
static OffsetNumber entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
Definition: ginentrypage.c:405
static bool entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off, GinBtreeEntryInsertData *insertData)
Definition: ginentrypage.c:459
static GinPlaceToPageRC entryBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void **ptp_workspace, Page *newlpage, Page *newrpage)
Definition: ginentrypage.c:527
ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum, IndexTuple itup, int *nitems)
Definition: ginentrypage.c:162
static void entryExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, void *insertPayload, BlockNumber updateblkno, void *ptp_workspace)
Definition: ginentrypage.c:554
static BlockNumber entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
Definition: ginentrypage.c:270
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
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:338
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:226
int ginCompareAttEntries(GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
Definition: ginutil.c:410
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:259
#define nitems(x)
Definition: indent.h:31
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: indextuple.c:44
int i
Definition: isn.c:73
Pointer Item
Definition: item.h:17
struct ItemIdData ItemIdData
ItemPointerData * ItemPointer
Definition: itemptr.h:49
#define IndexTupleHasNulls(itup)
Definition: itup.h:71
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
#define INDEX_SIZE_MASK
Definition: itup.h:65
void pfree(void *pointer)
Definition: mcxt.c:1520
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1540
void * palloc(Size size)
Definition: mcxt.c:1316
#define InvalidOffsetNumber
Definition: off.h:26
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
int16 attnum
Definition: pg_attribute.h:74
const void * data
static char * buf
Definition: pg_test_fsync.c:73
uintptr_t Datum
Definition: postgres.h:64
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:192
tree ctl root
Definition: radixtree.h:1884
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define RelationNeedsWAL(relation)
Definition: rel.h:628
static pg_noinline void Size size
Definition: slab.c:607
Datum entryKey
Definition: gin_private.h:175
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:153
GinState * ginstate
Definition: gin_private.h:169
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:161
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:154
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:156
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:155
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:160
GinNullCategory entryCategory
Definition: gin_private.h:176
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:162
OffsetNumber entryAttnum
Definition: gin_private.h:174
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:159
Relation index
Definition: gin_private.h:167
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:163
BlockNumber rootBlkno
Definition: gin_private.h:168
OffsetNumber off
Definition: gin_private.h:133
uint32 predictNumber
Definition: gin_private.h:136
bool oneCol
Definition: gin_private.h:60
TupleDesc tupdesc[INDEX_MAX_KEYS]
Definition: gin_private.h:74
Relation index
Definition: gin_private.h:59
unsigned short t_info
Definition: itup.h:49
char data[BLCKSZ]
Definition: c.h:1119
void XLogRegisterBufData(uint8 block_id, char *data, uint32 len)
Definition: xloginsert.c:405
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
#define REGBUF_STANDARD
Definition: xloginsert.h:34