PostgreSQL Source Code git master
nbtpreprocesskeys.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * nbtpreprocesskeys.c
4 * Preprocessing for Postgres btree scan keys.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/access/nbtree/nbtpreprocesskeys.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "access/nbtree.h"
19#include "access/relscan.h"
20#include "common/int.h"
21#include "lib/qunique.h"
22#include "utils/array.h"
23#include "utils/lsyscache.h"
24#include "utils/memutils.h"
25#include "utils/rel.h"
26
27typedef struct BTScanKeyPreproc
28{
30 int inkeyi;
33
34typedef struct BTSortArrayContext
35{
38 bool reverse;
40
41static bool _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption);
42static void _bt_mark_scankey_required(ScanKey skey);
44 ScanKey leftarg, ScanKey rightarg,
45 BTArrayKeyInfo *array, FmgrInfo *orderproc,
46 bool *result);
48 ScanKey arraysk, ScanKey skey,
49 FmgrInfo *orderproc, BTArrayKeyInfo *array,
50 bool *qual_ok);
51static bool _bt_saoparray_shrink(IndexScanDesc scan, ScanKey arraysk,
52 ScanKey skey, FmgrInfo *orderproc,
53 BTArrayKeyInfo *array, bool *qual_ok);
54static bool _bt_skiparray_shrink(IndexScanDesc scan, ScanKey skey,
55 BTArrayKeyInfo *array, bool *qual_ok);
56static void _bt_skiparray_strat_adjust(IndexScanDesc scan, ScanKey arraysk,
57 BTArrayKeyInfo *array);
59 BTArrayKeyInfo *array);
61 BTArrayKeyInfo *array);
62static void _bt_unmark_keys(IndexScanDesc scan, int *keyDataMap);
63static int _bt_reorder_array_cmp(const void *a, const void *b);
64static ScanKey _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys);
65static void _bt_preprocess_array_keys_final(IndexScanDesc scan, int *keyDataMap);
66static int _bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out,
67 int *numSkipArrayKeys_out);
69 Oid elemtype, StrategyNumber strat,
70 const Datum *elems, int nelems);
71static void _bt_setup_array_cmp(IndexScanDesc scan, ScanKey skey, Oid elemtype,
72 FmgrInfo *orderproc, FmgrInfo **sortprocp);
73static int _bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc,
74 bool reverse, Datum *elems, int nelems);
75static bool _bt_merge_arrays(IndexScanDesc scan, ScanKey skey,
76 FmgrInfo *sortproc, bool reverse,
77 Oid origelemtype, Oid nextelemtype,
78 Datum *elems_orig, int *nelems_orig,
79 Datum *elems_next, int nelems_next);
80static int _bt_compare_array_elements(const void *a, const void *b, void *arg);
81
82
83/*
84 * _bt_preprocess_keys() -- Preprocess scan keys
85 *
86 * The given search-type keys (taken from scan->keyData[])
87 * are copied to so->keyData[] with possible transformation.
88 * scan->numberOfKeys is the number of input keys, so->numberOfKeys gets
89 * the number of output keys. Calling here a second or subsequent time
90 * (during the same btrescan) is a no-op.
91 *
92 * The output keys are marked with additional sk_flags bits beyond the
93 * system-standard bits supplied by the caller. The DESC and NULLS_FIRST
94 * indoption bits for the relevant index attribute are copied into the flags.
95 * Also, for a DESC column, we commute (flip) all the sk_strategy numbers
96 * so that the index sorts in the desired direction.
97 *
98 * One key purpose of this routine is to discover which scan keys must be
99 * satisfied to continue the scan. It also attempts to eliminate redundant
100 * keys and detect contradictory keys. (If the index opfamily provides
101 * incomplete sets of cross-type operators, we may fail to detect redundant
102 * or contradictory keys, but we can survive that.)
103 *
104 * Required output keys are sorted by index attribute. Presently we expect
105 * (but verify) that the input keys are already so sorted --- this is done
106 * by match_clauses_to_index() in indxpath.c. Some reordering of the keys
107 * within each attribute may be done as a byproduct of the processing here.
108 * That process must leave array scan keys (within an attribute) in the same
109 * order as corresponding entries from the scan's BTArrayKeyInfo array info.
110 * We might also construct skip array scan keys that weren't present in the
111 * original input keys; these are also output in standard attribute order.
112 *
113 * The output keys are marked with flags SK_BT_REQFWD and/or SK_BT_REQBKWD
114 * if they must be satisfied in order to continue the scan forward or backward
115 * respectively. _bt_checkkeys uses these flags. For example, if the quals
116 * are "x = 1 AND y < 4 AND z < 5", then _bt_checkkeys will reject a tuple
117 * (1,2,7), but we must continue the scan in case there are tuples (1,3,z).
118 * But once we reach tuples like (1,4,z) we can stop scanning because no
119 * later tuples could match. This is reflected by marking the x and y keys,
120 * but not the z key, with SK_BT_REQFWD. In general, the keys for leading
121 * attributes with "=" keys are marked both SK_BT_REQFWD and SK_BT_REQBKWD.
122 * For the first attribute without an "=" key, any "<" and "<=" keys are
123 * marked SK_BT_REQFWD while any ">" and ">=" keys are marked SK_BT_REQBKWD.
124 * This can be seen to be correct by considering the above example.
125 * (Actually, the z key _will_ be marked SK_BT_REQFWD, since preprocessing
126 * will generate a skip array on y -- except when DEBUG_DISABLE_SKIP_SCAN.
127 * See below description of how and why we generate skip array = keys in the
128 * presence of a "contradictory" condition such as "y < 4".)
129 *
130 * If we never generated skip array scan keys, it would be possible for "gaps"
131 * to appear that make it unsafe to mark any subsequent input scan keys
132 * (copied from scan->keyData[]) as required to continue the scan. Prior to
133 * Postgres 18, a qual like "WHERE y = 4" always resulted in a full scan.
134 * This qual now becomes "WHERE x = ANY('{every possible x value}') and y = 4"
135 * on output. In other words, preprocessing now adds a skip array on "x".
136 * This has the potential to be much more efficient than a full index scan
137 * (though it behaves like a full scan when there's many distinct "x" values).
138 *
139 * Typically, redundant keys are eliminated: we keep only the tightest
140 * >/>= bound and the tightest </<= bound, and if there's an = key then
141 * that's the only one returned. (So, we return either a single = key,
142 * or one or two boundary-condition keys for each attr.) However, if we
143 * cannot compare two keys for lack of a suitable cross-type operator,
144 * we cannot eliminate either key.
145 *
146 * When all redundant keys could not be eliminated, we'll output a key array
147 * that can more or less be treated as if it had no redundant keys. Suppose
148 * we have "x > 4::int AND x > 10::bigint AND x < 70", and we are unable to
149 * determine which > key is more restrictive for lack of a suitable cross-type
150 * operator. We'll arbitrarily pick one of the > keys; the other > key won't
151 * be marked required. Obviously, the scan will be less efficient if we
152 * choose x > 4 over x > 10 -- but it can still largely proceed as if there
153 * was only a single > condition. "x > 10" will be placed at the end of the
154 * so->keyData[] output array. It'll always be evaluated last, after the keys
155 * that could be marked required in the usual way (after "x > 4 AND x < 70").
156 * This can sometimes result in so->keyData[] keys that aren't even in index
157 * attribute order (if the qual involves multiple attributes). The scan's
158 * required keys will still be in attribute order, though, so it can't matter.
159 *
160 * This scheme ensures that _bt_first always uses the same set of keys at the
161 * start of a forwards scan as those _bt_checkkeys uses to determine when to
162 * end a similar backwards scan (and vice-versa). _bt_advance_array_keys
163 * depends on this: it expects to be able to reliably predict what the next
164 * _bt_first call will do by testing whether _bt_checkkeys' routines report
165 * that the final tuple on the page is past the end of matches for the scan's
166 * keys with the scan direction flipped. If it is (if continuescan=false),
167 * then it follows that calling _bt_first will, at a minimum, relocate the
168 * scan to the very next leaf page (in the current scan direction).
169 *
170 * As a byproduct of this work, we can detect contradictory quals such
171 * as "x = 1 AND x > 2". If we see that, we return so->qual_ok = false,
172 * indicating the scan need not be run at all since no tuples can match.
173 * (In this case we do not bother completing the output key array!)
174 * Again, missing cross-type operators might cause us to fail to prove the
175 * quals contradictory when they really are, but the scan will work correctly.
176 *
177 * Skip array = keys will even be generated in the presence of "contradictory"
178 * inequality quals when it'll enable marking later input quals as required.
179 * We'll merge any such inequalities into the generated skip array by setting
180 * its array.low_compare or array.high_compare key field. The resulting skip
181 * array will generate its array elements from a range that's constrained by
182 * any merged input inequalities (which won't get output in so->keyData[]).
183 *
184 * Row compares are treated as ordinary inequality comparisons on the row's
185 * first index column whenever possible. We treat their first subkey as if it
186 * was a simple scalar inequality for the purposes of the logic about required
187 * keys. This also gives us limited ability to detect contradictory/redundant
188 * conditions involving a row compare: we can do so whenever it involves an
189 * SK_ISNULL condition on a row compare's first column (the same rules used
190 * with simple inequalities work just as well here). We have no ability to
191 * detect redundant/contradictory conditions in any other row compare case.
192 * Note in particular that we are unable to merge a row comparison key into a
193 * skip array (only ordinary inequalities are merged). Any so->keyData[] key
194 * on a column that comes after a row comparison's first column can therefore
195 * never be marked as required at present.
196 *
197 * Note: the reason we have to copy the preprocessed scan keys into private
198 * storage is that we are modifying the array based on comparisons of the
199 * key argument values, which could change on a rescan. Therefore we can't
200 * overwrite the source data.
201 */
202void
204{
205 BTScanOpaque so = (BTScanOpaque) scan->opaque;
206 int numberOfKeys = scan->numberOfKeys;
207 int16 *indoption = scan->indexRelation->rd_indoption;
208 int new_numberOfKeys;
209 int numberOfEqualCols;
210 ScanKey inkeys;
212 bool test_result,
213 redundant_key_kept = false;
214 AttrNumber attno;
215 ScanKey arrayKeyData;
216 int *keyDataMap = NULL;
217 int arrayidx = 0;
218
219 if (so->numberOfKeys > 0)
220 {
221 /*
222 * Only need to do preprocessing once per btrescan, at most. All
223 * calls after the first are handled as no-ops.
224 */
225 return;
226 }
227
228 /* initialize result variables */
229 so->qual_ok = true;
230 so->numberOfKeys = 0;
231
232 if (numberOfKeys < 1)
233 return; /* done if qual-less scan */
234
235 /* If any keys are SK_SEARCHARRAY type, set up array-key info */
236 arrayKeyData = _bt_preprocess_array_keys(scan, &numberOfKeys);
237 if (!so->qual_ok)
238 {
239 /* unmatchable array, so give up */
240 return;
241 }
242
243 /*
244 * Treat arrayKeyData[] (a partially preprocessed copy of scan->keyData[])
245 * as our input if _bt_preprocess_array_keys just allocated it, else just
246 * use scan->keyData[]
247 */
248 if (arrayKeyData)
249 {
250 inkeys = arrayKeyData;
251
252 /* Also maintain keyDataMap for remapping so->orderProcs[] later */
253 keyDataMap = MemoryContextAlloc(so->arrayContext,
254 numberOfKeys * sizeof(int));
255
256 /*
257 * Also enlarge output array when it might otherwise not have room for
258 * a skip array's scan key
259 */
260 if (numberOfKeys > scan->numberOfKeys)
261 so->keyData = repalloc(so->keyData,
262 numberOfKeys * sizeof(ScanKeyData));
263 }
264 else
265 inkeys = scan->keyData;
266
267 /* we check that input keys are correctly ordered */
268 if (inkeys[0].sk_attno < 1)
269 elog(ERROR, "btree index keys must be ordered by attribute");
270
271 /* We can short-circuit most of the work if there's just one key */
272 if (numberOfKeys == 1)
273 {
274 /* Apply indoption to scankey (might change sk_strategy!) */
275 if (!_bt_fix_scankey_strategy(&inkeys[0], indoption))
276 so->qual_ok = false;
277 memcpy(&so->keyData[0], &inkeys[0], sizeof(ScanKeyData));
278 so->numberOfKeys = 1;
279 /* We can mark the qual as required if it's for first index col */
280 if (inkeys[0].sk_attno == 1)
282 if (arrayKeyData)
283 {
284 /*
285 * Don't call _bt_preprocess_array_keys_final in this fast path
286 * (we'll miss out on the single value array transformation, but
287 * that's not nearly as important when there's only one scan key)
288 */
291 (so->arrayKeys[0].scan_key == 0 &&
292 !(so->keyData[0].sk_flags & SK_BT_SKIP) &&
293 OidIsValid(so->orderProcs[0].fn_oid)));
294 }
295
296 return;
297 }
298
299 /*
300 * Otherwise, do the full set of pushups.
301 */
302 new_numberOfKeys = 0;
303 numberOfEqualCols = 0;
304
305 /*
306 * Initialize for processing of keys for attr 1.
307 *
308 * xform[i] points to the currently best scan key of strategy type i+1; it
309 * is NULL if we haven't yet found such a key for this attr.
310 */
311 attno = 1;
312 memset(xform, 0, sizeof(xform));
313
314 /*
315 * Loop iterates from 0 to numberOfKeys inclusive; we use the last pass to
316 * handle after-last-key processing. Actual exit from the loop is at the
317 * "break" statement below.
318 */
319 for (int i = 0;; i++)
320 {
321 ScanKey inkey = inkeys + i;
322 int j;
323
324 if (i < numberOfKeys)
325 {
326 /* Apply indoption to scankey (might change sk_strategy!) */
327 if (!_bt_fix_scankey_strategy(inkey, indoption))
328 {
329 /* NULL can't be matched, so give up */
330 so->qual_ok = false;
331 return;
332 }
333 }
334
335 /*
336 * If we are at the end of the keys for a particular attr, finish up
337 * processing and emit the cleaned-up keys.
338 */
339 if (i == numberOfKeys || inkey->sk_attno != attno)
340 {
341 int priorNumberOfEqualCols = numberOfEqualCols;
342
343 /* check input keys are correctly ordered */
344 if (i < numberOfKeys && inkey->sk_attno < attno)
345 elog(ERROR, "btree index keys must be ordered by attribute");
346
347 /*
348 * If = has been specified, all other keys can be eliminated as
349 * redundant. Note that this is no less true if the = key is
350 * SEARCHARRAY; the only real difference is that the inequality
351 * key _becomes_ redundant by making _bt_compare_scankey_args
352 * eliminate the subset of elements that won't need to be matched
353 * (with SAOP arrays and skip arrays alike).
354 *
355 * If we have a case like "key = 1 AND key > 2", we set qual_ok to
356 * false and abandon further processing. We'll do the same thing
357 * given a case like "key IN (0, 1) AND key > 2".
358 *
359 * We also have to deal with the case of "key IS NULL", which is
360 * unsatisfiable in combination with any other index condition. By
361 * the time we get here, that's been classified as an equality
362 * check, and we've rejected any combination of it with a regular
363 * equality condition; but not with other types of conditions.
364 */
365 if (xform[BTEqualStrategyNumber - 1].inkey)
366 {
367 ScanKey eq = xform[BTEqualStrategyNumber - 1].inkey;
368 BTArrayKeyInfo *array = NULL;
369 FmgrInfo *orderproc = NULL;
370
371 if (arrayKeyData && (eq->sk_flags & SK_SEARCHARRAY))
372 {
373 int eq_in_ikey,
374 eq_arrayidx;
375
376 eq_in_ikey = xform[BTEqualStrategyNumber - 1].inkeyi;
377 eq_arrayidx = xform[BTEqualStrategyNumber - 1].arrayidx;
378 array = &so->arrayKeys[eq_arrayidx - 1];
379 orderproc = so->orderProcs + eq_in_ikey;
380
381 Assert(array->scan_key == eq_in_ikey);
382 Assert(OidIsValid(orderproc->fn_oid));
383 }
384
385 for (j = BTMaxStrategyNumber; --j >= 0;)
386 {
387 ScanKey chk = xform[j].inkey;
388
389 if (!chk || j == (BTEqualStrategyNumber - 1))
390 continue;
391
392 if (eq->sk_flags & SK_SEARCHNULL)
393 {
394 /* IS NULL is contradictory to anything else */
395 so->qual_ok = false;
396 return;
397 }
398
399 if (_bt_compare_scankey_args(scan, chk, eq, chk,
400 array, orderproc,
401 &test_result))
402 {
403 if (!test_result)
404 {
405 /* keys proven mutually contradictory */
406 so->qual_ok = false;
407 return;
408 }
409 /* else discard the redundant non-equality key */
410 xform[j].inkey = NULL;
411 xform[j].inkeyi = -1;
412 }
413 else
414 redundant_key_kept = true;
415 }
416 /* track number of attrs for which we have "=" keys */
417 numberOfEqualCols++;
418 }
419
420 /* try to keep only one of <, <= */
421 if (xform[BTLessStrategyNumber - 1].inkey &&
422 xform[BTLessEqualStrategyNumber - 1].inkey)
423 {
424 ScanKey lt = xform[BTLessStrategyNumber - 1].inkey;
425 ScanKey le = xform[BTLessEqualStrategyNumber - 1].inkey;
426
427 if (_bt_compare_scankey_args(scan, le, lt, le, NULL, NULL,
428 &test_result))
429 {
430 if (test_result)
431 xform[BTLessEqualStrategyNumber - 1].inkey = NULL;
432 else
433 xform[BTLessStrategyNumber - 1].inkey = NULL;
434 }
435 else
436 redundant_key_kept = true;
437 }
438
439 /* try to keep only one of >, >= */
440 if (xform[BTGreaterStrategyNumber - 1].inkey &&
441 xform[BTGreaterEqualStrategyNumber - 1].inkey)
442 {
443 ScanKey gt = xform[BTGreaterStrategyNumber - 1].inkey;
444 ScanKey ge = xform[BTGreaterEqualStrategyNumber - 1].inkey;
445
446 if (_bt_compare_scankey_args(scan, ge, gt, ge, NULL, NULL,
447 &test_result))
448 {
449 if (test_result)
450 xform[BTGreaterEqualStrategyNumber - 1].inkey = NULL;
451 else
452 xform[BTGreaterStrategyNumber - 1].inkey = NULL;
453 }
454 else
455 redundant_key_kept = true;
456 }
457
458 /*
459 * Emit the cleaned-up keys into the so->keyData[] array, and then
460 * mark them if they are required. They are required (possibly
461 * only in one direction) if all attrs before this one had "=".
462 *
463 * In practice we'll rarely output non-required scan keys here;
464 * typically, _bt_preprocess_array_keys has already added "=" keys
465 * sufficient to form an unbroken series of "=" constraints on all
466 * attrs prior to the attr from the final scan->keyData[] key.
467 */
468 for (j = BTMaxStrategyNumber; --j >= 0;)
469 {
470 if (xform[j].inkey)
471 {
472 ScanKey outkey = &so->keyData[new_numberOfKeys++];
473
474 memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
475 if (arrayKeyData)
476 keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
477 if (priorNumberOfEqualCols == attno - 1)
479 }
480 }
481
482 /*
483 * Exit loop here if done.
484 */
485 if (i == numberOfKeys)
486 break;
487
488 /* Re-initialize for new attno */
489 attno = inkey->sk_attno;
490 memset(xform, 0, sizeof(xform));
491 }
492
493 /* check strategy this key's operator corresponds to */
494 j = inkey->sk_strategy - 1;
495
496 if (inkey->sk_strategy == BTEqualStrategyNumber &&
497 (inkey->sk_flags & SK_SEARCHARRAY))
498 {
499 /* must track how input scan keys map to arrays */
500 Assert(arrayKeyData);
501 arrayidx++;
502 }
503
504 /*
505 * have we seen a scan key for this same attribute and using this same
506 * operator strategy before now?
507 */
508 if (xform[j].inkey == NULL)
509 {
510 /* nope, so this scan key wins by default (at least for now) */
511 xform[j].inkey = inkey;
512 xform[j].inkeyi = i;
513 xform[j].arrayidx = arrayidx;
514 }
515 else
516 {
517 FmgrInfo *orderproc = NULL;
518 BTArrayKeyInfo *array = NULL;
519
520 /*
521 * Seen one of these before, so keep only the more restrictive key
522 * if possible
523 */
524 if (j == (BTEqualStrategyNumber - 1) && arrayKeyData)
525 {
526 /*
527 * Have to set up array keys
528 */
529 if (inkey->sk_flags & SK_SEARCHARRAY)
530 {
531 array = &so->arrayKeys[arrayidx - 1];
532 orderproc = so->orderProcs + i;
533
534 Assert(array->scan_key == i);
535 Assert(OidIsValid(orderproc->fn_oid));
536 Assert(!(inkey->sk_flags & SK_BT_SKIP));
537 }
538 else if (xform[j].inkey->sk_flags & SK_SEARCHARRAY)
539 {
540 array = &so->arrayKeys[xform[j].arrayidx - 1];
541 orderproc = so->orderProcs + xform[j].inkeyi;
542
543 Assert(array->scan_key == xform[j].inkeyi);
544 Assert(OidIsValid(orderproc->fn_oid));
545 Assert(!(xform[j].inkey->sk_flags & SK_BT_SKIP));
546 }
547
548 /*
549 * Both scan keys might have arrays, in which case we'll
550 * arbitrarily pass only one of the arrays. That won't
551 * matter, since _bt_compare_scankey_args is aware that two
552 * SEARCHARRAY scan keys mean that _bt_preprocess_array_keys
553 * failed to eliminate redundant arrays through array merging.
554 * _bt_compare_scankey_args just returns false when it sees
555 * this; it won't even try to examine either array.
556 */
557 }
558
559 if (_bt_compare_scankey_args(scan, inkey, inkey, xform[j].inkey,
560 array, orderproc, &test_result))
561 {
562 /* Have all we need to determine redundancy */
563 if (test_result)
564 {
565 /*
566 * New key is more restrictive, and so replaces old key...
567 */
568 if (j != (BTEqualStrategyNumber - 1) ||
569 !(xform[j].inkey->sk_flags & SK_SEARCHARRAY))
570 {
571 xform[j].inkey = inkey;
572 xform[j].inkeyi = i;
573 xform[j].arrayidx = arrayidx;
574 }
575 else
576 {
577 /*
578 * ...unless we have to keep the old key because it's
579 * an array that rendered the new key redundant. We
580 * need to make sure that we don't throw away an array
581 * scan key. _bt_preprocess_array_keys_final expects
582 * us to keep all of the arrays that weren't already
583 * eliminated by _bt_preprocess_array_keys earlier on.
584 */
585 Assert(!(inkey->sk_flags & SK_SEARCHARRAY));
586 }
587 }
588 else if (j == (BTEqualStrategyNumber - 1))
589 {
590 /* key == a && key == b, but a != b */
591 so->qual_ok = false;
592 return;
593 }
594 /* else old key is more restrictive, keep it */
595 }
596 else
597 {
598 /*
599 * We can't determine which key is more restrictive. Push
600 * xform[j] directly to the output array, then set xform[j] to
601 * the new scan key.
602 *
603 * Note: We do things this way around so that our arrays are
604 * always in the same order as their corresponding scan keys.
605 * _bt_preprocess_array_keys_final expects this.
606 */
607 ScanKey outkey = &so->keyData[new_numberOfKeys++];
608
609 memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
610 if (arrayKeyData)
611 keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
612 if (numberOfEqualCols == attno - 1)
614 xform[j].inkey = inkey;
615 xform[j].inkeyi = i;
616 xform[j].arrayidx = arrayidx;
617 redundant_key_kept = true;
618 }
619 }
620 }
621
622 so->numberOfKeys = new_numberOfKeys;
623
624 /*
625 * Now that we've built a temporary mapping from so->keyData[] (output
626 * scan keys) to arrayKeyData[] (our input scan keys), fix array->scan_key
627 * references. Also consolidate the so->orderProcs[] array such that it
628 * can be subscripted using so->keyData[]-wise offsets.
629 */
630 if (arrayKeyData)
631 _bt_preprocess_array_keys_final(scan, keyDataMap);
632
633 /*
634 * If there are remaining redundant inequality keys, we must make sure
635 * that each index attribute has no more than one required >/>= key, and
636 * no more than one required </<= key. Attributes that have one or more
637 * required = keys now must keep only one required key (the first = key).
638 */
639 if (unlikely(redundant_key_kept) && so->qual_ok)
640 _bt_unmark_keys(scan, keyDataMap);
641
642 /* Could pfree arrayKeyData/keyDataMap now, but not worth the cycles */
643}
644
645/*
646 * Adjust a scankey's strategy and flags setting as needed for indoptions.
647 *
648 * We copy the appropriate indoption value into the scankey sk_flags
649 * (shifting to avoid clobbering system-defined flag bits). Also, if
650 * the DESC option is set, commute (flip) the operator strategy number.
651 *
652 * A secondary purpose is to check for IS NULL/NOT NULL scankeys and set up
653 * the strategy field correctly for them.
654 *
655 * Lastly, for ordinary scankeys (not IS NULL/NOT NULL), we check for a
656 * NULL comparison value. Since all btree operators are assumed strict,
657 * a NULL means that the qual cannot be satisfied. We return true if the
658 * comparison value isn't NULL, or false if the scan should be abandoned.
659 *
660 * This function is applied to the *input* scankey structure; therefore
661 * on a rescan we will be looking at already-processed scankeys. Hence
662 * we have to be careful not to re-commute the strategy if we already did it.
663 * It's a bit ugly to modify the caller's copy of the scankey but in practice
664 * there shouldn't be any problem, since the index's indoptions are certainly
665 * not going to change while the scankey survives.
666 */
667static bool
669{
670 int addflags;
671
672 addflags = indoption[skey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
673
674 /*
675 * We treat all btree operators as strict (even if they're not so marked
676 * in pg_proc). This means that it is impossible for an operator condition
677 * with a NULL comparison constant to succeed, and we can reject it right
678 * away.
679 *
680 * However, we now also support "x IS NULL" clauses as search conditions,
681 * so in that case keep going. The planner has not filled in any
682 * particular strategy in this case, so set it to BTEqualStrategyNumber
683 * --- we can treat IS NULL as an equality operator for purposes of search
684 * strategy.
685 *
686 * Likewise, "x IS NOT NULL" is supported. We treat that as either "less
687 * than NULL" in a NULLS LAST index, or "greater than NULL" in a NULLS
688 * FIRST index.
689 *
690 * Note: someday we might have to fill in sk_collation from the index
691 * column's collation. At the moment this is a non-issue because we'll
692 * never actually call the comparison operator on a NULL.
693 */
694 if (skey->sk_flags & SK_ISNULL)
695 {
696 /* SK_ISNULL shouldn't be set in a row header scankey */
697 Assert(!(skey->sk_flags & SK_ROW_HEADER));
698
699 /* Set indoption flags in scankey (might be done already) */
700 skey->sk_flags |= addflags;
701
702 /* Set correct strategy for IS NULL or NOT NULL search */
703 if (skey->sk_flags & SK_SEARCHNULL)
704 {
706 skey->sk_subtype = InvalidOid;
707 skey->sk_collation = InvalidOid;
708 }
709 else if (skey->sk_flags & SK_SEARCHNOTNULL)
710 {
711 if (skey->sk_flags & SK_BT_NULLS_FIRST)
713 else
715 skey->sk_subtype = InvalidOid;
716 skey->sk_collation = InvalidOid;
717 }
718 else
719 {
720 /* regular qual, so it cannot be satisfied */
721 return false;
722 }
723
724 /* Needn't do the rest */
725 return true;
726 }
727
728 /* Adjust strategy for DESC, if we didn't already */
729 if ((addflags & SK_BT_DESC) && !(skey->sk_flags & SK_BT_DESC))
731 skey->sk_flags |= addflags;
732
733 /* If it's a row header, fix row member flags and strategies similarly */
734 if (skey->sk_flags & SK_ROW_HEADER)
735 {
736 ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
737
738 if (subkey->sk_flags & SK_ISNULL)
739 {
740 /* First row member is NULL, so RowCompare is unsatisfiable */
741 Assert(subkey->sk_flags & SK_ROW_MEMBER);
742 return false;
743 }
744
745 for (;;)
746 {
747 Assert(subkey->sk_flags & SK_ROW_MEMBER);
748 addflags = indoption[subkey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
749 if ((addflags & SK_BT_DESC) && !(subkey->sk_flags & SK_BT_DESC))
751 subkey->sk_flags |= addflags;
752 if (subkey->sk_flags & SK_ROW_END)
753 break;
754 subkey++;
755 }
756 }
757
758 return true;
759}
760
761/*
762 * Mark a scankey as "required to continue the scan".
763 *
764 * Depending on the operator type, the key may be required for both scan
765 * directions or just one. Also, if the key is a row comparison header,
766 * we have to mark the appropriate subsidiary ScanKeys as required. In such
767 * cases, the first subsidiary key is required, but subsequent ones are
768 * required only as long as they correspond to successive index columns and
769 * match the leading column as to sort direction. Otherwise the row
770 * comparison ordering is different from the index ordering and so we can't
771 * stop the scan on the basis of those lower-order columns.
772 *
773 * Note: when we set required-key flag bits in a subsidiary scankey, we are
774 * scribbling on a data structure belonging to the index AM's caller, not on
775 * our private copy. This should be OK because the marking will not change
776 * from scan to scan within a query, and so we'd just re-mark the same way
777 * anyway on a rescan. Something to keep an eye on though.
778 */
779static void
781{
782 int addflags;
783
784 switch (skey->sk_strategy)
785 {
788 addflags = SK_BT_REQFWD;
789 break;
791 addflags = SK_BT_REQFWD | SK_BT_REQBKWD;
792 break;
795 addflags = SK_BT_REQBKWD;
796 break;
797 default:
798 elog(ERROR, "unrecognized StrategyNumber: %d",
799 (int) skey->sk_strategy);
800 addflags = 0; /* keep compiler quiet */
801 break;
802 }
803
804 skey->sk_flags |= addflags;
805
806 if (skey->sk_flags & SK_ROW_HEADER)
807 {
808 ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
809 AttrNumber attno = skey->sk_attno;
810
811 /* First subkey should be same column/operator as the header */
812 Assert(subkey->sk_attno == attno);
813 Assert(subkey->sk_strategy == skey->sk_strategy);
814
815 for (;;)
816 {
817 Assert(subkey->sk_flags & SK_ROW_MEMBER);
818 if (subkey->sk_attno != attno)
819 break; /* non-adjacent key, so not required */
820 if (subkey->sk_strategy != skey->sk_strategy)
821 break; /* wrong direction, so not required */
822 subkey->sk_flags |= addflags;
823 if (subkey->sk_flags & SK_ROW_END)
824 break;
825 subkey++;
826 attno++;
827 }
828 }
829}
830
831/*
832 * Compare two scankey values using a specified operator.
833 *
834 * The test we want to perform is logically "leftarg op rightarg", where
835 * leftarg and rightarg are the sk_argument values in those ScanKeys, and
836 * the comparison operator is the one in the op ScanKey. However, in
837 * cross-data-type situations we may need to look up the correct operator in
838 * the index's opfamily: it is the one having amopstrategy = op->sk_strategy
839 * and amoplefttype/amoprighttype equal to the two argument datatypes.
840 *
841 * If the opfamily doesn't supply a complete set of cross-type operators we
842 * may not be able to make the comparison. If we can make the comparison
843 * we store the operator result in *result and return true. We return false
844 * if the comparison could not be made.
845 *
846 * If either leftarg or rightarg are an array, we'll apply array-specific
847 * rules to determine which array elements are redundant on behalf of caller.
848 * It is up to our caller to save whichever of the two scan keys is the array,
849 * and discard the non-array scan key (the non-array scan key is guaranteed to
850 * be redundant with any complete opfamily). Caller isn't expected to call
851 * here with a pair of array scan keys provided we're dealing with a complete
852 * opfamily (_bt_preprocess_array_keys will merge array keys together to make
853 * sure of that).
854 *
855 * Note: we'll also shrink caller's array as needed to eliminate redundant
856 * array elements. One reason why caller should prefer to discard non-array
857 * scan keys is so that we'll have the opportunity to shrink the array
858 * multiple times, in multiple calls (for each of several other scan keys on
859 * the same index attribute).
860 *
861 * Note: op always points at the same ScanKey as either leftarg or rightarg.
862 * Since we don't scribble on the scankeys themselves, this aliasing should
863 * cause no trouble.
864 *
865 * Note: this routine needs to be insensitive to any DESC option applied
866 * to the index column. For example, "x < 4" is a tighter constraint than
867 * "x < 5" regardless of which way the index is sorted.
868 */
869static bool
871 ScanKey leftarg, ScanKey rightarg,
872 BTArrayKeyInfo *array, FmgrInfo *orderproc,
873 bool *result)
874{
875 Relation rel = scan->indexRelation;
876 Oid lefttype,
877 righttype,
878 optype,
879 opcintype,
880 cmp_op;
881 StrategyNumber strat;
882
883 Assert(!((leftarg->sk_flags | rightarg->sk_flags) & SK_ROW_MEMBER));
884
885 /*
886 * First, deal with cases where one or both args are NULL. This should
887 * only happen when the scankeys represent IS NULL/NOT NULL conditions.
888 */
889 if ((leftarg->sk_flags | rightarg->sk_flags) & SK_ISNULL)
890 {
891 bool leftnull,
892 rightnull;
893
894 /* Handle skip array comparison with IS NOT NULL scan key */
895 if ((leftarg->sk_flags | rightarg->sk_flags) & SK_BT_SKIP)
896 {
897 /* Shouldn't generate skip array in presence of IS NULL key */
898 Assert(!((leftarg->sk_flags | rightarg->sk_flags) & SK_SEARCHNULL));
899 Assert((leftarg->sk_flags | rightarg->sk_flags) & SK_SEARCHNOTNULL);
900
901 /* Skip array will have no NULL element/IS NULL scan key */
902 Assert(array->num_elems == -1);
903 array->null_elem = false;
904
905 /* IS NOT NULL key (could be leftarg or rightarg) now redundant */
906 *result = true;
907 return true;
908 }
909
910 if (leftarg->sk_flags & SK_ISNULL)
911 {
913 leftnull = true;
914 }
915 else
916 leftnull = false;
917 if (rightarg->sk_flags & SK_ISNULL)
918 {
920 rightnull = true;
921 }
922 else
923 rightnull = false;
924
925 /*
926 * We treat NULL as either greater than or less than all other values.
927 * Since true > false, the tests below work correctly for NULLS LAST
928 * logic. If the index is NULLS FIRST, we need to flip the strategy.
929 */
930 strat = op->sk_strategy;
931 if (op->sk_flags & SK_BT_NULLS_FIRST)
932 strat = BTCommuteStrategyNumber(strat);
933
934 switch (strat)
935 {
937 *result = (leftnull < rightnull);
938 break;
940 *result = (leftnull <= rightnull);
941 break;
943 *result = (leftnull == rightnull);
944 break;
946 *result = (leftnull >= rightnull);
947 break;
949 *result = (leftnull > rightnull);
950 break;
951 default:
952 elog(ERROR, "unrecognized StrategyNumber: %d", (int) strat);
953 *result = false; /* keep compiler quiet */
954 break;
955 }
956 return true;
957 }
958
959 /*
960 * We don't yet know how to determine redundancy when it involves a row
961 * compare key (barring simple cases involving IS NULL/IS NOT NULL)
962 */
963 if ((leftarg->sk_flags | rightarg->sk_flags) & SK_ROW_HEADER)
964 {
965 Assert(!((leftarg->sk_flags | rightarg->sk_flags) & SK_BT_SKIP));
966 return false;
967 }
968
969 /*
970 * If either leftarg or rightarg are equality-type array scankeys, we need
971 * specialized handling (since by now we know that IS NULL wasn't used)
972 */
973 if (array)
974 {
975 bool leftarray,
976 rightarray;
977
978 leftarray = ((leftarg->sk_flags & SK_SEARCHARRAY) &&
980 rightarray = ((rightarg->sk_flags & SK_SEARCHARRAY) &&
982
983 /*
984 * _bt_preprocess_array_keys is responsible for merging together array
985 * scan keys, and will do so whenever the opfamily has the required
986 * cross-type support. If it failed to do that, we handle it just
987 * like the case where we can't make the comparison ourselves.
988 */
989 if (leftarray && rightarray)
990 {
991 /* Can't make the comparison */
992 *result = false; /* suppress compiler warnings */
993 Assert(!((leftarg->sk_flags | rightarg->sk_flags) & SK_BT_SKIP));
994 return false;
995 }
996
997 /*
998 * Otherwise we need to determine if either one of leftarg or rightarg
999 * uses an array, then pass this through to a dedicated helper
1000 * function.
1001 */
1002 if (leftarray)
1003 return _bt_compare_array_scankey_args(scan, leftarg, rightarg,
1004 orderproc, array, result);
1005 else if (rightarray)
1006 return _bt_compare_array_scankey_args(scan, rightarg, leftarg,
1007 orderproc, array, result);
1008
1009 /* FALL THRU */
1010 }
1011
1012 /*
1013 * The opfamily we need to worry about is identified by the index column.
1014 */
1015 Assert(leftarg->sk_attno == rightarg->sk_attno);
1016
1017 opcintype = rel->rd_opcintype[leftarg->sk_attno - 1];
1018
1019 /*
1020 * Determine the actual datatypes of the ScanKey arguments. We have to
1021 * support the convention that sk_subtype == InvalidOid means the opclass
1022 * input type; this is a hack to simplify life for ScanKeyInit().
1023 */
1024 lefttype = leftarg->sk_subtype;
1025 if (lefttype == InvalidOid)
1026 lefttype = opcintype;
1027 righttype = rightarg->sk_subtype;
1028 if (righttype == InvalidOid)
1029 righttype = opcintype;
1030 optype = op->sk_subtype;
1031 if (optype == InvalidOid)
1032 optype = opcintype;
1033
1034 /*
1035 * If leftarg and rightarg match the types expected for the "op" scankey,
1036 * we can use its already-looked-up comparison function.
1037 */
1038 if (lefttype == opcintype && righttype == optype)
1039 {
1040 *result = DatumGetBool(FunctionCall2Coll(&op->sk_func,
1041 op->sk_collation,
1042 leftarg->sk_argument,
1043 rightarg->sk_argument));
1044 return true;
1045 }
1046
1047 /*
1048 * Otherwise, we need to go to the syscache to find the appropriate
1049 * operator. (This cannot result in infinite recursion, since no
1050 * indexscan initiated by syscache lookup will use cross-data-type
1051 * operators.)
1052 *
1053 * If the sk_strategy was flipped by _bt_fix_scankey_strategy, we have to
1054 * un-flip it to get the correct opfamily member.
1055 */
1056 strat = op->sk_strategy;
1057 if (op->sk_flags & SK_BT_DESC)
1058 strat = BTCommuteStrategyNumber(strat);
1059
1060 cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],
1061 lefttype,
1062 righttype,
1063 strat);
1064 if (OidIsValid(cmp_op))
1065 {
1066 RegProcedure cmp_proc = get_opcode(cmp_op);
1067
1068 if (RegProcedureIsValid(cmp_proc))
1069 {
1070 *result = DatumGetBool(OidFunctionCall2Coll(cmp_proc,
1071 op->sk_collation,
1072 leftarg->sk_argument,
1073 rightarg->sk_argument));
1074 return true;
1075 }
1076 }
1077
1078 /* Can't make the comparison */
1079 *result = false; /* suppress compiler warnings */
1080 return false;
1081}
1082
1083/*
1084 * Compare an array scan key to a scalar scan key, eliminating contradictory
1085 * array elements such that the scalar scan key becomes redundant.
1086 *
1087 * If the opfamily is incomplete we may not be able to determine which
1088 * elements are contradictory. When we return true we'll have validly set
1089 * *qual_ok, guaranteeing that at least the scalar scan key can be considered
1090 * redundant. We return false if the comparison could not be made (caller
1091 * must keep both scan keys when this happens).
1092 *
1093 * Note: it's up to caller to deal with IS [NOT] NULL scan keys, as well as
1094 * row comparison scan keys. We only deal with scalar scan keys.
1095 */
1096static bool
1098 FmgrInfo *orderproc, BTArrayKeyInfo *array,
1099 bool *qual_ok)
1100{
1101 Assert(arraysk->sk_attno == skey->sk_attno);
1103 Assert((arraysk->sk_flags & SK_SEARCHARRAY) &&
1105 /* don't expect to have to deal with NULLs/row comparison scan keys */
1107 Assert(!(skey->sk_flags & SK_SEARCHARRAY) ||
1109
1110 /*
1111 * Just call the appropriate helper function based on whether it's a SAOP
1112 * array or a skip array. Both helpers will set *qual_ok in passing.
1113 */
1114 if (array->num_elems != -1)
1115 return _bt_saoparray_shrink(scan, arraysk, skey, orderproc, array,
1116 qual_ok);
1117 else
1118 return _bt_skiparray_shrink(scan, skey, array, qual_ok);
1119}
1120
1121/*
1122 * Preprocessing of SAOP array scan key, used to determine which array
1123 * elements are eliminated as contradictory by a non-array scalar key.
1124 *
1125 * _bt_compare_array_scankey_args helper function.
1126 *
1127 * Array elements can be eliminated as contradictory when excluded by some
1128 * other operator on the same attribute. For example, with an index scan qual
1129 * "WHERE a IN (1, 2, 3) AND a < 2", all array elements except the value "1"
1130 * are eliminated, and the < scan key is eliminated as redundant. Cases where
1131 * every array element is eliminated by a redundant scalar scan key have an
1132 * unsatisfiable qual, which we handle by setting *qual_ok=false for caller.
1133 */
1134static bool
1136 FmgrInfo *orderproc, BTArrayKeyInfo *array, bool *qual_ok)
1137{
1138 Relation rel = scan->indexRelation;
1139 Oid opcintype = rel->rd_opcintype[arraysk->sk_attno - 1];
1140 int cmpresult = 0,
1141 cmpexact = 0,
1142 matchelem,
1143 new_nelems = 0;
1144 FmgrInfo crosstypeproc;
1145 FmgrInfo *orderprocp = orderproc;
1146
1147 Assert(array->num_elems > 0);
1148 Assert(!(arraysk->sk_flags & SK_BT_SKIP));
1149
1150 /*
1151 * _bt_binsrch_array_skey searches an array for the entry best matching a
1152 * datum of opclass input type for the index's attribute (on-disk type).
1153 * We can reuse the array's ORDER proc whenever the non-array scan key's
1154 * type is a match for the corresponding attribute's input opclass type.
1155 * Otherwise, we have to do another ORDER proc lookup so that our call to
1156 * _bt_binsrch_array_skey applies the correct comparator.
1157 *
1158 * Note: we have to support the convention that sk_subtype == InvalidOid
1159 * means the opclass input type; this is a hack to simplify life for
1160 * ScanKeyInit().
1161 */
1162 if (skey->sk_subtype != opcintype && skey->sk_subtype != InvalidOid)
1163 {
1164 RegProcedure cmp_proc;
1165 Oid arraysk_elemtype;
1166
1167 /*
1168 * Need an ORDER proc lookup to detect redundancy/contradictoriness
1169 * with this pair of scankeys.
1170 *
1171 * Scalar scan key's argument will be passed to _bt_compare_array_skey
1172 * as its tupdatum/lefthand argument (rhs arg is for array elements).
1173 */
1174 arraysk_elemtype = arraysk->sk_subtype;
1175 if (arraysk_elemtype == InvalidOid)
1176 arraysk_elemtype = rel->rd_opcintype[arraysk->sk_attno - 1];
1177 cmp_proc = get_opfamily_proc(rel->rd_opfamily[arraysk->sk_attno - 1],
1178 skey->sk_subtype, arraysk_elemtype,
1179 BTORDER_PROC);
1180 if (!RegProcedureIsValid(cmp_proc))
1181 {
1182 /* Can't make the comparison */
1183 *qual_ok = false; /* suppress compiler warnings */
1184 return false;
1185 }
1186
1187 /* We have all we need to determine redundancy/contradictoriness */
1188 orderprocp = &crosstypeproc;
1189 fmgr_info(cmp_proc, orderprocp);
1190 }
1191
1192 matchelem = _bt_binsrch_array_skey(orderprocp, false,
1194 skey->sk_argument, false, array,
1195 arraysk, &cmpresult);
1196
1197 switch (skey->sk_strategy)
1198 {
1200 cmpexact = 1; /* exclude exact match, if any */
1201 /* FALL THRU */
1203 if (cmpresult >= cmpexact)
1204 matchelem++;
1205 /* Resize, keeping elements from the start of the array */
1206 new_nelems = matchelem;
1207 break;
1209 if (cmpresult != 0)
1210 {
1211 /* qual is unsatisfiable */
1212 new_nelems = 0;
1213 }
1214 else
1215 {
1216 /* Shift matching element to the start of the array, resize */
1217 array->elem_values[0] = array->elem_values[matchelem];
1218 new_nelems = 1;
1219 }
1220 break;
1222 cmpexact = 1; /* include exact match, if any */
1223 /* FALL THRU */
1225 if (cmpresult >= cmpexact)
1226 matchelem++;
1227 /* Shift matching elements to the start of the array, resize */
1228 new_nelems = array->num_elems - matchelem;
1229 memmove(array->elem_values, array->elem_values + matchelem,
1230 sizeof(Datum) * new_nelems);
1231 break;
1232 default:
1233 elog(ERROR, "unrecognized StrategyNumber: %d",
1234 (int) skey->sk_strategy);
1235 break;
1236 }
1237
1238 Assert(new_nelems >= 0);
1239 Assert(new_nelems <= array->num_elems);
1240
1241 array->num_elems = new_nelems;
1242 *qual_ok = new_nelems > 0;
1243
1244 return true;
1245}
1246
1247/*
1248 * Preprocessing of skip array scan key, used to determine redundancy against
1249 * a non-array scalar scan key (must be an inequality).
1250 *
1251 * _bt_compare_array_scankey_args helper function.
1252 *
1253 * Skip arrays work by procedurally generating their elements as needed, so we
1254 * just store the inequality as the skip array's low_compare or high_compare
1255 * (except when there's already a more restrictive low_compare/high_compare).
1256 * The array's final elements are the range of values that still satisfy the
1257 * array's final low_compare and high_compare.
1258 */
1259static bool
1261 bool *qual_ok)
1262{
1263 bool test_result;
1264
1265 Assert(array->num_elems == -1);
1266
1267 /*
1268 * Array's index attribute will be constrained by a strict operator/key.
1269 * Array must not "contain a NULL element" (i.e. the scan must not apply
1270 * "IS NULL" qual when it reaches the end of the index that stores NULLs).
1271 */
1272 array->null_elem = false;
1273 *qual_ok = true;
1274
1275 /*
1276 * Consider if we should treat caller's scalar scan key as the skip
1277 * array's high_compare or low_compare.
1278 *
1279 * In general the current array element must either be a copy of a value
1280 * taken from an index tuple, or a derivative value generated by opclass's
1281 * skip support function. That way the scan can always safely assume that
1282 * it's okay to use the only-input-opclass-type proc from so->orderProcs[]
1283 * (they can be cross-type with SAOP arrays, but never with skip arrays).
1284 *
1285 * This approach is enabled by MINVAL/MAXVAL sentinel key markings, which
1286 * can be thought of as representing either the lowest or highest matching
1287 * array element (excluding the NULL element, where applicable, though as
1288 * just discussed it isn't applicable to this range skip array anyway).
1289 * Array keys marked MINVAL/MAXVAL never have a valid datum in their
1290 * sk_argument field. The scan directly applies the array's low_compare
1291 * key when it encounters MINVAL in the array key proper (just as it
1292 * applies high_compare when it sees MAXVAL set in the array key proper).
1293 * The scan must never use the array's so->orderProcs[] proc against
1294 * low_compare's/high_compare's sk_argument, either (so->orderProcs[] is
1295 * only intended to be used with rhs datums from the array proper/index).
1296 */
1297 switch (skey->sk_strategy)
1298 {
1301 if (array->high_compare)
1302 {
1303 /* replace existing high_compare with caller's key? */
1304 if (!_bt_compare_scankey_args(scan, array->high_compare, skey,
1305 array->high_compare, NULL, NULL,
1306 &test_result))
1307 return false; /* can't determine more restrictive key */
1308
1309 if (!test_result)
1310 return true; /* no, just discard caller's key */
1311
1312 /* yes, replace existing high_compare with caller's key */
1313 }
1314
1315 /* caller's key becomes skip array's high_compare */
1316 array->high_compare = skey;
1317 break;
1320 if (array->low_compare)
1321 {
1322 /* replace existing low_compare with caller's key? */
1323 if (!_bt_compare_scankey_args(scan, array->low_compare, skey,
1324 array->low_compare, NULL, NULL,
1325 &test_result))
1326 return false; /* can't determine more restrictive key */
1327
1328 if (!test_result)
1329 return true; /* no, just discard caller's key */
1330
1331 /* yes, replace existing low_compare with caller's key */
1332 }
1333
1334 /* caller's key becomes skip array's low_compare */
1335 array->low_compare = skey;
1336 break;
1338 default:
1339 elog(ERROR, "unrecognized StrategyNumber: %d",
1340 (int) skey->sk_strategy);
1341 break;
1342 }
1343
1344 return true;
1345}
1346
1347/*
1348 * Applies the opfamily's skip support routine to convert the skip array's >
1349 * low_compare key (if any) into a >= key, and to convert its < high_compare
1350 * key (if any) into a <= key. Decrements the high_compare key's sk_argument,
1351 * and/or increments the low_compare key's sk_argument (also adjusts their
1352 * operator strategies, while changing the operator as appropriate).
1353 *
1354 * This optional optimization reduces the number of descents required within
1355 * _bt_first. Whenever _bt_first is called with a skip array whose current
1356 * array element is the sentinel value MINVAL, using a transformed >= key
1357 * instead of using the original > key makes it safe to include lower-order
1358 * scan keys in the insertion scan key (there must be lower-order scan keys
1359 * after the skip array). We will avoid an extra _bt_first to find the first
1360 * value in the index > sk_argument -- at least when the first real matching
1361 * value in the index happens to be an exact match for the sk_argument value
1362 * that we produced here by incrementing the original input key's sk_argument.
1363 * (Backwards scans derive the same benefit when they encounter the sentinel
1364 * value MAXVAL, by converting the high_compare key from < to <=.)
1365 *
1366 * Note: The transformation is only correct when it cannot allow the scan to
1367 * overlook matching tuples, but we don't have enough semantic information to
1368 * safely make sure that can't happen during scans with cross-type operators.
1369 * That's why we'll never apply the transformation in cross-type scenarios.
1370 * For example, if we attempted to convert "sales_ts > '2024-01-01'::date"
1371 * into "sales_ts >= '2024-01-02'::date" given a "sales_ts" attribute whose
1372 * input opclass is timestamp_ops, the scan would overlook almost all (or all)
1373 * tuples for sales that fell on '2024-01-01'.
1374 *
1375 * Note: We can safely modify array->low_compare/array->high_compare in place
1376 * because they just point to copies of our scan->keyData[] input scan keys
1377 * (namely the copies returned by _bt_preprocess_array_keys to be used as
1378 * input into the standard preprocessing steps in _bt_preprocess_keys).
1379 * Everything will be reset if there's a rescan.
1380 */
1381static void
1383 BTArrayKeyInfo *array)
1384{
1385 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1386 MemoryContext oldContext;
1387
1388 /*
1389 * Called last among all preprocessing steps, when the skip array's final
1390 * low_compare and high_compare have both been chosen
1391 */
1392 Assert(arraysk->sk_flags & SK_BT_SKIP);
1393 Assert(array->num_elems == -1 && !array->null_elem && array->sksup);
1394
1395 oldContext = MemoryContextSwitchTo(so->arrayContext);
1396
1397 if (array->high_compare &&
1399 _bt_skiparray_strat_decrement(scan, arraysk, array);
1400
1401 if (array->low_compare &&
1403 _bt_skiparray_strat_increment(scan, arraysk, array);
1404
1405 MemoryContextSwitchTo(oldContext);
1406}
1407
1408/*
1409 * Convert skip array's > low_compare key into a >= key
1410 */
1411static void
1413 BTArrayKeyInfo *array)
1414{
1415 Relation rel = scan->indexRelation;
1416 Oid opfamily = rel->rd_opfamily[arraysk->sk_attno - 1],
1417 opcintype = rel->rd_opcintype[arraysk->sk_attno - 1],
1418 leop;
1419 RegProcedure cmp_proc;
1420 ScanKey high_compare = array->high_compare;
1421 Datum orig_sk_argument = high_compare->sk_argument,
1422 new_sk_argument;
1423 bool uflow;
1424 int16 lookupstrat;
1425
1426 Assert(high_compare->sk_strategy == BTLessStrategyNumber);
1427
1428 /*
1429 * Only perform the transformation when the operator type matches the
1430 * index attribute's input opclass type
1431 */
1432 if (high_compare->sk_subtype != opcintype &&
1433 high_compare->sk_subtype != InvalidOid)
1434 return;
1435
1436 /* Decrement, handling underflow by marking the qual unsatisfiable */
1437 new_sk_argument = array->sksup->decrement(rel, orig_sk_argument, &uflow);
1438 if (uflow)
1439 {
1440 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1441
1442 so->qual_ok = false;
1443 return;
1444 }
1445
1446 /*
1447 * Look up <= operator (might fail), accounting for the fact that a
1448 * high_compare on a DESC column already had its strategy commuted
1449 */
1450 lookupstrat = BTLessEqualStrategyNumber;
1451 if (high_compare->sk_flags & SK_BT_DESC)
1452 lookupstrat = BTGreaterEqualStrategyNumber; /* commute this too */
1453 leop = get_opfamily_member(opfamily, opcintype, opcintype, lookupstrat);
1454 if (!OidIsValid(leop))
1455 return;
1456 cmp_proc = get_opcode(leop);
1457 if (RegProcedureIsValid(cmp_proc))
1458 {
1459 /* Transform < high_compare key into <= key */
1460 fmgr_info(cmp_proc, &high_compare->sk_func);
1461 high_compare->sk_argument = new_sk_argument;
1462 high_compare->sk_strategy = BTLessEqualStrategyNumber;
1463 }
1464}
1465
1466/*
1467 * Convert skip array's < low_compare key into a <= key
1468 */
1469static void
1471 BTArrayKeyInfo *array)
1472{
1473 Relation rel = scan->indexRelation;
1474 Oid opfamily = rel->rd_opfamily[arraysk->sk_attno - 1],
1475 opcintype = rel->rd_opcintype[arraysk->sk_attno - 1],
1476 geop;
1477 RegProcedure cmp_proc;
1478 ScanKey low_compare = array->low_compare;
1479 Datum orig_sk_argument = low_compare->sk_argument,
1480 new_sk_argument;
1481 bool oflow;
1482 int16 lookupstrat;
1483
1485
1486 /*
1487 * Only perform the transformation when the operator type matches the
1488 * index attribute's input opclass type
1489 */
1490 if (low_compare->sk_subtype != opcintype &&
1491 low_compare->sk_subtype != InvalidOid)
1492 return;
1493
1494 /* Increment, handling overflow by marking the qual unsatisfiable */
1495 new_sk_argument = array->sksup->increment(rel, orig_sk_argument, &oflow);
1496 if (oflow)
1497 {
1498 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1499
1500 so->qual_ok = false;
1501 return;
1502 }
1503
1504 /*
1505 * Look up >= operator (might fail), accounting for the fact that a
1506 * low_compare on a DESC column already had its strategy commuted
1507 */
1508 lookupstrat = BTGreaterEqualStrategyNumber;
1509 if (low_compare->sk_flags & SK_BT_DESC)
1510 lookupstrat = BTLessEqualStrategyNumber; /* commute this too */
1511 geop = get_opfamily_member(opfamily, opcintype, opcintype, lookupstrat);
1512 if (!OidIsValid(geop))
1513 return;
1514 cmp_proc = get_opcode(geop);
1515 if (RegProcedureIsValid(cmp_proc))
1516 {
1517 /* Transform > low_compare key into >= key */
1518 fmgr_info(cmp_proc, &low_compare->sk_func);
1519 low_compare->sk_argument = new_sk_argument;
1521 }
1522}
1523
1524/*
1525 * _bt_unmark_keys() -- make superfluous required keys nonrequired after all
1526 *
1527 * When _bt_preprocess_keys fails to eliminate one or more redundant keys, it
1528 * calls here to make sure that no index attribute has more than one > or >=
1529 * key marked required, and no more than one required < or <= key. Attributes
1530 * with = keys will always get one = key as their required key. All other
1531 * keys that were initially marked required get "unmarked" here. That way,
1532 * _bt_first and _bt_checkkeys will reliably agree on which keys to use to
1533 * start and/or to end the scan.
1534 *
1535 * We also relocate keys that become/started out nonrequired to the end of
1536 * so->keyData[]. That way, _bt_first and _bt_checkkeys cannot fail to reach
1537 * a required key due to some earlier nonrequired key getting in the way.
1538 *
1539 * Only call here when _bt_compare_scankey_args returned false at least once
1540 * (otherwise, calling here will just waste cycles).
1541 */
1542static void
1543_bt_unmark_keys(IndexScanDesc scan, int *keyDataMap)
1544{
1545 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1546 AttrNumber attno;
1547 bool *unmarkikey;
1548 int nunmark,
1549 nunmarked,
1550 nkept,
1551 firsti;
1552 ScanKey keepKeys,
1553 unmarkKeys;
1554 FmgrInfo *keepOrderProcs = NULL,
1555 *unmarkOrderProcs = NULL;
1556 bool haveReqEquals,
1557 haveReqForward,
1558 haveReqBackward;
1559
1560 /*
1561 * Do an initial pass over so->keyData[] that determines which keys to
1562 * keep as required. We expect so->keyData[] to still be in attribute
1563 * order when we're called (though we don't expect any particular order
1564 * among each attribute's keys).
1565 *
1566 * When both equality and inequality keys remain on a single attribute, we
1567 * *must* make sure that exactly one of the equalities remains required.
1568 * Any requiredness markings that we might leave on later keys/attributes
1569 * are predicated on there being required = keys on all prior columns.
1570 */
1571 unmarkikey = palloc0(so->numberOfKeys * sizeof(bool));
1572 nunmark = 0;
1573
1574 /* Set things up for first key's attribute */
1575 attno = so->keyData[0].sk_attno;
1576 firsti = 0;
1577 haveReqEquals = false;
1578 haveReqForward = false;
1579 haveReqBackward = false;
1580 for (int i = 0; i < so->numberOfKeys; i++)
1581 {
1582 ScanKey origkey = &so->keyData[i];
1583
1584 if (origkey->sk_attno != attno)
1585 {
1586 /* Reset for next attribute */
1587 attno = origkey->sk_attno;
1588 firsti = i;
1589
1590 haveReqEquals = false;
1591 haveReqForward = false;
1592 haveReqBackward = false;
1593 }
1594
1595 /* Equalities get priority over inequalities */
1596 if (haveReqEquals)
1597 {
1598 /*
1599 * We already found the first "=" key for this attribute. We've
1600 * already decided that all its other keys will be unmarked.
1601 */
1602 Assert(!(origkey->sk_flags & SK_SEARCHNULL));
1603 unmarkikey[i] = true;
1604 nunmark++;
1605 continue;
1606 }
1607 else if ((origkey->sk_flags & SK_BT_REQFWD) &&
1608 (origkey->sk_flags & SK_BT_REQBKWD))
1609 {
1610 /*
1611 * Found the first "=" key for attno. All other attno keys will
1612 * be unmarked.
1613 */
1615
1616 haveReqEquals = true;
1617 for (int j = firsti; j < i; j++)
1618 {
1619 /* Unmark any prior inequality keys on attno after all */
1620 if (!unmarkikey[j])
1621 {
1622 unmarkikey[j] = true;
1623 nunmark++;
1624 }
1625 }
1626 continue;
1627 }
1628
1629 /* Deal with inequalities next */
1630 if ((origkey->sk_flags & SK_BT_REQFWD) && !haveReqForward)
1631 {
1632 haveReqForward = true;
1633 continue;
1634 }
1635 else if ((origkey->sk_flags & SK_BT_REQBKWD) && !haveReqBackward)
1636 {
1637 haveReqBackward = true;
1638 continue;
1639 }
1640
1641 /*
1642 * We have either a redundant inequality key that will be unmarked, or
1643 * we have a key that wasn't marked required in the first place
1644 */
1645 unmarkikey[i] = true;
1646 nunmark++;
1647 }
1648
1649 /* Should only be called when _bt_compare_scankey_args reported failure */
1650 Assert(nunmark > 0);
1651
1652 /*
1653 * Next, allocate temp arrays: one for required keys that'll remain
1654 * required, the other for all remaining keys
1655 */
1656 unmarkKeys = palloc(nunmark * sizeof(ScanKeyData));
1657 keepKeys = palloc((so->numberOfKeys - nunmark) * sizeof(ScanKeyData));
1658 nunmarked = 0;
1659 nkept = 0;
1660 if (so->numArrayKeys)
1661 {
1662 unmarkOrderProcs = palloc(nunmark * sizeof(FmgrInfo));
1663 keepOrderProcs = palloc((so->numberOfKeys - nunmark) * sizeof(FmgrInfo));
1664 }
1665
1666 /*
1667 * Next, copy the contents of so->keyData[] into the appropriate temp
1668 * array.
1669 *
1670 * Scans with = array keys need us to maintain invariants around the order
1671 * of so->orderProcs[] and so->arrayKeys[] relative to so->keyData[]. See
1672 * _bt_preprocess_array_keys_final for a full explanation.
1673 */
1674 for (int i = 0; i < so->numberOfKeys; i++)
1675 {
1676 ScanKey origkey = &so->keyData[i];
1677 ScanKey unmark;
1678
1679 if (!unmarkikey[i])
1680 {
1681 /*
1682 * Key gets to keep its original requiredness markings.
1683 *
1684 * Key will stay in its original position, unless we're going to
1685 * unmark an earlier key (in which case this key gets moved back).
1686 */
1687 memcpy(keepKeys + nkept, origkey, sizeof(ScanKeyData));
1688
1689 if (so->numArrayKeys)
1690 {
1691 keyDataMap[i] = nkept;
1692 memcpy(keepOrderProcs + nkept, &so->orderProcs[i],
1693 sizeof(FmgrInfo));
1694 }
1695
1696 nkept++;
1697 continue;
1698 }
1699
1700 /*
1701 * Key will be unmarked as needed, and moved to the end of the array,
1702 * next to other keys that will become (or always were) nonrequired
1703 */
1704 unmark = unmarkKeys + nunmarked;
1705 memcpy(unmark, origkey, sizeof(ScanKeyData));
1706
1707 if (so->numArrayKeys)
1708 {
1709 keyDataMap[i] = (so->numberOfKeys - nunmark) + nunmarked;
1710 memcpy(&unmarkOrderProcs[nunmarked], &so->orderProcs[i],
1711 sizeof(FmgrInfo));
1712 }
1713
1714 /*
1715 * Preprocessing only generates skip arrays when it knows that they'll
1716 * be the only required = key on the attr. We'll never unmark them.
1717 */
1718 Assert(!(unmark->sk_flags & SK_BT_SKIP));
1719
1720 /*
1721 * Also shouldn't have to unmark an IS NULL or an IS NOT NULL key.
1722 * They aren't cross-type, so an incomplete opfamily can't matter.
1723 */
1724 Assert(!(unmark->sk_flags & SK_ISNULL) ||
1725 !(unmark->sk_flags & (SK_BT_REQFWD | SK_BT_REQBKWD)));
1726
1727 /* Clear requiredness flags on redundant key (and on any subkeys) */
1728 unmark->sk_flags &= ~(SK_BT_REQFWD | SK_BT_REQBKWD);
1729 if (unmark->sk_flags & SK_ROW_HEADER)
1730 {
1731 ScanKey subkey = (ScanKey) DatumGetPointer(unmark->sk_argument);
1732
1733 Assert(subkey->sk_strategy == unmark->sk_strategy);
1734 for (;;)
1735 {
1736 Assert(subkey->sk_flags & SK_ROW_MEMBER);
1737 subkey->sk_flags &= ~(SK_BT_REQFWD | SK_BT_REQBKWD);
1738 if (subkey->sk_flags & SK_ROW_END)
1739 break;
1740 subkey++;
1741 }
1742 }
1743
1744 nunmarked++;
1745 }
1746
1747 /* Copy both temp arrays back into so->keyData[] to reorder */
1748 Assert(nkept == so->numberOfKeys - nunmark);
1749 Assert(nunmarked == nunmark);
1750 memcpy(so->keyData, keepKeys, sizeof(ScanKeyData) * nkept);
1751 memcpy(so->keyData + nkept, unmarkKeys, sizeof(ScanKeyData) * nunmarked);
1752
1753 /* Done with temp arrays */
1754 pfree(unmarkikey);
1755 pfree(keepKeys);
1756 pfree(unmarkKeys);
1757
1758 /*
1759 * Now copy so->orderProcs[] temp entries needed by scans with = array
1760 * keys back (just like with the so->keyData[] temp arrays)
1761 */
1762 if (so->numArrayKeys)
1763 {
1764 memcpy(so->orderProcs, keepOrderProcs, sizeof(FmgrInfo) * nkept);
1765 memcpy(so->orderProcs + nkept, unmarkOrderProcs,
1766 sizeof(FmgrInfo) * nunmarked);
1767
1768 /* Also fix-up array->scan_key references */
1769 for (int arridx = 0; arridx < so->numArrayKeys; arridx++)
1770 {
1771 BTArrayKeyInfo *array = &so->arrayKeys[arridx];
1772
1773 array->scan_key = keyDataMap[array->scan_key];
1774 }
1775
1776 /*
1777 * Sort so->arrayKeys[] based on its new BTArrayKeyInfo.scan_key
1778 * offsets, so that its order matches so->keyData[] order as expected
1779 */
1780 qsort(so->arrayKeys, so->numArrayKeys, sizeof(BTArrayKeyInfo),
1782
1783 /* Done with temp arrays */
1784 pfree(unmarkOrderProcs);
1785 pfree(keepOrderProcs);
1786 }
1787}
1788
1789/*
1790 * qsort comparator for reordering so->arrayKeys[] BTArrayKeyInfo entries
1791 */
1792static int
1793_bt_reorder_array_cmp(const void *a, const void *b)
1794{
1795 BTArrayKeyInfo *arraya = (BTArrayKeyInfo *) a;
1796 BTArrayKeyInfo *arrayb = (BTArrayKeyInfo *) b;
1797
1798 return pg_cmp_s32(arraya->scan_key, arrayb->scan_key);
1799}
1800
1801/*
1802 * _bt_preprocess_array_keys() -- Preprocess SK_SEARCHARRAY scan keys
1803 *
1804 * If there are any SK_SEARCHARRAY scan keys, deconstruct the array(s) and
1805 * set up BTArrayKeyInfo info for each one that is an equality-type key.
1806 * Returns modified scan keys as input for further, standard preprocessing.
1807 *
1808 * Currently we perform two kinds of preprocessing to deal with redundancies.
1809 * For inequality array keys, it's sufficient to find the extreme element
1810 * value and replace the whole array with that scalar value. This eliminates
1811 * all but one array element as redundant. Similarly, we are capable of
1812 * "merging together" multiple equality array keys (from two or more input
1813 * scan keys) into a single output scan key containing only the intersecting
1814 * array elements. This can eliminate many redundant array elements, as well
1815 * as eliminating whole array scan keys as redundant. It can also allow us to
1816 * detect contradictory quals.
1817 *
1818 * Caller must pass *new_numberOfKeys to give us a way to change the number of
1819 * scan keys that caller treats as input to standard preprocessing steps. The
1820 * returned array is smaller than scan->keyData[] when we could eliminate a
1821 * redundant array scan key (redundant with another array scan key). It is
1822 * convenient for _bt_preprocess_keys caller to have to deal with no more than
1823 * one equality strategy array scan key per index attribute. We'll always be
1824 * able to set things up that way when complete opfamilies are used.
1825 *
1826 * We're also responsible for generating skip arrays (and their associated
1827 * scan keys) here. This enables skip scan. We do this for index attributes
1828 * that initially lacked an equality condition within scan->keyData[], iff
1829 * doing so allows a later scan key (that was passed to us in scan->keyData[])
1830 * to be marked required by our _bt_preprocess_keys caller.
1831 *
1832 * We set the scan key references from the scan's BTArrayKeyInfo info array to
1833 * offsets into the temp modified input array returned to caller. Scans that
1834 * have array keys should call _bt_preprocess_array_keys_final when standard
1835 * preprocessing steps are complete. This will convert the scan key offset
1836 * references into references to the scan's so->keyData[] output scan keys.
1837 *
1838 * Note: the reason we need to return a temp scan key array, rather than just
1839 * modifying scan->keyData[], is that callers are permitted to call btrescan
1840 * without supplying a new set of scankey data. Certain other preprocessing
1841 * routines (e.g., _bt_fix_scankey_strategy) _can_ modify scan->keyData[], but
1842 * we can't make that work here because our modifications are non-idempotent.
1843 */
1844static ScanKey
1845_bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
1846{
1847 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1848 Relation rel = scan->indexRelation;
1849 int16 *indoption = rel->rd_indoption;
1850 Oid skip_eq_ops[INDEX_MAX_KEYS];
1851 int numArrayKeys,
1852 numSkipArrayKeys,
1853 numArrayKeyData;
1854 AttrNumber attno_skip = 1;
1855 int origarrayatt = InvalidAttrNumber,
1856 origarraykey = -1;
1857 Oid origelemtype = InvalidOid;
1858 MemoryContext oldContext;
1859 ScanKey arrayKeyData; /* modified copy of scan->keyData */
1860
1861 /*
1862 * Check the number of input array keys within scan->keyData[] input keys
1863 * (also checks if we should add extra skip arrays based on input keys)
1864 */
1865 numArrayKeys = _bt_num_array_keys(scan, skip_eq_ops, &numSkipArrayKeys);
1866 so->skipScan = (numSkipArrayKeys > 0);
1867
1868 /* Quit if nothing to do. */
1869 if (numArrayKeys == 0)
1870 return NULL;
1871
1872 /*
1873 * Estimated final size of arrayKeyData[] array we'll return to our caller
1874 * is the size of the original scan->keyData[] input array, plus space for
1875 * any additional skip array scan keys we'll need to generate below
1876 */
1877 numArrayKeyData = scan->numberOfKeys + numSkipArrayKeys;
1878
1879 /*
1880 * Make a scan-lifespan context to hold array-associated data, or reset it
1881 * if we already have one from a previous rescan cycle.
1882 */
1883 if (so->arrayContext == NULL)
1885 "BTree array context",
1887 else
1889
1890 oldContext = MemoryContextSwitchTo(so->arrayContext);
1891
1892 /* Create output scan keys in the workspace context */
1893 arrayKeyData = (ScanKey) palloc(numArrayKeyData * sizeof(ScanKeyData));
1894
1895 /* Allocate space for per-array data in the workspace context */
1896 so->arrayKeys = (BTArrayKeyInfo *) palloc(numArrayKeys * sizeof(BTArrayKeyInfo));
1897
1898 /* Allocate space for ORDER procs used to help _bt_checkkeys */
1899 so->orderProcs = (FmgrInfo *) palloc(numArrayKeyData * sizeof(FmgrInfo));
1900
1901 numArrayKeys = 0;
1902 numArrayKeyData = 0;
1903 for (int input_ikey = 0; input_ikey < scan->numberOfKeys; input_ikey++)
1904 {
1905 ScanKey inkey = scan->keyData + input_ikey,
1906 cur;
1907 FmgrInfo sortproc;
1908 FmgrInfo *sortprocp = &sortproc;
1909 Oid elemtype;
1910 bool reverse;
1911 ArrayType *arrayval;
1912 int16 elmlen;
1913 bool elmbyval;
1914 char elmalign;
1915 int num_elems;
1916 Datum *elem_values;
1917 bool *elem_nulls;
1918 int num_nonnulls;
1919
1920 /* set up next output scan key */
1921 cur = &arrayKeyData[numArrayKeyData];
1922
1923 /* Backfill skip arrays for attrs < or <= input key's attr? */
1924 while (numSkipArrayKeys && attno_skip <= inkey->sk_attno)
1925 {
1926 Oid opfamily = rel->rd_opfamily[attno_skip - 1];
1927 Oid opcintype = rel->rd_opcintype[attno_skip - 1];
1928 Oid collation = rel->rd_indcollation[attno_skip - 1];
1929 Oid eq_op = skip_eq_ops[attno_skip - 1];
1930 CompactAttribute *attr;
1931 RegProcedure cmp_proc;
1932
1933 if (!OidIsValid(eq_op))
1934 {
1935 /*
1936 * Attribute already has an = input key, so don't output a
1937 * skip array for attno_skip. Just copy attribute's = input
1938 * key into arrayKeyData[] once outside this inner loop.
1939 *
1940 * Note: When we get here there must be a later attribute that
1941 * lacks an equality input key, and still needs a skip array
1942 * (if there wasn't then numSkipArrayKeys would be 0 by now).
1943 */
1944 Assert(attno_skip == inkey->sk_attno);
1945 /* inkey can't be last input key to be marked required: */
1946 Assert(input_ikey < scan->numberOfKeys - 1);
1947#if 0
1948 /* Could be a redundant input scan key, so can't do this: */
1950 (inkey->sk_flags & SK_SEARCHNULL));
1951#endif
1952
1953 attno_skip++;
1954 break;
1955 }
1956
1957 cmp_proc = get_opcode(eq_op);
1958 if (!RegProcedureIsValid(cmp_proc))
1959 elog(ERROR, "missing oprcode for skipping equals operator %u", eq_op);
1960
1962 SK_SEARCHARRAY | SK_BT_SKIP, /* flags */
1963 attno_skip, /* skipped att number */
1964 BTEqualStrategyNumber, /* equality strategy */
1965 InvalidOid, /* opclass input subtype */
1966 collation, /* index column's collation */
1967 cmp_proc, /* equality operator's proc */
1968 (Datum) 0); /* constant */
1969
1970 /* Initialize generic BTArrayKeyInfo fields */
1971 so->arrayKeys[numArrayKeys].scan_key = numArrayKeyData;
1972 so->arrayKeys[numArrayKeys].num_elems = -1;
1973
1974 /* Initialize skip array specific BTArrayKeyInfo fields */
1975 attr = TupleDescCompactAttr(RelationGetDescr(rel), attno_skip - 1);
1976 reverse = (indoption[attno_skip - 1] & INDOPTION_DESC) != 0;
1977 so->arrayKeys[numArrayKeys].attlen = attr->attlen;
1978 so->arrayKeys[numArrayKeys].attbyval = attr->attbyval;
1979 so->arrayKeys[numArrayKeys].null_elem = true; /* for now */
1980 so->arrayKeys[numArrayKeys].sksup =
1981 PrepareSkipSupportFromOpclass(opfamily, opcintype, reverse);
1982 so->arrayKeys[numArrayKeys].low_compare = NULL; /* for now */
1983 so->arrayKeys[numArrayKeys].high_compare = NULL; /* for now */
1984
1985 /*
1986 * We'll need a 3-way ORDER proc. Set that up now.
1987 */
1988 _bt_setup_array_cmp(scan, cur, opcintype,
1989 &so->orderProcs[numArrayKeyData], NULL);
1990
1991 numArrayKeys++;
1992 numArrayKeyData++; /* keep this scan key/array */
1993
1994 /* set up next output scan key */
1995 cur = &arrayKeyData[numArrayKeyData];
1996
1997 /* remember having output this skip array and scan key */
1998 numSkipArrayKeys--;
1999 attno_skip++;
2000 }
2001
2002 /*
2003 * Provisionally copy scan key into arrayKeyData[] array we'll return
2004 * to _bt_preprocess_keys caller
2005 */
2006 *cur = *inkey;
2007
2008 if (!(cur->sk_flags & SK_SEARCHARRAY))
2009 {
2010 numArrayKeyData++; /* keep this non-array scan key */
2011 continue;
2012 }
2013
2014 /*
2015 * Process SAOP array scan key
2016 */
2018
2019 /* If array is null as a whole, the scan qual is unsatisfiable */
2020 if (cur->sk_flags & SK_ISNULL)
2021 {
2022 so->qual_ok = false;
2023 break;
2024 }
2025
2026 /*
2027 * Deconstruct the array into elements
2028 */
2029 arrayval = DatumGetArrayTypeP(cur->sk_argument);
2030 /* We could cache this data, but not clear it's worth it */
2032 &elmlen, &elmbyval, &elmalign);
2033 deconstruct_array(arrayval,
2034 ARR_ELEMTYPE(arrayval),
2035 elmlen, elmbyval, elmalign,
2036 &elem_values, &elem_nulls, &num_elems);
2037
2038 /*
2039 * Compress out any null elements. We can ignore them since we assume
2040 * all btree operators are strict.
2041 */
2042 num_nonnulls = 0;
2043 for (int j = 0; j < num_elems; j++)
2044 {
2045 if (!elem_nulls[j])
2046 elem_values[num_nonnulls++] = elem_values[j];
2047 }
2048
2049 /* We could pfree(elem_nulls) now, but not worth the cycles */
2050
2051 /* If there's no non-nulls, the scan qual is unsatisfiable */
2052 if (num_nonnulls == 0)
2053 {
2054 so->qual_ok = false;
2055 break;
2056 }
2057
2058 /*
2059 * Determine the nominal datatype of the array elements. We have to
2060 * support the convention that sk_subtype == InvalidOid means the
2061 * opclass input type; this is a hack to simplify life for
2062 * ScanKeyInit().
2063 */
2064 elemtype = cur->sk_subtype;
2065 if (elemtype == InvalidOid)
2066 elemtype = rel->rd_opcintype[cur->sk_attno - 1];
2067
2068 /*
2069 * If the comparison operator is not equality, then the array qual
2070 * degenerates to a simple comparison against the smallest or largest
2071 * non-null array element, as appropriate.
2072 */
2073 switch (cur->sk_strategy)
2074 {
2077 cur->sk_argument =
2078 _bt_find_extreme_element(scan, cur, elemtype,
2080 elem_values, num_nonnulls);
2081 numArrayKeyData++; /* keep this transformed scan key */
2082 continue;
2084 /* proceed with rest of loop */
2085 break;
2088 cur->sk_argument =
2089 _bt_find_extreme_element(scan, cur, elemtype,
2091 elem_values, num_nonnulls);
2092 numArrayKeyData++; /* keep this transformed scan key */
2093 continue;
2094 default:
2095 elog(ERROR, "unrecognized StrategyNumber: %d",
2096 (int) cur->sk_strategy);
2097 break;
2098 }
2099
2100 /*
2101 * We'll need a 3-way ORDER proc to perform binary searches for the
2102 * next matching array element. Set that up now.
2103 *
2104 * Array scan keys with cross-type equality operators will require a
2105 * separate same-type ORDER proc for sorting their array. Otherwise,
2106 * sortproc just points to the same proc used during binary searches.
2107 */
2108 _bt_setup_array_cmp(scan, cur, elemtype,
2109 &so->orderProcs[numArrayKeyData], &sortprocp);
2110
2111 /*
2112 * Sort the non-null elements and eliminate any duplicates. We must
2113 * sort in the same ordering used by the index column, so that the
2114 * arrays can be advanced in lockstep with the scan's progress through
2115 * the index's key space.
2116 */
2117 reverse = (indoption[cur->sk_attno - 1] & INDOPTION_DESC) != 0;
2118 num_elems = _bt_sort_array_elements(cur, sortprocp, reverse,
2119 elem_values, num_nonnulls);
2120
2121 if (origarrayatt == cur->sk_attno)
2122 {
2123 BTArrayKeyInfo *orig = &so->arrayKeys[origarraykey];
2124
2125 /*
2126 * This array scan key is redundant with a previous equality
2127 * operator array scan key. Merge the two arrays together to
2128 * eliminate contradictory non-intersecting elements (or try to).
2129 *
2130 * We merge this next array back into attribute's original array.
2131 */
2132 Assert(arrayKeyData[orig->scan_key].sk_attno == cur->sk_attno);
2133 Assert(arrayKeyData[orig->scan_key].sk_collation ==
2134 cur->sk_collation);
2135 if (_bt_merge_arrays(scan, cur, sortprocp, reverse,
2136 origelemtype, elemtype,
2137 orig->elem_values, &orig->num_elems,
2138 elem_values, num_elems))
2139 {
2140 /* Successfully eliminated this array */
2141 pfree(elem_values);
2142
2143 /*
2144 * If no intersecting elements remain in the original array,
2145 * the scan qual is unsatisfiable
2146 */
2147 if (orig->num_elems == 0)
2148 {
2149 so->qual_ok = false;
2150 break;
2151 }
2152
2153 /* Throw away this scan key/array */
2154 continue;
2155 }
2156
2157 /*
2158 * Unable to merge this array with previous array due to a lack of
2159 * suitable cross-type opfamily support. Will need to keep both
2160 * scan keys/arrays.
2161 */
2162 }
2163 else
2164 {
2165 /*
2166 * This array is the first for current index attribute.
2167 *
2168 * If it turns out to not be the last array (that is, if the next
2169 * array is redundantly applied to this same index attribute),
2170 * we'll then treat this array as the attribute's "original" array
2171 * when merging.
2172 */
2173 origarrayatt = cur->sk_attno;
2174 origarraykey = numArrayKeys;
2175 origelemtype = elemtype;
2176 }
2177
2178 /* Initialize generic BTArrayKeyInfo fields */
2179 so->arrayKeys[numArrayKeys].scan_key = numArrayKeyData;
2180 so->arrayKeys[numArrayKeys].num_elems = num_elems;
2181
2182 /* Initialize SAOP array specific BTArrayKeyInfo fields */
2183 so->arrayKeys[numArrayKeys].elem_values = elem_values;
2184 so->arrayKeys[numArrayKeys].cur_elem = -1; /* i.e. invalid */
2185
2186 numArrayKeys++;
2187 numArrayKeyData++; /* keep this scan key/array */
2188 }
2189
2190 Assert(numSkipArrayKeys == 0 || !so->qual_ok);
2191
2192 /* Set final number of equality-type array keys */
2193 so->numArrayKeys = numArrayKeys;
2194 /* Set number of scan keys in arrayKeyData[] */
2195 *new_numberOfKeys = numArrayKeyData;
2196
2197 MemoryContextSwitchTo(oldContext);
2198
2199 return arrayKeyData;
2200}
2201
2202/*
2203 * _bt_preprocess_array_keys_final() -- fix up array scan key references
2204 *
2205 * When _bt_preprocess_array_keys performed initial array preprocessing, it
2206 * set each array's array->scan_key to its scankey's arrayKeyData[] offset.
2207 * This function handles translation of the scan key references from the
2208 * BTArrayKeyInfo info array, from input scan key references (to the keys in
2209 * arrayKeyData[]), into output references (to the keys in so->keyData[]).
2210 * Caller's keyDataMap[] array tells us how to perform this remapping.
2211 *
2212 * Also finalizes so->orderProcs[] for the scan. Arrays already have an ORDER
2213 * proc, which might need to be repositioned to its so->keyData[]-wise offset
2214 * (very much like the remapping that we apply to array->scan_key references).
2215 * Non-array equality strategy scan keys (that survived preprocessing) don't
2216 * yet have an so->orderProcs[] entry, so we set one for them here.
2217 *
2218 * Also converts single-element array scan keys into equivalent non-array
2219 * equality scan keys, which decrements so->numArrayKeys. It's possible that
2220 * this will leave this new btrescan without any arrays at all. This isn't
2221 * necessary for correctness; it's just an optimization. Non-array equality
2222 * scan keys are slightly faster than equivalent array scan keys at runtime.
2223 */
2224static void
2226{
2227 BTScanOpaque so = (BTScanOpaque) scan->opaque;
2228 Relation rel = scan->indexRelation;
2229 int arrayidx = 0;
2230 int last_equal_output_ikey PG_USED_FOR_ASSERTS_ONLY = -1;
2231
2232 Assert(so->qual_ok);
2233
2234 /*
2235 * Nothing for us to do when _bt_preprocess_array_keys only had to deal
2236 * with array inequalities
2237 */
2238 if (so->numArrayKeys == 0)
2239 return;
2240
2241 for (int output_ikey = 0; output_ikey < so->numberOfKeys; output_ikey++)
2242 {
2243 ScanKey outkey = so->keyData + output_ikey;
2244 int input_ikey;
2245 bool found PG_USED_FOR_ASSERTS_ONLY = false;
2246
2248
2249 if (outkey->sk_strategy != BTEqualStrategyNumber)
2250 continue;
2251
2252 input_ikey = keyDataMap[output_ikey];
2253
2254 Assert(last_equal_output_ikey < output_ikey);
2255 Assert(last_equal_output_ikey < input_ikey);
2256 last_equal_output_ikey = output_ikey;
2257
2258 /*
2259 * We're lazy about looking up ORDER procs for non-array keys, since
2260 * not all input keys become output keys. Take care of it now.
2261 */
2262 if (!(outkey->sk_flags & SK_SEARCHARRAY))
2263 {
2264 Oid elemtype;
2265
2266 /* No need for an ORDER proc given an IS NULL scan key */
2267 if (outkey->sk_flags & SK_SEARCHNULL)
2268 continue;
2269
2270 /*
2271 * A non-required scan key doesn't need an ORDER proc, either
2272 * (unless it's associated with an array, which this one isn't)
2273 */
2274 if (!(outkey->sk_flags & SK_BT_REQFWD))
2275 continue;
2276
2277 elemtype = outkey->sk_subtype;
2278 if (elemtype == InvalidOid)
2279 elemtype = rel->rd_opcintype[outkey->sk_attno - 1];
2280
2281 _bt_setup_array_cmp(scan, outkey, elemtype,
2282 &so->orderProcs[output_ikey], NULL);
2283 continue;
2284 }
2285
2286 /*
2287 * Reorder existing array scan key so->orderProcs[] entries.
2288 *
2289 * Doing this in-place is safe because preprocessing is required to
2290 * output all equality strategy scan keys in original input order
2291 * (among each group of entries against the same index attribute).
2292 * This is also the order that the arrays themselves appear in.
2293 */
2294 so->orderProcs[output_ikey] = so->orderProcs[input_ikey];
2295
2296 /* Fix-up array->scan_key references for arrays */
2297 for (; arrayidx < so->numArrayKeys; arrayidx++)
2298 {
2299 BTArrayKeyInfo *array = &so->arrayKeys[arrayidx];
2300
2301 /*
2302 * All skip arrays must be marked required, and final column can
2303 * never have a skip array
2304 */
2305 Assert(array->num_elems > 0 || array->num_elems == -1);
2306 Assert(array->num_elems != -1 || outkey->sk_flags & SK_BT_REQFWD);
2307 Assert(array->num_elems != -1 ||
2309
2310 if (array->scan_key == input_ikey)
2311 {
2312 /* found it */
2313 array->scan_key = output_ikey;
2314 found = true;
2315
2316 /*
2317 * Transform array scan keys that have exactly 1 element
2318 * remaining (following all prior preprocessing) into
2319 * equivalent non-array scan keys.
2320 */
2321 if (array->num_elems == 1)
2322 {
2323 outkey->sk_flags &= ~SK_SEARCHARRAY;
2324 outkey->sk_argument = array->elem_values[0];
2325 so->numArrayKeys--;
2326
2327 /* If we're out of array keys, we can quit right away */
2328 if (so->numArrayKeys == 0)
2329 return;
2330
2331 /* Shift other arrays forward */
2332 memmove(array, array + 1,
2333 sizeof(BTArrayKeyInfo) *
2334 (so->numArrayKeys - arrayidx));
2335
2336 /*
2337 * Don't increment arrayidx (there was an entry that was
2338 * just shifted forward to the offset at arrayidx, which
2339 * will still need to be matched)
2340 */
2341 }
2342 else
2343 {
2344 /*
2345 * Any skip array low_compare and high_compare scan keys
2346 * are now final. Transform the array's > low_compare key
2347 * into a >= key (and < high_compare keys into a <= key).
2348 */
2349 if (array->num_elems == -1 && array->sksup &&
2350 !array->null_elem)
2351 _bt_skiparray_strat_adjust(scan, outkey, array);
2352
2353 /* Match found, so done with this array */
2354 arrayidx++;
2355 }
2356
2357 break;
2358 }
2359 }
2360
2361 Assert(found);
2362 }
2363
2364 /*
2365 * Parallel index scans require space in shared memory to store the
2366 * current array elements (for arrays kept by preprocessing) to schedule
2367 * the next primitive index scan. The underlying structure is protected
2368 * using an LWLock, so defensively limit its size. In practice this can
2369 * only affect parallel scans that use an incomplete opfamily.
2370 */
2371 if (scan->parallel_scan && so->numArrayKeys > INDEX_MAX_KEYS)
2372 ereport(ERROR,
2373 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2374 errmsg_internal("number of array scan keys left by preprocessing (%d) exceeds the maximum allowed by parallel btree index scans (%d)",
2376}
2377
2378/*
2379 * _bt_num_array_keys() -- determine # of BTArrayKeyInfo entries
2380 *
2381 * _bt_preprocess_array_keys helper function. Returns the estimated size of
2382 * the scan's BTArrayKeyInfo array, which is guaranteed to be large enough to
2383 * fit every so->arrayKeys[] entry.
2384 *
2385 * Also sets *numSkipArrayKeys_out to the number of skip arrays caller must
2386 * add to the scan keys it'll output. Caller must add this many skip arrays:
2387 * one array for each of the most significant attributes that lack a = input
2388 * key (IS NULL keys count as = input keys here). The specific attributes
2389 * that need skip arrays are indicated by initializing skip_eq_ops_out[] arg
2390 * 0-based attribute offset to a valid = op strategy Oid. We'll only ever set
2391 * skip_eq_ops_out[] entries to InvalidOid for attributes that already have an
2392 * equality key in scan->keyData[] input keys -- and only when there's some
2393 * later "attribute gap" for us to "fill-in" with a skip array.
2394 *
2395 * We're optimistic about skipping working out: we always add exactly the skip
2396 * arrays needed to maximize the number of input scan keys that can ultimately
2397 * be marked as required to continue the scan (but no more). Given a
2398 * multi-column index on (a, b, c, d), we add skip arrays as follows:
2399 *
2400 * Input keys Output keys (after all preprocessing)
2401 * ---------- -------------------------------------
2402 * a = 1 a = 1 (no skip arrays)
2403 * b = 42 skip a AND b = 42
2404 * a = 1 AND b = 42 a = 1 AND b = 42 (no skip arrays)
2405 * a >= 1 AND b = 42 range skip a AND b = 42
2406 * a = 1 AND b > 42 a = 1 AND b > 42 (no skip arrays)
2407 * a >= 1 AND a <= 3 AND b = 42 range skip a AND b = 42
2408 * a = 1 AND c <= 27 a = 1 AND skip b AND c <= 27
2409 * a = 1 AND d >= 1 a = 1 AND skip b AND skip c AND d >= 1
2410 * a = 1 AND b >= 42 AND d > 1 a = 1 AND range skip b AND skip c AND d > 1
2411 */
2412static int
2413_bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out,
2414 int *numSkipArrayKeys_out)
2415{
2416 Relation rel = scan->indexRelation;
2417 AttrNumber attno_skip = 1,
2418 attno_inkey = 1;
2419 bool attno_has_equal = false,
2420 attno_has_rowcompare = false;
2421 int numSAOPArrayKeys,
2422 numSkipArrayKeys,
2423 prev_numSkipArrayKeys;
2424
2425 Assert(scan->numberOfKeys);
2426
2427 /* Initial pass over input scan keys counts the number of SAOP arrays */
2428 numSAOPArrayKeys = 0;
2429 *numSkipArrayKeys_out = prev_numSkipArrayKeys = numSkipArrayKeys = 0;
2430 for (int i = 0; i < scan->numberOfKeys; i++)
2431 {
2432 ScanKey inkey = scan->keyData + i;
2433
2434 if (inkey->sk_flags & SK_SEARCHARRAY)
2435 numSAOPArrayKeys++;
2436 }
2437
2438#ifdef DEBUG_DISABLE_SKIP_SCAN
2439 /* don't attempt to add skip arrays */
2440 return numSAOPArrayKeys;
2441#endif
2442
2443 for (int i = 0;; i++)
2444 {
2445 ScanKey inkey = scan->keyData + i;
2446
2447 /*
2448 * Backfill skip arrays for any wholly omitted attributes prior to
2449 * attno_inkey
2450 */
2451 while (attno_skip < attno_inkey)
2452 {
2453 Oid opfamily = rel->rd_opfamily[attno_skip - 1];
2454 Oid opcintype = rel->rd_opcintype[attno_skip - 1];
2455
2456 /* Look up input opclass's equality operator (might fail) */
2457 skip_eq_ops_out[attno_skip - 1] =
2458 get_opfamily_member(opfamily, opcintype, opcintype,
2460 if (!OidIsValid(skip_eq_ops_out[attno_skip - 1]))
2461 {
2462 /*
2463 * Cannot generate a skip array for this or later attributes
2464 * (input opclass lacks an equality strategy operator)
2465 */
2466 *numSkipArrayKeys_out = prev_numSkipArrayKeys;
2467 return numSAOPArrayKeys + prev_numSkipArrayKeys;
2468 }
2469
2470 /* plan on adding a backfill skip array for this attribute */
2471 numSkipArrayKeys++;
2472 attno_skip++;
2473 }
2474
2475 prev_numSkipArrayKeys = numSkipArrayKeys;
2476
2477 /*
2478 * Stop once past the final input scan key. We deliberately never add
2479 * a skip array for the last input scan key's attribute -- even when
2480 * there are only inequality keys on that attribute.
2481 */
2482 if (i == scan->numberOfKeys)
2483 break;
2484
2485 /*
2486 * Later preprocessing steps cannot merge a RowCompare into a skip
2487 * array, so stop adding skip arrays once we see one. (Note that we
2488 * can backfill skip arrays before a RowCompare, which will allow keys
2489 * up to and including the RowCompare to be marked required.)
2490 *
2491 * Skip arrays work by maintaining a current array element value,
2492 * which anchors lower-order keys via an implied equality constraint.
2493 * This is incompatible with the current nbtree row comparison design,
2494 * which compares all columns together, as an indivisible group.
2495 * Alternative designs that can be used alongside skip arrays are
2496 * possible, but it's not clear that they're really worth pursuing.
2497 *
2498 * A RowCompare qual "(a, b, c) > (10, 'foo', 42)" is equivalent to
2499 * "(a=10 AND b='foo' AND c>42) OR (a=10 AND b>'foo') OR (a>10)".
2500 * Decomposing this RowCompare into these 3 disjuncts allows each
2501 * disjunct to be executed as a separate "single value" index scan.
2502 * That'll give all 3 scans the ability to add skip arrays in the
2503 * usual way (when there are any scalar keys after the RowCompare).
2504 * Under this scheme, a qual "(a, b, c) > (10, 'foo', 42) AND d = 99"
2505 * performs 3 separate scans, each of which can mark keys up to and
2506 * including its "d = 99" key as required to continue the scan.
2507 */
2508 if (attno_has_rowcompare)
2509 break;
2510
2511 /*
2512 * Now consider next attno_inkey (or keep going if this is an
2513 * additional scan key against the same attribute)
2514 */
2515 if (attno_inkey < inkey->sk_attno)
2516 {
2517 /*
2518 * Now add skip array for previous scan key's attribute, though
2519 * only if the attribute has no equality strategy scan keys
2520 */
2521 if (attno_has_equal)
2522 {
2523 /* Attributes with an = key must have InvalidOid eq_op set */
2524 skip_eq_ops_out[attno_skip - 1] = InvalidOid;
2525 }
2526 else
2527 {
2528 Oid opfamily = rel->rd_opfamily[attno_skip - 1];
2529 Oid opcintype = rel->rd_opcintype[attno_skip - 1];
2530
2531 /* Look up input opclass's equality operator (might fail) */
2532 skip_eq_ops_out[attno_skip - 1] =
2533 get_opfamily_member(opfamily, opcintype, opcintype,
2535
2536 if (!OidIsValid(skip_eq_ops_out[attno_skip - 1]))
2537 {
2538 /*
2539 * Input opclass lacks an equality strategy operator, so
2540 * don't generate a skip array that definitely won't work
2541 */
2542 break;
2543 }
2544
2545 /* plan on adding a backfill skip array for this attribute */
2546 numSkipArrayKeys++;
2547 }
2548
2549 /* Set things up for this new attribute */
2550 attno_skip++;
2551 attno_inkey = inkey->sk_attno;
2552 attno_has_equal = false;
2553 }
2554
2555 /*
2556 * Track if this attribute's scan keys include any equality strategy
2557 * scan keys (IS NULL keys count as equality keys here). Also track
2558 * if it has any RowCompare keys.
2559 */
2560 if (inkey->sk_strategy == BTEqualStrategyNumber ||
2561 (inkey->sk_flags & SK_SEARCHNULL))
2562 attno_has_equal = true;
2563 if (inkey->sk_flags & SK_ROW_HEADER)
2564 attno_has_rowcompare = true;
2565 }
2566
2567 *numSkipArrayKeys_out = numSkipArrayKeys;
2568 return numSAOPArrayKeys + numSkipArrayKeys;
2569}
2570
2571/*
2572 * _bt_find_extreme_element() -- get least or greatest array element
2573 *
2574 * scan and skey identify the index column, whose opfamily determines the
2575 * comparison semantics. strat should be BTLessStrategyNumber to get the
2576 * least element, or BTGreaterStrategyNumber to get the greatest.
2577 */
2578static Datum
2580 StrategyNumber strat,
2581 const Datum *elems, int nelems)
2582{
2583 Relation rel = scan->indexRelation;
2584 Oid cmp_op;
2585 RegProcedure cmp_proc;
2586 FmgrInfo flinfo;
2587 Datum result;
2588 int i;
2589
2590 /*
2591 * Look up the appropriate comparison operator in the opfamily.
2592 *
2593 * Note: it's possible that this would fail, if the opfamily is
2594 * incomplete, but it seems quite unlikely that an opfamily would omit
2595 * non-cross-type comparison operators for any datatype that it supports
2596 * at all.
2597 */
2599 Assert(OidIsValid(elemtype));
2600 cmp_op = get_opfamily_member(rel->rd_opfamily[skey->sk_attno - 1],
2601 elemtype,
2602 elemtype,
2603 strat);
2604 if (!OidIsValid(cmp_op))
2605 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2606 strat, elemtype, elemtype,
2607 rel->rd_opfamily[skey->sk_attno - 1]);
2608 cmp_proc = get_opcode(cmp_op);
2609 if (!RegProcedureIsValid(cmp_proc))
2610 elog(ERROR, "missing oprcode for operator %u", cmp_op);
2611
2612 fmgr_info(cmp_proc, &flinfo);
2613
2614 Assert(nelems > 0);
2615 result = elems[0];
2616 for (i = 1; i < nelems; i++)
2617 {
2618 if (DatumGetBool(FunctionCall2Coll(&flinfo,
2619 skey->sk_collation,
2620 elems[i],
2621 result)))
2622 result = elems[i];
2623 }
2624
2625 return result;
2626}
2627
2628/*
2629 * _bt_setup_array_cmp() -- Set up array comparison functions
2630 *
2631 * Sets ORDER proc in caller's orderproc argument, which is used during binary
2632 * searches of arrays during the index scan. Also sets a same-type ORDER proc
2633 * in caller's *sortprocp argument, which is used when sorting the array.
2634 *
2635 * Preprocessing calls here with all equality strategy scan keys (when scan
2636 * uses equality array keys), including those not associated with any array.
2637 * See _bt_advance_array_keys for an explanation of why it'll need to treat
2638 * simple scalar equality scan keys as degenerate single element arrays.
2639 *
2640 * Caller should pass an orderproc pointing to space that'll store the ORDER
2641 * proc for the scan, and a *sortprocp pointing to its own separate space.
2642 * When calling here for a non-array scan key, sortprocp arg should be NULL.
2643 *
2644 * In the common case where we don't need to deal with cross-type operators,
2645 * only one ORDER proc is actually required by caller. We'll set *sortprocp
2646 * to point to the same memory that caller's orderproc continues to point to.
2647 * Otherwise, *sortprocp will continue to point to caller's own space. Either
2648 * way, *sortprocp will point to a same-type ORDER proc (since that's the only
2649 * safe way to sort/deduplicate the array associated with caller's scan key).
2650 */
2651static void
2653 FmgrInfo *orderproc, FmgrInfo **sortprocp)
2654{
2655 BTScanOpaque so = (BTScanOpaque) scan->opaque;
2656 Relation rel = scan->indexRelation;
2657 RegProcedure cmp_proc;
2658 Oid opcintype = rel->rd_opcintype[skey->sk_attno - 1];
2659
2661 Assert(OidIsValid(elemtype));
2662
2663 /*
2664 * If scankey operator is not a cross-type comparison, we can use the
2665 * cached comparison function; otherwise gotta look it up in the catalogs
2666 */
2667 if (elemtype == opcintype)
2668 {
2669 /* Set same-type ORDER procs for caller */
2670 *orderproc = *index_getprocinfo(rel, skey->sk_attno, BTORDER_PROC);
2671 if (sortprocp)
2672 *sortprocp = orderproc;
2673
2674 return;
2675 }
2676
2677 /*
2678 * Look up the appropriate cross-type comparison function in the opfamily.
2679 *
2680 * Use the opclass input type as the left hand arg type, and the array
2681 * element type as the right hand arg type (since binary searches use an
2682 * index tuple's attribute value to search for a matching array element).
2683 *
2684 * Note: it's possible that this would fail, if the opfamily is
2685 * incomplete, but only in cases where it's quite likely that _bt_first
2686 * would fail in just the same way (had we not failed before it could).
2687 */
2688 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
2689 opcintype, elemtype, BTORDER_PROC);
2690 if (!RegProcedureIsValid(cmp_proc))
2691 elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
2692 BTORDER_PROC, opcintype, elemtype, skey->sk_attno,
2694
2695 /* Set cross-type ORDER proc for caller */
2696 fmgr_info_cxt(cmp_proc, orderproc, so->arrayContext);
2697
2698 /* Done if caller doesn't actually have an array they'll need to sort */
2699 if (!sortprocp)
2700 return;
2701
2702 /*
2703 * Look up the appropriate same-type comparison function in the opfamily.
2704 *
2705 * Note: it's possible that this would fail, if the opfamily is
2706 * incomplete, but it seems quite unlikely that an opfamily would omit
2707 * non-cross-type comparison procs for any datatype that it supports at
2708 * all.
2709 */
2710 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
2711 elemtype, elemtype, BTORDER_PROC);
2712 if (!RegProcedureIsValid(cmp_proc))
2713 elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
2714 BTORDER_PROC, elemtype, elemtype,
2715 skey->sk_attno, RelationGetRelationName(rel));
2716
2717 /* Set same-type ORDER proc for caller */
2718 fmgr_info_cxt(cmp_proc, *sortprocp, so->arrayContext);
2719}
2720
2721/*
2722 * _bt_sort_array_elements() -- sort and de-dup array elements
2723 *
2724 * The array elements are sorted in-place, and the new number of elements
2725 * after duplicate removal is returned.
2726 *
2727 * skey identifies the index column whose opfamily determines the comparison
2728 * semantics, and sortproc is a corresponding ORDER proc. If reverse is true,
2729 * we sort in descending order.
2730 */
2731static int
2732_bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc, bool reverse,
2733 Datum *elems, int nelems)
2734{
2736
2737 if (nelems <= 1)
2738 return nelems; /* no work to do */
2739
2740 /* Sort the array elements */
2741 cxt.sortproc = sortproc;
2742 cxt.collation = skey->sk_collation;
2743 cxt.reverse = reverse;
2744 qsort_arg(elems, nelems, sizeof(Datum),
2746
2747 /* Now scan the sorted elements and remove duplicates */
2748 return qunique_arg(elems, nelems, sizeof(Datum),
2750}
2751
2752/*
2753 * _bt_merge_arrays() -- merge next array's elements into an original array
2754 *
2755 * Called when preprocessing encounters a pair of array equality scan keys,
2756 * both against the same index attribute (during initial array preprocessing).
2757 * Merging reorganizes caller's original array (the left hand arg) in-place,
2758 * without ever copying elements from one array into the other. (Mixing the
2759 * elements together like this would be wrong, since they don't necessarily
2760 * use the same underlying element type, despite all the other similarities.)
2761 *
2762 * Both arrays must have already been sorted and deduplicated by calling
2763 * _bt_sort_array_elements. sortproc is the same-type ORDER proc that was
2764 * just used to sort and deduplicate caller's "next" array. We'll usually be
2765 * able to reuse that order PROC to merge the arrays together now. If not,
2766 * then we'll perform a separate ORDER proc lookup.
2767 *
2768 * If the opfamily doesn't supply a complete set of cross-type ORDER procs we
2769 * may not be able to determine which elements are contradictory. If we have
2770 * the required ORDER proc then we return true (and validly set *nelems_orig),
2771 * guaranteeing that at least the next array can be considered redundant. We
2772 * return false if the required comparisons cannot be made (caller must keep
2773 * both arrays when this happens).
2774 */
2775static bool
2777 bool reverse, Oid origelemtype, Oid nextelemtype,
2778 Datum *elems_orig, int *nelems_orig,
2779 Datum *elems_next, int nelems_next)
2780{
2781 Relation rel = scan->indexRelation;
2782 BTScanOpaque so = (BTScanOpaque) scan->opaque;
2784 int nelems_orig_start = *nelems_orig,
2785 nelems_orig_merged = 0;
2786 FmgrInfo *mergeproc = sortproc;
2787 FmgrInfo crosstypeproc;
2788
2790 Assert(OidIsValid(origelemtype) && OidIsValid(nextelemtype));
2791
2792 if (origelemtype != nextelemtype)
2793 {
2794 RegProcedure cmp_proc;
2795
2796 /*
2797 * Cross-array-element-type merging is required, so can't just reuse
2798 * sortproc when merging
2799 */
2800 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
2801 origelemtype, nextelemtype, BTORDER_PROC);
2802 if (!RegProcedureIsValid(cmp_proc))
2803 {
2804 /* Can't make the required comparisons */
2805 return false;
2806 }
2807
2808 /* We have all we need to determine redundancy/contradictoriness */
2809 mergeproc = &crosstypeproc;
2810 fmgr_info_cxt(cmp_proc, mergeproc, so->arrayContext);
2811 }
2812
2813 cxt.sortproc = mergeproc;
2814 cxt.collation = skey->sk_collation;
2815 cxt.reverse = reverse;
2816
2817 for (int i = 0, j = 0; i < nelems_orig_start && j < nelems_next;)
2818 {
2819 Datum *oelem = elems_orig + i,
2820 *nelem = elems_next + j;
2821 int res = _bt_compare_array_elements(oelem, nelem, &cxt);
2822
2823 if (res == 0)
2824 {
2825 elems_orig[nelems_orig_merged++] = *oelem;
2826 i++;
2827 j++;
2828 }
2829 else if (res < 0)
2830 i++;
2831 else /* res > 0 */
2832 j++;
2833 }
2834
2835 *nelems_orig = nelems_orig_merged;
2836
2837 return true;
2838}
2839
2840/*
2841 * qsort_arg comparator for sorting array elements
2842 */
2843static int
2844_bt_compare_array_elements(const void *a, const void *b, void *arg)
2845{
2846 Datum da = *((const Datum *) a);
2847 Datum db = *((const Datum *) b);
2849 int32 compare;
2850
2852 cxt->collation,
2853 da, db));
2854 if (cxt->reverse)
2856 return compare;
2857}
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
void deconstruct_array(const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3632
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
#define RegProcedureIsValid(p)
Definition: c.h:781
#define INVERT_COMPARE_RESULT(var)
Definition: c.h:1110
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:228
int16_t int16
Definition: c.h:538
regproc RegProcedure
Definition: c.h:660
int32_t int32
Definition: c.h:539
#define unlikely(x)
Definition: c.h:407
#define OidIsValid(objectId)
Definition: c.h:779
struct cursor * cur
Definition: ecpg.c:29
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1170
int errcode(int sqlerrcode)
Definition: elog.c:863
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
Datum OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1422
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:128
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:138
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
Assert(PointerIsAligned(start, uint64))
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:917
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:713
int b
Definition: isn.c:74
int a
Definition: isn.c:73
int j
Definition: isn.c:78
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2438
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:889
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1452
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:168
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1610
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
void * palloc(Size size)
Definition: mcxt.c:1365
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
static bool _bt_merge_arrays(IndexScanDesc scan, ScanKey skey, FmgrInfo *sortproc, bool reverse, Oid origelemtype, Oid nextelemtype, Datum *elems_orig, int *nelems_orig, Datum *elems_next, int nelems_next)
static void _bt_skiparray_strat_increment(IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
static int _bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out, int *numSkipArrayKeys_out)
static bool _bt_saoparray_shrink(IndexScanDesc scan, ScanKey arraysk, ScanKey skey, FmgrInfo *orderproc, BTArrayKeyInfo *array, bool *qual_ok)
struct BTScanKeyPreproc BTScanKeyPreproc
static void _bt_skiparray_strat_adjust(IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
struct BTSortArrayContext BTSortArrayContext
static int _bt_reorder_array_cmp(const void *a, const void *b)
static bool _bt_skiparray_shrink(IndexScanDesc scan, ScanKey skey, BTArrayKeyInfo *array, bool *qual_ok)
static bool _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
static void _bt_unmark_keys(IndexScanDesc scan, int *keyDataMap)
static void _bt_mark_scankey_required(ScanKey skey)
static ScanKey _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
static int _bt_compare_array_elements(const void *a, const void *b, void *arg)
static void _bt_preprocess_array_keys_final(IndexScanDesc scan, int *keyDataMap)
static void _bt_setup_array_cmp(IndexScanDesc scan, ScanKey skey, Oid elemtype, FmgrInfo *orderproc, FmgrInfo **sortprocp)
static int _bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc, bool reverse, Datum *elems, int nelems)
static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, const Datum *elems, int nelems)
static bool _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op, ScanKey leftarg, ScanKey rightarg, BTArrayKeyInfo *array, FmgrInfo *orderproc, bool *result)
static void _bt_skiparray_strat_decrement(IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
static bool _bt_compare_array_scankey_args(IndexScanDesc scan, ScanKey arraysk, ScanKey skey, FmgrInfo *orderproc, BTArrayKeyInfo *array, bool *qual_ok)
void _bt_preprocess_keys(IndexScanDesc scan)
#define SK_BT_SKIP
Definition: nbtree.h:1137
#define BTORDER_PROC
Definition: nbtree.h:717
#define SK_BT_INDOPTION_SHIFT
Definition: nbtree.h:1146
#define SK_BT_REQBKWD
Definition: nbtree.h:1136
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:1148
#define SK_BT_REQFWD
Definition: nbtree.h:1135
#define SK_BT_DESC
Definition: nbtree.h:1147
#define BTCommuteStrategyNumber(strat)
Definition: nbtree.h:686
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:1097
int _bt_binsrch_array_skey(FmgrInfo *orderproc, bool cur_elem_trig, ScanDirection dir, Datum tupdatum, bool tupnull, BTArrayKeyInfo *array, ScanKey cur, int32 *set_elem_result)
Definition: nbtutils.c:289
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
void * arg
#define INDEX_MAX_KEYS
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
#define qsort(a, b, c, d)
Definition: port.h:500
static bool DatumGetBool(Datum X)
Definition: postgres.h:100
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
static size_t qunique_arg(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *, void *), void *arg)
Definition: qunique.h:46
#define RelationGetDescr(relation)
Definition: rel.h:541
#define RelationGetRelationName(relation)
Definition: rel.h:549
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:534
void ScanKeyEntryInitialize(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, RegProcedure procedure, Datum argument)
Definition: scankey.c:32
@ NoMovementScanDirection
Definition: sdir.h:27
#define SK_ROW_HEADER
Definition: skey.h:117
#define SK_SEARCHARRAY
Definition: skey.h:120
#define SK_ROW_MEMBER
Definition: skey.h:118
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_SEARCHNULL
Definition: skey.h:121
#define SK_ROW_END
Definition: skey.h:119
ScanKeyData * ScanKey
Definition: skey.h:75
#define SK_ISNULL
Definition: skey.h:115
SkipSupport PrepareSkipSupportFromOpclass(Oid opfamily, Oid opcintype, bool reverse)
Definition: skipsupport.c:30
uint16 StrategyNumber
Definition: stratnum.h:22
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define InvalidStrategy
Definition: stratnum.h:24
#define BTMaxStrategyNumber
Definition: stratnum.h:35
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
bool attbyval
Definition: nbtree.h:1046
Datum * elem_values
Definition: nbtree.h:1041
ScanKey high_compare
Definition: nbtree.h:1050
ScanKey low_compare
Definition: nbtree.h:1049
SkipSupport sksup
Definition: nbtree.h:1048
int16 attlen
Definition: nbtree.h:1045
bool null_elem
Definition: nbtree.h:1047
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:1066
FmgrInfo * orderProcs
Definition: nbtree.h:1067
ScanKey keyData
Definition: nbtree.h:1058
MemoryContext arrayContext
Definition: nbtree.h:1068
int16 attlen
Definition: tupdesc.h:71
Definition: fmgr.h:57
Oid fn_oid
Definition: fmgr.h:59
struct ScanKeyData * keyData
Definition: relscan.h:143
struct ParallelIndexScanDescData * parallel_scan
Definition: relscan.h:193
Relation indexRelation
Definition: relscan.h:139
Oid * rd_opcintype
Definition: rel.h:208
int16 * rd_indoption
Definition: rel.h:211
Oid * rd_opfamily
Definition: rel.h:207
int sk_flags
Definition: skey.h:66
Datum sk_argument
Definition: skey.h:72
FmgrInfo sk_func
Definition: skey.h:71
Oid sk_subtype
Definition: skey.h:69
Oid sk_collation
Definition: skey.h:70
StrategyNumber sk_strategy
Definition: skey.h:68
AttrNumber sk_attno
Definition: skey.h:67
SkipSupportIncDec decrement
Definition: skipsupport.h:91
SkipSupportIncDec increment
Definition: skipsupport.h:92
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175