mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Unset SK_SEARCHARRAY when inequality arrays degenerate.
Initial array-specific preprocessing in _bt_preprocess_array_keys transforms inequality strategy SK_SEARCHARRAY scan keys into simple scalar scan keys, whose sk_argument contains the array's most restrictive element. The transformed keys nevertheless retained their SK_SEARCHARRAY markings. This approach left it up to everybody else to determine whether any given SK_SEARCHARRAY-marked key was an equality strategy key (which actually has an array) or an inequality key (which no longer has one). Simplify things by teaching preprocessing to unset SK_SEARCHARRAY from the flags for inequality scan keys, at the point where it already sets the key's sk_argument to a simple scalar datum. This makes it safe for code that runs after array preprocessing to assume that any key marked SK_SEARCHARRAY must be an equality key. This also fixes a minor inconsistency: _bt_advance_array_keys's precheck of the least significant key was skipped when that key came from a SAOP inequality, even though we were willing to apply that optimization given an inequality that had a scalar argument before preprocessing. Author: Peter Geoghegan <pg@bowt.ie> Discussion: https://postgr.es/m/CAH2-WznnuUH-fH84d60UHmDo4rO0Mio4_8DGvhxBo1yL0EwPng@mail.gmail.com Discussion: https://postgr.es/m/CAH2-Wznvj74CAwVydAs_Lh1hR3PGi_aN1s7BiRKE0iJYNdoixQ%40mail.gmail.com
This commit is contained in:
@@ -286,9 +286,11 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||
* (we'll miss out on the single value array transformation, but
|
||||
* that's not nearly as important when there's only one scan key)
|
||||
*/
|
||||
Assert(so->keyData[0].sk_flags & SK_SEARCHARRAY);
|
||||
Assert(so->keyData[0].sk_strategy == BTEqualStrategyNumber ||
|
||||
!(so->keyData[0].sk_flags & SK_SEARCHARRAY));
|
||||
Assert(so->keyData[0].sk_strategy != BTEqualStrategyNumber ||
|
||||
(so->arrayKeys[0].scan_key == 0 &&
|
||||
((so->keyData[0].sk_flags & SK_SEARCHARRAY) &&
|
||||
so->arrayKeys[0].scan_key == 0 &&
|
||||
!(so->keyData[0].sk_flags & SK_BT_SKIP) &&
|
||||
OidIsValid(so->orderProcs[0].fn_oid)));
|
||||
}
|
||||
@@ -493,10 +495,10 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||
/* check strategy this key's operator corresponds to */
|
||||
j = inkey->sk_strategy - 1;
|
||||
|
||||
if (inkey->sk_strategy == BTEqualStrategyNumber &&
|
||||
(inkey->sk_flags & SK_SEARCHARRAY))
|
||||
if (inkey->sk_flags & SK_SEARCHARRAY)
|
||||
{
|
||||
/* must track how input scan keys map to arrays */
|
||||
Assert(inkey->sk_strategy == BTEqualStrategyNumber);
|
||||
Assert(arrayKeyData);
|
||||
arrayidx++;
|
||||
}
|
||||
@@ -565,8 +567,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||
/*
|
||||
* New key is more restrictive, and so replaces old key...
|
||||
*/
|
||||
if (j != (BTEqualStrategyNumber - 1) ||
|
||||
!(xform[j].inkey->sk_flags & SK_SEARCHARRAY))
|
||||
if (!(xform[j].inkey->sk_flags & SK_SEARCHARRAY))
|
||||
{
|
||||
xform[j].inkey = inkey;
|
||||
xform[j].inkeyi = i;
|
||||
@@ -975,10 +976,8 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
|
||||
bool leftarray,
|
||||
rightarray;
|
||||
|
||||
leftarray = ((leftarg->sk_flags & SK_SEARCHARRAY) &&
|
||||
leftarg->sk_strategy == BTEqualStrategyNumber);
|
||||
rightarray = ((rightarg->sk_flags & SK_SEARCHARRAY) &&
|
||||
rightarg->sk_strategy == BTEqualStrategyNumber);
|
||||
leftarray = (leftarg->sk_flags & SK_SEARCHARRAY) != 0;
|
||||
rightarray = (rightarg->sk_flags & SK_SEARCHARRAY) != 0;
|
||||
|
||||
/*
|
||||
* _bt_preprocess_array_keys is responsible for merging together array
|
||||
@@ -1102,10 +1101,9 @@ _bt_compare_array_scankey_args(IndexScanDesc scan, ScanKey arraysk, ScanKey skey
|
||||
Assert(!(arraysk->sk_flags & (SK_ISNULL | SK_ROW_HEADER | SK_ROW_MEMBER)));
|
||||
Assert((arraysk->sk_flags & SK_SEARCHARRAY) &&
|
||||
arraysk->sk_strategy == BTEqualStrategyNumber);
|
||||
/* don't expect to have to deal with NULLs/row comparison scan keys */
|
||||
Assert(!(skey->sk_flags & (SK_ISNULL | SK_ROW_HEADER | SK_ROW_MEMBER)));
|
||||
Assert(!(skey->sk_flags & SK_SEARCHARRAY) ||
|
||||
skey->sk_strategy != BTEqualStrategyNumber);
|
||||
/* don't expect to have to deal with array/IS NULL/row compare skey */
|
||||
Assert(!(skey->sk_flags &
|
||||
(SK_SEARCHARRAY | SK_ISNULL | SK_ROW_HEADER | SK_ROW_MEMBER)));
|
||||
|
||||
/*
|
||||
* Just call the appropriate helper function based on whether it's a SAOP
|
||||
@@ -2078,6 +2076,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
|
||||
_bt_find_extreme_element(scan, cur, elemtype,
|
||||
BTGreaterStrategyNumber,
|
||||
elem_values, num_nonnulls);
|
||||
cur->sk_flags &= ~SK_SEARCHARRAY;
|
||||
numArrayKeyData++; /* keep this transformed scan key */
|
||||
continue;
|
||||
case BTEqualStrategyNumber:
|
||||
@@ -2089,6 +2088,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
|
||||
_bt_find_extreme_element(scan, cur, elemtype,
|
||||
BTLessStrategyNumber,
|
||||
elem_values, num_nonnulls);
|
||||
cur->sk_flags &= ~SK_SEARCHARRAY;
|
||||
numArrayKeyData++; /* keep this transformed scan key */
|
||||
continue;
|
||||
default:
|
||||
|
||||
@@ -548,6 +548,7 @@ _bt_start_array_keys(IndexScanDesc scan, ScanDirection dir)
|
||||
ScanKey skey = &so->keyData[array->scan_key];
|
||||
|
||||
Assert(skey->sk_flags & SK_SEARCHARRAY);
|
||||
Assert(skey->sk_strategy == BTEqualStrategyNumber);
|
||||
|
||||
_bt_array_set_low_or_high(rel, skey, array,
|
||||
ScanDirectionIsForward(dir));
|
||||
@@ -1196,18 +1197,17 @@ _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys,
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Only one _bt_check_compare call is required in the common case where
|
||||
* there are no equality strategy array scan keys. With array keys, we
|
||||
* can only accept _bt_check_compare's answer unreservedly when it set
|
||||
* pstate.continuescan=true.
|
||||
* Only one _bt_check_compare call is required when there are no array
|
||||
* scan keys. Otherwise, we can only accept _bt_check_compare's answer
|
||||
* unreservedly when it set pstate.continuescan=true.
|
||||
*/
|
||||
if (!arrayKeys || pstate->continuescan)
|
||||
return res;
|
||||
|
||||
/*
|
||||
* _bt_check_compare call set continuescan=false in the presence of
|
||||
* equality type array keys. This could mean that the tuple is just past
|
||||
* the end of matches for the current array keys.
|
||||
* _bt_check_compare call set continuescan=false in the presence of array
|
||||
* keys. This could mean that the tuple is just past the end of matches
|
||||
* for the current array keys.
|
||||
*
|
||||
* It's also possible that the scan is still _before_ the _start_ of
|
||||
* tuples matching the current set of array keys. Check for that first.
|
||||
@@ -1501,14 +1501,12 @@ _bt_check_compare(IndexScanDesc scan, ScanDirection dir,
|
||||
*continuescan = false;
|
||||
|
||||
/*
|
||||
* If this is a non-required equality-type array key, the tuple
|
||||
* needs to be checked against every possible array key. Handle
|
||||
* this by "advancing" the scan key's array to a matching value
|
||||
* (if we're successful then the tuple might match the qual).
|
||||
* If this is a non-required array key, the tuple needs to be
|
||||
* checked against every possible array key. Handle this by
|
||||
* "advancing" the scan key's array to a matching value (if we're
|
||||
* successful then the tuple might match the qual).
|
||||
*/
|
||||
else if (advancenonrequired &&
|
||||
key->sk_strategy == BTEqualStrategyNumber &&
|
||||
(key->sk_flags & SK_SEARCHARRAY))
|
||||
else if (advancenonrequired && (key->sk_flags & SK_SEARCHARRAY))
|
||||
return _bt_advance_array_keys(scan, NULL, tuple, tupnatts,
|
||||
tupdesc, *ikey, false);
|
||||
|
||||
@@ -2242,16 +2240,15 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,
|
||||
int32 result;
|
||||
int set_elem = 0;
|
||||
|
||||
if (cur->sk_strategy == BTEqualStrategyNumber)
|
||||
if (cur->sk_flags & SK_SEARCHARRAY)
|
||||
{
|
||||
/* Manage array state */
|
||||
if (cur->sk_flags & SK_SEARCHARRAY)
|
||||
{
|
||||
array = &so->arrayKeys[arrayidx++];
|
||||
Assert(array->scan_key == ikey);
|
||||
}
|
||||
array = &so->arrayKeys[arrayidx++];
|
||||
|
||||
Assert(array->scan_key == ikey);
|
||||
Assert(cur->sk_strategy == BTEqualStrategyNumber);
|
||||
}
|
||||
else
|
||||
else if (cur->sk_strategy != BTEqualStrategyNumber)
|
||||
{
|
||||
/*
|
||||
* Are any inequalities required in the opposite direction only
|
||||
@@ -3683,10 +3680,12 @@ _bt_verify_keys_with_arraykeys(IndexScanDesc scan)
|
||||
ScanKey cur = so->keyData + ikey;
|
||||
BTArrayKeyInfo *array;
|
||||
|
||||
if (cur->sk_strategy != BTEqualStrategyNumber ||
|
||||
!(cur->sk_flags & SK_SEARCHARRAY))
|
||||
if (!(cur->sk_flags & SK_SEARCHARRAY))
|
||||
continue;
|
||||
|
||||
if (cur->sk_strategy != BTEqualStrategyNumber)
|
||||
return false;
|
||||
|
||||
array = &so->arrayKeys[arrayidx++];
|
||||
if (array->scan_key != ikey)
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user