mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	It turns out that the item size limit for btree indexes is about BLCKSZ/3,
not BLCKSZ/2 as some of us thought. Add check for oversize item so that failure is detected before corrupting the index, not after.
This commit is contained in:
		@@ -7,7 +7,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.51 1999/11/22 17:55:54 momjian Exp $
 | 
			
		||||
 *	  $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.52 1999/12/26 03:48:22 tgl Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@@ -267,6 +267,18 @@ _bt_insertonpg(Relation rel,
 | 
			
		||||
										 * this but we need to be
 | 
			
		||||
										 * consistent */
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Check whether the item can fit on a btree page at all.
 | 
			
		||||
	 * (Eventually, we ought to try to apply TOAST methods if not.)
 | 
			
		||||
	 * We actually need to be able to fit three items on every page,
 | 
			
		||||
	 * so restrict any one item to 1/3 the per-page available space.
 | 
			
		||||
	 * Note that at this point, itemsz doesn't include the ItemId.
 | 
			
		||||
	 */
 | 
			
		||||
	if (itemsz > (PageGetPageSize(page)-sizeof(PageHeaderData)-MAXALIGN(sizeof(BTPageOpaqueData)))/3 - sizeof(ItemIdData))
 | 
			
		||||
		elog(ERROR, "btree: index item size %d exceeds maximum %d",
 | 
			
		||||
			 itemsz,
 | 
			
		||||
			 (PageGetPageSize(page)-sizeof(PageHeaderData)-MAXALIGN(sizeof(BTPageOpaqueData)))/3 - sizeof(ItemIdData));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we have to insert item on the leftmost page which is the first
 | 
			
		||||
	 * page in the chain of duplicates then: 1. if scankey == hikey (i.e.
 | 
			
		||||
@@ -342,36 +354,42 @@ _bt_insertonpg(Relation rel,
 | 
			
		||||
	{
 | 
			
		||||
		OffsetNumber offnum = (P_RIGHTMOST(lpageop)) ? P_HIKEY : P_FIRSTKEY;
 | 
			
		||||
		OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
 | 
			
		||||
		ItemId		itid;
 | 
			
		||||
		BTItem		previtem,
 | 
			
		||||
					chkitem;
 | 
			
		||||
		Size		maxsize;
 | 
			
		||||
		Size		currsize;
 | 
			
		||||
 | 
			
		||||
		itid = PageGetItemId(page, offnum);
 | 
			
		||||
		previtem = (BTItem) PageGetItem(page, itid);
 | 
			
		||||
		maxsize = currsize = (ItemIdGetLength(itid) + sizeof(ItemIdData));
 | 
			
		||||
		for (offnum = OffsetNumberNext(offnum);
 | 
			
		||||
			 offnum <= maxoff; offnum = OffsetNumberNext(offnum))
 | 
			
		||||
		if (offnum < maxoff)	/* can't split unless at least 2 items... */
 | 
			
		||||
		{
 | 
			
		||||
			ItemId		itid;
 | 
			
		||||
			BTItem		previtem,
 | 
			
		||||
						chkitem;
 | 
			
		||||
			Size		maxsize;
 | 
			
		||||
			Size		currsize;
 | 
			
		||||
 | 
			
		||||
			/* find largest group of identically-keyed items on page */
 | 
			
		||||
			itid = PageGetItemId(page, offnum);
 | 
			
		||||
			chkitem = (BTItem) PageGetItem(page, itid);
 | 
			
		||||
			if (!_bt_itemcmp(rel, keysz, previtem, chkitem,
 | 
			
		||||
							 BTEqualStrategyNumber))
 | 
			
		||||
			previtem = (BTItem) PageGetItem(page, itid);
 | 
			
		||||
			maxsize = currsize = (ItemIdGetLength(itid) + sizeof(ItemIdData));
 | 
			
		||||
			for (offnum = OffsetNumberNext(offnum);
 | 
			
		||||
				 offnum <= maxoff; offnum = OffsetNumberNext(offnum))
 | 
			
		||||
			{
 | 
			
		||||
				if (currsize > maxsize)
 | 
			
		||||
					maxsize = currsize;
 | 
			
		||||
				currsize = 0;
 | 
			
		||||
				previtem = chkitem;
 | 
			
		||||
				itid = PageGetItemId(page, offnum);
 | 
			
		||||
				chkitem = (BTItem) PageGetItem(page, itid);
 | 
			
		||||
				if (!_bt_itemcmp(rel, keysz, previtem, chkitem,
 | 
			
		||||
								 BTEqualStrategyNumber))
 | 
			
		||||
				{
 | 
			
		||||
					if (currsize > maxsize)
 | 
			
		||||
						maxsize = currsize;
 | 
			
		||||
					currsize = 0;
 | 
			
		||||
					previtem = chkitem;
 | 
			
		||||
				}
 | 
			
		||||
				currsize += (ItemIdGetLength(itid) + sizeof(ItemIdData));
 | 
			
		||||
			}
 | 
			
		||||
			currsize += (ItemIdGetLength(itid) + sizeof(ItemIdData));
 | 
			
		||||
			if (currsize > maxsize)
 | 
			
		||||
				maxsize = currsize;
 | 
			
		||||
			/* Decide to split if largest group is > 1/2 page size */
 | 
			
		||||
			maxsize += sizeof(PageHeaderData) +
 | 
			
		||||
				MAXALIGN(sizeof(BTPageOpaqueData));
 | 
			
		||||
			if (maxsize >= PageGetPageSize(page) / 2)
 | 
			
		||||
				do_split = true;
 | 
			
		||||
		}
 | 
			
		||||
		if (currsize > maxsize)
 | 
			
		||||
			maxsize = currsize;
 | 
			
		||||
		maxsize += sizeof(PageHeaderData) +
 | 
			
		||||
			MAXALIGN(sizeof(BTPageOpaqueData));
 | 
			
		||||
		if (maxsize >= PageGetPageSize(page) / 2)
 | 
			
		||||
			do_split = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (do_split)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user