PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeIndexscan.c
Go to the documentation of this file.
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 {
51  bool *orderbynulls;
52 } ReorderTuple;
53 
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);
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 *
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 *
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));
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  */
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  */
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
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
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
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
410  void *arg)
411 {
412  ReorderTuple *rta = (ReorderTuple *) a;
413  ReorderTuple *rtb = (ReorderTuple *) b;
414  IndexScanState *node = (IndexScanState *) arg;
415 
416  return -cmp_orderbyvals(rta->orderbyvals, rta->orderbynulls,
417  rtb->orderbyvals, rtb->orderbynulls,
418  node);
419 }
420 
421 /*
422  * Helper function to push a tuple to the reorder queue.
423  */
424 static void
426  Datum *orderbyvals, bool *orderbynulls)
427 {
428  IndexScanDesc scandesc = node->iss_ScanDesc;
429  EState *estate = node->ss.ps.state;
430  MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
431  ReorderTuple *rt;
432  int i;
433 
434  rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
435  rt->htup = heap_copytuple(tuple);
436  rt->orderbyvals =
437  (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
438  rt->orderbynulls =
439  (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
440  for (i = 0; i < node->iss_NumOrderByKeys; i++)
441  {
442  if (!orderbynulls[i])
443  rt->orderbyvals[i] = datumCopy(orderbyvals[i],
444  node->iss_OrderByTypByVals[i],
445  node->iss_OrderByTypLens[i]);
446  else
447  rt->orderbyvals[i] = (Datum) 0;
448  rt->orderbynulls[i] = orderbynulls[i];
449  }
451 
452  MemoryContextSwitchTo(oldContext);
453 }
454 
455 /*
456  * Helper function to pop the next tuple from the reorder queue.
457  */
458 static HeapTuple
460 {
461  HeapTuple result;
462  ReorderTuple *topmost;
463  int i;
464 
466 
467  result = topmost->htup;
468  for (i = 0; i < node->iss_NumOrderByKeys; i++)
469  {
470  if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
471  pfree(DatumGetPointer(topmost->orderbyvals[i]));
472  }
473  pfree(topmost->orderbyvals);
474  pfree(topmost->orderbynulls);
475  pfree(topmost);
476 
477  return result;
478 }
479 
480 
481 /* ----------------------------------------------------------------
482  * ExecIndexScan(node)
483  * ----------------------------------------------------------------
484  */
487 {
488  /*
489  * If we have runtime keys and they've not already been set up, do it now.
490  */
491  if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
492  ExecReScan((PlanState *) node);
493 
494  if (node->iss_NumOrderByKeys > 0)
495  return ExecScan(&node->ss,
498  else
499  return ExecScan(&node->ss,
501  (ExecScanRecheckMtd) IndexRecheck);
502 }
503 
504 /* ----------------------------------------------------------------
505  * ExecReScanIndexScan(node)
506  *
507  * Recalculates the values of any scan keys whose value depends on
508  * information known at runtime, then rescans the indexed relation.
509  *
510  * Updating the scan key was formerly done separately in
511  * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
512  * rescans of indices and relations/general streams more uniform.
513  * ----------------------------------------------------------------
514  */
515 void
517 {
518  /*
519  * If we are doing runtime key calculations (ie, any of the index key
520  * values weren't simple Consts), compute the new key values. But first,
521  * reset the context so we don't leak memory as each outer tuple is
522  * scanned. Note this assumes that we will recalculate *all* runtime keys
523  * on each call.
524  */
525  if (node->iss_NumRuntimeKeys != 0)
526  {
527  ExprContext *econtext = node->iss_RuntimeContext;
528 
529  ResetExprContext(econtext);
530  ExecIndexEvalRuntimeKeys(econtext,
531  node->iss_RuntimeKeys,
532  node->iss_NumRuntimeKeys);
533  }
534  node->iss_RuntimeKeysReady = true;
535 
536  /* flush the reorder queue */
537  if (node->iss_ReorderQueue)
538  {
539  while (!pairingheap_is_empty(node->iss_ReorderQueue))
540  reorderqueue_pop(node);
541  }
542 
543  /* reset index scan */
545  node->iss_ScanKeys, node->iss_NumScanKeys,
546  node->iss_OrderByKeys, node->iss_NumOrderByKeys);
547  node->iss_ReachedEnd = false;
548 
549  ExecScanReScan(&node->ss);
550 }
551 
552 
553 /*
554  * ExecIndexEvalRuntimeKeys
555  * Evaluate any runtime key values, and update the scankeys.
556  */
557 void
559  IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
560 {
561  int j;
562  MemoryContext oldContext;
563 
564  /* We want to keep the key values in per-tuple memory */
565  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
566 
567  for (j = 0; j < numRuntimeKeys; j++)
568  {
569  ScanKey scan_key = runtimeKeys[j].scan_key;
570  ExprState *key_expr = runtimeKeys[j].key_expr;
571  Datum scanvalue;
572  bool isNull;
573 
574  /*
575  * For each run-time key, extract the run-time expression and evaluate
576  * it with respect to the current context. We then stick the result
577  * into the proper scan key.
578  *
579  * Note: the result of the eval could be a pass-by-ref value that's
580  * stored in some outer scan's tuple, not in
581  * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
582  * will stay put throughout our scan. If this is wrong, we could copy
583  * the result into our context explicitly, but I think that's not
584  * necessary.
585  *
586  * It's also entirely possible that the result of the eval is a
587  * toasted value. In this case we should forcibly detoast it, to
588  * avoid repeat detoastings each time the value is examined by an
589  * index support function.
590  */
591  scanvalue = ExecEvalExpr(key_expr,
592  econtext,
593  &isNull,
594  NULL);
595  if (isNull)
596  {
597  scan_key->sk_argument = scanvalue;
598  scan_key->sk_flags |= SK_ISNULL;
599  }
600  else
601  {
602  if (runtimeKeys[j].key_toastable)
603  scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
604  scan_key->sk_argument = scanvalue;
605  scan_key->sk_flags &= ~SK_ISNULL;
606  }
607  }
608 
609  MemoryContextSwitchTo(oldContext);
610 }
611 
612 /*
613  * ExecIndexEvalArrayKeys
614  * Evaluate any array key values, and set up to iterate through arrays.
615  *
616  * Returns TRUE if there are array elements to consider; FALSE means there
617  * is at least one null or empty array, so no match is possible. On TRUE
618  * result, the scankeys are initialized with the first elements of the arrays.
619  */
620 bool
622  IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
623 {
624  bool result = true;
625  int j;
626  MemoryContext oldContext;
627 
628  /* We want to keep the arrays in per-tuple memory */
629  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
630 
631  for (j = 0; j < numArrayKeys; j++)
632  {
633  ScanKey scan_key = arrayKeys[j].scan_key;
634  ExprState *array_expr = arrayKeys[j].array_expr;
635  Datum arraydatum;
636  bool isNull;
637  ArrayType *arrayval;
638  int16 elmlen;
639  bool elmbyval;
640  char elmalign;
641  int num_elems;
642  Datum *elem_values;
643  bool *elem_nulls;
644 
645  /*
646  * Compute and deconstruct the array expression. (Notes in
647  * ExecIndexEvalRuntimeKeys() apply here too.)
648  */
649  arraydatum = ExecEvalExpr(array_expr,
650  econtext,
651  &isNull,
652  NULL);
653  if (isNull)
654  {
655  result = false;
656  break; /* no point in evaluating more */
657  }
658  arrayval = DatumGetArrayTypeP(arraydatum);
659  /* We could cache this data, but not clear it's worth it */
661  &elmlen, &elmbyval, &elmalign);
662  deconstruct_array(arrayval,
663  ARR_ELEMTYPE(arrayval),
664  elmlen, elmbyval, elmalign,
665  &elem_values, &elem_nulls, &num_elems);
666  if (num_elems <= 0)
667  {
668  result = false;
669  break; /* no point in evaluating more */
670  }
671 
672  /*
673  * Note: we expect the previous array data, if any, to be
674  * automatically freed by resetting the per-tuple context; hence no
675  * pfree's here.
676  */
677  arrayKeys[j].elem_values = elem_values;
678  arrayKeys[j].elem_nulls = elem_nulls;
679  arrayKeys[j].num_elems = num_elems;
680  scan_key->sk_argument = elem_values[0];
681  if (elem_nulls[0])
682  scan_key->sk_flags |= SK_ISNULL;
683  else
684  scan_key->sk_flags &= ~SK_ISNULL;
685  arrayKeys[j].next_elem = 1;
686  }
687 
688  MemoryContextSwitchTo(oldContext);
689 
690  return result;
691 }
692 
693 /*
694  * ExecIndexAdvanceArrayKeys
695  * Advance to the next set of array key values, if any.
696  *
697  * Returns TRUE if there is another set of values to consider, FALSE if not.
698  * On TRUE result, the scankeys are initialized with the next set of values.
699  */
700 bool
701 ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
702 {
703  bool found = false;
704  int j;
705 
706  /*
707  * Note we advance the rightmost array key most quickly, since it will
708  * correspond to the lowest-order index column among the available
709  * qualifications. This is hypothesized to result in better locality of
710  * access in the index.
711  */
712  for (j = numArrayKeys - 1; j >= 0; j--)
713  {
714  ScanKey scan_key = arrayKeys[j].scan_key;
715  int next_elem = arrayKeys[j].next_elem;
716  int num_elems = arrayKeys[j].num_elems;
717  Datum *elem_values = arrayKeys[j].elem_values;
718  bool *elem_nulls = arrayKeys[j].elem_nulls;
719 
720  if (next_elem >= num_elems)
721  {
722  next_elem = 0;
723  found = false; /* need to advance next array key */
724  }
725  else
726  found = true;
727  scan_key->sk_argument = elem_values[next_elem];
728  if (elem_nulls[next_elem])
729  scan_key->sk_flags |= SK_ISNULL;
730  else
731  scan_key->sk_flags &= ~SK_ISNULL;
732  arrayKeys[j].next_elem = next_elem + 1;
733  if (found)
734  break;
735  }
736 
737  return found;
738 }
739 
740 
741 /* ----------------------------------------------------------------
742  * ExecEndIndexScan
743  * ----------------------------------------------------------------
744  */
745 void
747 {
748  Relation indexRelationDesc;
749  IndexScanDesc indexScanDesc;
750  Relation relation;
751 
752  /*
753  * extract information from the node
754  */
755  indexRelationDesc = node->iss_RelationDesc;
756  indexScanDesc = node->iss_ScanDesc;
757  relation = node->ss.ss_currentRelation;
758 
759  /*
760  * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
761  */
762 #ifdef NOT_USED
763  ExecFreeExprContext(&node->ss.ps);
764  if (node->iss_RuntimeContext)
765  FreeExprContext(node->iss_RuntimeContext, true);
766 #endif
767 
768  /*
769  * clear out tuple table slots
770  */
773 
774  /*
775  * close the index relation (no-op if we didn't open it)
776  */
777  if (indexScanDesc)
778  index_endscan(indexScanDesc);
779  if (indexRelationDesc)
780  index_close(indexRelationDesc, NoLock);
781 
782  /*
783  * close the heap relation.
784  */
785  ExecCloseScanRelation(relation);
786 }
787 
788 /* ----------------------------------------------------------------
789  * ExecIndexMarkPos
790  * ----------------------------------------------------------------
791  */
792 void
794 {
796 }
797 
798 /* ----------------------------------------------------------------
799  * ExecIndexRestrPos
800  * ----------------------------------------------------------------
801  */
802 void
804 {
806 }
807 
808 /* ----------------------------------------------------------------
809  * ExecInitIndexScan
810  *
811  * Initializes the index scan's state information, creates
812  * scan keys, and opens the base and index relations.
813  *
814  * Note: index scans have 2 sets of state information because
815  * we have to keep track of the base relation and the
816  * index relation.
817  * ----------------------------------------------------------------
818  */
820 ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
821 {
822  IndexScanState *indexstate;
823  Relation currentRelation;
824  bool relistarget;
825 
826  /*
827  * create state structure
828  */
829  indexstate = makeNode(IndexScanState);
830  indexstate->ss.ps.plan = (Plan *) node;
831  indexstate->ss.ps.state = estate;
832 
833  /*
834  * Miscellaneous initialization
835  *
836  * create expression context for node
837  */
838  ExecAssignExprContext(estate, &indexstate->ss.ps);
839 
840  indexstate->ss.ps.ps_TupFromTlist = false;
841 
842  /*
843  * initialize child expressions
844  *
845  * Note: we don't initialize all of the indexqual expression, only the
846  * sub-parts corresponding to runtime keys (see below). Likewise for
847  * indexorderby, if any. But the indexqualorig expression is always
848  * initialized even though it will only be used in some uncommon cases ---
849  * would be nice to improve that. (Problem is that any SubPlans present
850  * in the expression must be found now...)
851  */
852  indexstate->ss.ps.targetlist = (List *)
854  (PlanState *) indexstate);
855  indexstate->ss.ps.qual = (List *)
856  ExecInitExpr((Expr *) node->scan.plan.qual,
857  (PlanState *) indexstate);
858  indexstate->indexqualorig = (List *)
859  ExecInitExpr((Expr *) node->indexqualorig,
860  (PlanState *) indexstate);
861  indexstate->indexorderbyorig = (List *)
863  (PlanState *) indexstate);
864 
865  /*
866  * tuple table initialization
867  */
868  ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
869  ExecInitScanTupleSlot(estate, &indexstate->ss);
870 
871  /*
872  * open the base relation and acquire appropriate lock on it.
873  */
874  currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
875 
876  indexstate->ss.ss_currentRelation = currentRelation;
877  indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
878 
879  /*
880  * get the scan type from the relation descriptor.
881  */
882  ExecAssignScanType(&indexstate->ss, RelationGetDescr(currentRelation));
883 
884  /*
885  * Initialize result tuple type and projection info.
886  */
887  ExecAssignResultTypeFromTL(&indexstate->ss.ps);
888  ExecAssignScanProjectionInfo(&indexstate->ss);
889 
890  /*
891  * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
892  * here. This allows an index-advisor plugin to EXPLAIN a plan containing
893  * references to nonexistent indexes.
894  */
895  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
896  return indexstate;
897 
898  /*
899  * Open the index relation.
900  *
901  * If the parent table is one of the target relations of the query, then
902  * InitPlan already opened and write-locked the index, so we can avoid
903  * taking another lock here. Otherwise we need a normal reader's lock.
904  */
905  relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
906  indexstate->iss_RelationDesc = index_open(node->indexid,
907  relistarget ? NoLock : AccessShareLock);
908 
909  /*
910  * Initialize index-specific scan state
911  */
912  indexstate->iss_RuntimeKeysReady = false;
913  indexstate->iss_RuntimeKeys = NULL;
914  indexstate->iss_NumRuntimeKeys = 0;
915 
916  /*
917  * build the index scan keys from the index qualification
918  */
919  ExecIndexBuildScanKeys((PlanState *) indexstate,
920  indexstate->iss_RelationDesc,
921  node->indexqual,
922  false,
923  &indexstate->iss_ScanKeys,
924  &indexstate->iss_NumScanKeys,
925  &indexstate->iss_RuntimeKeys,
926  &indexstate->iss_NumRuntimeKeys,
927  NULL, /* no ArrayKeys */
928  NULL);
929 
930  /*
931  * any ORDER BY exprs have to be turned into scankeys in the same way
932  */
933  ExecIndexBuildScanKeys((PlanState *) indexstate,
934  indexstate->iss_RelationDesc,
935  node->indexorderby,
936  true,
937  &indexstate->iss_OrderByKeys,
938  &indexstate->iss_NumOrderByKeys,
939  &indexstate->iss_RuntimeKeys,
940  &indexstate->iss_NumRuntimeKeys,
941  NULL, /* no ArrayKeys */
942  NULL);
943 
944  /* Initialize sort support, if we need to re-check ORDER BY exprs */
945  if (indexstate->iss_NumOrderByKeys > 0)
946  {
947  int numOrderByKeys = indexstate->iss_NumOrderByKeys;
948  int i;
949  ListCell *lco;
950  ListCell *lcx;
951 
952  /*
953  * Prepare sort support, and look up the data type for each ORDER BY
954  * expression.
955  */
956  Assert(numOrderByKeys == list_length(node->indexorderbyops));
957  Assert(numOrderByKeys == list_length(node->indexorderbyorig));
958  indexstate->iss_SortSupport = (SortSupportData *)
959  palloc0(numOrderByKeys * sizeof(SortSupportData));
960  indexstate->iss_OrderByTypByVals = (bool *)
961  palloc(numOrderByKeys * sizeof(bool));
962  indexstate->iss_OrderByTypLens = (int16 *)
963  palloc(numOrderByKeys * sizeof(int16));
964  i = 0;
965  forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
966  {
967  Oid orderbyop = lfirst_oid(lco);
968  Node *orderbyexpr = (Node *) lfirst(lcx);
969  Oid orderbyType = exprType(orderbyexpr);
970 
972  &indexstate->iss_SortSupport[i]);
973  get_typlenbyval(orderbyType,
974  &indexstate->iss_OrderByTypLens[i],
975  &indexstate->iss_OrderByTypByVals[i]);
976  i++;
977  }
978 
979  /* allocate arrays to hold the re-calculated distances */
980  indexstate->iss_OrderByValues = (Datum *)
981  palloc(numOrderByKeys * sizeof(Datum));
982  indexstate->iss_OrderByNulls = (bool *)
983  palloc(numOrderByKeys * sizeof(bool));
984 
985  /* and initialize the reorder queue */
987  indexstate);
988  }
989 
990  /*
991  * If we have runtime keys, we need an ExprContext to evaluate them. The
992  * node's standard context won't do because we want to reset that context
993  * for every tuple. So, build another context just like the other one...
994  * -tgl 7/11/00
995  */
996  if (indexstate->iss_NumRuntimeKeys != 0)
997  {
998  ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
999 
1000  ExecAssignExprContext(estate, &indexstate->ss.ps);
1001  indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1002  indexstate->ss.ps.ps_ExprContext = stdecontext;
1003  }
1004  else
1005  {
1006  indexstate->iss_RuntimeContext = NULL;
1007  }
1008 
1009  /*
1010  * Initialize scan descriptor.
1011  */
1012  indexstate->iss_ScanDesc = index_beginscan(currentRelation,
1013  indexstate->iss_RelationDesc,
1014  estate->es_snapshot,
1015  indexstate->iss_NumScanKeys,
1016  indexstate->iss_NumOrderByKeys);
1017 
1018  /*
1019  * If no run-time keys to calculate, go ahead and pass the scankeys to the
1020  * index AM.
1021  */
1022  if (indexstate->iss_NumRuntimeKeys == 0)
1023  index_rescan(indexstate->iss_ScanDesc,
1024  indexstate->iss_ScanKeys, indexstate->iss_NumScanKeys,
1025  indexstate->iss_OrderByKeys, indexstate->iss_NumOrderByKeys);
1026 
1027  /*
1028  * all done.
1029  */
1030  return indexstate;
1031 }
1032 
1033 
1034 /*
1035  * ExecIndexBuildScanKeys
1036  * Build the index scan keys from the index qualification expressions
1037  *
1038  * The index quals are passed to the index AM in the form of a ScanKey array.
1039  * This routine sets up the ScanKeys, fills in all constant fields of the
1040  * ScanKeys, and prepares information about the keys that have non-constant
1041  * comparison values. We divide index qual expressions into five types:
1042  *
1043  * 1. Simple operator with constant comparison value ("indexkey op constant").
1044  * For these, we just fill in a ScanKey containing the constant value.
1045  *
1046  * 2. Simple operator with non-constant value ("indexkey op expression").
1047  * For these, we create a ScanKey with everything filled in except the
1048  * expression value, and set up an IndexRuntimeKeyInfo struct to drive
1049  * evaluation of the expression at the right times.
1050  *
1051  * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
1052  * For these, we create a header ScanKey plus a subsidiary ScanKey array,
1053  * as specified in access/skey.h. The elements of the row comparison
1054  * can have either constant or non-constant comparison values.
1055  *
1056  * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). If the index
1057  * supports amsearcharray, we handle these the same as simple operators,
1058  * setting the SK_SEARCHARRAY flag to tell the AM to handle them. Otherwise,
1059  * we create a ScanKey with everything filled in except the comparison value,
1060  * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
1061  * (Note that if we use an IndexArrayKeyInfo struct, the array expression is
1062  * always treated as requiring runtime evaluation, even if it's a constant.)
1063  *
1064  * 5. NullTest ("indexkey IS NULL/IS NOT NULL"). We just fill in the
1065  * ScanKey properly.
1066  *
1067  * This code is also used to prepare ORDER BY expressions for amcanorderbyop
1068  * indexes. The behavior is exactly the same, except that we have to look up
1069  * the operator differently. Note that only cases 1 and 2 are currently
1070  * possible for ORDER BY.
1071  *
1072  * Input params are:
1073  *
1074  * planstate: executor state node we are working for
1075  * index: the index we are building scan keys for
1076  * quals: indexquals (or indexorderbys) expressions
1077  * isorderby: true if processing ORDER BY exprs, false if processing quals
1078  * *runtimeKeys: ptr to pre-existing IndexRuntimeKeyInfos, or NULL if none
1079  * *numRuntimeKeys: number of pre-existing runtime keys
1080  *
1081  * Output params are:
1082  *
1083  * *scanKeys: receives ptr to array of ScanKeys
1084  * *numScanKeys: receives number of scankeys
1085  * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
1086  * *numRuntimeKeys: receives number of runtime keys
1087  * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
1088  * *numArrayKeys: receives number of array keys
1089  *
1090  * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
1091  * IndexArrayKeyInfos are not supported.
1092  */
1093 void
1095  List *quals, bool isorderby,
1096  ScanKey *scanKeys, int *numScanKeys,
1097  IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
1098  IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
1099 {
1100  ListCell *qual_cell;
1101  ScanKey scan_keys;
1102  IndexRuntimeKeyInfo *runtime_keys;
1103  IndexArrayKeyInfo *array_keys;
1104  int n_scan_keys;
1105  int n_runtime_keys;
1106  int max_runtime_keys;
1107  int n_array_keys;
1108  int j;
1109 
1110  /* Allocate array for ScanKey structs: one per qual */
1111  n_scan_keys = list_length(quals);
1112  scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData));
1113 
1114  /*
1115  * runtime_keys array is dynamically resized as needed. We handle it this
1116  * way so that the same runtime keys array can be shared between
1117  * indexquals and indexorderbys, which will be processed in separate calls
1118  * of this function. Caller must be sure to pass in NULL/0 for first
1119  * call.
1120  */
1121  runtime_keys = *runtimeKeys;
1122  n_runtime_keys = max_runtime_keys = *numRuntimeKeys;
1123 
1124  /* Allocate array_keys as large as it could possibly need to be */
1125  array_keys = (IndexArrayKeyInfo *)
1126  palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
1127  n_array_keys = 0;
1128 
1129  /*
1130  * for each opclause in the given qual, convert the opclause into a single
1131  * scan key
1132  */
1133  j = 0;
1134  foreach(qual_cell, quals)
1135  {
1136  Expr *clause = (Expr *) lfirst(qual_cell);
1137  ScanKey this_scan_key = &scan_keys[j++];
1138  Oid opno; /* operator's OID */
1139  RegProcedure opfuncid; /* operator proc id used in scan */
1140  Oid opfamily; /* opfamily of index column */
1141  int op_strategy; /* operator's strategy number */
1142  Oid op_lefttype; /* operator's declared input types */
1143  Oid op_righttype;
1144  Expr *leftop; /* expr on lhs of operator */
1145  Expr *rightop; /* expr on rhs ... */
1146  AttrNumber varattno; /* att number used in scan */
1147 
1148  if (IsA(clause, OpExpr))
1149  {
1150  /* indexkey op const or indexkey op expression */
1151  int flags = 0;
1152  Datum scanvalue;
1153 
1154  opno = ((OpExpr *) clause)->opno;
1155  opfuncid = ((OpExpr *) clause)->opfuncid;
1156 
1157  /*
1158  * leftop should be the index key Var, possibly relabeled
1159  */
1160  leftop = (Expr *) get_leftop(clause);
1161 
1162  if (leftop && IsA(leftop, RelabelType))
1163  leftop = ((RelabelType *) leftop)->arg;
1164 
1165  Assert(leftop != NULL);
1166 
1167  if (!(IsA(leftop, Var) &&
1168  ((Var *) leftop)->varno == INDEX_VAR))
1169  elog(ERROR, "indexqual doesn't have key on left side");
1170 
1171  varattno = ((Var *) leftop)->varattno;
1172  if (varattno < 1 || varattno > index->rd_index->indnatts)
1173  elog(ERROR, "bogus index qualification");
1174 
1175  /*
1176  * We have to look up the operator's strategy number. This
1177  * provides a cross-check that the operator does match the index.
1178  */
1179  opfamily = index->rd_opfamily[varattno - 1];
1180 
1181  get_op_opfamily_properties(opno, opfamily, isorderby,
1182  &op_strategy,
1183  &op_lefttype,
1184  &op_righttype);
1185 
1186  if (isorderby)
1187  flags |= SK_ORDER_BY;
1188 
1189  /*
1190  * rightop is the constant or variable comparison value
1191  */
1192  rightop = (Expr *) get_rightop(clause);
1193 
1194  if (rightop && IsA(rightop, RelabelType))
1195  rightop = ((RelabelType *) rightop)->arg;
1196 
1197  Assert(rightop != NULL);
1198 
1199  if (IsA(rightop, Const))
1200  {
1201  /* OK, simple constant comparison value */
1202  scanvalue = ((Const *) rightop)->constvalue;
1203  if (((Const *) rightop)->constisnull)
1204  flags |= SK_ISNULL;
1205  }
1206  else
1207  {
1208  /* Need to treat this one as a runtime key */
1209  if (n_runtime_keys >= max_runtime_keys)
1210  {
1211  if (max_runtime_keys == 0)
1212  {
1213  max_runtime_keys = 8;
1214  runtime_keys = (IndexRuntimeKeyInfo *)
1215  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1216  }
1217  else
1218  {
1219  max_runtime_keys *= 2;
1220  runtime_keys = (IndexRuntimeKeyInfo *)
1221  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1222  }
1223  }
1224  runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1225  runtime_keys[n_runtime_keys].key_expr =
1226  ExecInitExpr(rightop, planstate);
1227  runtime_keys[n_runtime_keys].key_toastable =
1228  TypeIsToastable(op_righttype);
1229  n_runtime_keys++;
1230  scanvalue = (Datum) 0;
1231  }
1232 
1233  /*
1234  * initialize the scan key's fields appropriately
1235  */
1236  ScanKeyEntryInitialize(this_scan_key,
1237  flags,
1238  varattno, /* attribute number to scan */
1239  op_strategy, /* op's strategy */
1240  op_righttype, /* strategy subtype */
1241  ((OpExpr *) clause)->inputcollid, /* collation */
1242  opfuncid, /* reg proc to use */
1243  scanvalue); /* constant */
1244  }
1245  else if (IsA(clause, RowCompareExpr))
1246  {
1247  /* (indexkey, indexkey, ...) op (expression, expression, ...) */
1248  RowCompareExpr *rc = (RowCompareExpr *) clause;
1249  ListCell *largs_cell = list_head(rc->largs);
1250  ListCell *rargs_cell = list_head(rc->rargs);
1251  ListCell *opnos_cell = list_head(rc->opnos);
1252  ListCell *collids_cell = list_head(rc->inputcollids);
1253  ScanKey first_sub_key;
1254  int n_sub_key;
1255 
1256  Assert(!isorderby);
1257 
1258  first_sub_key = (ScanKey)
1259  palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
1260  n_sub_key = 0;
1261 
1262  /* Scan RowCompare columns and generate subsidiary ScanKey items */
1263  while (opnos_cell != NULL)
1264  {
1265  ScanKey this_sub_key = &first_sub_key[n_sub_key];
1266  int flags = SK_ROW_MEMBER;
1267  Datum scanvalue;
1268  Oid inputcollation;
1269 
1270  /*
1271  * leftop should be the index key Var, possibly relabeled
1272  */
1273  leftop = (Expr *) lfirst(largs_cell);
1274  largs_cell = lnext(largs_cell);
1275 
1276  if (leftop && IsA(leftop, RelabelType))
1277  leftop = ((RelabelType *) leftop)->arg;
1278 
1279  Assert(leftop != NULL);
1280 
1281  if (!(IsA(leftop, Var) &&
1282  ((Var *) leftop)->varno == INDEX_VAR))
1283  elog(ERROR, "indexqual doesn't have key on left side");
1284 
1285  varattno = ((Var *) leftop)->varattno;
1286 
1287  /*
1288  * We have to look up the operator's associated btree support
1289  * function
1290  */
1291  opno = lfirst_oid(opnos_cell);
1292  opnos_cell = lnext(opnos_cell);
1293 
1294  if (index->rd_rel->relam != BTREE_AM_OID ||
1295  varattno < 1 || varattno > index->rd_index->indnatts)
1296  elog(ERROR, "bogus RowCompare index qualification");
1297  opfamily = index->rd_opfamily[varattno - 1];
1298 
1299  get_op_opfamily_properties(opno, opfamily, isorderby,
1300  &op_strategy,
1301  &op_lefttype,
1302  &op_righttype);
1303 
1304  if (op_strategy != rc->rctype)
1305  elog(ERROR, "RowCompare index qualification contains wrong operator");
1306 
1307  opfuncid = get_opfamily_proc(opfamily,
1308  op_lefttype,
1309  op_righttype,
1310  BTORDER_PROC);
1311 
1312  inputcollation = lfirst_oid(collids_cell);
1313  collids_cell = lnext(collids_cell);
1314 
1315  /*
1316  * rightop is the constant or variable comparison value
1317  */
1318  rightop = (Expr *) lfirst(rargs_cell);
1319  rargs_cell = lnext(rargs_cell);
1320 
1321  if (rightop && IsA(rightop, RelabelType))
1322  rightop = ((RelabelType *) rightop)->arg;
1323 
1324  Assert(rightop != NULL);
1325 
1326  if (IsA(rightop, Const))
1327  {
1328  /* OK, simple constant comparison value */
1329  scanvalue = ((Const *) rightop)->constvalue;
1330  if (((Const *) rightop)->constisnull)
1331  flags |= SK_ISNULL;
1332  }
1333  else
1334  {
1335  /* Need to treat this one as a runtime key */
1336  if (n_runtime_keys >= max_runtime_keys)
1337  {
1338  if (max_runtime_keys == 0)
1339  {
1340  max_runtime_keys = 8;
1341  runtime_keys = (IndexRuntimeKeyInfo *)
1342  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1343  }
1344  else
1345  {
1346  max_runtime_keys *= 2;
1347  runtime_keys = (IndexRuntimeKeyInfo *)
1348  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1349  }
1350  }
1351  runtime_keys[n_runtime_keys].scan_key = this_sub_key;
1352  runtime_keys[n_runtime_keys].key_expr =
1353  ExecInitExpr(rightop, planstate);
1354  runtime_keys[n_runtime_keys].key_toastable =
1355  TypeIsToastable(op_righttype);
1356  n_runtime_keys++;
1357  scanvalue = (Datum) 0;
1358  }
1359 
1360  /*
1361  * initialize the subsidiary scan key's fields appropriately
1362  */
1363  ScanKeyEntryInitialize(this_sub_key,
1364  flags,
1365  varattno, /* attribute number */
1366  op_strategy, /* op's strategy */
1367  op_righttype, /* strategy subtype */
1368  inputcollation, /* collation */
1369  opfuncid, /* reg proc to use */
1370  scanvalue); /* constant */
1371  n_sub_key++;
1372  }
1373 
1374  /* Mark the last subsidiary scankey correctly */
1375  first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;
1376 
1377  /*
1378  * We don't use ScanKeyEntryInitialize for the header because it
1379  * isn't going to contain a valid sk_func pointer.
1380  */
1381  MemSet(this_scan_key, 0, sizeof(ScanKeyData));
1382  this_scan_key->sk_flags = SK_ROW_HEADER;
1383  this_scan_key->sk_attno = first_sub_key->sk_attno;
1384  this_scan_key->sk_strategy = rc->rctype;
1385  /* sk_subtype, sk_collation, sk_func not used in a header */
1386  this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
1387  }
1388  else if (IsA(clause, ScalarArrayOpExpr))
1389  {
1390  /* indexkey op ANY (array-expression) */
1391  ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1392  int flags = 0;
1393  Datum scanvalue;
1394 
1395  Assert(!isorderby);
1396 
1397  Assert(saop->useOr);
1398  opno = saop->opno;
1399  opfuncid = saop->opfuncid;
1400 
1401  /*
1402  * leftop should be the index key Var, possibly relabeled
1403  */
1404  leftop = (Expr *) linitial(saop->args);
1405 
1406  if (leftop && IsA(leftop, RelabelType))
1407  leftop = ((RelabelType *) leftop)->arg;
1408 
1409  Assert(leftop != NULL);
1410 
1411  if (!(IsA(leftop, Var) &&
1412  ((Var *) leftop)->varno == INDEX_VAR))
1413  elog(ERROR, "indexqual doesn't have key on left side");
1414 
1415  varattno = ((Var *) leftop)->varattno;
1416  if (varattno < 1 || varattno > index->rd_index->indnatts)
1417  elog(ERROR, "bogus index qualification");
1418 
1419  /*
1420  * We have to look up the operator's strategy number. This
1421  * provides a cross-check that the operator does match the index.
1422  */
1423  opfamily = index->rd_opfamily[varattno - 1];
1424 
1425  get_op_opfamily_properties(opno, opfamily, isorderby,
1426  &op_strategy,
1427  &op_lefttype,
1428  &op_righttype);
1429 
1430  /*
1431  * rightop is the constant or variable array value
1432  */
1433  rightop = (Expr *) lsecond(saop->args);
1434 
1435  if (rightop && IsA(rightop, RelabelType))
1436  rightop = ((RelabelType *) rightop)->arg;
1437 
1438  Assert(rightop != NULL);
1439 
1440  if (index->rd_amroutine->amsearcharray)
1441  {
1442  /* Index AM will handle this like a simple operator */
1443  flags |= SK_SEARCHARRAY;
1444  if (IsA(rightop, Const))
1445  {
1446  /* OK, simple constant comparison value */
1447  scanvalue = ((Const *) rightop)->constvalue;
1448  if (((Const *) rightop)->constisnull)
1449  flags |= SK_ISNULL;
1450  }
1451  else
1452  {
1453  /* Need to treat this one as a runtime key */
1454  if (n_runtime_keys >= max_runtime_keys)
1455  {
1456  if (max_runtime_keys == 0)
1457  {
1458  max_runtime_keys = 8;
1459  runtime_keys = (IndexRuntimeKeyInfo *)
1460  palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1461  }
1462  else
1463  {
1464  max_runtime_keys *= 2;
1465  runtime_keys = (IndexRuntimeKeyInfo *)
1466  repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1467  }
1468  }
1469  runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1470  runtime_keys[n_runtime_keys].key_expr =
1471  ExecInitExpr(rightop, planstate);
1472 
1473  /*
1474  * Careful here: the runtime expression is not of
1475  * op_righttype, but rather is an array of same; so
1476  * TypeIsToastable() isn't helpful. However, we can
1477  * assume that all array types are toastable.
1478  */
1479  runtime_keys[n_runtime_keys].key_toastable = true;
1480  n_runtime_keys++;
1481  scanvalue = (Datum) 0;
1482  }
1483  }
1484  else
1485  {
1486  /* Executor has to expand the array value */
1487  array_keys[n_array_keys].scan_key = this_scan_key;
1488  array_keys[n_array_keys].array_expr =
1489  ExecInitExpr(rightop, planstate);
1490  /* the remaining fields were zeroed by palloc0 */
1491  n_array_keys++;
1492  scanvalue = (Datum) 0;
1493  }
1494 
1495  /*
1496  * initialize the scan key's fields appropriately
1497  */
1498  ScanKeyEntryInitialize(this_scan_key,
1499  flags,
1500  varattno, /* attribute number to scan */
1501  op_strategy, /* op's strategy */
1502  op_righttype, /* strategy subtype */
1503  saop->inputcollid, /* collation */
1504  opfuncid, /* reg proc to use */
1505  scanvalue); /* constant */
1506  }
1507  else if (IsA(clause, NullTest))
1508  {
1509  /* indexkey IS NULL or indexkey IS NOT NULL */
1510  NullTest *ntest = (NullTest *) clause;
1511  int flags;
1512 
1513  Assert(!isorderby);
1514 
1515  /*
1516  * argument should be the index key Var, possibly relabeled
1517  */
1518  leftop = ntest->arg;
1519 
1520  if (leftop && IsA(leftop, RelabelType))
1521  leftop = ((RelabelType *) leftop)->arg;
1522 
1523  Assert(leftop != NULL);
1524 
1525  if (!(IsA(leftop, Var) &&
1526  ((Var *) leftop)->varno == INDEX_VAR))
1527  elog(ERROR, "NullTest indexqual has wrong key");
1528 
1529  varattno = ((Var *) leftop)->varattno;
1530 
1531  /*
1532  * initialize the scan key's fields appropriately
1533  */
1534  switch (ntest->nulltesttype)
1535  {
1536  case IS_NULL:
1537  flags = SK_ISNULL | SK_SEARCHNULL;
1538  break;
1539  case IS_NOT_NULL:
1540  flags = SK_ISNULL | SK_SEARCHNOTNULL;
1541  break;
1542  default:
1543  elog(ERROR, "unrecognized nulltesttype: %d",
1544  (int) ntest->nulltesttype);
1545  flags = 0; /* keep compiler quiet */
1546  break;
1547  }
1548 
1549  ScanKeyEntryInitialize(this_scan_key,
1550  flags,
1551  varattno, /* attribute number to scan */
1552  InvalidStrategy, /* no strategy */
1553  InvalidOid, /* no strategy subtype */
1554  InvalidOid, /* no collation */
1555  InvalidOid, /* no reg proc for this */
1556  (Datum) 0); /* constant */
1557  }
1558  else
1559  elog(ERROR, "unsupported indexqual type: %d",
1560  (int) nodeTag(clause));
1561  }
1562 
1563  Assert(n_runtime_keys <= max_runtime_keys);
1564 
1565  /* Get rid of any unused arrays */
1566  if (n_array_keys == 0)
1567  {
1568  pfree(array_keys);
1569  array_keys = NULL;
1570  }
1571 
1572  /*
1573  * Return info to our caller.
1574  */
1575  *scanKeys = scan_keys;
1576  *numScanKeys = n_scan_keys;
1577  *runtimeKeys = runtime_keys;
1578  *numRuntimeKeys = n_runtime_keys;
1579  if (arrayKeys)
1580  {
1581  *arrayKeys = array_keys;
1582  *numArrayKeys = n_array_keys;
1583  }
1584  else if (n_array_keys != 0)
1585  elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
1586 }
Datum * elem_values
Definition: execnodes.h:1300
bool * orderbynulls
Definition: nodeIndexscan.c:51
signed short int16
Definition: c.h:252
int(* comparator)(Datum x, Datum y, SortSupport ssup)
Definition: sortsupport.h:107
#define InvalidStrategy
Definition: stratnum.h:24
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:323
List * qual
Definition: plannodes.h:122
pairingheap_node * pairingheap_first(pairingheap *heap)
Definition: pairingheap.c:130
#define SK_ROW_MEMBER
Definition: skey.h:118
Plan plan
Definition: plannodes.h:286
#define IsA(nodeptr, _type_)
Definition: nodes.h:542
#define BTORDER_PROC
Definition: nbtree.h:455
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:174
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:845
Index scanrelid
Definition: plannodes.h:287
void ExecEndIndexScan(IndexScanState *node)
static int cmp_orderbyvals(const Datum *adist, const bool *anulls, const Datum *bdist, const bool *bnulls, IndexScanState *node)
#define SK_ORDER_BY
Definition: skey.h:124
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
#define RelationGetDescr(relation)
Definition: rel.h:353
Definition: plannodes.h:96
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:1989
IndexRuntimeKeyInfo * iss_RuntimeKeys
Definition: execnodes.h:1338
#define PointerGetDatum(X)
Definition: postgres.h:564
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:121
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:353
int16 * iss_OrderByTypLens
Definition: execnodes.h:1352
ExprContext * ps_ExprContext
Definition: execnodes.h:1058
bool ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
SortSupport iss_SortSupport
Definition: execnodes.h:1350
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:128
RowCompareType rctype
Definition: primnodes.h:1004
regproc RegProcedure
Definition: c.h:391
#define BTREE_AM_OID
Definition: pg_am.h:70
void ExecReScan(PlanState *node)
Definition: execAmi.c:73
void PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup)
Definition: sortsupport.c:133
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:442
static void reorderqueue_push(IndexScanState *node, HeapTuple tuple, Datum *orderbyvals, bool *orderbynulls)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * indexqualorig
Definition: plannodes.h:349
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
#define AccessShareLock
Definition: lockdefs.h:36
List * qual
Definition: execnodes.h:1042
#define InvalidBuffer
Definition: buf.h:25
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:296
Definition: nodes.h:491
Datum * xs_orderbyvals
Definition: relscan.h:122
bool xs_recheckorderby
Definition: relscan.h:124
#define MemSet(start, val, len)
Definition: c.h:849
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
List * targetlist
Definition: execnodes.h:1041
Snapshot es_snapshot
Definition: execnodes.h:360
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1251
Relation ss_currentRelation
Definition: execnodes.h:1249
EState * state
Definition: execnodes.h:1029
struct ScanKeyData ScanKeyData
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:148
#define SK_SEARCHARRAY
Definition: skey.h:120
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:136
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:696
#define lsecond(l)
Definition: pg_list.h:114
ScanKey iss_ScanKeys
Definition: execnodes.h:1334
ScanDirection es_direction
Definition: execnodes.h:359
Oid indexid
Definition: plannodes.h:347
List * indexorderbyorig
Definition: execnodes.h:1333
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:435
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:255
Definition: type.h:90
#define SK_ROW_END
Definition: skey.h:119
bool ExecIndexEvalArrayKeys(ExprContext *econtext, IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
bool * iss_OrderByNulls
Definition: execnodes.h:1349
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:378
PlanState ps
Definition: execnodes.h:1248
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:256
bool * xs_orderbynulls
Definition: relscan.h:123
TupleTableSlot * ExecIndexScan(IndexScanState *node)
Form_pg_index rd_index
Definition: rel.h:114
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1057
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4452
void pfree(void *pointer)
Definition: mcxt.c:995
MemoryContext es_query_cxt
Definition: execnodes.h:386
#define linitial(l)
Definition: pg_list.h:110
Buffer xs_cbuf
Definition: relscan.h:111
#define ERROR
Definition: elog.h:43
List * indexorderbyorig
Definition: plannodes.h:351
IndexScanState * ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:259
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:835
Node * get_leftop(const Expr *clause)
Definition: clauses.c:207
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:783
Scan scan
Definition: plannodes.h:346
StrategyNumber sk_strategy
Definition: skey.h:68
Expr * arg
Definition: primnodes.h:1106
bool iss_ReachedEnd
Definition: execnodes.h:1347
Datum * orderbyvals
Definition: nodeIndexscan.c:50
ExprState * key_expr
Definition: execnodes.h:1290
#define NoLock
Definition: lockdefs.h:34
int iss_NumRuntimeKeys
Definition: execnodes.h:1339
void ScanKeyEntryInitialize(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, RegProcedure procedure, Datum argument)
Definition: scankey.c:32
ScanKeyData * ScanKey
Definition: skey.h:75
void ExecIndexMarkPos(IndexScanState *node)
void ExecReScanIndexScan(IndexScanState *node)
ScanDirection
Definition: sdir.h:22
bool * iss_OrderByTypByVals
Definition: execnodes.h:1351
static int reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
Definition: execQual.c:5246
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define SK_SEARCHNOTNULL
Definition: skey.h:122
Oid * rd_opfamily
Definition: rel.h:137
bool iss_RuntimeKeysReady
Definition: execnodes.h:1340
static void EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:326
#define SK_ISNULL
Definition: skey.h:115
List * indexqual
Definition: plannodes.h:348
#define lnext(lc)
Definition: pg_list.h:105
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
#define SK_ROW_HEADER
Definition: skey.h:117
void * palloc0(Size size)
Definition: mcxt.c:923
pairingheap_node ph_node
Definition: nodeIndexscan.c:48
uintptr_t Datum
Definition: postgres.h:374
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:344
NullTestType nulltesttype
Definition: primnodes.h:1107
static TupleTableSlot * IndexNext(IndexScanState *node)
Definition: nodeIndexscan.c:76
bool amsearcharray
Definition: amapi.h:136
Plan * plan
Definition: execnodes.h:1027
#define InvalidOid
Definition: postgres_ext.h:36
static TupleTableSlot * IndexNextWithReorder(IndexScanState *node)
ExprState * array_expr
Definition: execnodes.h:1297
ScanState ss
Definition: execnodes.h:1331
#define makeNode(_type_)
Definition: nodes.h:539
List * indexorderby
Definition: plannodes.h:350
int sk_flags
Definition: skey.h:66
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define lfirst(lc)
Definition: pg_list.h:106
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:1080
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:413
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
static HeapTuple reorderqueue_pop(IndexScanState *node)
static int list_length(const List *l)
Definition: pg_list.h:89
void ExecCloseScanRelation(Relation scanrel)
Definition: execUtils.c:841
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:1969
List * indexqualorig
Definition: execnodes.h:1332
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:122
HeapTuple htup
Definition: nodeIndexscan.c:49
ExprContext * iss_RuntimeContext
Definition: execnodes.h:1341
void ExecIndexRestrPos(IndexScanState *node)
List * indexorderbyops
Definition: plannodes.h:352
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1024
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
#define nodeTag(nodeptr)
Definition: nodes.h:496
List * targetlist
Definition: plannodes.h:121
Node * get_rightop(const Expr *clause)
Definition: clauses.c:224
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:171
#define DatumGetPointer(X)
Definition: postgres.h:557
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3475
HeapScanDesc ss_currentScanDesc
Definition: execnodes.h:1250
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:133
void * palloc(Size size)
Definition: mcxt.c:894
int i
void ExecScanReScan(ScanState *node)
Definition: execScan.c:351
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
Definition: execUtils.c:720
void * arg
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:196
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
int numberOfOrderBys
Definition: relscan.h:91
#define elog
Definition: elog.h:218
Datum * iss_OrderByValues
Definition: execnodes.h:1348
List * inputcollids
Definition: primnodes.h:1007
int iss_NumOrderByKeys
Definition: execnodes.h:1337
#define INDEX_VAR
Definition: primnodes.h:140
IndexScanDesc iss_ScanDesc
Definition: execnodes.h:1343
bool ps_TupFromTlist
Definition: execnodes.h:1060
Definition: pg_list.h:45
#define TypeIsToastable(typid)
Definition: lsyscache.h:167
Datum sk_argument
Definition: skey.h:72
#define ARR_ELEMTYPE(a)
Definition: array.h:273
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:57
int16 AttrNumber
Definition: attnum.h:21
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:146
bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
Definition: execUtils.c:757
#define SK_SEARCHNULL
Definition: skey.h:121
HeapTuple index_getnext(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:533
AttrNumber sk_attno
Definition: skey.h:67
#define ResetExprContext(econtext)
Definition: executor.h:316
#define lfirst_oid(lc)
Definition: pg_list.h:108
Relation iss_RelationDesc
Definition: execnodes.h:1342
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:215
pairingheap * iss_ReorderQueue
Definition: execnodes.h:1346
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:702
#define ExecEvalExpr(expr, econtext, isNull, isDone)
Definition: executor.h:72
#define DatumGetArrayTypeP(X)
Definition: array.h:242
ScanKey iss_OrderByKeys
Definition: execnodes.h:1336