1
0
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:
Peter Geoghegan
2026-10-14 17:32:32 -04:00
parent 89e06d7829
commit 1d45c5da3a
2 changed files with 36 additions and 37 deletions

View File

@@ -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:

View File

@@ -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;