Refactor handling of nbtree array redundancies.
authorPeter Geoghegan <pg@bowt.ie>
Sat, 21 Sep 2024 17:25:49 +0000 (13:25 -0400)
committerPeter Geoghegan <pg@bowt.ie>
Sat, 21 Sep 2024 17:25:49 +0000 (13:25 -0400)
Teach _bt_preprocess_array_keys to eliminate redundant array equality
scan keys directly, rather than just marking them as redundant.  Its
_bt_preprocess_keys caller is no longer required to ignore input scan
keys that were marked redundant in this way.  Oversights like the one
fixed by commit f22e17f7 are no longer possible.

The new scheme also makes it easier for _bt_preprocess_keys to output a
so.keyData[] scan key array with _more_ scan keys than it was passed in
its scan.keyData[] input scan key array.  An upcoming patch that adds
skip scan optimizations to nbtree will take advantage of this.

In passing, remove and rename certain _bt_preprocess_keys variables to
make the difference between our input scan key array and our output scan
key array clearer.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-By: Tomas Vondra <tomas@vondra.me>
Discussion: https://postgr.es/m/CAH2-Wz=9A_UtM7HzUThSkQ+BcrQsQZuNhWOvQWK06PRkEp=SKQ@mail.gmail.com

src/backend/access/nbtree/nbtutils.c

index c22ccec789d2a6aa1665bde375c72aae387e9ba3..b9f8149697674e5e6cd0fc477c1e25f02155ef0c 100644 (file)
@@ -41,8 +41,8 @@ typedef struct BTSortArrayContext
 
 typedef struct BTScanKeyPreproc
 {
-       ScanKey         skey;
-       int                     ikey;
+       ScanKey         inkey;
+       int                     inkeyi;
        int                     arrayidx;
 } BTScanKeyPreproc;
 
@@ -62,7 +62,7 @@ static bool _bt_compare_array_scankey_args(IndexScanDesc scan,
                                                                                   ScanKey arraysk, ScanKey skey,
                                                                                   FmgrInfo *orderproc, BTArrayKeyInfo *array,
                                                                                   bool *qual_ok);
-static ScanKey _bt_preprocess_array_keys(IndexScanDesc scan);
+static ScanKey _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys);
 static void _bt_preprocess_array_keys_final(IndexScanDesc scan, int *keyDataMap);
 static int     _bt_compare_array_elements(const void *a, const void *b, void *arg);
 static inline int32 _bt_compare_array_skey(FmgrInfo *orderproc,
@@ -248,12 +248,13 @@ _bt_freestack(BTStack stack)
  * as eliminating whole array scan keys as redundant.  It can also allow us to
  * detect contradictory quals.
  *
- * It is convenient for _bt_preprocess_keys caller to have to deal with no
- * more than one equality strategy array scan key per index attribute.  We'll
- * always be able to set things up that way when complete opfamilies are used.
- * Eliminated array scan keys can be recognized as those that have had their
- * sk_strategy field set to InvalidStrategy here by us.  Caller should avoid
- * including these in the scan's so->keyData[] output array.
+ * Caller must pass *new_numberOfKeys to give us a way to change the number of
+ * scan keys that caller treats as input to standard preprocessing steps.  The
+ * returned array is smaller than scan->keyData[] when we could eliminate a
+ * redundant array scan key (redundant with another array scan key).  It is
+ * convenient for _bt_preprocess_keys caller to have to deal with no more than
+ * one equality strategy array scan key per index attribute.  We'll always be
+ * able to set things up that way when complete opfamilies are used.
  *
  * We set the scan key references from the scan's BTArrayKeyInfo info array to
  * offsets into the temp modified input array returned to caller.  Scans that
@@ -266,13 +267,14 @@ _bt_freestack(BTStack stack)
  * without supplying a new set of scankey data.
  */
 static ScanKey
-_bt_preprocess_array_keys(IndexScanDesc scan)
+_bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
 {
        BTScanOpaque so = (BTScanOpaque) scan->opaque;
        Relation        rel = scan->indexRelation;
        int                     numberOfKeys = scan->numberOfKeys;
        int16      *indoption = rel->rd_indoption;
-       int                     numArrayKeys;
+       int                     numArrayKeys,
+                               output_ikey = 0;
        int                     origarrayatt = InvalidAttrNumber,
                                origarraykey = -1;
        Oid                     origelemtype = InvalidOid;
@@ -317,9 +319,8 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
 
        oldContext = MemoryContextSwitchTo(so->arrayContext);
 
-       /* Create modifiable copy of scan->keyData in the workspace context */
+       /* Create output scan keys in the workspace context */
        arrayKeyData = (ScanKey) palloc(numberOfKeys * sizeof(ScanKeyData));
-       memcpy(arrayKeyData, scan->keyData, numberOfKeys * sizeof(ScanKeyData));
 
        /* Allocate space for per-array data in the workspace context */
        so->arrayKeys = (BTArrayKeyInfo *) palloc(numArrayKeys * sizeof(BTArrayKeyInfo));
@@ -329,7 +330,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
 
        /* Now process each array key */
        numArrayKeys = 0;
-       for (int i = 0; i < numberOfKeys; i++)
+       for (int input_ikey = 0; input_ikey < numberOfKeys; input_ikey++)
        {
                FmgrInfo        sortproc;
                FmgrInfo   *sortprocp = &sortproc;
@@ -345,14 +346,21 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
                int                     num_nonnulls;
                int                     j;
 
-               cur = &arrayKeyData[i];
+               /*
+                * Provisionally copy scan key into arrayKeyData[] array we'll return
+                * to _bt_preprocess_keys caller
+                */
+               cur = &arrayKeyData[output_ikey];
+               *cur = scan->keyData[input_ikey];
+
                if (!(cur->sk_flags & SK_SEARCHARRAY))
+               {
+                       output_ikey++;          /* keep this non-array scan key */
                        continue;
+               }
 
                /*
-                * First, deconstruct the array into elements.  Anything allocated
-                * here (including a possibly detoasted array value) is in the
-                * workspace context.
+                * Deconstruct the array into elements
                 */
                arrayval = DatumGetArrayTypeP(cur->sk_argument);
                /* We could cache this data, but not clear it's worth it */
@@ -406,6 +414,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
                                        _bt_find_extreme_element(scan, cur, elemtype,
                                                                                         BTGreaterStrategyNumber,
                                                                                         elem_values, num_nonnulls);
+                               output_ikey++;  /* keep this transformed scan key */
                                continue;
                        case BTEqualStrategyNumber:
                                /* proceed with rest of loop */
@@ -416,6 +425,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
                                        _bt_find_extreme_element(scan, cur, elemtype,
                                                                                         BTLessStrategyNumber,
                                                                                         elem_values, num_nonnulls);
+                               output_ikey++;  /* keep this transformed scan key */
                                continue;
                        default:
                                elog(ERROR, "unrecognized StrategyNumber: %d",
@@ -432,7 +442,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
                 * sortproc just points to the same proc used during binary searches.
                 */
                _bt_setup_array_cmp(scan, cur, elemtype,
-                                                       &so->orderProcs[i], &sortprocp);
+                                                       &so->orderProcs[output_ikey], &sortprocp);
 
                /*
                 * Sort the non-null elements and eliminate any duplicates.  We must
@@ -476,11 +486,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
                                        break;
                                }
 
-                               /*
-                                * Indicate to _bt_preprocess_keys caller that it must ignore
-                                * this scan key
-                                */
-                               cur->sk_strategy = InvalidStrategy;
+                               /* Throw away this scan key/array */
                                continue;
                        }
 
@@ -511,13 +517,17 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
                 * Note: _bt_preprocess_array_keys_final will fix-up each array's
                 * scan_key field later on, after so->keyData[] has been finalized.
                 */
-               so->arrayKeys[numArrayKeys].scan_key = i;
+               so->arrayKeys[numArrayKeys].scan_key = output_ikey;
                so->arrayKeys[numArrayKeys].num_elems = num_elems;
                so->arrayKeys[numArrayKeys].elem_values = elem_values;
                numArrayKeys++;
+               output_ikey++;                  /* keep this scan key/array */
        }
 
+       /* Set final number of equality-type array keys */
        so->numArrayKeys = numArrayKeys;
+       /* Set number of scan keys remaining in arrayKeyData[] */
+       *new_numberOfKeys = output_ikey;
 
        MemoryContextSwitchTo(oldContext);
 
@@ -2463,7 +2473,8 @@ end_toplevel_scan:
  * The given search-type keys (taken from scan->keyData[])
  * are copied to so->keyData[] with possible transformation.
  * scan->numberOfKeys is the number of input keys, so->numberOfKeys gets
- * the number of output keys (possibly less, never greater).
+ * the number of output keys.  Calling here a second or subsequent time
+ * (during the same btrescan) is a no-op.
  *
  * The output keys are marked with additional sk_flags bits beyond the
  * system-standard bits supplied by the caller.  The DESC and NULLS_FIRST
@@ -2551,12 +2562,8 @@ _bt_preprocess_keys(IndexScanDesc scan)
        int                     new_numberOfKeys;
        int                     numberOfEqualCols;
        ScanKey         inkeys;
-       ScanKey         outkeys;
-       ScanKey         cur;
        BTScanKeyPreproc xform[BTMaxStrategyNumber];
        bool            test_result;
-       int                     i,
-                               j;
        AttrNumber      attno;
        ScanKey         arrayKeyData;
        int                *keyDataMap = NULL;
@@ -2584,7 +2591,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
                return;                                 /* done if qual-less scan */
 
        /* If any keys are SK_SEARCHARRAY type, set up array-key info */
-       arrayKeyData = _bt_preprocess_array_keys(scan);
+       arrayKeyData = _bt_preprocess_array_keys(scan, &numberOfKeys);
        if (!so->qual_ok)
        {
                /* unmatchable array, so give up */
@@ -2607,23 +2614,21 @@ _bt_preprocess_keys(IndexScanDesc scan)
        else
                inkeys = scan->keyData;
 
-       outkeys = so->keyData;
-       cur = &inkeys[0];
        /* we check that input keys are correctly ordered */
-       if (cur->sk_attno < 1)
+       if (inkeys[0].sk_attno < 1)
                elog(ERROR, "btree index keys must be ordered by attribute");
 
        /* We can short-circuit most of the work if there's just one key */
        if (numberOfKeys == 1)
        {
                /* Apply indoption to scankey (might change sk_strategy!) */
-               if (!_bt_fix_scankey_strategy(cur, indoption))
+               if (!_bt_fix_scankey_strategy(&inkeys[0], indoption))
                        so->qual_ok = false;
-               memcpy(outkeys, cur, sizeof(ScanKeyData));
+               memcpy(&so->keyData[0], &inkeys[0], sizeof(ScanKeyData));
                so->numberOfKeys = 1;
                /* We can mark the qual as required if it's for first index col */
-               if (cur->sk_attno == 1)
-                       _bt_mark_scankey_required(outkeys);
+               if (inkeys[0].sk_attno == 1)
+                       _bt_mark_scankey_required(&so->keyData[0]);
                if (arrayKeyData)
                {
                        /*
@@ -2631,8 +2636,8 @@ _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(cur->sk_flags & SK_SEARCHARRAY);
-                       Assert(cur->sk_strategy != BTEqualStrategyNumber ||
+                       Assert(so->keyData[0].sk_flags & SK_SEARCHARRAY);
+                       Assert(so->keyData[0].sk_strategy != BTEqualStrategyNumber ||
                                   (so->arrayKeys[0].scan_key == 0 &&
                                        OidIsValid(so->orderProcs[0].fn_oid)));
                }
@@ -2660,12 +2665,15 @@ _bt_preprocess_keys(IndexScanDesc scan)
         * handle after-last-key processing.  Actual exit from the loop is at the
         * "break" statement below.
         */
-       for (i = 0;; cur++, i++)
+       for (int i = 0;; i++)
        {
+               ScanKey         inkey = inkeys + i;
+               int                     j;
+
                if (i < numberOfKeys)
                {
                        /* Apply indoption to scankey (might change sk_strategy!) */
-                       if (!_bt_fix_scankey_strategy(cur, indoption))
+                       if (!_bt_fix_scankey_strategy(inkey, indoption))
                        {
                                /* NULL can't be matched, so give up */
                                so->qual_ok = false;
@@ -2677,12 +2685,12 @@ _bt_preprocess_keys(IndexScanDesc scan)
                 * If we are at the end of the keys for a particular attr, finish up
                 * processing and emit the cleaned-up keys.
                 */
-               if (i == numberOfKeys || cur->sk_attno != attno)
+               if (i == numberOfKeys || inkey->sk_attno != attno)
                {
                        int                     priorNumberOfEqualCols = numberOfEqualCols;
 
                        /* check input keys are correctly ordered */
-                       if (i < numberOfKeys && cur->sk_attno < attno)
+                       if (i < numberOfKeys && inkey->sk_attno < attno)
                                elog(ERROR, "btree index keys must be ordered by attribute");
 
                        /*
@@ -2696,9 +2704,9 @@ _bt_preprocess_keys(IndexScanDesc scan)
                         * check, and we've rejected any combination of it with a regular
                         * equality condition; but not with other types of conditions.
                         */
-                       if (xform[BTEqualStrategyNumber - 1].skey)
+                       if (xform[BTEqualStrategyNumber - 1].inkey)
                        {
-                               ScanKey         eq = xform[BTEqualStrategyNumber - 1].skey;
+                               ScanKey         eq = xform[BTEqualStrategyNumber - 1].inkey;
                                BTArrayKeyInfo *array = NULL;
                                FmgrInfo   *orderproc = NULL;
 
@@ -2707,7 +2715,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                        int                     eq_in_ikey,
                                                                eq_arrayidx;
 
-                                       eq_in_ikey = xform[BTEqualStrategyNumber - 1].ikey;
+                                       eq_in_ikey = xform[BTEqualStrategyNumber - 1].inkeyi;
                                        eq_arrayidx = xform[BTEqualStrategyNumber - 1].arrayidx;
                                        array = &so->arrayKeys[eq_arrayidx - 1];
                                        orderproc = so->orderProcs + eq_in_ikey;
@@ -2718,7 +2726,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
 
                                for (j = BTMaxStrategyNumber; --j >= 0;)
                                {
-                                       ScanKey         chk = xform[j].skey;
+                                       ScanKey         chk = xform[j].inkey;
 
                                        if (!chk || j == (BTEqualStrategyNumber - 1))
                                                continue;
@@ -2742,8 +2750,8 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                                }
                                                /* else discard the redundant non-equality key */
                                                Assert(!array || array->num_elems > 0);
-                                               xform[j].skey = NULL;
-                                               xform[j].ikey = -1;
+                                               xform[j].inkey = NULL;
+                                               xform[j].inkeyi = -1;
                                        }
                                        /* else, cannot determine redundancy, keep both keys */
                                }
@@ -2752,53 +2760,53 @@ _bt_preprocess_keys(IndexScanDesc scan)
                        }
 
                        /* try to keep only one of <, <= */
-                       if (xform[BTLessStrategyNumber - 1].skey
-                               && xform[BTLessEqualStrategyNumber - 1].skey)
+                       if (xform[BTLessStrategyNumber - 1].inkey &&
+                               xform[BTLessEqualStrategyNumber - 1].inkey)
                        {
-                               ScanKey         lt = xform[BTLessStrategyNumber - 1].skey;
-                               ScanKey         le = xform[BTLessEqualStrategyNumber - 1].skey;
+                               ScanKey         lt = xform[BTLessStrategyNumber - 1].inkey;
+                               ScanKey         le = xform[BTLessEqualStrategyNumber - 1].inkey;
 
                                if (_bt_compare_scankey_args(scan, le, lt, le, NULL, NULL,
                                                                                         &test_result))
                                {
                                        if (test_result)
-                                               xform[BTLessEqualStrategyNumber - 1].skey = NULL;
+                                               xform[BTLessEqualStrategyNumber - 1].inkey = NULL;
                                        else
-                                               xform[BTLessStrategyNumber - 1].skey = NULL;
+                                               xform[BTLessStrategyNumber - 1].inkey = NULL;
                                }
                        }
 
                        /* try to keep only one of >, >= */
-                       if (xform[BTGreaterStrategyNumber - 1].skey
-                               && xform[BTGreaterEqualStrategyNumber - 1].skey)
+                       if (xform[BTGreaterStrategyNumber - 1].inkey &&
+                               xform[BTGreaterEqualStrategyNumber - 1].inkey)
                        {
-                               ScanKey         gt = xform[BTGreaterStrategyNumber - 1].skey;
-                               ScanKey         ge = xform[BTGreaterEqualStrategyNumber - 1].skey;
+                               ScanKey         gt = xform[BTGreaterStrategyNumber - 1].inkey;
+                               ScanKey         ge = xform[BTGreaterEqualStrategyNumber - 1].inkey;
 
                                if (_bt_compare_scankey_args(scan, ge, gt, ge, NULL, NULL,
                                                                                         &test_result))
                                {
                                        if (test_result)
-                                               xform[BTGreaterEqualStrategyNumber - 1].skey = NULL;
+                                               xform[BTGreaterEqualStrategyNumber - 1].inkey = NULL;
                                        else
-                                               xform[BTGreaterStrategyNumber - 1].skey = NULL;
+                                               xform[BTGreaterStrategyNumber - 1].inkey = NULL;
                                }
                        }
 
                        /*
-                        * Emit the cleaned-up keys into the outkeys[] array, and then
+                        * Emit the cleaned-up keys into the so->keyData[] array, and then
                         * mark them if they are required.  They are required (possibly
                         * only in one direction) if all attrs before this one had "=".
                         */
                        for (j = BTMaxStrategyNumber; --j >= 0;)
                        {
-                               if (xform[j].skey)
+                               if (xform[j].inkey)
                                {
-                                       ScanKey         outkey = &outkeys[new_numberOfKeys++];
+                                       ScanKey         outkey = &so->keyData[new_numberOfKeys++];
 
-                                       memcpy(outkey, xform[j].skey, sizeof(ScanKeyData));
+                                       memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
                                        if (arrayKeyData)
-                                               keyDataMap[new_numberOfKeys - 1] = xform[j].ikey;
+                                               keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
                                        if (priorNumberOfEqualCols == attno - 1)
                                                _bt_mark_scankey_required(outkey);
                                }
@@ -2811,19 +2819,19 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                break;
 
                        /* Re-initialize for new attno */
-                       attno = cur->sk_attno;
+                       attno = inkey->sk_attno;
                        memset(xform, 0, sizeof(xform));
                }
 
                /* check strategy this key's operator corresponds to */
-               j = cur->sk_strategy - 1;
+               j = inkey->sk_strategy - 1;
 
                /* if row comparison, push it directly to the output array */
-               if (cur->sk_flags & SK_ROW_HEADER)
+               if (inkey->sk_flags & SK_ROW_HEADER)
                {
-                       ScanKey         outkey = &outkeys[new_numberOfKeys++];
+                       ScanKey         outkey = &so->keyData[new_numberOfKeys++];
 
-                       memcpy(outkey, cur, sizeof(ScanKeyData));
+                       memcpy(outkey, inkey, sizeof(ScanKeyData));
                        if (arrayKeyData)
                                keyDataMap[new_numberOfKeys - 1] = i;
                        if (numberOfEqualCols == attno - 1)
@@ -2837,21 +2845,10 @@ _bt_preprocess_keys(IndexScanDesc scan)
                        continue;
                }
 
-               /*
-                * Does this input scan key require further processing as an array?
-                */
-               if (cur->sk_strategy == InvalidStrategy)
-               {
-                       /* _bt_preprocess_array_keys marked this array key redundant */
-                       Assert(arrayKeyData);
-                       Assert(cur->sk_flags & SK_SEARCHARRAY);
-                       continue;
-               }
-
-               if (cur->sk_strategy == BTEqualStrategyNumber &&
-                       (cur->sk_flags & SK_SEARCHARRAY))
+               if (inkey->sk_strategy == BTEqualStrategyNumber &&
+                       (inkey->sk_flags & SK_SEARCHARRAY))
                {
-                       /* _bt_preprocess_array_keys kept this array key */
+                       /* must track how input scan keys map to arrays */
                        Assert(arrayKeyData);
                        arrayidx++;
                }
@@ -2860,11 +2857,11 @@ _bt_preprocess_keys(IndexScanDesc scan)
                 * have we seen a scan key for this same attribute and using this same
                 * operator strategy before now?
                 */
-               if (xform[j].skey == NULL)
+               if (xform[j].inkey == NULL)
                {
                        /* nope, so this scan key wins by default (at least for now) */
-                       xform[j].skey = cur;
-                       xform[j].ikey = i;
+                       xform[j].inkey = inkey;
+                       xform[j].inkeyi = i;
                        xform[j].arrayidx = arrayidx;
                }
                else
@@ -2881,7 +2878,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                /*
                                 * Have to set up array keys
                                 */
-                               if ((cur->sk_flags & SK_SEARCHARRAY))
+                               if (inkey->sk_flags & SK_SEARCHARRAY)
                                {
                                        array = &so->arrayKeys[arrayidx - 1];
                                        orderproc = so->orderProcs + i;
@@ -2889,12 +2886,12 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                        Assert(array->scan_key == i);
                                        Assert(OidIsValid(orderproc->fn_oid));
                                }
-                               else if ((xform[j].skey->sk_flags & SK_SEARCHARRAY))
+                               else if (xform[j].inkey->sk_flags & SK_SEARCHARRAY)
                                {
                                        array = &so->arrayKeys[xform[j].arrayidx - 1];
-                                       orderproc = so->orderProcs + xform[j].ikey;
+                                       orderproc = so->orderProcs + xform[j].inkeyi;
 
-                                       Assert(array->scan_key == xform[j].ikey);
+                                       Assert(array->scan_key == xform[j].inkeyi);
                                        Assert(OidIsValid(orderproc->fn_oid));
                                }
 
@@ -2909,7 +2906,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                 */
                        }
 
-                       if (_bt_compare_scankey_args(scan, cur, cur, xform[j].skey,
+                       if (_bt_compare_scankey_args(scan, inkey, inkey, xform[j].inkey,
                                                                                 array, orderproc, &test_result))
                        {
                                /* Have all we need to determine redundancy */
@@ -2921,10 +2918,10 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                         * New key is more restrictive, and so replaces old key...
                                         */
                                        if (j != (BTEqualStrategyNumber - 1) ||
-                                               !(xform[j].skey->sk_flags & SK_SEARCHARRAY))
+                                               !(xform[j].inkey->sk_flags & SK_SEARCHARRAY))
                                        {
-                                               xform[j].skey = cur;
-                                               xform[j].ikey = i;
+                                               xform[j].inkey = inkey;
+                                               xform[j].inkeyi = i;
                                                xform[j].arrayidx = arrayidx;
                                        }
                                        else
@@ -2936,7 +2933,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                                 * scan key.  _bt_compare_scankey_args expects us to
                                                 * always keep arrays (and discard non-arrays).
                                                 */
-                                               Assert(!(cur->sk_flags & SK_SEARCHARRAY));
+                                               Assert(!(inkey->sk_flags & SK_SEARCHARRAY));
                                        }
                                }
                                else if (j == (BTEqualStrategyNumber - 1))
@@ -2959,15 +2956,15 @@ _bt_preprocess_keys(IndexScanDesc scan)
                                 * even with incomplete opfamilies.  _bt_advance_array_keys
                                 * depends on this.
                                 */
-                               ScanKey         outkey = &outkeys[new_numberOfKeys++];
+                               ScanKey         outkey = &so->keyData[new_numberOfKeys++];
 
-                               memcpy(outkey, xform[j].skey, sizeof(ScanKeyData));
+                               memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
                                if (arrayKeyData)
-                                       keyDataMap[new_numberOfKeys - 1] = xform[j].ikey;
+                                       keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
                                if (numberOfEqualCols == attno - 1)
                                        _bt_mark_scankey_required(outkey);
-                               xform[j].skey = cur;
-                               xform[j].ikey = i;
+                               xform[j].inkey = inkey;
+                               xform[j].inkeyi = i;
                                xform[j].arrayidx = arrayidx;
                        }
                }
@@ -3380,13 +3377,6 @@ _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
                return true;
        }
 
-       if (skey->sk_strategy == InvalidStrategy)
-       {
-               /* Already-eliminated array scan key; don't need to fix anything */
-               Assert(skey->sk_flags & SK_SEARCHARRAY);
-               return true;
-       }
-
        /* Adjust strategy for DESC, if we didn't already */
        if ((addflags & SK_BT_DESC) && !(skey->sk_flags & SK_BT_DESC))
                skey->sk_strategy = BTCommuteStrategyNumber(skey->sk_strategy);