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