mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix btmarkpos/btrestrpos to handle array keys.
This fixes another error in commit 9e8da0f757.
I neglected to make the mark/restore functionality save and restore the
current set of array key values, which led to strange behavior if an
IndexScan with ScalarArrayOpExpr quals was used as the inner side of a
mergejoin.  Per bug #7570 from Melese Tesfaye.
			
			
This commit is contained in:
		@@ -583,6 +583,10 @@ btmarkpos(PG_FUNCTION_ARGS)
 | 
			
		||||
	else
 | 
			
		||||
		so->markItemIndex = -1;
 | 
			
		||||
 | 
			
		||||
	/* Also record the current positions of any array keys */
 | 
			
		||||
	if (so->numArrayKeys)
 | 
			
		||||
		_bt_mark_array_keys(scan);
 | 
			
		||||
 | 
			
		||||
	PG_RETURN_VOID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -595,6 +599,10 @@ btrestrpos(PG_FUNCTION_ARGS)
 | 
			
		||||
	IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
 | 
			
		||||
	BTScanOpaque so = (BTScanOpaque) scan->opaque;
 | 
			
		||||
 | 
			
		||||
	/* Restore the marked positions of any array keys */
 | 
			
		||||
	if (so->numArrayKeys)
 | 
			
		||||
		_bt_restore_array_keys(scan);
 | 
			
		||||
 | 
			
		||||
	if (so->markItemIndex >= 0)
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
 
 | 
			
		||||
@@ -595,6 +595,65 @@ _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir)
 | 
			
		||||
	return found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _bt_mark_array_keys() -- Handle array keys during btmarkpos
 | 
			
		||||
 *
 | 
			
		||||
 * Save the current state of the array keys as the "mark" position.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
_bt_mark_array_keys(IndexScanDesc scan)
 | 
			
		||||
{
 | 
			
		||||
	BTScanOpaque so = (BTScanOpaque) scan->opaque;
 | 
			
		||||
	int			i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < so->numArrayKeys; i++)
 | 
			
		||||
	{
 | 
			
		||||
		BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
 | 
			
		||||
 | 
			
		||||
		curArrayKey->mark_elem = curArrayKey->cur_elem;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _bt_restore_array_keys() -- Handle array keys during btrestrpos
 | 
			
		||||
 *
 | 
			
		||||
 * Restore the array keys to where they were when the mark was set.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
_bt_restore_array_keys(IndexScanDesc scan)
 | 
			
		||||
{
 | 
			
		||||
	BTScanOpaque so = (BTScanOpaque) scan->opaque;
 | 
			
		||||
	bool		changed = false;
 | 
			
		||||
	int			i;
 | 
			
		||||
 | 
			
		||||
	/* Restore each array key to its position when the mark was set */
 | 
			
		||||
	for (i = 0; i < so->numArrayKeys; i++)
 | 
			
		||||
	{
 | 
			
		||||
		BTArrayKeyInfo *curArrayKey = &so->arrayKeys[i];
 | 
			
		||||
		ScanKey		skey = &so->arrayKeyData[curArrayKey->scan_key];
 | 
			
		||||
		int			mark_elem = curArrayKey->mark_elem;
 | 
			
		||||
 | 
			
		||||
		if (curArrayKey->cur_elem != mark_elem)
 | 
			
		||||
		{
 | 
			
		||||
			curArrayKey->cur_elem = mark_elem;
 | 
			
		||||
			skey->sk_argument = curArrayKey->elem_values[mark_elem];
 | 
			
		||||
			changed = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we changed any keys, we must redo _bt_preprocess_keys.  That might
 | 
			
		||||
	 * sound like overkill, but in cases with multiple keys per index column
 | 
			
		||||
	 * it seems necessary to do the full set of pushups.
 | 
			
		||||
	 */
 | 
			
		||||
	if (changed)
 | 
			
		||||
	{
 | 
			
		||||
		_bt_preprocess_keys(scan);
 | 
			
		||||
		/* The mark should have been set on a consistent set of keys... */
 | 
			
		||||
		Assert(so->qual_ok);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	_bt_preprocess_keys() -- Preprocess scan keys
 | 
			
		||||
 
 | 
			
		||||
@@ -535,6 +535,7 @@ typedef struct BTArrayKeyInfo
 | 
			
		||||
{
 | 
			
		||||
	int			scan_key;		/* index of associated key in arrayKeyData */
 | 
			
		||||
	int			cur_elem;		/* index of current element in elem_values */
 | 
			
		||||
	int			mark_elem;		/* index of marked element in elem_values */
 | 
			
		||||
	int			num_elems;		/* number of elems in current array value */
 | 
			
		||||
	Datum	   *elem_values;	/* array of num_elems Datums */
 | 
			
		||||
} BTArrayKeyInfo;
 | 
			
		||||
@@ -665,6 +666,8 @@ extern void _bt_freestack(BTStack stack);
 | 
			
		||||
extern void _bt_preprocess_array_keys(IndexScanDesc scan);
 | 
			
		||||
extern void _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir);
 | 
			
		||||
extern bool _bt_advance_array_keys(IndexScanDesc scan, ScanDirection dir);
 | 
			
		||||
extern void _bt_mark_array_keys(IndexScanDesc scan);
 | 
			
		||||
extern void _bt_restore_array_keys(IndexScanDesc scan);
 | 
			
		||||
extern void _bt_preprocess_keys(IndexScanDesc scan);
 | 
			
		||||
extern IndexTuple _bt_checkkeys(IndexScanDesc scan,
 | 
			
		||||
			  Page page, OffsetNumber offnum,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user