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