Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2973d7d

Browse files
committed
Fix PageAddItem BRIN bug
BRIN was relying on the ability to remove a tuple from an index page,then putting another tuple in the same line pointer. But PageAddItemrefuses to add a tuple beyond the first free item past the last useditem, and in particular, it rejects an attempt to add an item to anempty page anywhere other than the first line pointer. PageAddItemissues a WARNING and indicates to the caller that it failed, which inturn causes the BRIN calling code to issue a PANIC, so the wholesequence looks like this:WARNING: specified item offset is too largePANIC: failed to add BRIN tupleTo fix, create a new function PageAddItemExtended which is likePageAddItem except that the two boolean arguments become a flags bitmap;the "overwrite" and "is_heap" boolean flags in PageAddItem becomePAI_OVERWITE and PAI_IS_HEAP flags in the new function, and a new flagPAI_ALLOW_FAR_OFFSET enables the behavior required by BRIN.PageAddItem() retains its original signature, for compatibility withthird-party modules (other callers in core code are not modified,either).Also, in the belt-and-suspenders spirit, I added a new sanity check inbrinGetTupleForHeapBlock to raise an error if an TID found in the revmapis not marked as live by the page header. This causes it to react with"ERROR: corrupted BRIN index" to the bug at hand, rather than a hardcrash.Backpatch to 9.5.Bug reported by Andreas Seltenreich as detected by his handy sqlsmithfuzzer.Discussion:https://www.postgresql.org/message-id/87mvni77jh.fsf@elite.ansel.ydns.eu
1 parent73f5acc commit2973d7d

File tree

5 files changed

+60
-18
lines changed

5 files changed

+60
-18
lines changed

‎src/backend/access/brin/brin_pageops.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
179179

180180
START_CRIT_SECTION();
181181
PageIndexDeleteNoCompact(oldpage,&oldoff,1);
182-
if (PageAddItem(oldpage, (Item)newtup,newsz,oldoff, true,
183-
false)==InvalidOffsetNumber)
182+
if (PageAddItemExtended(oldpage, (Item)newtup,newsz,oldoff,
183+
PAI_OVERWRITE |PAI_ALLOW_FAR_OFFSET)==InvalidOffsetNumber)
184184
elog(ERROR,"failed to add BRIN tuple");
185185
MarkBufferDirty(oldbuf);
186186

‎src/backend/access/brin/brin_revmap.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@ brinGetTupleForHeapBlock(BrinRevmap *revmap, BlockNumber heapBlk,
266266
/* If we land on a revmap page, start over */
267267
if (BRIN_IS_REGULAR_PAGE(page))
268268
{
269+
if (*off>PageGetMaxOffsetNumber(page))
270+
ereport(ERROR,
271+
(errcode(ERRCODE_INDEX_CORRUPTED),
272+
errmsg_internal("corrupted BRIN index: inconsistent range map")));
269273
lp=PageGetItemId(page,*off);
270274
if (ItemIdIsUsed(lp))
271275
{

‎src/backend/access/brin/brin_xlog.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ brin_xlog_samepage_update(XLogReaderState *record)
193193
elog(PANIC,"brin_xlog_samepage_update: invalid max offset number");
194194

195195
PageIndexDeleteNoCompact(page,&offnum,1);
196-
offnum=PageAddItem(page, (Item)brintuple,tuplen,offnum, true, false);
196+
offnum=PageAddItemExtended(page, (Item)brintuple,tuplen,offnum,
197+
PAI_OVERWRITE |PAI_ALLOW_FAR_OFFSET);
197198
if (offnum==InvalidOffsetNumber)
198199
elog(PANIC,"brin_xlog_samepage_update: failed to add tuple");
199200

‎src/backend/storage/page/bufpage.c

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,13 @@ PageIsVerified(Page page, BlockNumber blkno)
153153

154154

155155
/*
156-
*PageAddItem
156+
*PageAddItemExtended
157157
*
158-
*Add an item to a page. Return value is offset at which it was
159-
*inserted, or InvalidOffsetNumber if there's not room to insert.
158+
*Add an item to a page. Return value is the offset at which it was
159+
*inserted, or InvalidOffsetNumber if the item is not inserted for any
160+
*reason. A WARNING is issued indicating the reason for the refusal.
160161
*
161-
*Ifoverwriteistrue, we just store the item at the specified
162+
*Ifflag PAI_OVERWRITEisset, we just store the item at the specified
162163
*offsetNumber (which must be either a currently-unused item pointer,
163164
*or one past the last existing item). Otherwise,
164165
*if offsetNumber is valid and <= current max offset in the page,
@@ -167,18 +168,20 @@ PageIsVerified(Page page, BlockNumber blkno)
167168
*If offsetNumber is not valid, then assign one by finding the first
168169
*one that is both unused and deallocated.
169170
*
170-
*Ifis_heapistrue, we enforce that there can't be more than
171+
*Ifflag PAI_IS_HEAPisset, we enforce that there can't be more than
171172
*MaxHeapTuplesPerPage line pointers on the page.
172173
*
174+
*If flag PAI_ALLOW_FAR_OFFSET is not set, we disallow placing items
175+
*beyond one past the last existing item.
176+
*
173177
*!!! EREPORT(ERROR) IS DISALLOWED HERE !!!
174178
*/
175179
OffsetNumber
176-
PageAddItem(Pagepage,
177-
Itemitem,
178-
Sizesize,
179-
OffsetNumberoffsetNumber,
180-
booloverwrite,
181-
boolis_heap)
180+
PageAddItemExtended(Pagepage,
181+
Itemitem,
182+
Sizesize,
183+
OffsetNumberoffsetNumber,
184+
intflags)
182185
{
183186
PageHeaderphdr= (PageHeader)page;
184187
SizealignedSize;
@@ -209,7 +212,7 @@ PageAddItem(Page page,
209212
if (OffsetNumberIsValid(offsetNumber))
210213
{
211214
/* yes, check it */
212-
if (overwrite)
215+
if ((flags&PAI_OVERWRITE)!=0)
213216
{
214217
if (offsetNumber<limit)
215218
{
@@ -257,13 +260,18 @@ PageAddItem(Page page,
257260
}
258261
}
259262

260-
if (offsetNumber>limit)
263+
/*
264+
* Reject placing items beyond the first unused line pointer, unless
265+
* caller asked for that behavior specifically.
266+
*/
267+
if ((flags&PAI_ALLOW_FAR_OFFSET)==0&&offsetNumber>limit)
261268
{
262269
elog(WARNING,"specified item offset is too large");
263270
returnInvalidOffsetNumber;
264271
}
265272

266-
if (is_heap&&offsetNumber>MaxHeapTuplesPerPage)
273+
/* Reject placing items beyond heap boundary, if heap */
274+
if ((flags&PAI_IS_HEAP)!=0&&offsetNumber>MaxHeapTuplesPerPage)
267275
{
268276
elog(WARNING,"can't put more than MaxHeapTuplesPerPage items in a heap page");
269277
returnInvalidOffsetNumber;
@@ -275,7 +283,10 @@ PageAddItem(Page page,
275283
* Note: do arithmetic as signed ints, to avoid mistakes if, say,
276284
* alignedSize > pd_upper.
277285
*/
278-
if (offsetNumber==limit||needshuffle)
286+
if ((flags&PAI_ALLOW_FAR_OFFSET)!=0)
287+
lower=Max(phdr->pd_lower,
288+
SizeOfPageHeaderData+sizeof(ItemIdData)*offsetNumber);
289+
elseif (offsetNumber==limit||needshuffle)
279290
lower=phdr->pd_lower+sizeof(ItemIdData);
280291
else
281292
lower=phdr->pd_lower;
@@ -323,6 +334,27 @@ PageAddItem(Page page,
323334
returnoffsetNumber;
324335
}
325336

337+
/*
338+
*PageAddItem
339+
*
340+
*Add an item to a page. Return value is offset at which it was
341+
*inserted, or InvalidOffsetNumber if the item is not inserted for
342+
*any reason.
343+
*
344+
*Passing the 'overwrite' and 'is_heap' parameters as true causes the
345+
*PAI_OVERWRITE and PAI_IS_HEAP flags to be set, respectively.
346+
*
347+
*!!! EREPORT(ERROR) IS DISALLOWED HERE !!!
348+
*/
349+
OffsetNumber
350+
PageAddItem(Pagepage,Itemitem,Sizesize,OffsetNumberoffsetNumber,
351+
booloverwrite,boolis_heap)
352+
{
353+
returnPageAddItemExtended(page,item,size,offsetNumber,
354+
overwrite ?PAI_OVERWRITE :0 |
355+
is_heap ?PAI_IS_HEAP :0);
356+
}
357+
326358
/*
327359
* PageGetTempPage
328360
*Get a temporary page in local memory for special processing.

‎src/include/storage/bufpage.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,11 +390,16 @@ do { \
390390
*extern declarations
391391
* ----------------------------------------------------------------
392392
*/
393+
#definePAI_OVERWRITE(1 << 0)
394+
#definePAI_IS_HEAP(1 << 1)
395+
#definePAI_ALLOW_FAR_OFFSET(1 << 2)
393396

394397
externvoidPageInit(Pagepage,SizepageSize,SizespecialSize);
395398
externboolPageIsVerified(Pagepage,BlockNumberblkno);
396399
externOffsetNumberPageAddItem(Pagepage,Itemitem,Sizesize,
397400
OffsetNumberoffsetNumber,booloverwrite,boolis_heap);
401+
externOffsetNumberPageAddItemExtended(Pagepage,Itemitem,Sizesize,
402+
OffsetNumberoffsetNumber,intflags);
398403
externPagePageGetTempPage(Pagepage);
399404
externPagePageGetTempPageCopy(Pagepage);
400405
externPagePageGetTempPageCopySpecial(Pagepage);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp