diff options
-rw-r--r-- | src/backend/access/brin/brin_pageops.c | 4 | ||||
-rw-r--r-- | src/backend/access/brin/brin_revmap.c | 4 | ||||
-rw-r--r-- | src/backend/access/brin/brin_xlog.c | 3 | ||||
-rw-r--r-- | src/backend/storage/page/bufpage.c | 62 | ||||
-rw-r--r-- | src/include/storage/bufpage.h | 5 |
5 files changed, 60 insertions, 18 deletions
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c index d0ca485caa6..6ebfedd6a97 100644 --- a/src/backend/access/brin/brin_pageops.c +++ b/src/backend/access/brin/brin_pageops.c @@ -179,8 +179,8 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange, START_CRIT_SECTION(); PageIndexDeleteNoCompact(oldpage, &oldoff, 1); - if (PageAddItem(oldpage, (Item) newtup, newsz, oldoff, true, - false) == InvalidOffsetNumber) + if (PageAddItemExtended(oldpage, (Item) newtup, newsz, oldoff, + PAI_OVERWRITE | PAI_ALLOW_FAR_OFFSET) == InvalidOffsetNumber) elog(ERROR, "failed to add BRIN tuple"); MarkBufferDirty(oldbuf); diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c index 812f76c71b8..853181b3fa1 100644 --- a/src/backend/access/brin/brin_revmap.c +++ b/src/backend/access/brin/brin_revmap.c @@ -272,6 +272,10 @@ brinGetTupleForHeapBlock(BrinRevmap *revmap, BlockNumber heapBlk, /* If we land on a revmap page, start over */ if (BRIN_IS_REGULAR_PAGE(page)) { + if (*off > PageGetMaxOffsetNumber(page)) + ereport(ERROR, + (errcode(ERRCODE_INDEX_CORRUPTED), + errmsg_internal("corrupted BRIN index: inconsistent range map"))); lp = PageGetItemId(page, *off); if (ItemIdIsUsed(lp)) { diff --git a/src/backend/access/brin/brin_xlog.c b/src/backend/access/brin/brin_xlog.c index deb7af4ca6e..6f3e37cc37c 100644 --- a/src/backend/access/brin/brin_xlog.c +++ b/src/backend/access/brin/brin_xlog.c @@ -193,7 +193,8 @@ brin_xlog_samepage_update(XLogReaderState *record) elog(PANIC, "brin_xlog_samepage_update: invalid max offset number"); PageIndexDeleteNoCompact(page, &offnum, 1); - offnum = PageAddItem(page, (Item) brintuple, tuplen, offnum, true, false); + offnum = PageAddItemExtended(page, (Item) brintuple, tuplen, offnum, + PAI_OVERWRITE | PAI_ALLOW_FAR_OFFSET); if (offnum == InvalidOffsetNumber) elog(PANIC, "brin_xlog_samepage_update: failed to add tuple"); diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index 0189bc9cc75..f2a07f21116 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -153,12 +153,13 @@ PageIsVerified(Page page, BlockNumber blkno) /* - * PageAddItem + * PageAddItemExtended * - * Add an item to a page. Return value is offset at which it was - * inserted, or InvalidOffsetNumber if there's not room to insert. + * Add an item to a page. Return value is the offset at which it was + * inserted, or InvalidOffsetNumber if the item is not inserted for any + * reason. A WARNING is issued indicating the reason for the refusal. * - * If overwrite is true, we just store the item at the specified + * If flag PAI_OVERWRITE is set, we just store the item at the specified * offsetNumber (which must be either a currently-unused item pointer, * or one past the last existing item). Otherwise, * if offsetNumber is valid and <= current max offset in the page, @@ -167,18 +168,20 @@ PageIsVerified(Page page, BlockNumber blkno) * If offsetNumber is not valid, then assign one by finding the first * one that is both unused and deallocated. * - * If is_heap is true, we enforce that there can't be more than + * If flag PAI_IS_HEAP is set, we enforce that there can't be more than * MaxHeapTuplesPerPage line pointers on the page. * + * If flag PAI_ALLOW_FAR_OFFSET is not set, we disallow placing items + * beyond one past the last existing item. + * * !!! EREPORT(ERROR) IS DISALLOWED HERE !!! */ OffsetNumber -PageAddItem(Page page, - Item item, - Size size, - OffsetNumber offsetNumber, - bool overwrite, - bool is_heap) +PageAddItemExtended(Page page, + Item item, + Size size, + OffsetNumber offsetNumber, + int flags) { PageHeader phdr = (PageHeader) page; Size alignedSize; @@ -209,7 +212,7 @@ PageAddItem(Page page, if (OffsetNumberIsValid(offsetNumber)) { /* yes, check it */ - if (overwrite) + if ((flags & PAI_OVERWRITE) != 0) { if (offsetNumber < limit) { @@ -257,13 +260,18 @@ PageAddItem(Page page, } } - if (offsetNumber > limit) + /* + * Reject placing items beyond the first unused line pointer, unless + * caller asked for that behavior specifically. + */ + if ((flags & PAI_ALLOW_FAR_OFFSET) == 0 && offsetNumber > limit) { elog(WARNING, "specified item offset is too large"); return InvalidOffsetNumber; } - if (is_heap && offsetNumber > MaxHeapTuplesPerPage) + /* Reject placing items beyond heap boundary, if heap */ + if ((flags & PAI_IS_HEAP) != 0 && offsetNumber > MaxHeapTuplesPerPage) { elog(WARNING, "can't put more than MaxHeapTuplesPerPage items in a heap page"); return InvalidOffsetNumber; @@ -275,7 +283,10 @@ PageAddItem(Page page, * Note: do arithmetic as signed ints, to avoid mistakes if, say, * alignedSize > pd_upper. */ - if (offsetNumber == limit || needshuffle) + if ((flags & PAI_ALLOW_FAR_OFFSET) != 0) + lower = Max(phdr->pd_lower, + SizeOfPageHeaderData + sizeof(ItemIdData) * offsetNumber); + else if (offsetNumber == limit || needshuffle) lower = phdr->pd_lower + sizeof(ItemIdData); else lower = phdr->pd_lower; @@ -324,6 +335,27 @@ PageAddItem(Page page, } /* + * PageAddItem + * + * Add an item to a page. Return value is offset at which it was + * inserted, or InvalidOffsetNumber if the item is not inserted for + * any reason. + * + * Passing the 'overwrite' and 'is_heap' parameters as true causes the + * PAI_OVERWRITE and PAI_IS_HEAP flags to be set, respectively. + * + * !!! EREPORT(ERROR) IS DISALLOWED HERE !!! + */ +OffsetNumber +PageAddItem(Page page, Item item, Size size, OffsetNumber offsetNumber, + bool overwrite, bool is_heap) +{ + return PageAddItemExtended(page, item, size, offsetNumber, + overwrite ? PAI_OVERWRITE : 0 | + is_heap ? PAI_IS_HEAP : 0); +} + +/* * PageGetTempPage * Get a temporary page in local memory for special processing. * The returned page is not initialized at all; caller must do that. diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index 63053d469a6..15cebfc60d6 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -407,11 +407,16 @@ do { \ * extern declarations * ---------------------------------------------------------------- */ +#define PAI_OVERWRITE (1 << 0) +#define PAI_IS_HEAP (1 << 1) +#define PAI_ALLOW_FAR_OFFSET (1 << 2) extern void PageInit(Page page, Size pageSize, Size specialSize); extern bool PageIsVerified(Page page, BlockNumber blkno); extern OffsetNumber PageAddItem(Page page, Item item, Size size, OffsetNumber offsetNumber, bool overwrite, bool is_heap); +extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size, + OffsetNumber offsetNumber, int flags); extern Page PageGetTempPage(Page page); extern Page PageGetTempPageCopy(Page page); extern Page PageGetTempPageCopySpecial(Page page); |