1 /*-------------------------------------------------------------------------
2 *
3 * nodeIndexscan.c
4 * Routines to support indexed scans of relations
5 *
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/executor/nodeIndexscan.c
12 *
13 *-------------------------------------------------------------------------
14 */
15 /*
16 * INTERFACE ROUTINES
17 * ExecIndexScan scans a relation using an index
18 * IndexNext retrieve next tuple using index
19 * IndexNextWithReorder same, but recheck ORDER BY expressions
20 * ExecInitIndexScan creates and initializes state info.
21 * ExecReScanIndexScan rescans the indexed relation.
22 * ExecEndIndexScan releases all storage.
23 * ExecIndexMarkPos marks scan position.
24 * ExecIndexRestrPos restores scan position.
25 */
26 #include "postgres.h"
27
28 #include "access/nbtree.h"
29 #include "access/relscan.h"
30 #include "catalog/pg_am.h"
31 #include "executor/execdebug.h"
32 #include "executor/nodeIndexscan.h"
33 #include "lib/pairingheap.h"
34 #include "nodes/nodeFuncs.h"
35 #include "optimizer/clauses.h"
36 #include "utils/array.h"
37 #include "utils/datum.h"
38 #include "utils/lsyscache.h"
39 #include "utils/memutils.h"
40 #include "utils/rel.h"
41
42 /*
43 * When an ordering operator is used, tuples fetched from the index that
44 * need to be reordered are queued in a pairing heap, as ReorderTuples.
45 */
46 typedef struct
47 {
48 pairingheap_node ph_node;
49 HeapTuple htup;
50 Datum *orderbyvals;
51 bool *orderbynulls;
52 } ReorderTuple;
53
54 static TupleTableSlot *IndexNext(IndexScanState *node);
55 static TupleTableSlot *IndexNextWithReorder(IndexScanState *node);
56 static void EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext);
57 static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot);
58 static int cmp_orderbyvals(const Datum *adist, const bool *anulls,
59 const Datum *bdist, const bool *bnulls,
60 IndexScanState *node);
61 static int reorderqueue_cmp(const pairingheap_node *a,
62 const pairingheap_node *b, void *arg);
63 static void reorderqueue_push(IndexScanState *node, HeapTuple tuple,
64 Datum *orderbyvals, bool *orderbynulls);
65 static HeapTuple reorderqueue_pop(IndexScanState *node);
66
67
68 /* ----------------------------------------------------------------
69 * IndexNext
70 *
71 * Retrieve a tuple from the IndexScan node's currentRelation
72 * using the index specified in the IndexScanState information.
73 * ----------------------------------------------------------------
74 */
75 static TupleTableSlot *
IndexNext(IndexScanState * node)76 IndexNext(IndexScanState *node)
77 {
78 EState *estate;
79 ExprContext *econtext;
80 ScanDirection direction;
81 IndexScanDesc scandesc;
82 HeapTuple tuple;
83 TupleTableSlot *slot;
84
85 /*
86 * extract necessary information from index scan node
87 */
88 estate = node->ss.ps.state;
89 direction = estate->es_direction;
90 /* flip direction if this is an overall backward scan */
91 if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir))
92 {
93 if (ScanDirectionIsForward(direction))
94 direction = BackwardScanDirection;
95 else if (ScanDirectionIsBackward(direction))
96 direction = ForwardScanDirection;
97 }
98 scandesc = node->iss_ScanDesc;
99 econtext = node->ss.ps.ps_ExprContext;
100 slot = node->ss.ss_ScanTupleSlot;
101
102 /*
103 * ok, now that we have what we need, fetch the next tuple.
104 */
105 while ((tuple = index_getnext(scandesc, direction)) != NULL)
106 {
107 /*
108 * Store the scanned tuple in the scan tuple slot of the scan state.
109 * Note: we pass 'false' because tuples returned by amgetnext are
110 * pointers onto disk pages and must not be pfree()'d.
111 */
112 ExecStoreTuple(tuple, /* tuple to store */
113 slot, /* slot to store in */
114 scandesc->xs_cbuf, /* buffer containing tuple */
115 false); /* don't pfree */
116
117 /*
118 * If the index was lossy, we have to recheck the index quals using
119 * the fetched tuple.
120 */
121 if (scandesc->xs_recheck)
122 {
123 econtext->ecxt_scantuple = slot;
124 ResetExprContext(econtext);
125 if (!ExecQual(node->indexqualorig, econtext, false))
126 {
127 /* Fails recheck, so drop it and loop back for another */
128 InstrCountFiltered2(node, 1);
129 continue;
130 }
131 }
132
133 return slot;
134 }
135
136 /*
137 * if we get here it means the index scan failed so we are at the end of
138 * the scan..
139 */
140 node->iss_ReachedEnd = true;
141 return ExecClearTuple(slot);
142 }
143
144 /* ----------------------------------------------------------------
145 * IndexNextWithReorder
146 *
147 * Like IndexNext, but this version can also re-check ORDER BY
148 * expressions, and reorder the tuples as necessary.
149 * ----------------------------------------------------------------
150 */
151 static TupleTableSlot *
IndexNextWithReorder(IndexScanState * node)152 IndexNextWithReorder(IndexScanState *node)
153 {
154 ExprContext *econtext;
155 IndexScanDesc scandesc;
156 HeapTuple tuple;
157 TupleTableSlot *slot;
158 ReorderTuple *topmost = NULL;
159 bool was_exact;
160 Datum *lastfetched_vals;
161 bool *lastfetched_nulls;
162 int cmp;
163
164 /*
165 * Only forward scan is supported with reordering. Note: we can get away
166 * with just Asserting here because the system will not try to run the
167 * plan backwards if ExecSupportsBackwardScan() says it won't work.
168 * Currently, that is guaranteed because no index AMs support both
169 * amcanorderbyop and amcanbackward; if any ever do,
170 * ExecSupportsBackwardScan() will need to consider indexorderbys
171 * explicitly.
172 */
173 Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir));
174 Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
175
176 scandesc = node->iss_ScanDesc;
177 econtext = node->ss.ps.ps_ExprContext;
178 slot = node->ss.ss_ScanTupleSlot;
179
180 for (;;)
181 {
182 /*
183 * Check the reorder queue first. If the topmost tuple in the queue
184 * has an ORDER BY value smaller than (or equal to) the value last
185 * returned by the index, we can return it now.
186 */
187 if (!pairingheap_is_empty(node->iss_ReorderQueue))
188 {
189 topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
190
191 if (node->iss_ReachedEnd ||
192 cmp_orderbyvals(topmost->orderbyvals,
193 topmost->orderbynulls,
194 scandesc->xs_orderbyvals,
195 scandesc->xs_orderbynulls,
196 node) <= 0)
197 {
198 tuple = reorderqueue_pop(node);
199
200 /* Pass 'true', as the tuple in the queue is a palloc'd copy */
201 ExecStoreTuple(tuple, slot, InvalidBuffer, true);
202 return slot;
203 }
204 }
205 else if (node->iss_ReachedEnd)
206 {
207 /* Queue is empty, and no more tuples from index. We're done. */
208 return ExecClearTuple(slot);
209 }
210
211 /*
212 * Fetch next tuple from the index.
213 */
214 next_indextuple:
215 tuple = index_getnext(scandesc, ForwardScanDirection);
216 if (!tuple)
217 {
218 /*
219 * No more tuples from the index. But we still need to drain any
220 * remaining tuples from the queue before we're done.
221 */
222 node->iss_ReachedEnd = true;
223 continue;
224 }
225
226 /*
227 * Store the scanned tuple in the scan tuple slot of the scan state.
228 * Note: we pass 'false' because tuples returned by amgetnext are
229 * pointers onto disk pages and must not be pfree()'d.
230 */
231 ExecStoreTuple(tuple, /* tuple to store */
232 slot, /* slot to store in */
233 scandesc->xs_cbuf, /* buffer containing tuple */
234 false); /* don't pfree */
235
236 /*
237 * If the index was lossy, we have to recheck the index quals and
238 * ORDER BY expressions using the fetched tuple.
239 */
240 if (scandesc->xs_recheck)
241 {
242 econtext->ecxt_scantuple = slot;
243 ResetExprContext(econtext);
244 if (!ExecQual(node->indexqualorig, econtext, false))
245 {
246 /* Fails recheck, so drop it and loop back for another */
247 InstrCountFiltered2(node, 1);
248 goto next_indextuple;
249 }
250 }
251
252 if (scandesc->xs_recheckorderby)
253 {
254 econtext->ecxt_scantuple = slot;
255 ResetExprContext(econtext);
256 EvalOrderByExpressions(node, econtext);
257
258 /*
259 * Was the ORDER BY value returned by the index accurate? The
260 * recheck flag means that the index can return inaccurate values,
261 * but then again, the value returned for any particular tuple
262 * could also be exactly correct. Compare the value returned by
263 * the index with the recalculated value. (If the value returned
264 * by the index happened to be exact right, we can often avoid
265 * pushing the tuple to the queue, just to pop it back out again.)
266 */
267 cmp = cmp_orderbyvals(node->iss_OrderByValues,
268 node->iss_OrderByNulls,
269 scandesc->xs_orderbyvals,
270 scandesc->xs_orderbynulls,
271 node);
272 if (cmp < 0)
273 elog(ERROR, "index returned tuples in wrong order");
274 else if (cmp == 0)
275 was_exact = true;
276 else
277 was_exact = false;
278 lastfetched_vals = node->iss_OrderByValues;
279 lastfetched_nulls = node->iss_OrderByNulls;
280 }
281 else
282 {
283 was_exact = true;
284 lastfetched_vals = scandesc->xs_orderbyvals;
285 lastfetched_nulls = scandesc->xs_orderbynulls;
286 }
287
288 /*
289 * Can we return this tuple immediately, or does it need to be pushed
290 * to the reorder queue? If the ORDER BY expression values returned
291 * by the index were inaccurate, we can't return it yet, because the
292 * next tuple from the index might need to come before this one. Also,
293 * we can't return it yet if there are any smaller tuples in the queue
294 * already.
295 */
296 if (!was_exact || (topmost && cmp_orderbyvals(lastfetched_vals,
297 lastfetched_nulls,
298 topmost->orderbyvals,
299 topmost->orderbynulls,
300 node) > 0))
301 {
302 /* Put this tuple to the queue */
303 reorderqueue_push(node, tuple, lastfetched_vals, lastfetched_nulls);
304 continue;
305 }
306 else
307 {
308 /* Can return this tuple immediately. */
309 return slot;
310 }
311 }
312
313 /*
314 * if we get here it means the index scan failed so we are at the end of
315 * the scan..
316 */
317 return ExecClearTuple(slot);
318 }
319
320 /*
321 * Calculate the expressions in the ORDER BY clause, based on the heap tuple.
322 */
323 static void
EvalOrderByExpressions(IndexScanState * node,ExprContext * econtext)324 EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
325 {
326 int i;
327 ListCell *l;
328 MemoryContext oldContext;
329
330 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
331
332 i = 0;
333 foreach(l, node->indexorderbyorig)
334 {
335 ExprState *orderby = (ExprState *) lfirst(l);
336
337 node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
338 econtext,
339 &node->iss_OrderByNulls[i],
340 NULL);
341 i++;
342 }
343
344 MemoryContextSwitchTo(oldContext);
345 }
346
347 /*
348 * IndexRecheck -- access method routine to recheck a tuple in EvalPlanQual
349 */
350 static bool
IndexRecheck(IndexScanState * node,TupleTableSlot * slot)351 IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
352 {
353 ExprContext *econtext;
354
355 /*
356 * extract necessary information from index scan node
357 */
358 econtext = node->ss.ps.ps_ExprContext;
359
360 /* Does the tuple meet the indexqual condition? */
361 econtext->ecxt_scantuple = slot;
362
363 ResetExprContext(econtext);
364
365 return ExecQual(node->indexqualorig, econtext, false);
366 }
367
368
369 /*
370 * Compare ORDER BY expression values.
371 */
372 static int
cmp_orderbyvals(const Datum * adist,const bool * anulls,const Datum * bdist,const bool * bnulls,IndexScanState * node)373 cmp_orderbyvals(const Datum *adist, const bool *anulls,
374 const Datum *bdist, const bool *bnulls,
375 IndexScanState *node)
376 {
377 int i;
378 int result;
379
380 for (i = 0; i < node->iss_NumOrderByKeys; i++)
381 {
382 SortSupport ssup = &node->iss_SortSupport[i];
383
384 /*
385 * Handle nulls. We only need to support NULLS LAST ordering, because
386 * match_pathkeys_to_index() doesn't consider indexorderby
387 * implementation otherwise.
388 */
389 if (anulls[i] && !bnulls[i])
390 return 1;
391 else if (!anulls[i] && bnulls[i])
392 return -1;
393 else if (anulls[i] && bnulls[i])
394 return 0;
395
396 result = ssup->comparator(adist[i], bdist[i], ssup);
397 if (result != 0)
398 return result;
399 }
400
401 return 0;
402 }
403
404 /*
405 * Pairing heap provides getting topmost (greatest) element while KNN provides
406 * ascending sort. That's why we invert the sort order.
407 */
408 static int
reorderqueue_cmp(const pairingheap_node * a,const pairingheap_node * b,void * arg)409 reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b,
410 void *arg)
411 {
412 ReorderTuple *rta = (ReorderTuple *) a;
413 ReorderTuple *rtb = (ReorderTuple *) b;
414 IndexScanState *node = (IndexScanState *) arg;
415
416 /* exchange argument order to invert the sort order */
417 return cmp_orderbyvals(rtb->orderbyvals, rtb->orderbynulls,
418 rta->orderbyvals, rta->orderbynulls,
419 node);
420 }
421
422 /*
423 * Helper function to push a tuple to the reorder queue.
424 */
425 static void
reorderqueue_push(IndexScanState * node,HeapTuple tuple,Datum * orderbyvals,bool * orderbynulls)426 reorderqueue_push(IndexScanState *node, HeapTuple tuple,
427 Datum *orderbyvals, bool *orderbynulls)
428 {
429 IndexScanDesc scandesc = node->iss_ScanDesc;
430 EState *estate = node->ss.ps.state;
431 MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
432 ReorderTuple *rt;
433 int i;
434
435 rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
436 rt->htup = heap_copytuple(tuple);
437 rt->orderbyvals =
438 (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
439 rt->orderbynulls =
440 (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
441 for (i = 0; i < node->iss_NumOrderByKeys; i++)
442 {
443 if (!orderbynulls[i])
444 rt->orderbyvals[i] = datumCopy(orderbyvals[i],
445 node->iss_OrderByTypByVals[i],
446 node->iss_OrderByTypLens[i]);
447 else
448 rt->orderbyvals[i] = (Datum) 0;
449 rt->orderbynulls[i] = orderbynulls[i];
450 }
451 pairingheap_add(node->iss_ReorderQueue, &rt->ph_node);
452
453 MemoryContextSwitchTo(oldContext);
454 }
455
456 /*
457 * Helper function to pop the next tuple from the reorder queue.
458 */
459 static HeapTuple
reorderqueue_pop(IndexScanState * node)460 reorderqueue_pop(IndexScanState *node)
461 {
462 HeapTuple result;
463 ReorderTuple *topmost;
464 int i;
465
466 topmost = (ReorderTuple *) pairingheap_remove_first(node->iss_ReorderQueue);
467
468 result = topmost->htup;
469 for (i = 0; i < node->iss_NumOrderByKeys; i++)
470 {
471 if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
472 pfree(DatumGetPointer(topmost->orderbyvals[i]));
473 }
474 pfree(topmost->orderbyvals);
475 pfree(topmost->orderbynulls);
476 pfree(topmost);
477
478 return result;
479 }
480
481
482 /* ----------------------------------------------------------------
483 * ExecIndexScan(node)
484 * ----------------------------------------------------------------
485 */
486 TupleTableSlot *
ExecIndexScan(IndexScanState * node)487 ExecIndexScan(IndexScanState *node)
488 {
489 /*
490 * If we have runtime keys and they've not already been set up, do it now.
491 */
492 if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
493 ExecReScan((PlanState *) node);
494
495 if (node->iss_NumOrderByKeys > 0)
496 return ExecScan(&node->ss,
497 (ExecScanAccessMtd) IndexNextWithReorder,
498 (ExecScanRecheckMtd) IndexRecheck);
499 else
500 return ExecScan(&node->ss,
501 (ExecScanAccessMtd) IndexNext,
502 (ExecScanRecheckMtd) IndexRecheck);
503 }
504
505 /* ----------------------------------------------------------------
506 * ExecReScanIndexScan(node)
507 *
508 * Recalculates the values of any scan keys whose value depends on
509 * information known at runtime, then rescans the indexed relation.
510 *
511 * Updating the scan key was formerly done separately in
512 * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
513 * rescans of indices and relations/general streams more uniform.
514 * ----------------------------------------------------------------
515 */
516 void
ExecReScanIndexScan(IndexScanState * node)517 ExecReScanIndexScan(IndexScanState *node)
518 {
519 /*
520 * If we are doing runtime key calculations (ie, any of the index key
521 * values weren't simple Consts), compute the new key values. But first,
522 * reset the context so we don't leak memory as each outer tuple is
523 * scanned. Note this assumes that we will recalculate *all* runtime keys
524 * on each call.
525 */
526 if (node->iss_NumRuntimeKeys != 0)
527 {
528 ExprContext *econtext = node->iss_RuntimeContext;
529
530 ResetExprContext(econtext);
531 ExecIndexEvalRuntimeKeys(econtext,
532 node->iss_RuntimeKeys,
533 node->iss_NumRuntimeKeys);
534 }
535 node->iss_RuntimeKeysReady = true;
536
537 /* flush the reorder queue */
538 if (node->iss_ReorderQueue)
539 {
540 while (!pairingheap_is_empty(node->iss_ReorderQueue))
541 reorderqueue_pop(node);
542 }
543
544 /* reset index scan */
545 index_rescan(node->iss_ScanDesc,
546 node->iss_ScanKeys, node->iss_NumScanKeys,
547 node->iss_OrderByKeys, node->iss_NumOrderByKeys);
548 node->iss_ReachedEnd = false;
549
550 ExecScanReScan(&node->ss);
551 }
552
553
554 /*
555 * ExecIndexEvalRuntimeKeys
556 * Evaluate any runtime key values, and update the scankeys.
557 */
558 void
ExecIndexEvalRuntimeKeys(ExprContext * econtext,IndexRuntimeKeyInfo * runtimeKeys,int numRuntimeKeys)559 ExecIndexEvalRuntimeKeys(ExprContext *econtext,
560 IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
561 {
562 int j;
563 MemoryContext oldContext;
564
565 /* We want to keep the key values in per-tuple memory */
566 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
567
568 for (j = 0; j < numRuntimeKeys; j++)
569 {
570 ScanKey scan_key = runtimeKeys[j].scan_key;
571 ExprState *key_expr = runtimeKeys[j].key_expr;
572 Datum scanvalue;
573 bool isNull;
574
575 /*
576 * For each run-time key, extract the run-time expression and evaluate
577 * it with respect to the current context. We then stick the result
578 * into the proper scan key.
579 *
580 * Note: the result of the eval could be a pass-by-ref value that's
581 * stored in some outer scan's tuple, not in
582 * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
583 * will stay put throughout our scan. If this is wrong, we could copy
584 * the result into our context explicitly, but I think that's not
585 * necessary.
586 *
587 * It's also entirely possible that the result of the eval is a
588 * toasted value. In this case we should forcibly detoast it, to
589 * avoid repeat detoastings each time the value is examined by an
590 * index support function.
591 */
592 scanvalue = ExecEvalExpr(key_expr,
593 econtext,
594 &isNull,
595 NULL);
596 if (isNull)
597 {
598 scan_key->sk_argument = scanvalue;
599 scan_key->sk_flags |= SK_ISNULL;
600 }
601 else
602 {
603 if (runtimeKeys[j].key_toastable)
604 scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
605 scan_key->sk_argument = scanvalue;
606 scan_key->sk_flags &= ~SK_ISNULL;
607 }
608 }
609
610 MemoryContextSwitchTo(oldContext);
611 }
612
613 /*
614 * ExecIndexEvalArrayKeys
615 * Evaluate any array key values, and set up to iterate through arrays.
616 *
617 * Returns TRUE if there are array elements to consider; FALSE means there
618 * is at least one null or empty array, so no match is possible. On TRUE
619 * result, the scankeys are initialized with the first elements of the arrays.
620 */
621 bool
ExecIndexEvalArrayKeys(ExprContext * econtext,IndexArrayKeyInfo * arrayKeys,int numArrayKeys)622 ExecIndexEvalArrayKeys(ExprContext *econtext,
623 IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
624 {
625 bool result = true;
626 int j;
627 MemoryContext oldContext;
628
629 /* We want to keep the arrays in per-tuple memory */
630 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
631
632 for (j = 0; j < numArrayKeys; j++)
633 {
634 ScanKey scan_key = arrayKeys[j].scan_key;
635 ExprState *array_expr = arrayKeys[j].array_expr;
636 Datum arraydatum;
637 bool isNull;
638 ArrayType *arrayval;
639 int16 elmlen;
640 bool elmbyval;
641 char elmalign;
642 int num_elems;
643 Datum *elem_values;
644 bool *elem_nulls;
645
646 /*
647 * Compute and deconstruct the array expression. (Notes in
648 * ExecIndexEvalRuntimeKeys() apply here too.)
649 */
650 arraydatum = ExecEvalExpr(array_expr,
651 econtext,
652 &isNull,
653 NULL);
654 if (isNull)
655 {
656 result = false;
657 break; /* no point in evaluating more */
658 }
659 arrayval = DatumGetArrayTypeP(arraydatum);
660 /* We could cache this data, but not clear it's worth it */
661 get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
662 &elmlen, &elmbyval, &elmalign);
663 deconstruct_array(arrayval,
664 ARR_ELEMTYPE(arrayval),
665 elmlen, elmbyval, elmalign,
666 &elem_values, &elem_nulls, &num_elems);
667 if (num_elems <= 0)
668 {
669 result = false;
670 break; /* no point in evaluating more */
671 }
672
673 /*
674 * Note: we expect the previous array data, if any, to be
675 * automatically freed by resetting the per-tuple context; hence no
676 * pfree's here.
677 */
678 arrayKeys[j].elem_values = elem_values;
679 arrayKeys[j].elem_nulls = elem_nulls;
680 arrayKeys[j].num_elems = num_elems;
681 scan_key->sk_argument = elem_values[0];
682 if (elem_nulls[0])
683 scan_key->sk_flags |= SK_ISNULL;
684 else
685 scan_key->sk_flags &= ~SK_ISNULL;
686 arrayKeys[j].next_elem = 1;
687 }
688
689 MemoryContextSwitchTo(oldContext);
690
691 return result;
692 }
693
694 /*
695 * ExecIndexAdvanceArrayKeys
696 * Advance to the next set of array key values, if any.
697 *
698 * Returns TRUE if there is another set of values to consider, FALSE if not.
699 * On TRUE result, the scankeys are initialized with the next set of values.
700 */
701 bool
ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo * arrayKeys,int numArrayKeys)702 ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
703 {
704 bool found = false;
705 int j;
706
707 /*
708 * Note we advance the rightmost array key most quickly, since it will
709 * correspond to the lowest-order index column among the available
710 * qualifications. This is hypothesized to result in better locality of
711 * access in the index.
712 */
713 for (j = numArrayKeys - 1; j >= 0; j--)
714 {
715 ScanKey scan_key = arrayKeys[j].scan_key;
716 int next_elem = arrayKeys[j].next_elem;
717 int num_elems = arrayKeys[j].num_elems;
718 Datum *elem_values = arrayKeys[j].elem_values;
719 bool *elem_nulls = arrayKeys[j].elem_nulls;
720
721 if (next_elem >= num_elems)
722 {
723 next_elem = 0;
724 found = false; /* need to advance next array key */
725 }
726 else
727 found = true;
728 scan_key->sk_argument = elem_values[next_elem];
729 if (elem_nulls[next_elem])
730 scan_key->sk_flags |= SK_ISNULL;
731 else
732 scan_key->sk_flags &= ~SK_ISNULL;
733 arrayKeys[j].next_elem = next_elem + 1;
734 if (found)
735 break;
736 }
737
738 return found;
739 }
740
741
742 /* ----------------------------------------------------------------
743 * ExecEndIndexScan
744 * ----------------------------------------------------------------
745 */
746 void
ExecEndIndexScan(IndexScanState * node)747 ExecEndIndexScan(IndexScanState *node)
748 {
749 Relation indexRelationDesc;
750 IndexScanDesc indexScanDesc;
751 Relation relation;
752
753 /*
754 * extract information from the node
755 */
756 indexRelationDesc = node->iss_RelationDesc;
757 indexScanDesc = node->iss_ScanDesc;
758 relation = node->ss.ss_currentRelation;
759
760 /*
761 * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
762 */
763 #ifdef NOT_USED
764 ExecFreeExprContext(&node->ss.ps);
765 if (node->iss_RuntimeContext)
766 FreeExprContext(node->iss_RuntimeContext, true);
767 #endif
768
769 /*
770 * clear out tuple table slots
771 */
772 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
773 ExecClearTuple(node->ss.ss_ScanTupleSlot);
774
775 /*
776 * close the index relation (no-op if we didn't open it)
777 */
778 if (indexScanDesc)
779 index_endscan(indexScanDesc);
780 if (indexRelationDesc)
781 index_close(indexRelationDesc, NoLock);
782
783 /*
784 * close the heap relation.
785 */
786 ExecCloseScanRelation(relation);
787 }
788
789 /* ----------------------------------------------------------------
790 * ExecIndexMarkPos
791 * ----------------------------------------------------------------
792 */
793 void
ExecIndexMarkPos(IndexScanState * node)794 ExecIndexMarkPos(IndexScanState *node)
795 {
796 index_markpos(node->iss_ScanDesc);
797 }
798
799 /* ----------------------------------------------------------------
800 * ExecIndexRestrPos
801 * ----------------------------------------------------------------
802 */
803 void
ExecIndexRestrPos(IndexScanState * node)804 ExecIndexRestrPos(IndexScanState *node)
805 {
806 index_restrpos(node->iss_ScanDesc);
807 }
808
809 /* ----------------------------------------------------------------
810 * ExecInitIndexScan
811 *
812 * Initializes the index scan's state information, creates
813 * scan keys, and opens the base and index relations.
814 *
815 * Note: index scans have 2 sets of state information because
816 * we have to keep track of the base relation and the
817 * index relation.
818 * ----------------------------------------------------------------
819 */
820 IndexScanState *
ExecInitIndexScan(IndexScan * node,EState * estate,int eflags)821 ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
822 {
823 IndexScanState *indexstate;
824 Relation currentRelation;
825 bool relistarget;
826
827 /*
828 * create state structure
829 */
830 indexstate = makeNode(IndexScanState);
831 indexstate->ss.ps.plan = (Plan *) node;
832 indexstate->ss.ps.state = estate;
833
834 /*
835 * Miscellaneous initialization
836 *
837 * create expression context for node
838 */
839 ExecAssignExprContext(estate, &indexstate->ss.ps);
840
841 indexstate->ss.ps.ps_TupFromTlist = false;
842
843 /*
844 * initialize child expressions
845 *
846 * Note: we don't initialize all of the indexqual expression, only the
847 * sub-parts corresponding to runtime keys (see below). Likewise for
848 * indexorderby, if any. But the indexqualorig expression is always
849 * initialized even though it will only be used in some uncommon cases ---
850 * would be nice to improve that. (Problem is that any SubPlans present
851 * in the expression must be found now...)
852 */
853 indexstate->ss.ps.targetlist = (List *)
854 ExecInitExpr((Expr *) node->scan.plan.targetlist,
855 (PlanState *) indexstate);
856 indexstate->ss.ps.qual = (List *)
857 ExecInitExpr((Expr *) node->scan.plan.qual,
858 (PlanState *) indexstate);
859 indexstate->indexqualorig = (List *)
860 ExecInitExpr((Expr *) node->indexqualorig,
861 (PlanState *) indexstate);
862 indexstate->indexorderbyorig = (List *)
863 ExecInitExpr((Expr *) node->indexorderbyorig,
864 (PlanState *) indexstate);
865
866 /*
867 * tuple table initialization
868 */
869 ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
870 ExecInitScanTupleSlot(estate, &indexstate->ss);
871
872 /*
873 * open the base relation and acquire appropriate lock on it.
874 */
875 currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
876
877 indexstate->ss.ss_currentRelation = currentRelation;
878 indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
879
880 /*
881 * get the scan type from the relation descriptor.
882 */
883 ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
884
885 /*
886 * Initialize result tuple type and projection info.
887 */
888 ExecAssignResultTypeFromTL(&indexstate->ss.ps);
889 ExecAssignScanProjectionInfo(&indexstate->ss);
890
891 /*
892 * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
893 * here. This allows an index-advisor plugin to EXPLAIN a plan containing
894 * references to nonexistent indexes.
895 */
896 if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
897 return indexstate;
898
899 /*
900 * Open the index relation.
901 *
902 * If the parent table is one of the target relations of the query, then
903 * InitPlan already opened and write-locked the index, so we can avoid
904 * taking another lock here. Otherwise we need a normal reader's lock.
905 */
906 relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
907 indexstate->iss_RelationDesc = index_open(node->indexid,
908 relistarget ? NoLock : AccessShareLock);
909
910 /*
911 * Initialize index-specific scan state
912 */
913 indexstate->iss_RuntimeKeysReady = false;
914 indexstate->iss_RuntimeKeys = NULL;
915 indexstate->iss_NumRuntimeKeys = 0;
916
917 /*
918 * build the index scan keys from the index qualification
919 */
920 ExecIndexBuildScanKeys((PlanState *) indexstate,
921 indexstate->iss_RelationDesc,
922 node->indexqual,
923 false,
924 &indexstate->iss_ScanKeys,
925 &indexstate->iss_NumScanKeys,
926 &indexstate->iss_RuntimeKeys,
927 &indexstate->iss_NumRuntimeKeys,
928 NULL, /* no ArrayKeys */
929 NULL);
930
931 /*
932 * any ORDER BY exprs have to be turned into scankeys in the same way
933 */
934 ExecIndexBuildScanKeys((PlanState *) indexstate,
935 indexstate->iss_RelationDesc,
936 node->indexorderby,
937 true,
938 &indexstate->iss_OrderByKeys,
939 &indexstate->iss_NumOrderByKeys,
940 &indexstate->iss_RuntimeKeys,
941 &indexstate->iss_NumRuntimeKeys,
942 NULL, /* no ArrayKeys */
943 NULL);
944
945 /* Initialize sort support, if we need to re-check ORDER BY exprs */
946 if (indexstate->iss_NumOrderByKeys > 0)
947 {
948 int numOrderByKeys = indexstate->iss_NumOrderByKeys;
949 int i;
950 ListCell *lco;
951 ListCell *lcx;
952
953 /*
954 * Prepare sort support, and look up the data type for each ORDER BY
955 * expression.
956 */
957 Assert(numOrderByKeys == list_length(node->indexorderbyops));
958 Assert(numOrderByKeys == list_length(node->indexorderbyorig));
959 indexstate->iss_SortSupport = (SortSupportData *)
960 palloc0(numOrderByKeys * sizeof(SortSupportData));
961 indexstate->iss_OrderByTypByVals = (bool *)
962 palloc(numOrderByKeys * sizeof(bool));
963 indexstate->iss_OrderByTypLens = (int16 *)
964 palloc(numOrderByKeys * sizeof(int16));
965 i = 0;
966 forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
967 {
968 Oid orderbyop = lfirst_oid(lco);
969 Node *orderbyexpr = (Node *) lfirst(lcx);
970 Oid orderbyType = exprType(orderbyexpr);
971 Oid orderbyColl = exprCollation(orderbyexpr);
972 SortSupport orderbysort = &indexstate->iss_SortSupport[i];
973
974 /* Initialize sort support */
975 orderbysort->ssup_cxt = CurrentMemoryContext;
976 orderbysort->ssup_collation = orderbyColl;
977 /* See cmp_orderbyvals() comments on NULLS LAST */
978 orderbysort->ssup_nulls_first = false;
979 /* ssup_attno is unused here and elsewhere */
980 orderbysort->ssup_attno = 0;
981 /* No abbreviation */
982 orderbysort->abbreviate = false;
983 PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
984
985 get_typlenbyval(orderbyType,
986 &indexstate->iss_OrderByTypLens[i],
987 &indexstate->iss_OrderByTypByVals[i]);
988 i++;
989 }
990
991 /* allocate arrays to hold the re-calculated distances */
992 indexstate->iss_OrderByValues = (Datum *)
993 palloc(numOrderByKeys * sizeof(Datum));
994 indexstate->iss_OrderByNulls = (bool *)
995 palloc(numOrderByKeys * sizeof(bool));
996
997 /* and initialize the reorder queue */
998 indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
999 indexstate);
1000 }
1001
1002 /*
1003 * If we have runtime keys, we need an ExprContext to evaluate them. The
1004 * node's standard context won't do because we want to reset that context
1005 * for every tuple. So, build another context just like the other one...
1006 * -tgl 7/11/00
1007 */
1008 if (indexstate->iss_NumRuntimeKeys != 0)
1009 {
1010 ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
1011
1012 ExecAssignExprContext(estate, &indexstate->ss.ps);
1013 indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1014 indexstate->ss.ps.ps_ExprContext = stdecontext;
1015 }
1016 else
1017 {
1018 indexstate->iss_RuntimeContext = NULL;
1019 }
1020
1021 /*
1022 * Initialize scan descriptor.
1023 */
1024 indexstate->iss_ScanDesc = index_beginscan(currentRelation,
1025 indexstate->iss_RelationDesc,
1026 estate->es_snapshot,
1027 indexstate->iss_NumScanKeys,
1028 indexstate->iss_NumOrderByKeys);
1029
1030 /*
1031 * If no run-time keys to calculate, go ahead and pass the scankeys to the
1032 * index AM.
1033 */
1034 if (indexstate->iss_NumRuntimeKeys == 0)
1035 index_rescan(indexstate->iss_ScanDesc,
1036 indexstate->iss_ScanKeys, indexstate->iss_NumScanKeys,
1037 indexstate->iss_OrderByKeys, indexstate->iss_NumOrderByKeys);
1038
1039 /*
1040 * all done.
1041 */
1042 return indexstate;
1043 }
1044
1045
1046 /*
1047 * ExecIndexBuildScanKeys
1048 * Build the index scan keys from the index qualification expressions
1049 *
1050 * The index quals are passed to the index AM in the form of a ScanKey array.
1051 * This routine sets up the ScanKeys, fills in all constant fields of the
1052 * ScanKeys, and prepares information about the keys that have non-constant
1053 * comparison values. We divide index qual expressions into five types:
1054 *
1055 * 1. Simple operator with constant comparison value ("indexkey op constant").
1056 * For these, we just fill in a ScanKey containing the constant value.
1057 *
1058 * 2. Simple operator with non-constant value ("indexkey op expression").
1059 * For these, we create a ScanKey with everything filled in except the
1060 * expression value, and set up an IndexRuntimeKeyInfo struct to drive
1061 * evaluation of the expression at the right times.
1062 *
1063 * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
1064 * For these, we create a header ScanKey plus a subsidiary ScanKey array,
1065 * as specified in access/skey.h. The elements of the row comparison
1066 * can have either constant or non-constant comparison values.
1067 *
1068 * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). If the index
1069 * supports amsearcharray, we handle these the same as simple operators,
1070 * setting the SK_SEARCHARRAY flag to tell the AM to handle them. Otherwise,
1071 * we create a ScanKey with everything filled in except the comparison value,
1072 * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
1073 * (Note that if we use an IndexArrayKeyInfo struct, the array expression is
1074 * always treated as requiring runtime evaluation, even if it's a constant.)
1075 *
1076 * 5. NullTest ("indexkey IS NULL/IS NOT NULL"). We just fill in the
1077 * ScanKey properly.
1078 *
1079 * This code is also used to prepare ORDER BY expressions for amcanorderbyop
1080 * indexes. The behavior is exactly the same, except that we have to look up
1081 * the operator differently. Note that only cases 1 and 2 are currently
1082 * possible for ORDER BY.
1083 *
1084 * Input params are:
1085 *
1086 * planstate: executor state node we are working for
1087 * index: the index we are building scan keys for
1088 * quals: indexquals (or indexorderbys) expressions
1089 * isorderby: true if processing ORDER BY exprs, false if processing quals
1090 * *runtimeKeys: ptr to pre-existing IndexRuntimeKeyInfos, or NULL if none
1091 * *numRuntimeKeys: number of pre-existing runtime keys
1092 *
1093 * Output params are:
1094 *
1095 * *scanKeys: receives ptr to array of ScanKeys
1096 * *numScanKeys: receives number of scankeys
1097 * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
1098 * *numRuntimeKeys: receives number of runtime keys
1099 * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
1100 * *numArrayKeys: receives number of array keys
1101 *
1102 * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
1103 * IndexArrayKeyInfos are not supported.
1104 */
1105 void
ExecIndexBuildScanKeys(PlanState * planstate,Relation index,List * quals,bool isorderby,ScanKey * scanKeys,int * numScanKeys,IndexRuntimeKeyInfo ** runtimeKeys,int * numRuntimeKeys,IndexArrayKeyInfo ** arrayKeys,int * numArrayKeys)1106 ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
1107 List *quals, bool isorderby,
1108 ScanKey *scanKeys, int *numScanKeys,
1109 IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
1110 IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
1111 {
1112 ListCell *qual_cell;
1113 ScanKey scan_keys;
1114 IndexRuntimeKeyInfo *runtime_keys;
1115 IndexArrayKeyInfo *array_keys;
1116 int n_scan_keys;
1117 int n_runtime_keys;
1118 int max_runtime_keys;
1119 int n_array_keys;
1120 int j;
1121
1122 /* Allocate array for ScanKey structs: one per qual */
1123 n_scan_keys = list_length(quals);
1124 scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData));
1125
1126 /*
1127 * runtime_keys array is dynamically resized as needed. We handle it this
1128 * way so that the same runtime keys array can be shared between
1129 * indexquals and indexorderbys, which will be processed in separate calls
1130 * of this function. Caller must be sure to pass in NULL/0 for first
1131 * call.
1132 */
1133 runtime_keys = *runtimeKeys;
1134 n_runtime_keys = max_runtime_keys = *numRuntimeKeys;
1135
1136 /* Allocate array_keys as large as it could possibly need to be */
1137 array_keys = (IndexArrayKeyInfo *)
1138 palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
1139 n_array_keys = 0;
1140
1141 /*
1142 * for each opclause in the given qual, convert the opclause into a single
1143 * scan key
1144 */
1145 j = 0;
1146 foreach(qual_cell, quals)
1147 {
1148 Expr *clause = (Expr *) lfirst(qual_cell);
1149 ScanKey this_scan_key = &scan_keys[j++];
1150 Oid opno; /* operator's OID */
1151 RegProcedure opfuncid; /* operator proc id used in scan */
1152 Oid opfamily; /* opfamily of index column */
1153 int op_strategy; /* operator's strategy number */
1154 Oid op_lefttype; /* operator's declared input types */
1155 Oid op_righttype;
1156 Expr *leftop; /* expr on lhs of operator */
1157 Expr *rightop; /* expr on rhs ... */
1158 AttrNumber varattno; /* att number used in scan */
1159
1160 if (IsA(clause, OpExpr))
1161 {
1162 /* indexkey op const or indexkey op expression */
1163 int flags = 0;
1164 Datum scanvalue;
1165
1166 opno = ((OpExpr *) clause)->opno;
1167 opfuncid = ((OpExpr *) clause)->opfuncid;
1168
1169 /*
1170 * leftop should be the index key Var, possibly relabeled
1171 */
1172 leftop = (Expr *) get_leftop(clause);
1173
1174 if (leftop && IsA(leftop, RelabelType))
1175 leftop = ((RelabelType *) leftop)->arg;
1176
1177 Assert(leftop != NULL);
1178
1179 if (!(IsA(leftop, Var) &&
1180 ((Var *) leftop)->varno == INDEX_VAR))
1181 elog(ERROR, "indexqual doesn't have key on left side");
1182
1183 varattno = ((Var *) leftop)->varattno;
1184 if (varattno < 1 || varattno > index->rd_index->indnatts)
1185 elog(ERROR, "bogus index qualification");
1186
1187 /*
1188 * We have to look up the operator's strategy number. This
1189 * provides a cross-check that the operator does match the index.
1190 */
1191 opfamily = index->rd_opfamily[varattno - 1];
1192
1193 get_op_opfamily_properties(opno, opfamily, isorderby,
1194 &op_strategy,
1195 &op_lefttype,
1196 &op_righttype);
1197
1198 if (isorderby)
1199 flags |= SK_ORDER_BY;
1200
1201 /*
1202 * rightop is the constant or variable comparison value
1203 */
1204 rightop = (Expr *) get_rightop(clause);
1205
1206 if (rightop && IsA(rightop, RelabelType))
1207 rightop = ((RelabelType *) rightop)->arg;
1208
1209 Assert(rightop != NULL);
1210
1211 if (IsA(rightop, Const))
1212 {
1213 /* OK, simple constant comparison value */
1214 scanvalue = ((Const *) rightop)->constvalue;
1215 if (((Const *) rightop)->constisnull)
1216 flags |= SK_ISNULL;
1217 }
1218 else
1219 {
1220 /* Need to treat this one as a runtime key */
1221 if (n_runtime_keys >= max_runtime_keys)
1222 {
1223 if (max_runtime_keys == 0)
1224 {
1225 max_runtime_keys = 8;
1226 runtime_keys = (IndexRuntimeKeyInfo *)
1227 palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1228 }
1229 else
1230 {
1231 max_runtime_keys *= 2;
1232 runtime_keys = (IndexRuntimeKeyInfo *)
1233 repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1234 }
1235 }
1236 runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1237 runtime_keys[n_runtime_keys].key_expr =
1238 ExecInitExpr(rightop, planstate);
1239 runtime_keys[n_runtime_keys].key_toastable =
1240 TypeIsToastable(op_righttype);
1241 n_runtime_keys++;
1242 scanvalue = (Datum) 0;
1243 }
1244
1245 /*
1246 * initialize the scan key's fields appropriately
1247 */
1248 ScanKeyEntryInitialize(this_scan_key,
1249 flags,
1250 varattno, /* attribute number to scan */
1251 op_strategy, /* op's strategy */
1252 op_righttype, /* strategy subtype */
1253 ((OpExpr *) clause)->inputcollid, /* collation */
1254 opfuncid, /* reg proc to use */
1255 scanvalue); /* constant */
1256 }
1257 else if (IsA(clause, RowCompareExpr))
1258 {
1259 /* (indexkey, indexkey, ...) op (expression, expression, ...) */
1260 RowCompareExpr *rc = (RowCompareExpr *) clause;
1261 ListCell *largs_cell = list_head(rc->largs);
1262 ListCell *rargs_cell = list_head(rc->rargs);
1263 ListCell *opnos_cell = list_head(rc->opnos);
1264 ListCell *collids_cell = list_head(rc->inputcollids);
1265 ScanKey first_sub_key;
1266 int n_sub_key;
1267
1268 Assert(!isorderby);
1269
1270 first_sub_key = (ScanKey)
1271 palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
1272 n_sub_key = 0;
1273
1274 /* Scan RowCompare columns and generate subsidiary ScanKey items */
1275 while (opnos_cell != NULL)
1276 {
1277 ScanKey this_sub_key = &first_sub_key[n_sub_key];
1278 int flags = SK_ROW_MEMBER;
1279 Datum scanvalue;
1280 Oid inputcollation;
1281
1282 /*
1283 * leftop should be the index key Var, possibly relabeled
1284 */
1285 leftop = (Expr *) lfirst(largs_cell);
1286 largs_cell = lnext(largs_cell);
1287
1288 if (leftop && IsA(leftop, RelabelType))
1289 leftop = ((RelabelType *) leftop)->arg;
1290
1291 Assert(leftop != NULL);
1292
1293 if (!(IsA(leftop, Var) &&
1294 ((Var *) leftop)->varno == INDEX_VAR))
1295 elog(ERROR, "indexqual doesn't have key on left side");
1296
1297 varattno = ((Var *) leftop)->varattno;
1298
1299 /*
1300 * We have to look up the operator's associated btree support
1301 * function
1302 */
1303 opno = lfirst_oid(opnos_cell);
1304 opnos_cell = lnext(opnos_cell);
1305
1306 if (index->rd_rel->relam != BTREE_AM_OID ||
1307 varattno < 1 || varattno > index->rd_index->indnatts)
1308 elog(ERROR, "bogus RowCompare index qualification");
1309 opfamily = index->rd_opfamily[varattno - 1];
1310
1311 get_op_opfamily_properties(opno, opfamily, isorderby,
1312 &op_strategy,
1313 &op_lefttype,
1314 &op_righttype);
1315
1316 if (op_strategy != rc->rctype)
1317 elog(ERROR, "RowCompare index qualification contains wrong operator");
1318
1319 opfuncid = get_opfamily_proc(opfamily,
1320 op_lefttype,
1321 op_righttype,
1322 BTORDER_PROC);
1323
1324 inputcollation = lfirst_oid(collids_cell);
1325 collids_cell = lnext(collids_cell);
1326
1327 /*
1328 * rightop is the constant or variable comparison value
1329 */
1330 rightop = (Expr *) lfirst(rargs_cell);
1331 rargs_cell = lnext(rargs_cell);
1332
1333 if (rightop && IsA(rightop, RelabelType))
1334 rightop = ((RelabelType *) rightop)->arg;
1335
1336 Assert(rightop != NULL);
1337
1338 if (IsA(rightop, Const))
1339 {
1340 /* OK, simple constant comparison value */
1341 scanvalue = ((Const *) rightop)->constvalue;
1342 if (((Const *) rightop)->constisnull)
1343 flags |= SK_ISNULL;
1344 }
1345 else
1346 {
1347 /* Need to treat this one as a runtime key */
1348 if (n_runtime_keys >= max_runtime_keys)
1349 {
1350 if (max_runtime_keys == 0)
1351 {
1352 max_runtime_keys = 8;
1353 runtime_keys = (IndexRuntimeKeyInfo *)
1354 palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1355 }
1356 else
1357 {
1358 max_runtime_keys *= 2;
1359 runtime_keys = (IndexRuntimeKeyInfo *)
1360 repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1361 }
1362 }
1363 runtime_keys[n_runtime_keys].scan_key = this_sub_key;
1364 runtime_keys[n_runtime_keys].key_expr =
1365 ExecInitExpr(rightop, planstate);
1366 runtime_keys[n_runtime_keys].key_toastable =
1367 TypeIsToastable(op_righttype);
1368 n_runtime_keys++;
1369 scanvalue = (Datum) 0;
1370 }
1371
1372 /*
1373 * initialize the subsidiary scan key's fields appropriately
1374 */
1375 ScanKeyEntryInitialize(this_sub_key,
1376 flags,
1377 varattno, /* attribute number */
1378 op_strategy, /* op's strategy */
1379 op_righttype, /* strategy subtype */
1380 inputcollation, /* collation */
1381 opfuncid, /* reg proc to use */
1382 scanvalue); /* constant */
1383 n_sub_key++;
1384 }
1385
1386 /* Mark the last subsidiary scankey correctly */
1387 first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;
1388
1389 /*
1390 * We don't use ScanKeyEntryInitialize for the header because it
1391 * isn't going to contain a valid sk_func pointer.
1392 */
1393 MemSet(this_scan_key, 0, sizeof(ScanKeyData));
1394 this_scan_key->sk_flags = SK_ROW_HEADER;
1395 this_scan_key->sk_attno = first_sub_key->sk_attno;
1396 this_scan_key->sk_strategy = rc->rctype;
1397 /* sk_subtype, sk_collation, sk_func not used in a header */
1398 this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
1399 }
1400 else if (IsA(clause, ScalarArrayOpExpr))
1401 {
1402 /* indexkey op ANY (array-expression) */
1403 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1404 int flags = 0;
1405 Datum scanvalue;
1406
1407 Assert(!isorderby);
1408
1409 Assert(saop->useOr);
1410 opno = saop->opno;
1411 opfuncid = saop->opfuncid;
1412
1413 /*
1414 * leftop should be the index key Var, possibly relabeled
1415 */
1416 leftop = (Expr *) linitial(saop->args);
1417
1418 if (leftop && IsA(leftop, RelabelType))
1419 leftop = ((RelabelType *) leftop)->arg;
1420
1421 Assert(leftop != NULL);
1422
1423 if (!(IsA(leftop, Var) &&
1424 ((Var *) leftop)->varno == INDEX_VAR))
1425 elog(ERROR, "indexqual doesn't have key on left side");
1426
1427 varattno = ((Var *) leftop)->varattno;
1428 if (varattno < 1 || varattno > index->rd_index->indnatts)
1429 elog(ERROR, "bogus index qualification");
1430
1431 /*
1432 * We have to look up the operator's strategy number. This
1433 * provides a cross-check that the operator does match the index.
1434 */
1435 opfamily = index->rd_opfamily[varattno - 1];
1436
1437 get_op_opfamily_properties(opno, opfamily, isorderby,
1438 &op_strategy,
1439 &op_lefttype,
1440 &op_righttype);
1441
1442 /*
1443 * rightop is the constant or variable array value
1444 */
1445 rightop = (Expr *) lsecond(saop->args);
1446
1447 if (rightop && IsA(rightop, RelabelType))
1448 rightop = ((RelabelType *) rightop)->arg;
1449
1450 Assert(rightop != NULL);
1451
1452 if (index->rd_amroutine->amsearcharray)
1453 {
1454 /* Index AM will handle this like a simple operator */
1455 flags |= SK_SEARCHARRAY;
1456 if (IsA(rightop, Const))
1457 {
1458 /* OK, simple constant comparison value */
1459 scanvalue = ((Const *) rightop)->constvalue;
1460 if (((Const *) rightop)->constisnull)
1461 flags |= SK_ISNULL;
1462 }
1463 else
1464 {
1465 /* Need to treat this one as a runtime key */
1466 if (n_runtime_keys >= max_runtime_keys)
1467 {
1468 if (max_runtime_keys == 0)
1469 {
1470 max_runtime_keys = 8;
1471 runtime_keys = (IndexRuntimeKeyInfo *)
1472 palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1473 }
1474 else
1475 {
1476 max_runtime_keys *= 2;
1477 runtime_keys = (IndexRuntimeKeyInfo *)
1478 repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1479 }
1480 }
1481 runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1482 runtime_keys[n_runtime_keys].key_expr =
1483 ExecInitExpr(rightop, planstate);
1484
1485 /*
1486 * Careful here: the runtime expression is not of
1487 * op_righttype, but rather is an array of same; so
1488 * TypeIsToastable() isn't helpful. However, we can
1489 * assume that all array types are toastable.
1490 */
1491 runtime_keys[n_runtime_keys].key_toastable = true;
1492 n_runtime_keys++;
1493 scanvalue = (Datum) 0;
1494 }
1495 }
1496 else
1497 {
1498 /* Executor has to expand the array value */
1499 array_keys[n_array_keys].scan_key = this_scan_key;
1500 array_keys[n_array_keys].array_expr =
1501 ExecInitExpr(rightop, planstate);
1502 /* the remaining fields were zeroed by palloc0 */
1503 n_array_keys++;
1504 scanvalue = (Datum) 0;
1505 }
1506
1507 /*
1508 * initialize the scan key's fields appropriately
1509 */
1510 ScanKeyEntryInitialize(this_scan_key,
1511 flags,
1512 varattno, /* attribute number to scan */
1513 op_strategy, /* op's strategy */
1514 op_righttype, /* strategy subtype */
1515 saop->inputcollid, /* collation */
1516 opfuncid, /* reg proc to use */
1517 scanvalue); /* constant */
1518 }
1519 else if (IsA(clause, NullTest))
1520 {
1521 /* indexkey IS NULL or indexkey IS NOT NULL */
1522 NullTest *ntest = (NullTest *) clause;
1523 int flags;
1524
1525 Assert(!isorderby);
1526
1527 /*
1528 * argument should be the index key Var, possibly relabeled
1529 */
1530 leftop = ntest->arg;
1531
1532 if (leftop && IsA(leftop, RelabelType))
1533 leftop = ((RelabelType *) leftop)->arg;
1534
1535 Assert(leftop != NULL);
1536
1537 if (!(IsA(leftop, Var) &&
1538 ((Var *) leftop)->varno == INDEX_VAR))
1539 elog(ERROR, "NullTest indexqual has wrong key");
1540
1541 varattno = ((Var *) leftop)->varattno;
1542
1543 /*
1544 * initialize the scan key's fields appropriately
1545 */
1546 switch (ntest->nulltesttype)
1547 {
1548 case IS_NULL:
1549 flags = SK_ISNULL | SK_SEARCHNULL;
1550 break;
1551 case IS_NOT_NULL:
1552 flags = SK_ISNULL | SK_SEARCHNOTNULL;
1553 break;
1554 default:
1555 elog(ERROR, "unrecognized nulltesttype: %d",
1556 (int) ntest->nulltesttype);
1557 flags = 0; /* keep compiler quiet */
1558 break;
1559 }
1560
1561 ScanKeyEntryInitialize(this_scan_key,
1562 flags,
1563 varattno, /* attribute number to scan */
1564 InvalidStrategy, /* no strategy */
1565 InvalidOid, /* no strategy subtype */
1566 InvalidOid, /* no collation */
1567 InvalidOid, /* no reg proc for this */
1568 (Datum) 0); /* constant */
1569 }
1570 else
1571 elog(ERROR, "unsupported indexqual type: %d",
1572 (int) nodeTag(clause));
1573 }
1574
1575 Assert(n_runtime_keys <= max_runtime_keys);
1576
1577 /* Get rid of any unused arrays */
1578 if (n_array_keys == 0)
1579 {
1580 pfree(array_keys);
1581 array_keys = NULL;
1582 }
1583
1584 /*
1585 * Return info to our caller.
1586 */
1587 *scanKeys = scan_keys;
1588 *numScanKeys = n_scan_keys;
1589 *runtimeKeys = runtime_keys;
1590 *numRuntimeKeys = n_runtime_keys;
1591 if (arrayKeys)
1592 {
1593 *arrayKeys = array_keys;
1594 *numArrayKeys = n_array_keys;
1595 }
1596 else if (n_array_keys != 0)
1597 elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
1598 }
1599