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