PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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
22static 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)
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 {
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 */
200static 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 */
234static IndexTuple
236{
238
239 return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff));
240}
241
242static 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
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 */
269static 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;
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 */
345static 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
404static OffsetNumber
406{
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
445static BlockNumber
447{
448 IndexTuple itup;
449
450 Assert(!GinPageIsLeaf(page));
451 Assert(!GinPageIsData(page));
453
455 return GinGetDownlink(itup);
456}
457
458static 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 */
489static 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 */
526static 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 */
553static 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 */
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 */
601static void
603 GinBtreeStack *stack,
604 GinBtreeEntryInsertData *insertData,
605 BlockNumber updateblkno,
606 Page *newlpage, Page *newrpage)
607{
608 OffsetNumber off = stack->off;
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));
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 */
701static 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 */
722void
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 */
746void
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
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:3724
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1041
Page PageGetTempPageCopy(Page page)
Definition: bufpage.c:371
Size PageGetFreeSpace(Page page)
Definition: bufpage.c:896
Pointer Page
Definition: bufpage.h:81
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:354
static Size PageGetPageSize(Page page)
Definition: bufpage.h:276
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
#define MAXALIGN(LEN)
Definition: c.h:765
#define Max(x, y)
Definition: c.h:952
char * Pointer
Definition: c.h:476
#define Assert(condition)
Definition: c.h:812
#define SHORTALIGN(LEN)
Definition: c.h:761
uint32_t uint32
Definition: c.h:485
size_t Size
Definition: c.h:559
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#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 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
static void * entryPrepareDownlink(GinBtree btree, Buffer lbuf)
Definition: ginentrypage.c:702
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:339
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:227
int ginCompareAttEntries(GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
Definition: ginutil.c:411
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:260
#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:72
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
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
#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:72
uintptr_t Datum
Definition: postgres.h:64
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:192
tree ctl root
Definition: radixtree.h:1888
#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
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:162
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
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:1073
void XLogRegisterBufData(uint8 block_id, const 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