mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	Duplicates handling...
This commit is contained in:
		| @@ -7,7 +7,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *    $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.15 1997/06/06 03:11:42 vadim Exp $ | ||||
|  *    $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.16 1997/06/10 07:28:47 vadim Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -28,14 +28,16 @@ | ||||
| #endif | ||||
|  | ||||
| static InsertIndexResult _bt_insertonpg(Relation rel, Buffer buf, BTStack stack, int keysz, ScanKey scankey, BTItem btitem, BTItem afteritem); | ||||
| static Buffer _bt_split(Relation rel, Buffer buf, BTItem hiRightItem); | ||||
| static Buffer _bt_split(Relation rel, Buffer buf, OffsetNumber firstright); | ||||
| static OffsetNumber _bt_findsplitloc(Relation rel, Page page, OffsetNumber start, OffsetNumber maxoff, Size llimit); | ||||
| static void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf); | ||||
| static OffsetNumber _bt_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, BTItem btitem, BTItem afteritem); | ||||
| static bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey, BTItem afteritem); | ||||
| static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, BTItem oldItem, BTItem newItem); | ||||
| static bool _bt_isequal (TupleDesc itupdesc, Page page, OffsetNumber offnum, int keysz, ScanKey scankey); | ||||
| #if 0 | ||||
| static InsertIndexResult _bt_shift (Relation rel, Buffer buf, BTStack stack, int keysz, ScanKey scankey, BTItem btitem, BTItem hikey); | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  *  _bt_doinsert() -- Handle insertion of a single btitem in the tree. | ||||
| @@ -52,14 +54,13 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel | ||||
|     BTStack stack; | ||||
|     Buffer buf; | ||||
|     BlockNumber blkno; | ||||
|     int natts; | ||||
|     int natts = rel->rd_rel->relnatts; | ||||
|     InsertIndexResult res; | ||||
|      | ||||
|     itup = &(btitem->bti_itup); | ||||
|      | ||||
|     /* we need a scan key to do our search, so build one */ | ||||
|     itup_scankey = _bt_mkscankey(rel, itup); | ||||
|     natts = rel->rd_rel->relnatts; | ||||
|      | ||||
|     /* find the page containing this key */ | ||||
|     stack = _bt_search(rel, natts, itup_scankey, &buf); | ||||
| @@ -223,17 +224,13 @@ _bt_insertonpg(Relation rel, | ||||
| { | ||||
|     InsertIndexResult res; | ||||
|     Page page; | ||||
|     Buffer rbuf; | ||||
|     Buffer pbuf; | ||||
|     Page rpage; | ||||
|     BTItem ritem; | ||||
|     BTPageOpaque lpageop; | ||||
|     BTPageOpaque rpageop; | ||||
|     BlockNumber rbknum, itup_blkno; | ||||
|     BlockNumber itup_blkno; | ||||
|     OffsetNumber itup_off; | ||||
|     OffsetNumber firstright = InvalidOffsetNumber; | ||||
|     int itemsz; | ||||
|     Page ppage; | ||||
|     BTPageOpaque ppageop; | ||||
|     bool do_split = false; | ||||
|     bool keys_equal = false; | ||||
|      | ||||
|     page = BufferGetPage(buf); | ||||
|     lpageop = (BTPageOpaque) PageGetSpecialPointer(page); | ||||
| @@ -248,8 +245,9 @@ _bt_insertonpg(Relation rel, | ||||
|      * page in the chain of duplicates then: | ||||
|      * 1. if scankey == hikey (i.e. - new duplicate item) then | ||||
|      *    insert it here; | ||||
|      * 2. if scankey < hikey then we grab new page, copy current page | ||||
|      *    content there and insert new item on the current page. | ||||
|      * 2. if scankey < hikey then: | ||||
|      *    2.a if there is duplicate key(s) here - we force splitting; | ||||
|      *    2.b else - we may "eat" this page from duplicates chain. | ||||
|      */ | ||||
|     if ( lpageop->btpo_flags & BTP_CHAIN ) | ||||
|     { | ||||
| @@ -274,26 +272,105 @@ _bt_insertonpg(Relation rel, | ||||
|     	    if ( !_bt_skeycmp (rel, keysz, scankey, page, hitemid,  | ||||
|     	    				BTLessStrategyNumber) ) | ||||
| 	    	elog (FATAL, "btree: attempt to insert higher key on the leftmost page in the chain of duplicates"); | ||||
| 	    return (_bt_shift(rel, buf, stack, keysz, scankey, btitem, hitem)); | ||||
| 	    if ( maxoff > P_HIKEY )	/* have duplicate(s) */ | ||||
| 	    { | ||||
| 	    	firstright = P_FIRSTKEY; | ||||
| 	    	do_split = true; | ||||
| 	    } | ||||
| 	    else			/* "eat" page */ | ||||
| 	    { | ||||
|     		Buffer pbuf; | ||||
|     		Page ppage; | ||||
|     		 | ||||
|     		itup_blkno = BufferGetBlockNumber(buf); | ||||
|     		itup_off = PageAddItem(page, (Item) btitem, itemsz,  | ||||
|     						P_FIRSTKEY, LP_USED); | ||||
|     		if ( itup_off == InvalidOffsetNumber ) | ||||
|     		    elog (FATAL, "btree: failed to add item"); | ||||
|     		lpageop->btpo_flags &= ~BTP_CHAIN; | ||||
| 	    	pbuf = _bt_getstackbuf(rel, stack, BT_WRITE); | ||||
| 	    	ppage = BufferGetPage(pbuf); | ||||
|        		PageIndexTupleDelete(ppage, stack->bts_offset); | ||||
| 		pfree(stack->bts_btitem); | ||||
| 		stack->bts_btitem = _bt_formitem(&(btitem->bti_itup)); | ||||
| 		ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),  | ||||
| 			       itup_blkno, P_HIKEY); | ||||
| 		_bt_wrtbuf(rel, buf); | ||||
| 		res = _bt_insertonpg(rel, pbuf, stack->bts_parent, | ||||
| 					keysz, scankey, stack->bts_btitem, | ||||
| 					NULL); | ||||
|     		ItemPointerSet(&(res->pointerData), itup_blkno, itup_off); | ||||
|     		return (res); | ||||
| 	    } | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    keys_equal = true; | ||||
|     	    if ( PageGetFreeSpace(page) < itemsz ) | ||||
|     	    	do_split = true; | ||||
|     	} | ||||
|     } | ||||
|  | ||||
|      | ||||
|     if (PageGetFreeSpace(page) < itemsz) | ||||
|     else if ( PageGetFreeSpace(page) < itemsz ) | ||||
|     	do_split = true; | ||||
|     else if ( PageGetFreeSpace(page) < 3*itemsz + 2*sizeof(ItemIdData) ) | ||||
|     { | ||||
|     	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) ) | ||||
| 	{ | ||||
|     	    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)); | ||||
| 	} | ||||
|     	if ( currsize > maxsize ) | ||||
|     	    maxsize = currsize; | ||||
|     	maxsize += sizeof (PageHeaderData) +  | ||||
|     			DOUBLEALIGN (sizeof (BTPageOpaqueData)); | ||||
|     	if ( maxsize >= PageGetPageSize (page) / 2 ) | ||||
|     	    do_split = true; | ||||
|     } | ||||
|      | ||||
|     if ( do_split ) | ||||
|     { | ||||
|     	Buffer rbuf; | ||||
|     	Page rpage; | ||||
|     	BTItem ritem; | ||||
|     	BlockNumber rbknum; | ||||
|     	BTPageOpaque rpageop; | ||||
|     	Buffer pbuf; | ||||
|     	Page ppage; | ||||
|     	BTPageOpaque ppageop; | ||||
|     	BlockNumber bknum = BufferGetBlockNumber(buf); | ||||
|     	BTItem lowLeftItem; | ||||
|     	BTItem hiRightItem = NULL; | ||||
|     	OffsetNumber maxoff; | ||||
|     	bool shifted = false; | ||||
|     	bool left_chained = ( lpageop->btpo_flags & BTP_CHAIN ) ? true : false; | ||||
| 	 | ||||
| 	/*  | ||||
| 	 * If we have to split leaf page in the chain of duplicates | ||||
| 	 * then we try to look at our right sibling first. | ||||
| 	 * If we have to split leaf page in the chain of duplicates by | ||||
| 	 * new duplicate then we try to look at our right sibling first. | ||||
| 	 */ | ||||
| 	if ( ( lpageop->btpo_flags & BTP_CHAIN ) && | ||||
| 			( lpageop->btpo_flags & BTP_LEAF ) ) | ||||
| 		( lpageop->btpo_flags & BTP_LEAF ) && keys_equal ) | ||||
| 	{ | ||||
|     	    bool use_left = true; | ||||
|     	    bool keys_equal = false; | ||||
|     		 | ||||
| 	    rbuf = _bt_getbuf(rel, lpageop->btpo_next, BT_WRITE); | ||||
| 	    rpage = BufferGetPage(rbuf); | ||||
| @@ -309,29 +386,20 @@ _bt_insertonpg(Relation rel, | ||||
|     	    	{ | ||||
|     	    	    if ( !( rpageop->btpo_flags & BTP_CHAIN ) ) | ||||
|     	    	    	elog (FATAL, "btree: lost page in the chain of duplicates"); | ||||
|     	    	    keys_equal = true; | ||||
|     	    	} | ||||
|     	    	else if ( _bt_skeycmp (rel, keysz, scankey, rpage,  | ||||
|     	    			PageGetItemId(rpage, P_HIKEY),  | ||||
|     	    			BTGreaterStrategyNumber) ) | ||||
|     	            elog (FATAL, "btree: hikey is out of order"); | ||||
| 	    	/* | ||||
| 	    	 * If hikey > scankey and BTP_CHAIN is ON  | ||||
| 	   	 * then it's first page of the chain of higher keys: | ||||
| 	    	 * our left sibling hikey was lying! We can't add new  | ||||
| 	    	 * item here, but we can turn BTP_CHAIN off on our | ||||
| 	    	 * left page and overwrite its hikey. | ||||
|     	        else if ( rpageop->btpo_flags & BTP_CHAIN ) | ||||
| 	    	/*  | ||||
| 	    	 * If hikey > scankey then it's last page in chain and | ||||
| 	    	 * BTP_CHAIN must be OFF  | ||||
| 	    	 */ | ||||
| 	    	if ( !keys_equal && ( rpageop->btpo_flags & BTP_CHAIN ) ) | ||||
| 	    	{ | ||||
|     		    BTItem tmp; | ||||
|     		     | ||||
| 	    	    lpageop->btpo_flags &= ~BTP_CHAIN; | ||||
| 	    	    tmp = (BTItem) PageGetItem(rpage, PageGetItemId(rpage, P_HIKEY)); | ||||
| 	    	    hiRightItem = _bt_formitem(&(tmp->bti_itup)); | ||||
|     	    	} | ||||
|     	    	    elog (FATAL, "btree: lost last page in the chain of duplicates"); | ||||
|     	    	 | ||||
|     	    	/* if there is room here then we use this page. */ | ||||
|     	    	else if ( PageGetFreeSpace (rpage) > itemsz ) | ||||
|     	    	if ( PageGetFreeSpace (rpage) > itemsz ) | ||||
| 	    	    use_left = false; | ||||
| 	    } | ||||
| 	    else	/* rightmost page */ | ||||
| @@ -349,12 +417,70 @@ _bt_insertonpg(Relation rel, | ||||
| 	    } | ||||
| 	    _bt_relbuf(rel, rbuf, BT_WRITE); | ||||
| 	} | ||||
| 	/* | ||||
| 	 * If after splitting un-chained page we'll got chain of pages  | ||||
| 	 * with duplicates then we want to know  | ||||
| 	 * 1. on which of two pages new btitem will go (current | ||||
| 	 *    _bt_findsplitloc is quite bad); | ||||
| 	 * 2. what parent (if there's one) thinking about it | ||||
| 	 *    (remember about deletions) | ||||
| 	 */ | ||||
| 	else if ( !( lpageop->btpo_flags & BTP_CHAIN ) ) | ||||
| 	{ | ||||
|     	    OffsetNumber start = ( P_RIGHTMOST(lpageop) ) ? P_HIKEY : P_FIRSTKEY; | ||||
|     	    Size llimit; | ||||
|     	     | ||||
|     	    maxoff = PageGetMaxOffsetNumber (page); | ||||
|     	    llimit = PageGetPageSize(page) - sizeof (PageHeaderData) -  | ||||
|     	    		DOUBLEALIGN (sizeof (BTPageOpaqueData))  | ||||
|     	    		+ sizeof(ItemIdData); | ||||
|     	    llimit /= 2; | ||||
|     	    firstright = _bt_findsplitloc(rel, page, start, maxoff, llimit); | ||||
|     	     | ||||
|     	    if ( _bt_itemcmp (rel, keysz,  | ||||
| 	    	(BTItem) PageGetItem(page, PageGetItemId(page, start)), | ||||
| 	    	(BTItem) PageGetItem(page, PageGetItemId(page, firstright)),  | ||||
| 	    			BTEqualStrategyNumber) ) | ||||
| 	    { | ||||
|     	    	if ( _bt_skeycmp (rel, keysz, scankey, page,  | ||||
|     	    				PageGetItemId(page, firstright),  | ||||
|     	    				BTLessStrategyNumber) ) | ||||
|     	    	/*  | ||||
|     	    	 * force moving current items to the new page: | ||||
|     	    	 * new item will go on the current page. | ||||
|     	    	 */ | ||||
|     	    	    firstright = start; | ||||
|     	    	else | ||||
|     	    	/*  | ||||
|     	    	 * new btitem >= firstright, start item == firstright - | ||||
|     	    	 * new chain of duplicates: if this non-leftmost leaf | ||||
|     	    	 * page and parent item < start item then force moving | ||||
|     	    	 * all items to the new page - current page will be | ||||
|     	    	 * "empty" after it. | ||||
|     	    	 */ | ||||
|     	    	{ | ||||
|     	    	    if ( !P_LEFTMOST (lpageop) &&  | ||||
|     	    	    	( lpageop->btpo_flags & BTP_LEAF ) ) | ||||
|     	    	    { | ||||
| 	    		ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),  | ||||
| 			       bknum, P_HIKEY); | ||||
| 	    		pbuf = _bt_getstackbuf(rel, stack, BT_WRITE); | ||||
| 	    		if ( _bt_itemcmp (rel, keysz, stack->bts_btitem,  | ||||
| 	    				(BTItem) PageGetItem(page,  | ||||
| 	    					PageGetItemId(page, start)), | ||||
| 	                    		BTLessStrategyNumber) ) | ||||
| 	                { | ||||
|     	    	    	    firstright = start; | ||||
|     	    	    	    shifted = true; | ||||
|     	    	    	} | ||||
| 			_bt_relbuf(rel, pbuf, BT_WRITE); | ||||
|     	    	    } | ||||
|     	    	} | ||||
|     	    }	/* else - no new chain if start item < firstright one */ | ||||
| 	} | ||||
| 	 | ||||
| 	/* split the buffer into left and right halves */ | ||||
| 	rbuf = _bt_split(rel, buf, hiRightItem); | ||||
| 	 | ||||
| 	if ( hiRightItem != (BTItem) NULL ) | ||||
| 	    pfree (hiRightItem); | ||||
| 	rbuf = _bt_split(rel, buf, firstright); | ||||
| 	 | ||||
| 	/* which new page (left half or right half) gets the tuple? */ | ||||
| 	if (_bt_goesonpg(rel, buf, keysz, scankey, afteritem)) { | ||||
| @@ -369,13 +495,24 @@ _bt_insertonpg(Relation rel, | ||||
| 	    itup_blkno = BufferGetBlockNumber(rbuf); | ||||
| 	} | ||||
| 	 | ||||
| 	lowLeftItem = (BTItem) PageGetItem(page, | ||||
|     	maxoff = PageGetMaxOffsetNumber (page); | ||||
|     	if ( shifted ) | ||||
|     	{ | ||||
|     	    if ( maxoff > P_FIRSTKEY ) | ||||
|     	    	elog (FATAL, "btree: shifted page is not empty"); | ||||
|     	    lowLeftItem = (BTItem) NULL; | ||||
|     	} | ||||
|     	else | ||||
|     	{ | ||||
|     	    if ( maxoff < P_FIRSTKEY ) | ||||
|     	    	elog (FATAL, "btree: un-shifted page is empty"); | ||||
| 	    lowLeftItem = (BTItem) PageGetItem(page, | ||||
| 					 PageGetItemId(page, P_FIRSTKEY)); | ||||
| 	 | ||||
|     	if ( _bt_itemcmp (rel, keysz, lowLeftItem,  | ||||
| 	    if ( _bt_itemcmp (rel, keysz, lowLeftItem,  | ||||
| 	    	(BTItem) PageGetItem(page, PageGetItemId(page, P_HIKEY)),  | ||||
| 	    			BTEqualStrategyNumber) )  | ||||
| 	    lpageop->btpo_flags |= BTP_CHAIN; | ||||
| 	    	lpageop->btpo_flags |= BTP_CHAIN; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 *  By here, | ||||
| @@ -405,6 +542,8 @@ _bt_insertonpg(Relation rel, | ||||
|     	    BTItem new_item; | ||||
|     	    OffsetNumber upditem_offset = P_HIKEY; | ||||
|     	    bool do_update = false; | ||||
|     	    bool update_in_place = true; | ||||
|     	    bool parent_chained; | ||||
|  | ||||
| 	    /* form a index tuple that points at the new right page */ | ||||
| 	    rbknum = BufferGetBlockNumber(rbuf); | ||||
| @@ -449,6 +588,10 @@ _bt_insertonpg(Relation rel, | ||||
| 	    pbuf = _bt_getstackbuf(rel, stack, BT_WRITE); | ||||
| 	    ppage = BufferGetPage(pbuf); | ||||
| 	    ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage); | ||||
| 	    parent_chained = (( ppageop->btpo_flags & BTP_CHAIN )) ? true : false; | ||||
| 	     | ||||
| 	    if ( parent_chained && !left_chained ) | ||||
| 	    	elog (FATAL, "nbtree: unexpected chained parent of unchained page"); | ||||
| 	     | ||||
| 	    /* | ||||
| 	     *  If the key of new_item is < than the key of the item | ||||
| @@ -472,7 +615,8 @@ _bt_insertonpg(Relation rel, | ||||
| 	     */ | ||||
| 	    if ( _bt_itemcmp (rel, keysz, stack->bts_btitem, new_item, | ||||
| 	                    			BTGreaterStrategyNumber) || | ||||
| 	    		( _bt_itemcmp(rel, keysz, stack->bts_btitem,  | ||||
| 	    		( !shifted &&  | ||||
| 	    		  _bt_itemcmp(rel, keysz, stack->bts_btitem,  | ||||
| 	    				new_item, BTEqualStrategyNumber) && | ||||
| 	    		  _bt_itemcmp(rel, keysz, lowLeftItem,  | ||||
| 	    				new_item, BTLessStrategyNumber) ) ) | ||||
| @@ -491,34 +635,17 @@ _bt_insertonpg(Relation rel, | ||||
| 		    elog (FATAL, "btree: items are out of order (leftmost %d, stack %u, update %u)", | ||||
| 		    	P_LEFTMOST(lpageop), stack->bts_offset, upditem_offset); | ||||
| 	    } | ||||
| 	    /* | ||||
| 	     * There was bug caused by deletion all minimum keys (K1) from  | ||||
| 	     * an index page and insertion there (up to page splitting)  | ||||
| 	     * higher duplicate keys (K2): after it parent item for left | ||||
| 	     * page contained K1 and the next item (for new right page) - K2,  | ||||
| 	     * - and scan for the key = K2 lost items on the left page. | ||||
| 	     * So, we have to update parent item if its key < minimum | ||||
| 	     * key on the left and minimum keys on the left and on the right | ||||
| 	     * are equal. It would be nice to update hikey on the previous | ||||
| 	     * page of the left one too, but we may get deadlock here | ||||
| 	     * (read comments in _bt_split), so we leave previous page | ||||
| 	     * hikey _inconsistent_, but there should to be BTP_CHAIN flag | ||||
| 	     * on it, which privents _bt_moveright from dangerous movings  | ||||
| 	     * from there.	- vadim 05/27/97 | ||||
| 	     */ | ||||
| 	    else if ( _bt_itemcmp (rel, keysz, stack->bts_btitem,  | ||||
| 	    				lowLeftItem, BTLessStrategyNumber) &&  | ||||
| 	    		_bt_itemcmp (rel, keysz, new_item,  | ||||
| 	    				lowLeftItem, BTEqualStrategyNumber) )  | ||||
| 	    { | ||||
| 	        do_update = true; | ||||
| 	        upditem_offset = stack->bts_offset; | ||||
| 	    } | ||||
| 	     | ||||
| 	    if ( do_update ) | ||||
| 	    { | ||||
| 		/* Try to update in place. */ | ||||
| 	    	if ( DOUBLEALIGN (IndexTupleDSize (lowLeftItem->bti_itup)) == | ||||
| 	    	if ( shifted ) | ||||
|     	    	    elog (FATAL, "btree: attempt to update parent for shifted page"); | ||||
| 		/*  | ||||
| 		 * Try to update in place. If out parent page is chained | ||||
| 		 * then we must forse insertion. | ||||
| 		 */ | ||||
| 	    	if ( !parent_chained &&  | ||||
| 	    		DOUBLEALIGN (IndexTupleDSize (lowLeftItem->bti_itup)) == | ||||
|        			DOUBLEALIGN (IndexTupleDSize (stack->bts_btitem->bti_itup)) )  | ||||
|        		{ | ||||
| 		    _bt_updateitem(rel, keysz, pbuf,  | ||||
| @@ -528,6 +655,7 @@ _bt_insertonpg(Relation rel, | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 		    update_in_place = false; | ||||
|        		    PageIndexTupleDelete(ppage, upditem_offset); | ||||
| 		 | ||||
| 		   /*  | ||||
| @@ -543,14 +671,18 @@ _bt_insertonpg(Relation rel, | ||||
| 		    ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),  | ||||
| 			       bknum, P_HIKEY); | ||||
| 		 | ||||
| 		    /* unlock the children before doing this */ | ||||
| 		    /*  | ||||
| 		     * Unlock the children before doing this | ||||
| 		     * | ||||
| 		     * Mmm ... I foresee problems here.	- vadim 06/10/97 | ||||
| 		     */ | ||||
| 		    _bt_relbuf(rel, buf, BT_WRITE); | ||||
| 		    _bt_relbuf(rel, rbuf, BT_WRITE); | ||||
| 		 | ||||
| 		    /*  | ||||
| 		     * A regular _bt_binsrch should find the right place to | ||||
| 		     * put the new entry, since it should be either lower  | ||||
| 		     * than any other key on the page or unique.  | ||||
| 		     * put the new entry, since it should be lower than any  | ||||
| 		     * other key on the page.  | ||||
| 		     * Therefore set afteritem to NULL. | ||||
| 		     */ | ||||
| 		    newskey = _bt_mkscankey(rel, &(stack->bts_btitem->bti_itup)); | ||||
| @@ -575,9 +707,49 @@ _bt_insertonpg(Relation rel, | ||||
| 	    } | ||||
| 	     | ||||
| 	    newskey = _bt_mkscankey(rel, &(new_item->bti_itup)); | ||||
| 	     | ||||
| 	    afteritem = stack->bts_btitem; | ||||
| 	    if ( parent_chained && !update_in_place ) | ||||
| 	    { | ||||
| 	    	ppage = BufferGetPage(pbuf); | ||||
| 	    	ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage); | ||||
| 	    	if ( ppageop->btpo_flags & BTP_CHAIN ) | ||||
| 	    	    elog (FATAL, "btree: unexpected BTP_CHAIN flag in parent after update"); | ||||
| 	    	if ( P_RIGHTMOST (ppageop) ) | ||||
| 	    	    elog (FATAL, "btree: chained parent is RIGHTMOST after update"); | ||||
| 	    	maxoff = PageGetMaxOffsetNumber (ppage); | ||||
| 	    	if ( maxoff != P_FIRSTKEY ) | ||||
| 	    	    elog (FATAL, "btree: FIRSTKEY was unexpected in parent after update"); | ||||
|     	    	if ( _bt_skeycmp (rel, keysz, newskey, ppage,  | ||||
|     	    				PageGetItemId(ppage, P_FIRSTKEY),  | ||||
|     	    				BTLessEqualStrategyNumber) ) | ||||
| 	    	    elog (FATAL, "btree: parent FIRSTKEY is >= duplicate key after update"); | ||||
|     	    	if ( !_bt_skeycmp (rel, keysz, newskey, ppage,  | ||||
|     	    				PageGetItemId(ppage, P_HIKEY),  | ||||
|     	    				BTEqualStrategyNumber) ) | ||||
| 	    	    elog (FATAL, "btree: parent HIGHKEY is not equal duplicate key after update"); | ||||
| 	    	afteritem = (BTItem) NULL; | ||||
| 	    } | ||||
| 	    else if ( left_chained && !update_in_place ) | ||||
| 	    { | ||||
| 	    	ppage = BufferGetPage(pbuf); | ||||
| 	    	ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage); | ||||
| 	    	if ( !P_RIGHTMOST (ppageop) && | ||||
|     	    		_bt_skeycmp (rel, keysz, newskey, ppage,  | ||||
|     	    				PageGetItemId(ppage, P_HIKEY),  | ||||
|     	    				BTGreaterStrategyNumber) ) | ||||
| 	    	    afteritem = (BTItem) NULL; | ||||
| 	    } | ||||
| 	    if ( afteritem == (BTItem) NULL) | ||||
| 	    { | ||||
| 		rbuf = _bt_getbuf(rel, ppageop->btpo_next, BT_WRITE); | ||||
| 		_bt_relbuf(rel, pbuf, BT_WRITE); | ||||
| 		pbuf = rbuf; | ||||
| 	    } | ||||
| 	     | ||||
| 	    newres = _bt_insertonpg(rel, pbuf, stack->bts_parent, | ||||
| 				    keysz, newskey, new_item, | ||||
| 				    stack->bts_btitem); | ||||
| 				    afteritem); | ||||
| 	     | ||||
| 	    /* be tidy */ | ||||
| 	    pfree(newres); | ||||
| @@ -607,7 +779,7 @@ _bt_insertonpg(Relation rel, | ||||
|  *	pin and lock on buf are maintained. | ||||
|  */ | ||||
| static Buffer | ||||
| _bt_split(Relation rel, Buffer buf, BTItem hiRightItem) | ||||
| _bt_split(Relation rel, Buffer buf, OffsetNumber firstright) | ||||
| { | ||||
|     Buffer rbuf; | ||||
|     Page origpage; | ||||
| @@ -622,9 +794,7 @@ _bt_split(Relation rel, Buffer buf, BTItem hiRightItem) | ||||
|     OffsetNumber leftoff, rightoff; | ||||
|     OffsetNumber start; | ||||
|     OffsetNumber maxoff; | ||||
|     OffsetNumber firstright; | ||||
|     OffsetNumber i; | ||||
|     Size llimit; | ||||
|      | ||||
|     rbuf = _bt_getbuf(rel, P_NEW, BT_WRITE); | ||||
|     origpage = BufferGetPage(buf); | ||||
| @@ -666,23 +836,9 @@ _bt_split(Relation rel, Buffer buf, BTItem hiRightItem) | ||||
| 	/* splitting a non-rightmost page, start at the first data item */ | ||||
| 	start = P_FIRSTKEY; | ||||
|  | ||||
| 	/*  | ||||
| 	 * Copy the original high key to the new page if high key | ||||
| 	 * was not passed by caller. | ||||
| 	 */ | ||||
| 	if ( hiRightItem == NULL ) | ||||
| 	{ | ||||
| 	    itemid = PageGetItemId(origpage, P_HIKEY); | ||||
| 	    itemsz = ItemIdGetLength(itemid); | ||||
| 	    item = (BTItem) PageGetItem(origpage, itemid); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    item = hiRightItem; | ||||
|     	    itemsz = IndexTupleDSize(hiRightItem->bti_itup) | ||||
| 			+ (sizeof(BTItemData) - sizeof(IndexTupleData)); | ||||
|     	    itemsz = DOUBLEALIGN(itemsz); | ||||
| 	} | ||||
| 	itemid = PageGetItemId(origpage, P_HIKEY); | ||||
| 	itemsz = ItemIdGetLength(itemid); | ||||
| 	item = (BTItem) PageGetItem(origpage, itemid); | ||||
| 	if ( PageAddItem(rightpage, (Item) item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber ) | ||||
| 	    elog (FATAL, "btree: failed to add hikey to the right sibling"); | ||||
| 	rightoff = P_FIRSTKEY; | ||||
| @@ -694,8 +850,11 @@ _bt_split(Relation rel, Buffer buf, BTItem hiRightItem) | ||||
| 	rightoff = P_HIKEY; | ||||
|     } | ||||
|     maxoff = PageGetMaxOffsetNumber(origpage); | ||||
|     llimit = PageGetFreeSpace(leftpage) / 2; | ||||
|     firstright = _bt_findsplitloc(rel, origpage, start, maxoff, llimit); | ||||
|     if ( firstright == InvalidOffsetNumber ) | ||||
|     { | ||||
|     	Size llimit = PageGetFreeSpace(leftpage) / 2; | ||||
|     	firstright = _bt_findsplitloc(rel, origpage, start, maxoff, llimit); | ||||
|     } | ||||
|      | ||||
|     for (i = start; i <= maxoff; i = OffsetNumberNext(i)) { | ||||
| 	itemid = PageGetItemId(origpage, i); | ||||
| @@ -814,6 +973,9 @@ _bt_findsplitloc(Relation rel, | ||||
|     Size nbytes; | ||||
|     int natts; | ||||
|      | ||||
|     if ( start >= maxoff ) | ||||
|     	elog (FATAL, "btree: cannot split if start (%d) >= maxoff (%d)", | ||||
|     	    		start, maxoff); | ||||
|     natts = rel->rd_rel->relnatts; | ||||
|     saferight = start; | ||||
|     safeitemid = PageGetItemId(page, saferight); | ||||
| @@ -822,8 +984,8 @@ _bt_findsplitloc(Relation rel, | ||||
|      | ||||
|     i = OffsetNumberNext(start); | ||||
|      | ||||
|     while (nbytes < llimit) { | ||||
| 	 | ||||
|     while (nbytes < llimit) | ||||
|     { | ||||
| 	/* check the next item on the page */ | ||||
| 	nxtitemid = PageGetItemId(page, i); | ||||
| 	nbytes += (ItemIdGetLength(nxtitemid) + sizeof(ItemIdData)); | ||||
| @@ -840,7 +1002,10 @@ _bt_findsplitloc(Relation rel, | ||||
| 	    safeitem = nxtitem; | ||||
| 	    saferight = i; | ||||
| 	} | ||||
| 	i = OffsetNumberNext(i); | ||||
| 	if ( i < maxoff ) | ||||
| 	    i = OffsetNumberNext(i); | ||||
| 	else | ||||
| 	    break; | ||||
|     } | ||||
|      | ||||
|     /* | ||||
| @@ -851,6 +1016,9 @@ _bt_findsplitloc(Relation rel, | ||||
|     if (saferight == start) | ||||
| 	saferight = i; | ||||
|      | ||||
|     if ( saferight == maxoff  && ( maxoff - start ) > 1 ) | ||||
|     	saferight = start + ( maxoff - start ) / 2; | ||||
|      | ||||
|     return (saferight); | ||||
| } | ||||
|  | ||||
| @@ -1051,10 +1219,22 @@ _bt_goesonpg(Relation rel, | ||||
|      *  If we have no adjacency information, and the item is equal to the | ||||
|      *  high key on the page (by here it is), then the item does not belong | ||||
|      *  on this page. | ||||
|      * | ||||
|      *  Now it's not true in all cases.		- vadim 06/10/97 | ||||
|      */ | ||||
|      | ||||
|     if (afteritem == (BTItem) NULL) | ||||
|     { | ||||
|     	if ( opaque->btpo_flags & BTP_LEAF ) | ||||
| 	    return (false); | ||||
|     	if ( opaque->btpo_flags & BTP_CHAIN ) | ||||
| 	    return (true); | ||||
|     	if ( _bt_skeycmp (rel, keysz, scankey, page,  | ||||
|     				PageGetItemId(page, P_FIRSTKEY),  | ||||
|     				BTEqualStrategyNumber) ) | ||||
| 	    return (true); | ||||
| 	return (false); | ||||
|     } | ||||
|      | ||||
|     /* damn, have to work for it.  i hate that. */ | ||||
|     maxoff = PageGetMaxOffsetNumber(page); | ||||
| @@ -1269,6 +1449,7 @@ _bt_isequal (TupleDesc itupdesc, Page page, OffsetNumber offnum, | ||||
|     return (true); | ||||
| } | ||||
|  | ||||
| #if 0 | ||||
| /* | ||||
|  * _bt_shift - insert btitem on the passed page after shifting page  | ||||
|  *	       to the right in the tree. | ||||
| @@ -1404,3 +1585,4 @@ _bt_shift (Relation rel, Buffer buf, BTStack stack, int keysz, | ||||
|      | ||||
|     return (res); | ||||
| } | ||||
| #endif | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *    $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.20 1997/05/30 18:35:37 vadim Exp $ | ||||
|  *    $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.21 1997/06/10 07:28:50 vadim Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @@ -159,6 +159,7 @@ _bt_moveright(Relation rel, | ||||
|     BTPageOpaque opaque; | ||||
|     ItemId hikey; | ||||
|     BlockNumber rblkno; | ||||
|     int natts = rel->rd_rel->relnatts; | ||||
|          | ||||
|     page = BufferGetPage(buf); | ||||
|     opaque = (BTPageOpaque) PageGetSpecialPointer(page); | ||||
| @@ -195,26 +196,9 @@ _bt_moveright(Relation rel, | ||||
| 	     *  on this page to do not lose "good" tuples if number | ||||
| 	     *  of attrs > keysize. Example: (2,0) - last items on  | ||||
| 	     *  this page, (2,1) - first item on next page (hikey),  | ||||
| 	     *  our scankey is x = 2. Scankey >= (2,1) because of  | ||||
| 	     *  our scankey is x = 2. Scankey == (2,1) because of  | ||||
| 	     *  we compare first attrs only, but we shouldn't to move | ||||
| 	     *  right of here.		- vadim 04/15/97 | ||||
| 	     * | ||||
| 	     *  XXX | ||||
| 	     *  This code changed again! Actually, we break our | ||||
| 	     *  duplicates handling in single case: if we insert  | ||||
| 	     *  new minimum key into leftmost page with duplicates | ||||
| 	     *  and splitting doesn't occure then _bt_insertonpg doesn't  | ||||
| 	     *  worry about duplicates-rule. Fix _bt_insertonpg ? | ||||
| 	     *  But I don't see why don't compare scankey with _last_ | ||||
| 	     *  item on the page instead of first one, in any cases. | ||||
| 	     *  So - we do it in that way now.	- vadim 05/26/97 | ||||
| 	     * | ||||
| 	     *  Also, if we are on an "pseudo-empty" leaf page (i.e. there is | ||||
| 	     *  only hikey here) and scankey == hikey then we don't move | ||||
| 	     *  right! It's fix for bug described in _bt_insertonpg(). It's  | ||||
| 	     *  right - at least till index cleanups are perfomed by vacuum  | ||||
| 	     *  in exclusive mode: so, though this page may be just splitted,  | ||||
| 	     *  it may not be "emptied" before we got here. - vadim 05/27/97 | ||||
| 	     */ | ||||
| 	     | ||||
| 	    if ( _bt_skeycmp (rel, keysz, scankey, page, hikey,  | ||||
| @@ -227,14 +211,27 @@ _bt_moveright(Relation rel, | ||||
| 	    	} | ||||
| 	    	if ( offmax > P_HIKEY ) | ||||
| 	    	{ | ||||
| 		    if ( _bt_skeycmp (rel, keysz, scankey, page,  | ||||
| 	    	    if ( natts == keysz )	/* sanity checks */ | ||||
| 	    	    { | ||||
| 		    	if ( _bt_skeycmp (rel, keysz, scankey, page,  | ||||
| 		    			PageGetItemId (page, P_FIRSTKEY), | ||||
| 					BTEqualStrategyNumber) ) | ||||
| 			    elog (FATAL, "btree: BTP_CHAIN flag was expected"); | ||||
| 		    	if ( _bt_skeycmp (rel, keysz, scankey, page,  | ||||
| 		    			PageGetItemId (page, offmax), | ||||
| 					BTEqualStrategyNumber) ) | ||||
| 			    elog (FATAL, "btree: unexpected equal last item"); | ||||
| 		    	if ( _bt_skeycmp (rel, keysz, scankey, page,  | ||||
| 		    			PageGetItemId (page, offmax), | ||||
| 					BTLessStrategyNumber) ) | ||||
| 			    elog (FATAL, "btree: unexpected greater last item"); | ||||
| 			/* move right */ | ||||
| 		    } | ||||
| 		    else if ( _bt_skeycmp (rel, keysz, scankey, page,  | ||||
| 		    		PageGetItemId (page, offmax), | ||||
| 				BTLessEqualStrategyNumber) ) | ||||
| 		    	break; | ||||
| 	    	} | ||||
| 	    	else if ( offmax == P_HIKEY &&  | ||||
| 	    		( opaque->btpo_flags & BTP_LEAF ) ) | ||||
| 	    	    break; | ||||
| 	    } | ||||
| 	     | ||||
| 	    /* step right one page */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user