PostgreSQL Source Code git master
Loading...
Searching...
No Matches
verify_gin.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * verify_gin.c
4 * Verifies the integrity of GIN indexes based on invariants.
5 *
6 *
7 * GIN index verification checks a number of invariants:
8 *
9 * - consistency: Paths in GIN graph have to contain consistent keys: tuples
10 * on parent pages consistently include tuples from children pages.
11 *
12 * - graph invariants: Each internal page must have at least one downlink, and
13 * can reference either only leaf pages or only internal pages.
14 *
15 *
16 * Copyright (c) 2016-2026, PostgreSQL Global Development Group
17 *
18 * IDENTIFICATION
19 * contrib/amcheck/verify_gin.c
20 *
21 *-------------------------------------------------------------------------
22 */
23#include "postgres.h"
24
25#include "access/gin_private.h"
26#include "access/nbtree.h"
27#include "catalog/pg_am.h"
28#include "utils/memutils.h"
29#include "utils/rel.h"
30#include "verify_common.h"
31#include "string.h"
32
33/*
34 * GinScanItem represents one item of depth-first scan of the index.
35 */
44
45/*
46 * GinPostingTreeScanItem represents one item of a depth-first posting tree scan.
47 */
56
57
59
61 Relation heaprel,
62 void *callback_state, bool readonly);
63static void check_index_page(Relation rel, Buffer buffer, BlockNumber blockNo);
65 BlockNumber parentblkno,
66 BlockNumber childblkno,
67 BufferAccessStrategy strategy);
69 OffsetNumber offset);
70
71/*
72 * gin_index_check(index regclass)
73 *
74 * Verify integrity of GIN index.
75 *
76 * Acquires AccessShareLock on heap & index relations.
77 */
91
92/*
93 * Read item pointers from leaf entry tuple.
94 *
95 * Returns a palloc'd array of ItemPointers. The number of items is returned
96 * in *nitems.
97 */
98static ItemPointer
100{
101 Pointer ptr = GinGetPosting(itup);
102 int nipd = GinGetNPosting(itup);
103 ItemPointer ipd;
104 int ndecoded;
105
106 if (GinItupIsCompressed(itup))
107 {
108 if (nipd > 0)
109 {
110 ipd = ginPostingListDecode(ptr, &ndecoded);
111 if (nipd != ndecoded)
112 elog(ERROR, "number of items mismatch in GIN entry tuple, %d in tuple header, %d decoded",
113 nipd, ndecoded);
114 }
115 else
116 ipd = palloc(0);
117 }
118 else
119 {
120 ipd = palloc_array(ItemPointerData, nipd);
121 memcpy(ipd, ptr, sizeof(ItemPointerData) * nipd);
122 }
123 *nitems = nipd;
124 return ipd;
125}
126
127/*
128 * Scans through a posting tree (given by the root), and verifies that the keys
129 * on a child keys are consistent with the parent.
130 *
131 * Allocates a separate memory context and scans through posting tree graph.
132 */
133static void
135{
138 MemoryContext mctx;
139 MemoryContext oldcontext;
140
141 int leafdepth;
142
144 "posting tree check context",
146 oldcontext = MemoryContextSwitchTo(mctx);
147
148 /*
149 * We don't know the height of the tree yet, but as soon as we encounter a
150 * leaf page, we will set 'leafdepth' to its depth.
151 */
152 leafdepth = -1;
153
154 /* Start the scan at the root page */
156 stack->depth = 0;
159 stack->blkno = posting_tree_root;
160
161 elog(DEBUG3, "processing posting tree at blk %u", posting_tree_root);
162
163 while (stack)
164 {
165 GinPostingTreeScanItem *stack_next;
166 Buffer buffer;
167 Page page;
169 maxoff;
170 BlockNumber rightlink;
171
173
174 buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
175 RBM_NORMAL, strategy);
176 LockBuffer(buffer, GIN_SHARE);
177 page = BufferGetPage(buffer);
178
179 Assert(GinPageIsData(page));
180
181 /* Check that the tree has the same height in all branches */
182 if (GinPageIsLeaf(page))
183 {
184 ItemPointerData minItem;
185 int nlist;
186 ItemPointerData *list;
187 char tidrange_buf[MAXPGPATH];
188
189 ItemPointerSetMin(&minItem);
190
191 elog(DEBUG1, "page blk: %u, type leaf", stack->blkno);
192
193 if (leafdepth == -1)
194 leafdepth = stack->depth;
195 else if (stack->depth != leafdepth)
197 (errcode(ERRCODE_INDEX_CORRUPTED),
198 errmsg("index \"%s\": internal pages traversal encountered leaf page unexpectedly on block %u",
199 RelationGetRelationName(rel), stack->blkno)));
200 list = GinDataLeafPageGetItems(page, &nlist, minItem);
201
202 if (nlist > 0)
203 snprintf(tidrange_buf, sizeof(tidrange_buf),
204 "%d tids (%u, %u) - (%u, %u)",
205 nlist,
208 ItemPointerGetBlockNumberNoCheck(&list[nlist - 1]),
209 ItemPointerGetOffsetNumberNoCheck(&list[nlist - 1]));
210 else
211 snprintf(tidrange_buf, sizeof(tidrange_buf), "0 tids");
212
213 if (stack->parentblk != InvalidBlockNumber)
214 elog(DEBUG3, "blk %u: parent %u highkey (%u, %u), %s",
215 stack->blkno,
216 stack->parentblk,
219 tidrange_buf);
220 else
221 elog(DEBUG3, "blk %u: root leaf, %s",
222 stack->blkno,
223 tidrange_buf);
224
225 if (stack->parentblk != InvalidBlockNumber &&
227 nlist > 0 && ItemPointerCompare(&stack->parentkey, &list[nlist - 1]) < 0)
229 (errcode(ERRCODE_INDEX_CORRUPTED),
230 errmsg("index \"%s\": tid exceeds parent's high key in postingTree leaf on block %u",
231 RelationGetRelationName(rel), stack->blkno)));
232 }
233 else
234 {
235 LocationIndex pd_lower;
236 ItemPointerData bound;
237 int lowersize;
238
239 /*
240 * Check that tuples in each page are properly ordered and
241 * consistent with parent high key
242 */
243 maxoff = GinPageGetOpaque(page)->maxoff;
244 rightlink = GinPageGetOpaque(page)->rightlink;
245
246 elog(DEBUG1, "page blk: %u, type data, maxoff %d", stack->blkno, maxoff);
247
248 if (stack->parentblk != InvalidBlockNumber)
249 elog(DEBUG3, "blk %u: internal posting tree page with %u items, parent %u highkey (%u, %u)",
250 stack->blkno, maxoff, stack->parentblk,
253 else
254 elog(DEBUG3, "blk %u: root internal posting tree page with %u items",
255 stack->blkno, maxoff);
256
257 /*
258 * A GIN posting tree internal page stores PostingItems in the
259 * 'lower' part of the page. The 'upper' part is unused. The
260 * number of elements is stored in the opaque area (maxoff). Make
261 * sure the size of the 'lower' part agrees with 'maxoff'
262 *
263 * We didn't set pd_lower until PostgreSQL version 9.4, so if this
264 * check fails, it could also be because the index was
265 * binary-upgraded from an earlier version. That was a long time
266 * ago, though, so let's warn if it doesn't match.
267 */
268 pd_lower = ((PageHeader) page)->pd_lower;
269 lowersize = pd_lower - MAXALIGN(SizeOfPageHeaderData);
270 if ((lowersize - MAXALIGN(sizeof(ItemPointerData))) / sizeof(PostingItem) != maxoff)
272 (errcode(ERRCODE_INDEX_CORRUPTED),
273 errmsg("index \"%s\" has unexpected pd_lower %u in posting tree block %u with maxoff %u)",
274 RelationGetRelationName(rel), pd_lower, stack->blkno, maxoff)));
275
276 /*
277 * Before the PostingItems, there's one ItemPointerData in the
278 * 'lower' part that stores the page's high key.
279 */
280 bound = *GinDataPageGetRightBound(page);
281
282 /*
283 * Gin page right bound has a sane value only when not a highkey
284 * on the rightmost page (at a given level). For the rightmost
285 * page does not store the highkey explicitly, and the value is
286 * infinity.
287 */
288 if (ItemPointerIsValid(&stack->parentkey) &&
289 rightlink != InvalidBlockNumber &&
290 !ItemPointerEquals(&stack->parentkey, &bound))
292 (errcode(ERRCODE_INDEX_CORRUPTED),
293 errmsg("index \"%s\": posting tree page's high key (%u, %u) doesn't match the downlink on block %u (parent blk %u, key (%u, %u))",
297 stack->blkno, stack->parentblk,
300
301 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
302 {
304 PostingItem *posting_item = GinDataPageGetPostingItem(page, i);
305
306 /* ItemPointerGetOffsetNumber expects a valid pointer */
307 if (!(i == maxoff &&
308 rightlink == InvalidBlockNumber))
309 elog(DEBUG3, "key (%u, %u) -> %u",
310 ItemPointerGetBlockNumber(&posting_item->key),
311 ItemPointerGetOffsetNumber(&posting_item->key),
312 BlockIdGetBlockNumber(&posting_item->child_blkno));
313 else
314 elog(DEBUG3, "key (%u, %u) -> %u",
315 0, 0, BlockIdGetBlockNumber(&posting_item->child_blkno));
316
317 if (i == maxoff && rightlink == InvalidBlockNumber)
318 {
319 /*
320 * The rightmost item in the tree level has (0, 0) as the
321 * key
322 */
323 if (ItemPointerGetBlockNumberNoCheck(&posting_item->key) != 0 ||
324 ItemPointerGetOffsetNumberNoCheck(&posting_item->key) != 0)
326 (errcode(ERRCODE_INDEX_CORRUPTED),
327 errmsg("index \"%s\": rightmost posting tree page (blk %u) has unexpected last key (%u, %u)",
329 stack->blkno,
331 ItemPointerGetOffsetNumberNoCheck(&posting_item->key))));
332 }
333 else if (i != FirstOffsetNumber)
334 {
335 PostingItem *previous_posting_item = GinDataPageGetPostingItem(page, i - 1);
336
337 if (ItemPointerCompare(&posting_item->key, &previous_posting_item->key) < 0)
339 (errcode(ERRCODE_INDEX_CORRUPTED),
340 errmsg("index \"%s\" has wrong tuple order in posting tree, block %u, offset %u",
341 RelationGetRelationName(rel), stack->blkno, i)));
342 }
343
344 /*
345 * Check if this tuple is consistent with the downlink in the
346 * parent.
347 */
348 if (i == maxoff && ItemPointerIsValid(&stack->parentkey) &&
349 ItemPointerCompare(&stack->parentkey, &posting_item->key) < 0)
351 (errcode(ERRCODE_INDEX_CORRUPTED),
352 errmsg("index \"%s\": posting item exceeds parent's high key in postingTree internal page on block %u offset %u",
354 stack->blkno, i)));
355
356 /* This is an internal page, recurse into the child. */
358 ptr->depth = stack->depth + 1;
359
360 /*
361 * The rightmost parent key is always invalid item pointer.
362 * Its value is 'Infinity' and not explicitly stored.
363 */
364 ptr->parentkey = posting_item->key;
365 ptr->parentblk = stack->blkno;
366 ptr->blkno = BlockIdGetBlockNumber(&posting_item->child_blkno);
367 ptr->next = stack->next;
368 stack->next = ptr;
369 }
370 }
371 UnlockReleaseBuffer(buffer);
372
373 /* Step to next item in the queue */
374 stack_next = stack->next;
375 pfree(stack);
376 stack = stack_next;
377 }
378
379 MemoryContextSwitchTo(oldcontext);
381}
382
383/*
384 * Main entry point for GIN checks.
385 *
386 * Allocates memory context and scans through the whole GIN graph.
387 */
388static void
390 Relation heaprel,
391 void *callback_state,
392 bool readonly)
393{
395 GinScanItem *stack;
396 MemoryContext mctx;
397 MemoryContext oldcontext;
399 int leafdepth;
400
402 "amcheck consistency check context",
404 oldcontext = MemoryContextSwitchTo(mctx);
405 initGinState(&state, rel);
406
407 /*
408 * We don't know the height of the tree yet, but as soon as we encounter a
409 * leaf page, we will set 'leafdepth' to its depth.
410 */
411 leafdepth = -1;
412
413 /* Start the scan at the root page */
415 stack->depth = 0;
416 stack->parenttup = NULL;
418 stack->blkno = GIN_ROOT_BLKNO;
419
420 while (stack)
421 {
422 GinScanItem *stack_next;
423 Buffer buffer;
424 Page page;
426 maxoff,
427 prev_attnum;
428 IndexTuple prev_tuple;
429 BlockNumber rightlink;
430
432
433 buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
434 RBM_NORMAL, strategy);
435 LockBuffer(buffer, GIN_SHARE);
436 page = BufferGetPage(buffer);
437 maxoff = PageGetMaxOffsetNumber(page);
438 rightlink = GinPageGetOpaque(page)->rightlink;
439
440 /* Do basic sanity checks on the page headers */
441 check_index_page(rel, buffer, stack->blkno);
442
443 elog(DEBUG3, "processing entry tree page at blk %u, maxoff: %u", stack->blkno, maxoff);
444
445 /*
446 * It's possible that the page was split since we looked at the
447 * parent, so that we didn't missed the downlink of the right sibling
448 * when we scanned the parent. If so, add the right sibling to the
449 * stack now.
450 */
451 if (stack->parenttup != NULL)
452 {
453 GinNullCategory parent_key_category;
454 Datum parent_key = gintuple_get_key(&state,
455 stack->parenttup,
456 &parent_key_category);
457 OffsetNumber parent_key_attnum = gintuple_get_attrnum(&state, stack->parenttup);
458 ItemId iid = PageGetItemIdCareful(rel, stack->blkno,
459 page, maxoff);
460 IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
461 OffsetNumber page_max_key_attnum = gintuple_get_attrnum(&state, idxtuple);
462 GinNullCategory page_max_key_category;
463 Datum page_max_key = gintuple_get_key(&state, idxtuple, &page_max_key_category);
464
465 if (rightlink != InvalidBlockNumber &&
466 ginCompareAttEntries(&state, page_max_key_attnum, page_max_key,
467 page_max_key_category, parent_key_attnum,
468 parent_key, parent_key_category) < 0)
469 {
470 /* split page detected, install right link to the stack */
471 GinScanItem *ptr;
472
473 elog(DEBUG3, "split detected for blk: %u, parent blk: %u", stack->blkno, stack->parentblk);
474
476 ptr->depth = stack->depth;
477 ptr->parenttup = CopyIndexTuple(stack->parenttup);
478 ptr->parentblk = stack->parentblk;
479 ptr->blkno = rightlink;
480 ptr->next = stack->next;
481 stack->next = ptr;
482 }
483 }
484
485 /* Check that the tree has the same height in all branches */
486 if (GinPageIsLeaf(page))
487 {
488 if (leafdepth == -1)
489 leafdepth = stack->depth;
490 else if (stack->depth != leafdepth)
492 (errcode(ERRCODE_INDEX_CORRUPTED),
493 errmsg("index \"%s\": internal pages traversal encountered leaf page unexpectedly on block %u",
494 RelationGetRelationName(rel), stack->blkno)));
495 }
496
497 /*
498 * Check that tuples in each page are properly ordered and consistent
499 * with parent high key
500 */
501 prev_tuple = NULL;
502 prev_attnum = InvalidAttrNumber;
503 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
504 {
505 ItemId iid = PageGetItemIdCareful(rel, stack->blkno, page, i);
506 IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
507 OffsetNumber current_attnum = gintuple_get_attrnum(&state, idxtuple);
508 GinNullCategory current_key_category;
509 Datum current_key;
510
511 if (MAXALIGN(ItemIdGetLength(iid)) != MAXALIGN(IndexTupleSize(idxtuple)))
513 (errcode(ERRCODE_INDEX_CORRUPTED),
514 errmsg("index \"%s\" has inconsistent tuple sizes, block %u, offset %u",
515 RelationGetRelationName(rel), stack->blkno, i)));
516
517 current_key = gintuple_get_key(&state, idxtuple, &current_key_category);
518
519 /*
520 * Compare the entry to the preceding one.
521 *
522 * Don't check for high key on the rightmost inner page, as this
523 * key is not really stored explicitly.
524 *
525 * The entries may be for different attributes, so make sure to
526 * use ginCompareAttEntries for comparison.
527 */
528 if ((i != FirstOffsetNumber) &&
529 !(i == maxoff && rightlink == InvalidBlockNumber && !GinPageIsLeaf(page)))
530 {
531 Datum prev_key;
532 GinNullCategory prev_key_category;
533
534 prev_key = gintuple_get_key(&state, prev_tuple, &prev_key_category);
535 if (ginCompareAttEntries(&state, prev_attnum, prev_key,
536 prev_key_category, current_attnum,
537 current_key, current_key_category) >= 0)
539 (errcode(ERRCODE_INDEX_CORRUPTED),
540 errmsg("index \"%s\" has wrong tuple order on entry tree page, block %u, offset %u, rightlink %u",
541 RelationGetRelationName(rel), stack->blkno, i, rightlink)));
542 }
543
544 /*
545 * Check if this tuple is consistent with the downlink in the
546 * parent.
547 */
548 if (stack->parenttup &&
549 i == maxoff)
550 {
554 stack->parenttup,
556
560 {
561 /*
562 * There was a discrepancy between parent and child
563 * tuples. We need to verify it is not a result of
564 * concurrent call of gistplacetopage(). So, lock parent
565 * and try to find downlink for current page. It may be
566 * missing due to concurrent page split, this is OK.
567 */
568 pfree(stack->parenttup);
569 stack->parenttup = gin_refind_parent(rel, stack->parentblk,
570 stack->blkno, strategy);
571
572 /* We found it - make a final check before failing */
573 if (!stack->parenttup)
574 elog(NOTICE, "Unable to find parent tuple for block %u on block %u due to concurrent split",
575 stack->blkno, stack->parentblk);
576 else
577 {
580 stack->parenttup,
582
583 /*
584 * Check if it is properly adjusted. If succeed,
585 * proceed to the next key.
586 */
592 errmsg("index \"%s\" has inconsistent records on page %u offset %u",
593 RelationGetRelationName(rel), stack->blkno, i)));
594 }
595 }
596 }
597
598 /* If this is an internal page, recurse into the child */
599 if (!GinPageIsLeaf(page))
600 {
601 GinScanItem *ptr;
602
604 ptr->depth = stack->depth + 1;
605 /* last tuple in layer has no high key */
606 if (i == maxoff && rightlink == InvalidBlockNumber)
607 ptr->parenttup = NULL;
608 else
610 ptr->parentblk = stack->blkno;
612 ptr->next = stack->next;
613 stack->next = ptr;
614 }
615 /* If this item is a pointer to a posting tree, recurse into it */
616 else if (GinIsPostingTree(idxtuple))
617 {
619
621 }
622 else
623 {
625 int nipd;
626
628
629 for (int j = 0; j < nipd; j++)
630 {
634 errmsg("index \"%s\": posting list contains invalid heap pointer on block %u",
635 RelationGetRelationName(rel), stack->blkno)));
636 }
637 pfree(ipd);
638 }
639
642 }
643
644 UnlockReleaseBuffer(buffer);
645
646 /* Step to next item in the queue */
647 stack_next = stack->next;
648 if (stack->parenttup)
649 pfree(stack->parenttup);
650 pfree(stack);
651 stack = stack_next;
652 }
653
654 MemoryContextSwitchTo(oldcontext);
656}
657
658/*
659 * Verify that a freshly-read page looks sane.
660 */
661static void
663{
664 Page page = BufferGetPage(buffer);
665
666 /*
667 * ReadBuffer verifies that every newly-read page passes
668 * PageHeaderIsValid, which means it either contains a reasonably sane
669 * page header or is all-zero. We have to defend against the all-zero
670 * case, however.
671 */
672 if (PageIsNew(page))
675 errmsg("index \"%s\" contains unexpected zero page at block %u",
677 BufferGetBlockNumber(buffer)),
678 errhint("Please REINDEX it.")));
679
680 /*
681 * Additionally check that the special area looks sane.
682 */
683 if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
686 errmsg("index \"%s\" contains corrupted page at block %u",
688 BufferGetBlockNumber(buffer)),
689 errhint("Please REINDEX it.")));
690
691 if (GinPageIsDeleted(page))
692 {
693 if (!GinPageIsLeaf(page))
696 errmsg("index \"%s\" has deleted internal page %u",
701 errmsg("index \"%s\" has deleted page %u with tuples",
703 }
707 errmsg("index \"%s\" has page %u with exceeding count of tuples",
709}
710
711/*
712 * Try to re-find downlink pointing to 'blkno', in 'parentblkno'.
713 *
714 * If found, returns a palloc'd copy of the downlink tuple. Otherwise,
715 * returns NULL.
716 */
717static IndexTuple
719 BlockNumber childblkno, BufferAccessStrategy strategy)
720{
726
728 strategy);
729
732
734 {
736 return result;
737 }
738
741 {
742 ItemId p_iid = PageGetItemIdCareful(rel, parentblkno, parentpage, o);
744
745 if (GinGetDownlink(itup) == childblkno)
746 {
747 /* Found it! Make copy and return it */
748 result = CopyIndexTuple(itup);
749 break;
750 }
751 }
752
754
755 return result;
756}
757
758static ItemId
760 OffsetNumber offset)
761{
762 ItemId itemid = PageGetItemId(page, offset);
763
764 if (ItemIdGetOffset(itemid) + ItemIdGetLength(itemid) >
768 errmsg("line pointer points past end of tuple space in index \"%s\"",
770 errdetail_internal("Index tid=(%u,%u) lp_off=%u, lp_len=%u lp_flags=%u.",
771 block, offset, ItemIdGetOffset(itemid),
772 ItemIdGetLength(itemid),
773 ItemIdGetFlags(itemid))));
774
775 /*
776 * Verify that line pointer isn't LP_REDIRECT or LP_UNUSED or LP_DEAD,
777 * since GIN never uses all three. Verify that line pointer has storage,
778 * too.
779 */
780 if (ItemIdIsRedirected(itemid) || !ItemIdIsUsed(itemid) ||
781 ItemIdIsDead(itemid) || ItemIdGetLength(itemid) == 0)
784 errmsg("invalid line pointer storage in index \"%s\"",
786 errdetail_internal("Index tid=(%u,%u) lp_off=%u, lp_len=%u lp_flags=%u.",
787 block, offset, ItemIdGetOffset(itemid),
788 ItemIdGetLength(itemid),
789 ItemIdGetFlags(itemid))));
790
791 return itemid;
792}
#define InvalidAttrNumber
Definition attnum.h:23
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
static BlockNumber BlockIdGetBlockNumber(const BlockIdData *blockId)
Definition block.h:103
int Buffer
Definition buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4446
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5603
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:926
@ BAS_BULKREAD
Definition bufmgr.h:37
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:468
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334
@ RBM_NORMAL
Definition bufmgr.h:46
PageHeaderData * PageHeader
Definition bufpage.h:199
static uint16 PageGetSpecialSize(const PageData *page)
Definition bufpage.h:341
static bool PageIsNew(const PageData *page)
Definition bufpage.h:258
#define SizeOfPageHeaderData
Definition bufpage.h:241
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:268
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:378
PageData * Page
Definition bufpage.h:81
uint16 LocationIndex
Definition bufpage.h:90
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:396
#define MAXALIGN(LEN)
Definition c.h:896
#define Assert(condition)
Definition c.h:943
void * Pointer
Definition c.h:615
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int errcode(int sqlerrcode)
Definition elog.c:874
int int errdetail_internal(const char *fmt,...) pg_attribute_printf(1
int errhint(const char *fmt,...) pg_attribute_printf(1
#define DEBUG3
Definition elog.h:29
#define DEBUG1
Definition elog.h:31
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define NOTICE
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_object(type)
Definition fe_memutils.h:75
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition freelist.c:426
static int ginCompareAttEntries(GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
#define GIN_SHARE
Definition gin_private.h:52
#define GinIsPostingTree(itup)
Definition ginblock.h:231
#define GinPageGetOpaque(page)
Definition ginblock.h:110
#define GinGetPosting(itup)
Definition ginblock.h:238
#define GIN_ROOT_BLKNO
Definition ginblock.h:52
#define GinGetDownlink(itup)
Definition ginblock.h:257
#define GinItupIsCompressed(itup)
Definition ginblock.h:239
#define GinGetNPosting(itup)
Definition ginblock.h:228
#define GinDataPageGetRightBound(page)
Definition ginblock.h:288
#define GinGetPostingTree(itup)
Definition ginblock.h:233
#define GinPageIsData(page)
Definition ginblock.h:115
signed char GinNullCategory
Definition ginblock.h:206
#define ItemPointerSetMin(p)
Definition ginblock.h:166
#define GinDataPageGetPostingItem(page, i)
Definition ginblock.h:298
#define GinPageIsDeleted(page)
Definition ginblock.h:124
#define GinPageIsLeaf(page)
Definition ginblock.h:112
ItemPointer GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast)
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition ginutil.c:234
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition ginutil.c:267
void initGinState(GinState *state, Relation index)
Definition ginutil.c:104
#define nitems(x)
Definition indent.h:31
IndexTuple CopyIndexTuple(IndexTuple source)
Definition indextuple.c:479
int j
Definition isn.c:78
int i
Definition isn.c:77
#define ItemIdGetLength(itemId)
Definition itemid.h:59
#define ItemIdGetOffset(itemId)
Definition itemid.h:65
#define ItemIdIsDead(itemId)
Definition itemid.h:113
#define ItemIdIsUsed(itemId)
Definition itemid.h:92
#define ItemIdIsRedirected(itemId)
Definition itemid.h:106
#define ItemIdGetFlags(itemId)
Definition itemid.h:71
int32 ItemPointerCompare(const ItemPointerData *arg1, const ItemPointerData *arg2)
Definition itemptr.c:51
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
Definition itemptr.c:35
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition itemptr.h:124
static OffsetNumber ItemPointerGetOffsetNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:114
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
static BlockNumber ItemPointerGetBlockNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:93
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition itemptr.h:83
IndexTupleData * IndexTuple
Definition itup.h:53
static Size IndexTupleSize(const IndexTupleData *itup)
Definition itup.h:71
#define MaxIndexTuplesPerPage
Definition itup.h:181
#define AccessShareLock
Definition lockdefs.h:36
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
static char * errmsg
#define InvalidOffsetNumber
Definition off.h:26
#define OffsetNumberIsValid(offsetNumber)
Definition off.h:39
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define MAXPGPATH
#define snprintf
Definition port.h:260
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
static int fb(int x)
#define RelationGetRelationName(relation)
Definition rel.h:550
@ MAIN_FORKNUM
Definition relpath.h:58
BlockNumber parentblk
Definition verify_gin.c:52
ItemPointerData parentkey
Definition verify_gin.c:51
struct GinPostingTreeScanItem * next
Definition verify_gin.c:54
IndexTuple parenttup
Definition verify_gin.c:39
BlockNumber parentblk
Definition verify_gin.c:40
BlockNumber blkno
Definition verify_gin.c:41
struct GinScanItem * next
Definition verify_gin.c:42
ItemPointerData key
Definition ginblock.h:186
BlockIdData child_blkno
Definition ginblock.h:185
void amcheck_lock_relation_and_check(Oid indrelid, Oid am_id, IndexDoCheckCallback check, LOCKMODE lockmode, void *state)
Datum gin_index_check(PG_FUNCTION_ARGS)
Definition verify_gin.c:79
static IndexTuple gin_refind_parent(Relation rel, BlockNumber parentblkno, BlockNumber childblkno, BufferAccessStrategy strategy)
Definition verify_gin.c:718
static void gin_check_parent_keys_consistency(Relation rel, Relation heaprel, void *callback_state, bool readonly)
Definition verify_gin.c:389
static ItemPointer ginReadTupleWithoutState(IndexTuple itup, int *nitems)
Definition verify_gin.c:99
static void gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting_tree_root)
Definition verify_gin.c:134
static void check_index_page(Relation rel, Buffer buffer, BlockNumber blockNo)
Definition verify_gin.c:662
static ItemId PageGetItemIdCareful(Relation rel, BlockNumber block, Page page, OffsetNumber offset)
Definition verify_gin.c:759