summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/brin/brin_pageops.c4
-rw-r--r--src/backend/access/brin/brin_revmap.c4
-rw-r--r--src/backend/access/brin/brin_xlog.c3
-rw-r--r--src/backend/storage/page/bufpage.c62
-rw-r--r--src/include/storage/bufpage.h5
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);