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 "lib/qunique.h"
20#include "utils/array.h"
21#include "utils/lsyscache.h"
22#include "utils/memutils.h"
23
24typedef struct BTScanKeyPreproc
25{
27 int inkeyi;
30
31typedef struct BTSortArrayContext
32{
35 bool reverse;
37
38static bool _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption);
39static void _bt_mark_scankey_required(ScanKey skey);
41 ScanKey leftarg, ScanKey rightarg,
42 BTArrayKeyInfo *array, FmgrInfo *orderproc,
43 bool *result);
45 ScanKey arraysk, ScanKey skey,
46 FmgrInfo *orderproc, BTArrayKeyInfo *array,
47 bool *qual_ok);
48static ScanKey _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys);
49static void _bt_preprocess_array_keys_final(IndexScanDesc scan, int *keyDataMap);
51 Oid elemtype, StrategyNumber strat,
52 Datum *elems, int nelems);
53static void _bt_setup_array_cmp(IndexScanDesc scan, ScanKey skey, Oid elemtype,
54 FmgrInfo *orderproc, FmgrInfo **sortprocp);
55static int _bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc,
56 bool reverse, Datum *elems, int nelems);
57static bool _bt_merge_arrays(IndexScanDesc scan, ScanKey skey,
58 FmgrInfo *sortproc, bool reverse,
59 Oid origelemtype, Oid nextelemtype,
60 Datum *elems_orig, int *nelems_orig,
61 Datum *elems_next, int nelems_next);
62static int _bt_compare_array_elements(const void *a, const void *b, void *arg);
63
64
65/*
66 * _bt_preprocess_keys() -- Preprocess scan keys
67 *
68 * The given search-type keys (taken from scan->keyData[])
69 * are copied to so->keyData[] with possible transformation.
70 * scan->numberOfKeys is the number of input keys, so->numberOfKeys gets
71 * the number of output keys. Calling here a second or subsequent time
72 * (during the same btrescan) is a no-op.
73 *
74 * The output keys are marked with additional sk_flags bits beyond the
75 * system-standard bits supplied by the caller. The DESC and NULLS_FIRST
76 * indoption bits for the relevant index attribute are copied into the flags.
77 * Also, for a DESC column, we commute (flip) all the sk_strategy numbers
78 * so that the index sorts in the desired direction.
79 *
80 * One key purpose of this routine is to discover which scan keys must be
81 * satisfied to continue the scan. It also attempts to eliminate redundant
82 * keys and detect contradictory keys. (If the index opfamily provides
83 * incomplete sets of cross-type operators, we may fail to detect redundant
84 * or contradictory keys, but we can survive that.)
85 *
86 * The output keys must be sorted by index attribute. Presently we expect
87 * (but verify) that the input keys are already so sorted --- this is done
88 * by match_clauses_to_index() in indxpath.c. Some reordering of the keys
89 * within each attribute may be done as a byproduct of the processing here.
90 * That process must leave array scan keys (within an attribute) in the same
91 * order as corresponding entries from the scan's BTArrayKeyInfo array info.
92 *
93 * The output keys are marked with flags SK_BT_REQFWD and/or SK_BT_REQBKWD
94 * if they must be satisfied in order to continue the scan forward or backward
95 * respectively. _bt_checkkeys uses these flags. For example, if the quals
96 * are "x = 1 AND y < 4 AND z < 5", then _bt_checkkeys will reject a tuple
97 * (1,2,7), but we must continue the scan in case there are tuples (1,3,z).
98 * But once we reach tuples like (1,4,z) we can stop scanning because no
99 * later tuples could match. This is reflected by marking the x and y keys,
100 * but not the z key, with SK_BT_REQFWD. In general, the keys for leading
101 * attributes with "=" keys are marked both SK_BT_REQFWD and SK_BT_REQBKWD.
102 * For the first attribute without an "=" key, any "<" and "<=" keys are
103 * marked SK_BT_REQFWD while any ">" and ">=" keys are marked SK_BT_REQBKWD.
104 * This can be seen to be correct by considering the above example. Note
105 * in particular that if there are no keys for a given attribute, the keys for
106 * subsequent attributes can never be required; for instance "WHERE y = 4"
107 * requires a full-index scan.
108 *
109 * If possible, redundant keys are eliminated: we keep only the tightest
110 * >/>= bound and the tightest </<= bound, and if there's an = key then
111 * that's the only one returned. (So, we return either a single = key,
112 * or one or two boundary-condition keys for each attr.) However, if we
113 * cannot compare two keys for lack of a suitable cross-type operator,
114 * we cannot eliminate either. If there are two such keys of the same
115 * operator strategy, the second one is just pushed into the output array
116 * without further processing here. We may also emit both >/>= or both
117 * </<= keys if we can't compare them. The logic about required keys still
118 * works if we don't eliminate redundant keys.
119 *
120 * Note that one reason we need direction-sensitive required-key flags is
121 * precisely that we may not be able to eliminate redundant keys. Suppose
122 * we have "x > 4::int AND x > 10::bigint", and we are unable to determine
123 * which key is more restrictive for lack of a suitable cross-type operator.
124 * _bt_first will arbitrarily pick one of the keys to do the initial
125 * positioning with. If it picks x > 4, then the x > 10 condition will fail
126 * until we reach index entries > 10; but we can't stop the scan just because
127 * x > 10 is failing. On the other hand, if we are scanning backwards, then
128 * failure of either key is indeed enough to stop the scan. (In general, when
129 * inequality keys are present, the initial-positioning code only promises to
130 * position before the first possible match, not exactly at the first match,
131 * for a forward scan; or after the last match for a backward scan.)
132 *
133 * As a byproduct of this work, we can detect contradictory quals such
134 * as "x = 1 AND x > 2". If we see that, we return so->qual_ok = false,
135 * indicating the scan need not be run at all since no tuples can match.
136 * (In this case we do not bother completing the output key array!)
137 * Again, missing cross-type operators might cause us to fail to prove the
138 * quals contradictory when they really are, but the scan will work correctly.
139 *
140 * Row comparison keys are currently also treated without any smarts:
141 * we just transfer them into the preprocessed array without any
142 * editorialization. We can treat them the same as an ordinary inequality
143 * comparison on the row's first index column, for the purposes of the logic
144 * about required keys.
145 *
146 * Note: the reason we have to copy the preprocessed scan keys into private
147 * storage is that we are modifying the array based on comparisons of the
148 * key argument values, which could change on a rescan. Therefore we can't
149 * overwrite the source data.
150 */
151void
153{
154 BTScanOpaque so = (BTScanOpaque) scan->opaque;
155 int numberOfKeys = scan->numberOfKeys;
156 int16 *indoption = scan->indexRelation->rd_indoption;
157 int new_numberOfKeys;
158 int numberOfEqualCols;
159 ScanKey inkeys;
161 bool test_result;
162 AttrNumber attno;
163 ScanKey arrayKeyData;
164 int *keyDataMap = NULL;
165 int arrayidx = 0;
166
167 if (so->numberOfKeys > 0)
168 {
169 /*
170 * Only need to do preprocessing once per btrescan, at most. All
171 * calls after the first are handled as no-ops.
172 */
173 return;
174 }
175
176 /* initialize result variables */
177 so->qual_ok = true;
178 so->numberOfKeys = 0;
179
180 if (numberOfKeys < 1)
181 return; /* done if qual-less scan */
182
183 /* If any keys are SK_SEARCHARRAY type, set up array-key info */
184 arrayKeyData = _bt_preprocess_array_keys(scan, &numberOfKeys);
185 if (!so->qual_ok)
186 {
187 /* unmatchable array, so give up */
188 return;
189 }
190
191 /*
192 * Treat arrayKeyData[] (a partially preprocessed copy of scan->keyData[])
193 * as our input if _bt_preprocess_array_keys just allocated it, else just
194 * use scan->keyData[]
195 */
196 if (arrayKeyData)
197 {
198 inkeys = arrayKeyData;
199
200 /* Also maintain keyDataMap for remapping so->orderProcs[] later */
201 keyDataMap = MemoryContextAlloc(so->arrayContext,
202 numberOfKeys * sizeof(int));
203 }
204 else
205 inkeys = scan->keyData;
206
207 /* we check that input keys are correctly ordered */
208 if (inkeys[0].sk_attno < 1)
209 elog(ERROR, "btree index keys must be ordered by attribute");
210
211 /* We can short-circuit most of the work if there's just one key */
212 if (numberOfKeys == 1)
213 {
214 /* Apply indoption to scankey (might change sk_strategy!) */
215 if (!_bt_fix_scankey_strategy(&inkeys[0], indoption))
216 so->qual_ok = false;
217 memcpy(&so->keyData[0], &inkeys[0], sizeof(ScanKeyData));
218 so->numberOfKeys = 1;
219 /* We can mark the qual as required if it's for first index col */
220 if (inkeys[0].sk_attno == 1)
222 if (arrayKeyData)
223 {
224 /*
225 * Don't call _bt_preprocess_array_keys_final in this fast path
226 * (we'll miss out on the single value array transformation, but
227 * that's not nearly as important when there's only one scan key)
228 */
231 (so->arrayKeys[0].scan_key == 0 &&
232 OidIsValid(so->orderProcs[0].fn_oid)));
233 }
234
235 return;
236 }
237
238 /*
239 * Otherwise, do the full set of pushups.
240 */
241 new_numberOfKeys = 0;
242 numberOfEqualCols = 0;
243
244 /*
245 * Initialize for processing of keys for attr 1.
246 *
247 * xform[i] points to the currently best scan key of strategy type i+1; it
248 * is NULL if we haven't yet found such a key for this attr.
249 */
250 attno = 1;
251 memset(xform, 0, sizeof(xform));
252
253 /*
254 * Loop iterates from 0 to numberOfKeys inclusive; we use the last pass to
255 * handle after-last-key processing. Actual exit from the loop is at the
256 * "break" statement below.
257 */
258 for (int i = 0;; i++)
259 {
260 ScanKey inkey = inkeys + i;
261 int j;
262
263 if (i < numberOfKeys)
264 {
265 /* Apply indoption to scankey (might change sk_strategy!) */
266 if (!_bt_fix_scankey_strategy(inkey, indoption))
267 {
268 /* NULL can't be matched, so give up */
269 so->qual_ok = false;
270 return;
271 }
272 }
273
274 /*
275 * If we are at the end of the keys for a particular attr, finish up
276 * processing and emit the cleaned-up keys.
277 */
278 if (i == numberOfKeys || inkey->sk_attno != attno)
279 {
280 int priorNumberOfEqualCols = numberOfEqualCols;
281
282 /* check input keys are correctly ordered */
283 if (i < numberOfKeys && inkey->sk_attno < attno)
284 elog(ERROR, "btree index keys must be ordered by attribute");
285
286 /*
287 * If = has been specified, all other keys can be eliminated as
288 * redundant. Note that this is no less true if the = key is
289 * SEARCHARRAY; the only real difference is that the inequality
290 * key _becomes_ redundant by making _bt_compare_scankey_args
291 * eliminate the subset of elements that won't need to be matched.
292 *
293 * If we have a case like "key = 1 AND key > 2", we set qual_ok to
294 * false and abandon further processing. We'll do the same thing
295 * given a case like "key IN (0, 1) AND key > 2".
296 *
297 * We also have to deal with the case of "key IS NULL", which is
298 * unsatisfiable in combination with any other index condition. By
299 * the time we get here, that's been classified as an equality
300 * check, and we've rejected any combination of it with a regular
301 * equality condition; but not with other types of conditions.
302 */
303 if (xform[BTEqualStrategyNumber - 1].inkey)
304 {
305 ScanKey eq = xform[BTEqualStrategyNumber - 1].inkey;
306 BTArrayKeyInfo *array = NULL;
307 FmgrInfo *orderproc = NULL;
308
309 if (arrayKeyData && (eq->sk_flags & SK_SEARCHARRAY))
310 {
311 int eq_in_ikey,
312 eq_arrayidx;
313
314 eq_in_ikey = xform[BTEqualStrategyNumber - 1].inkeyi;
315 eq_arrayidx = xform[BTEqualStrategyNumber - 1].arrayidx;
316 array = &so->arrayKeys[eq_arrayidx - 1];
317 orderproc = so->orderProcs + eq_in_ikey;
318
319 Assert(array->scan_key == eq_in_ikey);
320 Assert(OidIsValid(orderproc->fn_oid));
321 }
322
323 for (j = BTMaxStrategyNumber; --j >= 0;)
324 {
325 ScanKey chk = xform[j].inkey;
326
327 if (!chk || j == (BTEqualStrategyNumber - 1))
328 continue;
329
330 if (eq->sk_flags & SK_SEARCHNULL)
331 {
332 /* IS NULL is contradictory to anything else */
333 so->qual_ok = false;
334 return;
335 }
336
337 if (_bt_compare_scankey_args(scan, chk, eq, chk,
338 array, orderproc,
339 &test_result))
340 {
341 if (!test_result)
342 {
343 /* keys proven mutually contradictory */
344 so->qual_ok = false;
345 return;
346 }
347 /* else discard the redundant non-equality key */
348 Assert(!array || array->num_elems > 0);
349 xform[j].inkey = NULL;
350 xform[j].inkeyi = -1;
351 }
352 /* else, cannot determine redundancy, keep both keys */
353 }
354 /* track number of attrs for which we have "=" keys */
355 numberOfEqualCols++;
356 }
357
358 /* try to keep only one of <, <= */
359 if (xform[BTLessStrategyNumber - 1].inkey &&
360 xform[BTLessEqualStrategyNumber - 1].inkey)
361 {
362 ScanKey lt = xform[BTLessStrategyNumber - 1].inkey;
363 ScanKey le = xform[BTLessEqualStrategyNumber - 1].inkey;
364
365 if (_bt_compare_scankey_args(scan, le, lt, le, NULL, NULL,
366 &test_result))
367 {
368 if (test_result)
369 xform[BTLessEqualStrategyNumber - 1].inkey = NULL;
370 else
371 xform[BTLessStrategyNumber - 1].inkey = NULL;
372 }
373 }
374
375 /* try to keep only one of >, >= */
376 if (xform[BTGreaterStrategyNumber - 1].inkey &&
377 xform[BTGreaterEqualStrategyNumber - 1].inkey)
378 {
379 ScanKey gt = xform[BTGreaterStrategyNumber - 1].inkey;
380 ScanKey ge = xform[BTGreaterEqualStrategyNumber - 1].inkey;
381
382 if (_bt_compare_scankey_args(scan, ge, gt, ge, NULL, NULL,
383 &test_result))
384 {
385 if (test_result)
386 xform[BTGreaterEqualStrategyNumber - 1].inkey = NULL;
387 else
388 xform[BTGreaterStrategyNumber - 1].inkey = NULL;
389 }
390 }
391
392 /*
393 * Emit the cleaned-up keys into the so->keyData[] array, and then
394 * mark them if they are required. They are required (possibly
395 * only in one direction) if all attrs before this one had "=".
396 */
397 for (j = BTMaxStrategyNumber; --j >= 0;)
398 {
399 if (xform[j].inkey)
400 {
401 ScanKey outkey = &so->keyData[new_numberOfKeys++];
402
403 memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
404 if (arrayKeyData)
405 keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
406 if (priorNumberOfEqualCols == attno - 1)
408 }
409 }
410
411 /*
412 * Exit loop here if done.
413 */
414 if (i == numberOfKeys)
415 break;
416
417 /* Re-initialize for new attno */
418 attno = inkey->sk_attno;
419 memset(xform, 0, sizeof(xform));
420 }
421
422 /* check strategy this key's operator corresponds to */
423 j = inkey->sk_strategy - 1;
424
425 /* if row comparison, push it directly to the output array */
426 if (inkey->sk_flags & SK_ROW_HEADER)
427 {
428 ScanKey outkey = &so->keyData[new_numberOfKeys++];
429
430 memcpy(outkey, inkey, sizeof(ScanKeyData));
431 if (arrayKeyData)
432 keyDataMap[new_numberOfKeys - 1] = i;
433 if (numberOfEqualCols == attno - 1)
435
436 /*
437 * We don't support RowCompare using equality; such a qual would
438 * mess up the numberOfEqualCols tracking.
439 */
441 continue;
442 }
443
444 if (inkey->sk_strategy == BTEqualStrategyNumber &&
445 (inkey->sk_flags & SK_SEARCHARRAY))
446 {
447 /* must track how input scan keys map to arrays */
448 Assert(arrayKeyData);
449 arrayidx++;
450 }
451
452 /*
453 * have we seen a scan key for this same attribute and using this same
454 * operator strategy before now?
455 */
456 if (xform[j].inkey == NULL)
457 {
458 /* nope, so this scan key wins by default (at least for now) */
459 xform[j].inkey = inkey;
460 xform[j].inkeyi = i;
461 xform[j].arrayidx = arrayidx;
462 }
463 else
464 {
465 FmgrInfo *orderproc = NULL;
466 BTArrayKeyInfo *array = NULL;
467
468 /*
469 * Seen one of these before, so keep only the more restrictive key
470 * if possible
471 */
472 if (j == (BTEqualStrategyNumber - 1) && arrayKeyData)
473 {
474 /*
475 * Have to set up array keys
476 */
477 if (inkey->sk_flags & SK_SEARCHARRAY)
478 {
479 array = &so->arrayKeys[arrayidx - 1];
480 orderproc = so->orderProcs + i;
481
482 Assert(array->scan_key == i);
483 Assert(OidIsValid(orderproc->fn_oid));
484 }
485 else if (xform[j].inkey->sk_flags & SK_SEARCHARRAY)
486 {
487 array = &so->arrayKeys[xform[j].arrayidx - 1];
488 orderproc = so->orderProcs + xform[j].inkeyi;
489
490 Assert(array->scan_key == xform[j].inkeyi);
491 Assert(OidIsValid(orderproc->fn_oid));
492 }
493
494 /*
495 * Both scan keys might have arrays, in which case we'll
496 * arbitrarily pass only one of the arrays. That won't
497 * matter, since _bt_compare_scankey_args is aware that two
498 * SEARCHARRAY scan keys mean that _bt_preprocess_array_keys
499 * failed to eliminate redundant arrays through array merging.
500 * _bt_compare_scankey_args just returns false when it sees
501 * this; it won't even try to examine either array.
502 */
503 }
504
505 if (_bt_compare_scankey_args(scan, inkey, inkey, xform[j].inkey,
506 array, orderproc, &test_result))
507 {
508 /* Have all we need to determine redundancy */
509 if (test_result)
510 {
511 Assert(!array || array->num_elems > 0);
512
513 /*
514 * New key is more restrictive, and so replaces old key...
515 */
516 if (j != (BTEqualStrategyNumber - 1) ||
517 !(xform[j].inkey->sk_flags & SK_SEARCHARRAY))
518 {
519 xform[j].inkey = inkey;
520 xform[j].inkeyi = i;
521 xform[j].arrayidx = arrayidx;
522 }
523 else
524 {
525 /*
526 * ...unless we have to keep the old key because it's
527 * an array that rendered the new key redundant. We
528 * need to make sure that we don't throw away an array
529 * scan key. _bt_preprocess_array_keys_final expects
530 * us to keep all of the arrays that weren't already
531 * eliminated by _bt_preprocess_array_keys earlier on.
532 */
533 Assert(!(inkey->sk_flags & SK_SEARCHARRAY));
534 }
535 }
536 else if (j == (BTEqualStrategyNumber - 1))
537 {
538 /* key == a && key == b, but a != b */
539 so->qual_ok = false;
540 return;
541 }
542 /* else old key is more restrictive, keep it */
543 }
544 else
545 {
546 /*
547 * We can't determine which key is more restrictive. Push
548 * xform[j] directly to the output array, then set xform[j] to
549 * the new scan key.
550 *
551 * Note: We do things this way around so that our arrays are
552 * always in the same order as their corresponding scan keys,
553 * even with incomplete opfamilies. _bt_advance_array_keys
554 * depends on this.
555 */
556 ScanKey outkey = &so->keyData[new_numberOfKeys++];
557
558 memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
559 if (arrayKeyData)
560 keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
561 if (numberOfEqualCols == attno - 1)
563 xform[j].inkey = inkey;
564 xform[j].inkeyi = i;
565 xform[j].arrayidx = arrayidx;
566 }
567 }
568 }
569
570 so->numberOfKeys = new_numberOfKeys;
571
572 /*
573 * Now that we've built a temporary mapping from so->keyData[] (output
574 * scan keys) to arrayKeyData[] (our input scan keys), fix array->scan_key
575 * references. Also consolidate the so->orderProcs[] array such that it
576 * can be subscripted using so->keyData[]-wise offsets.
577 */
578 if (arrayKeyData)
579 _bt_preprocess_array_keys_final(scan, keyDataMap);
580
581 /* Could pfree arrayKeyData/keyDataMap now, but not worth the cycles */
582}
583
584/*
585 * Adjust a scankey's strategy and flags setting as needed for indoptions.
586 *
587 * We copy the appropriate indoption value into the scankey sk_flags
588 * (shifting to avoid clobbering system-defined flag bits). Also, if
589 * the DESC option is set, commute (flip) the operator strategy number.
590 *
591 * A secondary purpose is to check for IS NULL/NOT NULL scankeys and set up
592 * the strategy field correctly for them.
593 *
594 * Lastly, for ordinary scankeys (not IS NULL/NOT NULL), we check for a
595 * NULL comparison value. Since all btree operators are assumed strict,
596 * a NULL means that the qual cannot be satisfied. We return true if the
597 * comparison value isn't NULL, or false if the scan should be abandoned.
598 *
599 * This function is applied to the *input* scankey structure; therefore
600 * on a rescan we will be looking at already-processed scankeys. Hence
601 * we have to be careful not to re-commute the strategy if we already did it.
602 * It's a bit ugly to modify the caller's copy of the scankey but in practice
603 * there shouldn't be any problem, since the index's indoptions are certainly
604 * not going to change while the scankey survives.
605 */
606static bool
608{
609 int addflags;
610
611 addflags = indoption[skey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
612
613 /*
614 * We treat all btree operators as strict (even if they're not so marked
615 * in pg_proc). This means that it is impossible for an operator condition
616 * with a NULL comparison constant to succeed, and we can reject it right
617 * away.
618 *
619 * However, we now also support "x IS NULL" clauses as search conditions,
620 * so in that case keep going. The planner has not filled in any
621 * particular strategy in this case, so set it to BTEqualStrategyNumber
622 * --- we can treat IS NULL as an equality operator for purposes of search
623 * strategy.
624 *
625 * Likewise, "x IS NOT NULL" is supported. We treat that as either "less
626 * than NULL" in a NULLS LAST index, or "greater than NULL" in a NULLS
627 * FIRST index.
628 *
629 * Note: someday we might have to fill in sk_collation from the index
630 * column's collation. At the moment this is a non-issue because we'll
631 * never actually call the comparison operator on a NULL.
632 */
633 if (skey->sk_flags & SK_ISNULL)
634 {
635 /* SK_ISNULL shouldn't be set in a row header scankey */
636 Assert(!(skey->sk_flags & SK_ROW_HEADER));
637
638 /* Set indoption flags in scankey (might be done already) */
639 skey->sk_flags |= addflags;
640
641 /* Set correct strategy for IS NULL or NOT NULL search */
642 if (skey->sk_flags & SK_SEARCHNULL)
643 {
645 skey->sk_subtype = InvalidOid;
646 skey->sk_collation = InvalidOid;
647 }
648 else if (skey->sk_flags & SK_SEARCHNOTNULL)
649 {
650 if (skey->sk_flags & SK_BT_NULLS_FIRST)
652 else
654 skey->sk_subtype = InvalidOid;
655 skey->sk_collation = InvalidOid;
656 }
657 else
658 {
659 /* regular qual, so it cannot be satisfied */
660 return false;
661 }
662
663 /* Needn't do the rest */
664 return true;
665 }
666
667 /* Adjust strategy for DESC, if we didn't already */
668 if ((addflags & SK_BT_DESC) && !(skey->sk_flags & SK_BT_DESC))
670 skey->sk_flags |= addflags;
671
672 /* If it's a row header, fix row member flags and strategies similarly */
673 if (skey->sk_flags & SK_ROW_HEADER)
674 {
675 ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
676
677 if (subkey->sk_flags & SK_ISNULL)
678 {
679 /* First row member is NULL, so RowCompare is unsatisfiable */
680 Assert(subkey->sk_flags & SK_ROW_MEMBER);
681 return false;
682 }
683
684 for (;;)
685 {
686 Assert(subkey->sk_flags & SK_ROW_MEMBER);
687 addflags = indoption[subkey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
688 if ((addflags & SK_BT_DESC) && !(subkey->sk_flags & SK_BT_DESC))
690 subkey->sk_flags |= addflags;
691 if (subkey->sk_flags & SK_ROW_END)
692 break;
693 subkey++;
694 }
695 }
696
697 return true;
698}
699
700/*
701 * Mark a scankey as "required to continue the scan".
702 *
703 * Depending on the operator type, the key may be required for both scan
704 * directions or just one. Also, if the key is a row comparison header,
705 * we have to mark its first subsidiary ScanKey as required. (Subsequent
706 * subsidiary ScanKeys are normally for lower-order columns, and thus
707 * cannot be required, since they're after the first non-equality scankey.)
708 *
709 * Note: when we set required-key flag bits in a subsidiary scankey, we are
710 * scribbling on a data structure belonging to the index AM's caller, not on
711 * our private copy. This should be OK because the marking will not change
712 * from scan to scan within a query, and so we'd just re-mark the same way
713 * anyway on a rescan. Something to keep an eye on though.
714 */
715static void
717{
718 int addflags;
719
720 switch (skey->sk_strategy)
721 {
724 addflags = SK_BT_REQFWD;
725 break;
727 addflags = SK_BT_REQFWD | SK_BT_REQBKWD;
728 break;
731 addflags = SK_BT_REQBKWD;
732 break;
733 default:
734 elog(ERROR, "unrecognized StrategyNumber: %d",
735 (int) skey->sk_strategy);
736 addflags = 0; /* keep compiler quiet */
737 break;
738 }
739
740 skey->sk_flags |= addflags;
741
742 if (skey->sk_flags & SK_ROW_HEADER)
743 {
744 ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
745
746 /* First subkey should be same column/operator as the header */
747 Assert(subkey->sk_flags & SK_ROW_MEMBER);
748 Assert(subkey->sk_attno == skey->sk_attno);
749 Assert(subkey->sk_strategy == skey->sk_strategy);
750 subkey->sk_flags |= addflags;
751 }
752}
753
754/*
755 * Compare two scankey values using a specified operator.
756 *
757 * The test we want to perform is logically "leftarg op rightarg", where
758 * leftarg and rightarg are the sk_argument values in those ScanKeys, and
759 * the comparison operator is the one in the op ScanKey. However, in
760 * cross-data-type situations we may need to look up the correct operator in
761 * the index's opfamily: it is the one having amopstrategy = op->sk_strategy
762 * and amoplefttype/amoprighttype equal to the two argument datatypes.
763 *
764 * If the opfamily doesn't supply a complete set of cross-type operators we
765 * may not be able to make the comparison. If we can make the comparison
766 * we store the operator result in *result and return true. We return false
767 * if the comparison could not be made.
768 *
769 * If either leftarg or rightarg are an array, we'll apply array-specific
770 * rules to determine which array elements are redundant on behalf of caller.
771 * It is up to our caller to save whichever of the two scan keys is the array,
772 * and discard the non-array scan key (the non-array scan key is guaranteed to
773 * be redundant with any complete opfamily). Caller isn't expected to call
774 * here with a pair of array scan keys provided we're dealing with a complete
775 * opfamily (_bt_preprocess_array_keys will merge array keys together to make
776 * sure of that).
777 *
778 * Note: we'll also shrink caller's array as needed to eliminate redundant
779 * array elements. One reason why caller should prefer to discard non-array
780 * scan keys is so that we'll have the opportunity to shrink the array
781 * multiple times, in multiple calls (for each of several other scan keys on
782 * the same index attribute).
783 *
784 * Note: op always points at the same ScanKey as either leftarg or rightarg.
785 * Since we don't scribble on the scankeys themselves, this aliasing should
786 * cause no trouble.
787 *
788 * Note: this routine needs to be insensitive to any DESC option applied
789 * to the index column. For example, "x < 4" is a tighter constraint than
790 * "x < 5" regardless of which way the index is sorted.
791 */
792static bool
794 ScanKey leftarg, ScanKey rightarg,
795 BTArrayKeyInfo *array, FmgrInfo *orderproc,
796 bool *result)
797{
798 Relation rel = scan->indexRelation;
799 Oid lefttype,
800 righttype,
801 optype,
802 opcintype,
803 cmp_op;
804 StrategyNumber strat;
805
806 /*
807 * First, deal with cases where one or both args are NULL. This should
808 * only happen when the scankeys represent IS NULL/NOT NULL conditions.
809 */
810 if ((leftarg->sk_flags | rightarg->sk_flags) & SK_ISNULL)
811 {
812 bool leftnull,
813 rightnull;
814
815 if (leftarg->sk_flags & SK_ISNULL)
816 {
818 leftnull = true;
819 }
820 else
821 leftnull = false;
822 if (rightarg->sk_flags & SK_ISNULL)
823 {
825 rightnull = true;
826 }
827 else
828 rightnull = false;
829
830 /*
831 * We treat NULL as either greater than or less than all other values.
832 * Since true > false, the tests below work correctly for NULLS LAST
833 * logic. If the index is NULLS FIRST, we need to flip the strategy.
834 */
835 strat = op->sk_strategy;
836 if (op->sk_flags & SK_BT_NULLS_FIRST)
837 strat = BTCommuteStrategyNumber(strat);
838
839 switch (strat)
840 {
842 *result = (leftnull < rightnull);
843 break;
845 *result = (leftnull <= rightnull);
846 break;
848 *result = (leftnull == rightnull);
849 break;
851 *result = (leftnull >= rightnull);
852 break;
854 *result = (leftnull > rightnull);
855 break;
856 default:
857 elog(ERROR, "unrecognized StrategyNumber: %d", (int) strat);
858 *result = false; /* keep compiler quiet */
859 break;
860 }
861 return true;
862 }
863
864 /*
865 * If either leftarg or rightarg are equality-type array scankeys, we need
866 * specialized handling (since by now we know that IS NULL wasn't used)
867 */
868 if (array)
869 {
870 bool leftarray,
871 rightarray;
872
873 leftarray = ((leftarg->sk_flags & SK_SEARCHARRAY) &&
875 rightarray = ((rightarg->sk_flags & SK_SEARCHARRAY) &&
877
878 /*
879 * _bt_preprocess_array_keys is responsible for merging together array
880 * scan keys, and will do so whenever the opfamily has the required
881 * cross-type support. If it failed to do that, we handle it just
882 * like the case where we can't make the comparison ourselves.
883 */
884 if (leftarray && rightarray)
885 {
886 /* Can't make the comparison */
887 *result = false; /* suppress compiler warnings */
888 return false;
889 }
890
891 /*
892 * Otherwise we need to determine if either one of leftarg or rightarg
893 * uses an array, then pass this through to a dedicated helper
894 * function.
895 */
896 if (leftarray)
897 return _bt_compare_array_scankey_args(scan, leftarg, rightarg,
898 orderproc, array, result);
899 else if (rightarray)
900 return _bt_compare_array_scankey_args(scan, rightarg, leftarg,
901 orderproc, array, result);
902
903 /* FALL THRU */
904 }
905
906 /*
907 * The opfamily we need to worry about is identified by the index column.
908 */
909 Assert(leftarg->sk_attno == rightarg->sk_attno);
910
911 opcintype = rel->rd_opcintype[leftarg->sk_attno - 1];
912
913 /*
914 * Determine the actual datatypes of the ScanKey arguments. We have to
915 * support the convention that sk_subtype == InvalidOid means the opclass
916 * input type; this is a hack to simplify life for ScanKeyInit().
917 */
918 lefttype = leftarg->sk_subtype;
919 if (lefttype == InvalidOid)
920 lefttype = opcintype;
921 righttype = rightarg->sk_subtype;
922 if (righttype == InvalidOid)
923 righttype = opcintype;
924 optype = op->sk_subtype;
925 if (optype == InvalidOid)
926 optype = opcintype;
927
928 /*
929 * If leftarg and rightarg match the types expected for the "op" scankey,
930 * we can use its already-looked-up comparison function.
931 */
932 if (lefttype == opcintype && righttype == optype)
933 {
935 op->sk_collation,
936 leftarg->sk_argument,
937 rightarg->sk_argument));
938 return true;
939 }
940
941 /*
942 * Otherwise, we need to go to the syscache to find the appropriate
943 * operator. (This cannot result in infinite recursion, since no
944 * indexscan initiated by syscache lookup will use cross-data-type
945 * operators.)
946 *
947 * If the sk_strategy was flipped by _bt_fix_scankey_strategy, we have to
948 * un-flip it to get the correct opfamily member.
949 */
950 strat = op->sk_strategy;
951 if (op->sk_flags & SK_BT_DESC)
952 strat = BTCommuteStrategyNumber(strat);
953
954 cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],
955 lefttype,
956 righttype,
957 strat);
958 if (OidIsValid(cmp_op))
959 {
960 RegProcedure cmp_proc = get_opcode(cmp_op);
961
962 if (RegProcedureIsValid(cmp_proc))
963 {
964 *result = DatumGetBool(OidFunctionCall2Coll(cmp_proc,
965 op->sk_collation,
966 leftarg->sk_argument,
967 rightarg->sk_argument));
968 return true;
969 }
970 }
971
972 /* Can't make the comparison */
973 *result = false; /* suppress compiler warnings */
974 return false;
975}
976
977/*
978 * Compare an array scan key to a scalar scan key, eliminating contradictory
979 * array elements such that the scalar scan key becomes redundant.
980 *
981 * Array elements can be eliminated as contradictory when excluded by some
982 * other operator on the same attribute. For example, with an index scan qual
983 * "WHERE a IN (1, 2, 3) AND a < 2", all array elements except the value "1"
984 * are eliminated, and the < scan key is eliminated as redundant. Cases where
985 * every array element is eliminated by a redundant scalar scan key have an
986 * unsatisfiable qual, which we handle by setting *qual_ok=false for caller.
987 *
988 * If the opfamily doesn't supply a complete set of cross-type ORDER procs we
989 * may not be able to determine which elements are contradictory. If we have
990 * the required ORDER proc then we return true (and validly set *qual_ok),
991 * guaranteeing that at least the scalar scan key can be considered redundant.
992 * We return false if the comparison could not be made (caller must keep both
993 * scan keys when this happens).
994 */
995static bool
997 FmgrInfo *orderproc, BTArrayKeyInfo *array,
998 bool *qual_ok)
999{
1000 Relation rel = scan->indexRelation;
1001 Oid opcintype = rel->rd_opcintype[arraysk->sk_attno - 1];
1002 int cmpresult = 0,
1003 cmpexact = 0,
1004 matchelem,
1005 new_nelems = 0;
1006 FmgrInfo crosstypeproc;
1007 FmgrInfo *orderprocp = orderproc;
1008
1009 Assert(arraysk->sk_attno == skey->sk_attno);
1010 Assert(array->num_elems > 0);
1012 Assert((arraysk->sk_flags & SK_SEARCHARRAY) &&
1015 Assert(!(skey->sk_flags & SK_SEARCHARRAY) ||
1017
1018 /*
1019 * _bt_binsrch_array_skey searches an array for the entry best matching a
1020 * datum of opclass input type for the index's attribute (on-disk type).
1021 * We can reuse the array's ORDER proc whenever the non-array scan key's
1022 * type is a match for the corresponding attribute's input opclass type.
1023 * Otherwise, we have to do another ORDER proc lookup so that our call to
1024 * _bt_binsrch_array_skey applies the correct comparator.
1025 *
1026 * Note: we have to support the convention that sk_subtype == InvalidOid
1027 * means the opclass input type; this is a hack to simplify life for
1028 * ScanKeyInit().
1029 */
1030 if (skey->sk_subtype != opcintype && skey->sk_subtype != InvalidOid)
1031 {
1032 RegProcedure cmp_proc;
1033 Oid arraysk_elemtype;
1034
1035 /*
1036 * Need an ORDER proc lookup to detect redundancy/contradictoriness
1037 * with this pair of scankeys.
1038 *
1039 * Scalar scan key's argument will be passed to _bt_compare_array_skey
1040 * as its tupdatum/lefthand argument (rhs arg is for array elements).
1041 */
1042 arraysk_elemtype = arraysk->sk_subtype;
1043 if (arraysk_elemtype == InvalidOid)
1044 arraysk_elemtype = rel->rd_opcintype[arraysk->sk_attno - 1];
1045 cmp_proc = get_opfamily_proc(rel->rd_opfamily[arraysk->sk_attno - 1],
1046 skey->sk_subtype, arraysk_elemtype,
1047 BTORDER_PROC);
1048 if (!RegProcedureIsValid(cmp_proc))
1049 {
1050 /* Can't make the comparison */
1051 *qual_ok = false; /* suppress compiler warnings */
1052 return false;
1053 }
1054
1055 /* We have all we need to determine redundancy/contradictoriness */
1056 orderprocp = &crosstypeproc;
1057 fmgr_info(cmp_proc, orderprocp);
1058 }
1059
1060 matchelem = _bt_binsrch_array_skey(orderprocp, false,
1062 skey->sk_argument, false, array,
1063 arraysk, &cmpresult);
1064
1065 switch (skey->sk_strategy)
1066 {
1068 cmpexact = 1; /* exclude exact match, if any */
1069 /* FALL THRU */
1071 if (cmpresult >= cmpexact)
1072 matchelem++;
1073 /* Resize, keeping elements from the start of the array */
1074 new_nelems = matchelem;
1075 break;
1077 if (cmpresult != 0)
1078 {
1079 /* qual is unsatisfiable */
1080 new_nelems = 0;
1081 }
1082 else
1083 {
1084 /* Shift matching element to the start of the array, resize */
1085 array->elem_values[0] = array->elem_values[matchelem];
1086 new_nelems = 1;
1087 }
1088 break;
1090 cmpexact = 1; /* include exact match, if any */
1091 /* FALL THRU */
1093 if (cmpresult >= cmpexact)
1094 matchelem++;
1095 /* Shift matching elements to the start of the array, resize */
1096 new_nelems = array->num_elems - matchelem;
1097 memmove(array->elem_values, array->elem_values + matchelem,
1098 sizeof(Datum) * new_nelems);
1099 break;
1100 default:
1101 elog(ERROR, "unrecognized StrategyNumber: %d",
1102 (int) skey->sk_strategy);
1103 break;
1104 }
1105
1106 Assert(new_nelems >= 0);
1107 Assert(new_nelems <= array->num_elems);
1108
1109 array->num_elems = new_nelems;
1110 *qual_ok = new_nelems > 0;
1111
1112 return true;
1113}
1114
1115/*
1116 * _bt_preprocess_array_keys() -- Preprocess SK_SEARCHARRAY scan keys
1117 *
1118 * If there are any SK_SEARCHARRAY scan keys, deconstruct the array(s) and
1119 * set up BTArrayKeyInfo info for each one that is an equality-type key.
1120 * Returns modified scan keys as input for further, standard preprocessing.
1121 *
1122 * Currently we perform two kinds of preprocessing to deal with redundancies.
1123 * For inequality array keys, it's sufficient to find the extreme element
1124 * value and replace the whole array with that scalar value. This eliminates
1125 * all but one array element as redundant. Similarly, we are capable of
1126 * "merging together" multiple equality array keys (from two or more input
1127 * scan keys) into a single output scan key containing only the intersecting
1128 * array elements. This can eliminate many redundant array elements, as well
1129 * as eliminating whole array scan keys as redundant. It can also allow us to
1130 * detect contradictory quals.
1131 *
1132 * Caller must pass *new_numberOfKeys to give us a way to change the number of
1133 * scan keys that caller treats as input to standard preprocessing steps. The
1134 * returned array is smaller than scan->keyData[] when we could eliminate a
1135 * redundant array scan key (redundant with another array scan key). It is
1136 * convenient for _bt_preprocess_keys caller to have to deal with no more than
1137 * one equality strategy array scan key per index attribute. We'll always be
1138 * able to set things up that way when complete opfamilies are used.
1139 *
1140 * We set the scan key references from the scan's BTArrayKeyInfo info array to
1141 * offsets into the temp modified input array returned to caller. Scans that
1142 * have array keys should call _bt_preprocess_array_keys_final when standard
1143 * preprocessing steps are complete. This will convert the scan key offset
1144 * references into references to the scan's so->keyData[] output scan keys.
1145 *
1146 * Note: the reason we need to return a temp scan key array, rather than just
1147 * scribbling on scan->keyData, is that callers are permitted to call btrescan
1148 * without supplying a new set of scankey data.
1149 */
1150static ScanKey
1151_bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
1152{
1153 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1154 Relation rel = scan->indexRelation;
1155 int numberOfKeys = scan->numberOfKeys;
1156 int16 *indoption = rel->rd_indoption;
1157 int numArrayKeys,
1158 output_ikey = 0;
1159 int origarrayatt = InvalidAttrNumber,
1160 origarraykey = -1;
1161 Oid origelemtype = InvalidOid;
1162 ScanKey cur;
1163 MemoryContext oldContext;
1164 ScanKey arrayKeyData; /* modified copy of scan->keyData */
1165
1166 Assert(numberOfKeys);
1167
1168 /* Quick check to see if there are any array keys */
1169 numArrayKeys = 0;
1170 for (int i = 0; i < numberOfKeys; i++)
1171 {
1172 cur = &scan->keyData[i];
1173 if (cur->sk_flags & SK_SEARCHARRAY)
1174 {
1175 numArrayKeys++;
1177 /* If any arrays are null as a whole, we can quit right now. */
1178 if (cur->sk_flags & SK_ISNULL)
1179 {
1180 so->qual_ok = false;
1181 return NULL;
1182 }
1183 }
1184 }
1185
1186 /* Quit if nothing to do. */
1187 if (numArrayKeys == 0)
1188 return NULL;
1189
1190 /*
1191 * Make a scan-lifespan context to hold array-associated data, or reset it
1192 * if we already have one from a previous rescan cycle.
1193 */
1194 if (so->arrayContext == NULL)
1196 "BTree array context",
1198 else
1200
1201 oldContext = MemoryContextSwitchTo(so->arrayContext);
1202
1203 /* Create output scan keys in the workspace context */
1204 arrayKeyData = (ScanKey) palloc(numberOfKeys * sizeof(ScanKeyData));
1205
1206 /* Allocate space for per-array data in the workspace context */
1207 so->arrayKeys = (BTArrayKeyInfo *) palloc(numArrayKeys * sizeof(BTArrayKeyInfo));
1208
1209 /* Allocate space for ORDER procs used to help _bt_checkkeys */
1210 so->orderProcs = (FmgrInfo *) palloc(numberOfKeys * sizeof(FmgrInfo));
1211
1212 /* Now process each array key */
1213 numArrayKeys = 0;
1214 for (int input_ikey = 0; input_ikey < numberOfKeys; input_ikey++)
1215 {
1216 FmgrInfo sortproc;
1217 FmgrInfo *sortprocp = &sortproc;
1218 Oid elemtype;
1219 bool reverse;
1220 ArrayType *arrayval;
1221 int16 elmlen;
1222 bool elmbyval;
1223 char elmalign;
1224 int num_elems;
1225 Datum *elem_values;
1226 bool *elem_nulls;
1227 int num_nonnulls;
1228 int j;
1229
1230 /*
1231 * Provisionally copy scan key into arrayKeyData[] array we'll return
1232 * to _bt_preprocess_keys caller
1233 */
1234 cur = &arrayKeyData[output_ikey];
1235 *cur = scan->keyData[input_ikey];
1236
1237 if (!(cur->sk_flags & SK_SEARCHARRAY))
1238 {
1239 output_ikey++; /* keep this non-array scan key */
1240 continue;
1241 }
1242
1243 /*
1244 * Deconstruct the array into elements
1245 */
1246 arrayval = DatumGetArrayTypeP(cur->sk_argument);
1247 /* We could cache this data, but not clear it's worth it */
1249 &elmlen, &elmbyval, &elmalign);
1250 deconstruct_array(arrayval,
1251 ARR_ELEMTYPE(arrayval),
1252 elmlen, elmbyval, elmalign,
1253 &elem_values, &elem_nulls, &num_elems);
1254
1255 /*
1256 * Compress out any null elements. We can ignore them since we assume
1257 * all btree operators are strict.
1258 */
1259 num_nonnulls = 0;
1260 for (j = 0; j < num_elems; j++)
1261 {
1262 if (!elem_nulls[j])
1263 elem_values[num_nonnulls++] = elem_values[j];
1264 }
1265
1266 /* We could pfree(elem_nulls) now, but not worth the cycles */
1267
1268 /* If there's no non-nulls, the scan qual is unsatisfiable */
1269 if (num_nonnulls == 0)
1270 {
1271 so->qual_ok = false;
1272 break;
1273 }
1274
1275 /*
1276 * Determine the nominal datatype of the array elements. We have to
1277 * support the convention that sk_subtype == InvalidOid means the
1278 * opclass input type; this is a hack to simplify life for
1279 * ScanKeyInit().
1280 */
1281 elemtype = cur->sk_subtype;
1282 if (elemtype == InvalidOid)
1283 elemtype = rel->rd_opcintype[cur->sk_attno - 1];
1284
1285 /*
1286 * If the comparison operator is not equality, then the array qual
1287 * degenerates to a simple comparison against the smallest or largest
1288 * non-null array element, as appropriate.
1289 */
1290 switch (cur->sk_strategy)
1291 {
1294 cur->sk_argument =
1295 _bt_find_extreme_element(scan, cur, elemtype,
1297 elem_values, num_nonnulls);
1298 output_ikey++; /* keep this transformed scan key */
1299 continue;
1301 /* proceed with rest of loop */
1302 break;
1305 cur->sk_argument =
1306 _bt_find_extreme_element(scan, cur, elemtype,
1308 elem_values, num_nonnulls);
1309 output_ikey++; /* keep this transformed scan key */
1310 continue;
1311 default:
1312 elog(ERROR, "unrecognized StrategyNumber: %d",
1313 (int) cur->sk_strategy);
1314 break;
1315 }
1316
1317 /*
1318 * We'll need a 3-way ORDER proc to perform binary searches for the
1319 * next matching array element. Set that up now.
1320 *
1321 * Array scan keys with cross-type equality operators will require a
1322 * separate same-type ORDER proc for sorting their array. Otherwise,
1323 * sortproc just points to the same proc used during binary searches.
1324 */
1325 _bt_setup_array_cmp(scan, cur, elemtype,
1326 &so->orderProcs[output_ikey], &sortprocp);
1327
1328 /*
1329 * Sort the non-null elements and eliminate any duplicates. We must
1330 * sort in the same ordering used by the index column, so that the
1331 * arrays can be advanced in lockstep with the scan's progress through
1332 * the index's key space.
1333 */
1334 reverse = (indoption[cur->sk_attno - 1] & INDOPTION_DESC) != 0;
1335 num_elems = _bt_sort_array_elements(cur, sortprocp, reverse,
1336 elem_values, num_nonnulls);
1337
1338 if (origarrayatt == cur->sk_attno)
1339 {
1340 BTArrayKeyInfo *orig = &so->arrayKeys[origarraykey];
1341
1342 /*
1343 * This array scan key is redundant with a previous equality
1344 * operator array scan key. Merge the two arrays together to
1345 * eliminate contradictory non-intersecting elements (or try to).
1346 *
1347 * We merge this next array back into attribute's original array.
1348 */
1349 Assert(arrayKeyData[orig->scan_key].sk_attno == cur->sk_attno);
1350 Assert(arrayKeyData[orig->scan_key].sk_collation ==
1351 cur->sk_collation);
1352 if (_bt_merge_arrays(scan, cur, sortprocp, reverse,
1353 origelemtype, elemtype,
1354 orig->elem_values, &orig->num_elems,
1355 elem_values, num_elems))
1356 {
1357 /* Successfully eliminated this array */
1358 pfree(elem_values);
1359
1360 /*
1361 * If no intersecting elements remain in the original array,
1362 * the scan qual is unsatisfiable
1363 */
1364 if (orig->num_elems == 0)
1365 {
1366 so->qual_ok = false;
1367 break;
1368 }
1369
1370 /* Throw away this scan key/array */
1371 continue;
1372 }
1373
1374 /*
1375 * Unable to merge this array with previous array due to a lack of
1376 * suitable cross-type opfamily support. Will need to keep both
1377 * scan keys/arrays.
1378 */
1379 }
1380 else
1381 {
1382 /*
1383 * This array is the first for current index attribute.
1384 *
1385 * If it turns out to not be the last array (that is, if the next
1386 * array is redundantly applied to this same index attribute),
1387 * we'll then treat this array as the attribute's "original" array
1388 * when merging.
1389 */
1390 origarrayatt = cur->sk_attno;
1391 origarraykey = numArrayKeys;
1392 origelemtype = elemtype;
1393 }
1394
1395 /*
1396 * And set up the BTArrayKeyInfo data.
1397 *
1398 * Note: _bt_preprocess_array_keys_final will fix-up each array's
1399 * scan_key field later on, after so->keyData[] has been finalized.
1400 */
1401 so->arrayKeys[numArrayKeys].scan_key = output_ikey;
1402 so->arrayKeys[numArrayKeys].num_elems = num_elems;
1403 so->arrayKeys[numArrayKeys].elem_values = elem_values;
1404 numArrayKeys++;
1405 output_ikey++; /* keep this scan key/array */
1406 }
1407
1408 /* Set final number of equality-type array keys */
1409 so->numArrayKeys = numArrayKeys;
1410 /* Set number of scan keys remaining in arrayKeyData[] */
1411 *new_numberOfKeys = output_ikey;
1412
1413 MemoryContextSwitchTo(oldContext);
1414
1415 return arrayKeyData;
1416}
1417
1418/*
1419 * _bt_preprocess_array_keys_final() -- fix up array scan key references
1420 *
1421 * When _bt_preprocess_array_keys performed initial array preprocessing, it
1422 * set each array's array->scan_key to its scankey's arrayKeyData[] offset.
1423 * This function handles translation of the scan key references from the
1424 * BTArrayKeyInfo info array, from input scan key references (to the keys in
1425 * arrayKeyData[]), into output references (to the keys in so->keyData[]).
1426 * Caller's keyDataMap[] array tells us how to perform this remapping.
1427 *
1428 * Also finalizes so->orderProcs[] for the scan. Arrays already have an ORDER
1429 * proc, which might need to be repositioned to its so->keyData[]-wise offset
1430 * (very much like the remapping that we apply to array->scan_key references).
1431 * Non-array equality strategy scan keys (that survived preprocessing) don't
1432 * yet have an so->orderProcs[] entry, so we set one for them here.
1433 *
1434 * Also converts single-element array scan keys into equivalent non-array
1435 * equality scan keys, which decrements so->numArrayKeys. It's possible that
1436 * this will leave this new btrescan without any arrays at all. This isn't
1437 * necessary for correctness; it's just an optimization. Non-array equality
1438 * scan keys are slightly faster than equivalent array scan keys at runtime.
1439 */
1440static void
1442{
1443 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1444 Relation rel = scan->indexRelation;
1445 int arrayidx = 0;
1446 int last_equal_output_ikey PG_USED_FOR_ASSERTS_ONLY = -1;
1447
1448 Assert(so->qual_ok);
1449
1450 /*
1451 * Nothing for us to do when _bt_preprocess_array_keys only had to deal
1452 * with array inequalities
1453 */
1454 if (so->numArrayKeys == 0)
1455 return;
1456
1457 for (int output_ikey = 0; output_ikey < so->numberOfKeys; output_ikey++)
1458 {
1459 ScanKey outkey = so->keyData + output_ikey;
1460 int input_ikey;
1461 bool found PG_USED_FOR_ASSERTS_ONLY = false;
1462
1464
1465 if (outkey->sk_strategy != BTEqualStrategyNumber)
1466 continue;
1467
1468 input_ikey = keyDataMap[output_ikey];
1469
1470 Assert(last_equal_output_ikey < output_ikey);
1471 Assert(last_equal_output_ikey < input_ikey);
1472 last_equal_output_ikey = output_ikey;
1473
1474 /*
1475 * We're lazy about looking up ORDER procs for non-array keys, since
1476 * not all input keys become output keys. Take care of it now.
1477 */
1478 if (!(outkey->sk_flags & SK_SEARCHARRAY))
1479 {
1480 Oid elemtype;
1481
1482 /* No need for an ORDER proc given an IS NULL scan key */
1483 if (outkey->sk_flags & SK_SEARCHNULL)
1484 continue;
1485
1486 /*
1487 * A non-required scan key doesn't need an ORDER proc, either
1488 * (unless it's associated with an array, which this one isn't)
1489 */
1490 if (!(outkey->sk_flags & SK_BT_REQFWD))
1491 continue;
1492
1493 elemtype = outkey->sk_subtype;
1494 if (elemtype == InvalidOid)
1495 elemtype = rel->rd_opcintype[outkey->sk_attno - 1];
1496
1497 _bt_setup_array_cmp(scan, outkey, elemtype,
1498 &so->orderProcs[output_ikey], NULL);
1499 continue;
1500 }
1501
1502 /*
1503 * Reorder existing array scan key so->orderProcs[] entries.
1504 *
1505 * Doing this in-place is safe because preprocessing is required to
1506 * output all equality strategy scan keys in original input order
1507 * (among each group of entries against the same index attribute).
1508 * This is also the order that the arrays themselves appear in.
1509 */
1510 so->orderProcs[output_ikey] = so->orderProcs[input_ikey];
1511
1512 /* Fix-up array->scan_key references for arrays */
1513 for (; arrayidx < so->numArrayKeys; arrayidx++)
1514 {
1515 BTArrayKeyInfo *array = &so->arrayKeys[arrayidx];
1516
1517 Assert(array->num_elems > 0);
1518
1519 if (array->scan_key == input_ikey)
1520 {
1521 /* found it */
1522 array->scan_key = output_ikey;
1523 found = true;
1524
1525 /*
1526 * Transform array scan keys that have exactly 1 element
1527 * remaining (following all prior preprocessing) into
1528 * equivalent non-array scan keys.
1529 */
1530 if (array->num_elems == 1)
1531 {
1532 outkey->sk_flags &= ~SK_SEARCHARRAY;
1533 outkey->sk_argument = array->elem_values[0];
1534 so->numArrayKeys--;
1535
1536 /* If we're out of array keys, we can quit right away */
1537 if (so->numArrayKeys == 0)
1538 return;
1539
1540 /* Shift other arrays forward */
1541 memmove(array, array + 1,
1542 sizeof(BTArrayKeyInfo) *
1543 (so->numArrayKeys - arrayidx));
1544
1545 /*
1546 * Don't increment arrayidx (there was an entry that was
1547 * just shifted forward to the offset at arrayidx, which
1548 * will still need to be matched)
1549 */
1550 }
1551 else
1552 {
1553 /* Match found, so done with this array */
1554 arrayidx++;
1555 }
1556
1557 break;
1558 }
1559 }
1560
1561 Assert(found);
1562 }
1563
1564 /*
1565 * Parallel index scans require space in shared memory to store the
1566 * current array elements (for arrays kept by preprocessing) to schedule
1567 * the next primitive index scan. The underlying structure is protected
1568 * using a spinlock, so defensively limit its size. In practice this can
1569 * only affect parallel scans that use an incomplete opfamily.
1570 */
1571 if (scan->parallel_scan && so->numArrayKeys > INDEX_MAX_KEYS)
1572 ereport(ERROR,
1573 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1574 errmsg_internal("number of array scan keys left by preprocessing (%d) exceeds the maximum allowed by parallel btree index scans (%d)",
1576}
1577
1578/*
1579 * _bt_find_extreme_element() -- get least or greatest array element
1580 *
1581 * scan and skey identify the index column, whose opfamily determines the
1582 * comparison semantics. strat should be BTLessStrategyNumber to get the
1583 * least element, or BTGreaterStrategyNumber to get the greatest.
1584 */
1585static Datum
1587 StrategyNumber strat,
1588 Datum *elems, int nelems)
1589{
1590 Relation rel = scan->indexRelation;
1591 Oid cmp_op;
1592 RegProcedure cmp_proc;
1593 FmgrInfo flinfo;
1594 Datum result;
1595 int i;
1596
1597 /*
1598 * Look up the appropriate comparison operator in the opfamily.
1599 *
1600 * Note: it's possible that this would fail, if the opfamily is
1601 * incomplete, but it seems quite unlikely that an opfamily would omit
1602 * non-cross-type comparison operators for any datatype that it supports
1603 * at all.
1604 */
1606 Assert(OidIsValid(elemtype));
1607 cmp_op = get_opfamily_member(rel->rd_opfamily[skey->sk_attno - 1],
1608 elemtype,
1609 elemtype,
1610 strat);
1611 if (!OidIsValid(cmp_op))
1612 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
1613 strat, elemtype, elemtype,
1614 rel->rd_opfamily[skey->sk_attno - 1]);
1615 cmp_proc = get_opcode(cmp_op);
1616 if (!RegProcedureIsValid(cmp_proc))
1617 elog(ERROR, "missing oprcode for operator %u", cmp_op);
1618
1619 fmgr_info(cmp_proc, &flinfo);
1620
1621 Assert(nelems > 0);
1622 result = elems[0];
1623 for (i = 1; i < nelems; i++)
1624 {
1625 if (DatumGetBool(FunctionCall2Coll(&flinfo,
1626 skey->sk_collation,
1627 elems[i],
1628 result)))
1629 result = elems[i];
1630 }
1631
1632 return result;
1633}
1634
1635/*
1636 * _bt_setup_array_cmp() -- Set up array comparison functions
1637 *
1638 * Sets ORDER proc in caller's orderproc argument, which is used during binary
1639 * searches of arrays during the index scan. Also sets a same-type ORDER proc
1640 * in caller's *sortprocp argument, which is used when sorting the array.
1641 *
1642 * Preprocessing calls here with all equality strategy scan keys (when scan
1643 * uses equality array keys), including those not associated with any array.
1644 * See _bt_advance_array_keys for an explanation of why it'll need to treat
1645 * simple scalar equality scan keys as degenerate single element arrays.
1646 *
1647 * Caller should pass an orderproc pointing to space that'll store the ORDER
1648 * proc for the scan, and a *sortprocp pointing to its own separate space.
1649 * When calling here for a non-array scan key, sortprocp arg should be NULL.
1650 *
1651 * In the common case where we don't need to deal with cross-type operators,
1652 * only one ORDER proc is actually required by caller. We'll set *sortprocp
1653 * to point to the same memory that caller's orderproc continues to point to.
1654 * Otherwise, *sortprocp will continue to point to caller's own space. Either
1655 * way, *sortprocp will point to a same-type ORDER proc (since that's the only
1656 * safe way to sort/deduplicate the array associated with caller's scan key).
1657 */
1658static void
1660 FmgrInfo *orderproc, FmgrInfo **sortprocp)
1661{
1662 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1663 Relation rel = scan->indexRelation;
1664 RegProcedure cmp_proc;
1665 Oid opcintype = rel->rd_opcintype[skey->sk_attno - 1];
1666
1668 Assert(OidIsValid(elemtype));
1669
1670 /*
1671 * If scankey operator is not a cross-type comparison, we can use the
1672 * cached comparison function; otherwise gotta look it up in the catalogs
1673 */
1674 if (elemtype == opcintype)
1675 {
1676 /* Set same-type ORDER procs for caller */
1677 *orderproc = *index_getprocinfo(rel, skey->sk_attno, BTORDER_PROC);
1678 if (sortprocp)
1679 *sortprocp = orderproc;
1680
1681 return;
1682 }
1683
1684 /*
1685 * Look up the appropriate cross-type comparison function in the opfamily.
1686 *
1687 * Use the opclass input type as the left hand arg type, and the array
1688 * element type as the right hand arg type (since binary searches use an
1689 * index tuple's attribute value to search for a matching array element).
1690 *
1691 * Note: it's possible that this would fail, if the opfamily is
1692 * incomplete, but only in cases where it's quite likely that _bt_first
1693 * would fail in just the same way (had we not failed before it could).
1694 */
1695 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
1696 opcintype, elemtype, BTORDER_PROC);
1697 if (!RegProcedureIsValid(cmp_proc))
1698 elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
1699 BTORDER_PROC, opcintype, elemtype, skey->sk_attno,
1701
1702 /* Set cross-type ORDER proc for caller */
1703 fmgr_info_cxt(cmp_proc, orderproc, so->arrayContext);
1704
1705 /* Done if caller doesn't actually have an array they'll need to sort */
1706 if (!sortprocp)
1707 return;
1708
1709 /*
1710 * Look up the appropriate same-type comparison function in the opfamily.
1711 *
1712 * Note: it's possible that this would fail, if the opfamily is
1713 * incomplete, but it seems quite unlikely that an opfamily would omit
1714 * non-cross-type comparison procs for any datatype that it supports at
1715 * all.
1716 */
1717 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
1718 elemtype, elemtype, BTORDER_PROC);
1719 if (!RegProcedureIsValid(cmp_proc))
1720 elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
1721 BTORDER_PROC, elemtype, elemtype,
1722 skey->sk_attno, RelationGetRelationName(rel));
1723
1724 /* Set same-type ORDER proc for caller */
1725 fmgr_info_cxt(cmp_proc, *sortprocp, so->arrayContext);
1726}
1727
1728/*
1729 * _bt_sort_array_elements() -- sort and de-dup array elements
1730 *
1731 * The array elements are sorted in-place, and the new number of elements
1732 * after duplicate removal is returned.
1733 *
1734 * skey identifies the index column whose opfamily determines the comparison
1735 * semantics, and sortproc is a corresponding ORDER proc. If reverse is true,
1736 * we sort in descending order.
1737 */
1738static int
1739_bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc, bool reverse,
1740 Datum *elems, int nelems)
1741{
1743
1744 if (nelems <= 1)
1745 return nelems; /* no work to do */
1746
1747 /* Sort the array elements */
1748 cxt.sortproc = sortproc;
1749 cxt.collation = skey->sk_collation;
1750 cxt.reverse = reverse;
1751 qsort_arg(elems, nelems, sizeof(Datum),
1753
1754 /* Now scan the sorted elements and remove duplicates */
1755 return qunique_arg(elems, nelems, sizeof(Datum),
1757}
1758
1759/*
1760 * _bt_merge_arrays() -- merge next array's elements into an original array
1761 *
1762 * Called when preprocessing encounters a pair of array equality scan keys,
1763 * both against the same index attribute (during initial array preprocessing).
1764 * Merging reorganizes caller's original array (the left hand arg) in-place,
1765 * without ever copying elements from one array into the other. (Mixing the
1766 * elements together like this would be wrong, since they don't necessarily
1767 * use the same underlying element type, despite all the other similarities.)
1768 *
1769 * Both arrays must have already been sorted and deduplicated by calling
1770 * _bt_sort_array_elements. sortproc is the same-type ORDER proc that was
1771 * just used to sort and deduplicate caller's "next" array. We'll usually be
1772 * able to reuse that order PROC to merge the arrays together now. If not,
1773 * then we'll perform a separate ORDER proc lookup.
1774 *
1775 * If the opfamily doesn't supply a complete set of cross-type ORDER procs we
1776 * may not be able to determine which elements are contradictory. If we have
1777 * the required ORDER proc then we return true (and validly set *nelems_orig),
1778 * guaranteeing that at least the next array can be considered redundant. We
1779 * return false if the required comparisons cannot be made (caller must keep
1780 * both arrays when this happens).
1781 */
1782static bool
1784 bool reverse, Oid origelemtype, Oid nextelemtype,
1785 Datum *elems_orig, int *nelems_orig,
1786 Datum *elems_next, int nelems_next)
1787{
1788 Relation rel = scan->indexRelation;
1789 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1791 int nelems_orig_start = *nelems_orig,
1792 nelems_orig_merged = 0;
1793 FmgrInfo *mergeproc = sortproc;
1794 FmgrInfo crosstypeproc;
1795
1797 Assert(OidIsValid(origelemtype) && OidIsValid(nextelemtype));
1798
1799 if (origelemtype != nextelemtype)
1800 {
1801 RegProcedure cmp_proc;
1802
1803 /*
1804 * Cross-array-element-type merging is required, so can't just reuse
1805 * sortproc when merging
1806 */
1807 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
1808 origelemtype, nextelemtype, BTORDER_PROC);
1809 if (!RegProcedureIsValid(cmp_proc))
1810 {
1811 /* Can't make the required comparisons */
1812 return false;
1813 }
1814
1815 /* We have all we need to determine redundancy/contradictoriness */
1816 mergeproc = &crosstypeproc;
1817 fmgr_info_cxt(cmp_proc, mergeproc, so->arrayContext);
1818 }
1819
1820 cxt.sortproc = mergeproc;
1821 cxt.collation = skey->sk_collation;
1822 cxt.reverse = reverse;
1823
1824 for (int i = 0, j = 0; i < nelems_orig_start && j < nelems_next;)
1825 {
1826 Datum *oelem = elems_orig + i,
1827 *nelem = elems_next + j;
1828 int res = _bt_compare_array_elements(oelem, nelem, &cxt);
1829
1830 if (res == 0)
1831 {
1832 elems_orig[nelems_orig_merged++] = *oelem;
1833 i++;
1834 j++;
1835 }
1836 else if (res < 0)
1837 i++;
1838 else /* res > 0 */
1839 j++;
1840 }
1841
1842 *nelems_orig = nelems_orig_merged;
1843
1844 return true;
1845}
1846
1847/*
1848 * qsort_arg comparator for sorting array elements
1849 */
1850static int
1851_bt_compare_array_elements(const void *a, const void *b, void *arg)
1852{
1853 Datum da = *((const Datum *) a);
1854 Datum db = *((const Datum *) b);
1856 int32 compare;
1857
1859 cxt->collation,
1860 da, db));
1861 if (cxt->reverse)
1863 return compare;
1864}
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3631
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
#define RegProcedureIsValid(p)
Definition: c.h:734
#define INVERT_COMPARE_RESULT(var)
Definition: c.h:1063
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:204
#define Assert(condition)
Definition: c.h:815
int16_t int16
Definition: c.h:483
regproc RegProcedure
Definition: c.h:607
int32_t int32
Definition: c.h:484
#define OidIsValid(objectId)
Definition: c.h:732
struct cursor * cur
Definition: ecpg.c:29
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errcode(int sqlerrcode)
Definition: elog.c:853
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
Datum OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1421
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:862
int b
Definition: isn.c:69
int a
Definition: isn.c:68
int j
Definition: isn.c:73
int i
Definition: isn.c:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2298
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:797
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1312
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:167
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#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)
struct BTScanKeyPreproc BTScanKeyPreproc
struct BTSortArrayContext BTSortArrayContext
static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, Datum *elems, int nelems)
static bool _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
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 bool _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op, ScanKey leftarg, ScanKey rightarg, BTArrayKeyInfo *array, FmgrInfo *orderproc, bool *result)
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 BTORDER_PROC
Definition: nbtree.h:712
#define SK_BT_INDOPTION_SHIFT
Definition: nbtree.h:1121
#define SK_BT_REQBKWD
Definition: nbtree.h:1120
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:1123
#define SK_BT_REQFWD
Definition: nbtree.h:1119
#define SK_BT_DESC
Definition: nbtree.h:1122
#define BTCommuteStrategyNumber(strat)
Definition: nbtree.h:685
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:1078
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:271
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)
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
uintptr_t Datum
Definition: postgres.h:69
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
#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 RelationGetRelationName(relation)
Definition: rel.h:546
@ 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
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
Datum * elem_values
Definition: nbtree.h:1033
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:1048
FmgrInfo * orderProcs
Definition: nbtree.h:1049
ScanKey keyData
Definition: nbtree.h:1041
MemoryContext arrayContext
Definition: nbtree.h:1050
Definition: fmgr.h:57
Oid fn_oid
Definition: fmgr.h:59
struct ScanKeyData * keyData
Definition: relscan.h:139
struct ParallelIndexScanDescData * parallel_scan
Definition: relscan.h:183
Relation indexRelation
Definition: relscan.h:135
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