diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/nbtree/nbtutils.c | 210 |
1 files changed, 100 insertions, 110 deletions
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index c22ccec789d..b9f81496976 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -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); |