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