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