PostgreSQL Source Code  git master
nodeIndexonlyscan.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeIndexonlyscan.c
4  * Routines to support index-only scans
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/executor/nodeIndexonlyscan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  * ExecIndexOnlyScan scans an index
18  * IndexOnlyNext retrieve next tuple
19  * ExecInitIndexOnlyScan creates and initializes state info.
20  * ExecReScanIndexOnlyScan rescans the indexed relation.
21  * ExecEndIndexOnlyScan releases all storage.
22  * ExecIndexOnlyMarkPos marks scan position.
23  * ExecIndexOnlyRestrPos restores scan position.
24  * ExecIndexOnlyScanEstimate estimates DSM space needed for
25  * parallel index-only scan
26  * ExecIndexOnlyScanInitializeDSM initialize DSM for parallel
27  * index-only scan
28  * ExecIndexOnlyScanReInitializeDSM reinitialize DSM for fresh scan
29  * ExecIndexOnlyScanInitializeWorker attach to DSM info in parallel worker
30  */
31 #include "postgres.h"
32 
33 #include "access/genam.h"
34 #include "access/relscan.h"
35 #include "access/tableam.h"
36 #include "access/tupdesc.h"
37 #include "access/visibilitymap.h"
38 #include "executor/execdebug.h"
40 #include "executor/nodeIndexscan.h"
41 #include "miscadmin.h"
42 #include "storage/bufmgr.h"
43 #include "storage/predicate.h"
44 #include "utils/memutils.h"
45 #include "utils/rel.h"
46 
47 
49 static void StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup,
50  TupleDesc itupdesc);
51 
52 
53 /* ----------------------------------------------------------------
54  * IndexOnlyNext
55  *
56  * Retrieve a tuple from the IndexOnlyScan node's index.
57  * ----------------------------------------------------------------
58  */
59 static TupleTableSlot *
61 {
62  EState *estate;
63  ExprContext *econtext;
64  ScanDirection direction;
65  IndexScanDesc scandesc;
66  TupleTableSlot *slot;
67  ItemPointer tid;
68 
69  /*
70  * extract necessary information from index scan node
71  */
72  estate = node->ss.ps.state;
73  direction = estate->es_direction;
74  /* flip direction if this is an overall backward scan */
75  if (ScanDirectionIsBackward(((IndexOnlyScan *) node->ss.ps.plan)->indexorderdir))
76  {
77  if (ScanDirectionIsForward(direction))
78  direction = BackwardScanDirection;
79  else if (ScanDirectionIsBackward(direction))
80  direction = ForwardScanDirection;
81  }
82  scandesc = node->ioss_ScanDesc;
83  econtext = node->ss.ps.ps_ExprContext;
84  slot = node->ss.ss_ScanTupleSlot;
85 
86  if (scandesc == NULL)
87  {
88  /*
89  * We reach here if the index only scan is not parallel, or if we're
90  * serially executing an index only scan that was planned to be
91  * parallel.
92  */
93  scandesc = index_beginscan(node->ss.ss_currentRelation,
94  node->ioss_RelationDesc,
95  estate->es_snapshot,
96  node->ioss_NumScanKeys,
97  node->ioss_NumOrderByKeys);
98 
99  node->ioss_ScanDesc = scandesc;
100 
101 
102  /* Set it up for index-only scan */
103  node->ioss_ScanDesc->xs_want_itup = true;
105 
106  /*
107  * If no run-time keys to calculate or they are ready, go ahead and
108  * pass the scankeys to the index AM.
109  */
110  if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
111  index_rescan(scandesc,
112  node->ioss_ScanKeys,
113  node->ioss_NumScanKeys,
114  node->ioss_OrderByKeys,
115  node->ioss_NumOrderByKeys);
116  }
117 
118  /*
119  * OK, now that we have what we need, fetch the next tuple.
120  */
121  while ((tid = index_getnext_tid(scandesc, direction)) != NULL)
122  {
123  bool tuple_from_heap = false;
124 
126 
127  /*
128  * We can skip the heap fetch if the TID references a heap page on
129  * which all tuples are known visible to everybody. In any case,
130  * we'll use the index tuple not the heap tuple as the data source.
131  *
132  * Note on Memory Ordering Effects: visibilitymap_get_status does not
133  * lock the visibility map buffer, and therefore the result we read
134  * here could be slightly stale. However, it can't be stale enough to
135  * matter.
136  *
137  * We need to detect clearing a VM bit due to an insert right away,
138  * because the tuple is present in the index page but not visible. The
139  * reading of the TID by this scan (using a shared lock on the index
140  * buffer) is serialized with the insert of the TID into the index
141  * (using an exclusive lock on the index buffer). Because the VM bit
142  * is cleared before updating the index, and locking/unlocking of the
143  * index page acts as a full memory barrier, we are sure to see the
144  * cleared bit if we see a recently-inserted TID.
145  *
146  * Deletes do not update the index page (only VACUUM will clear out
147  * the TID), so the clearing of the VM bit by a delete is not
148  * serialized with this test below, and we may see a value that is
149  * significantly stale. However, we don't care about the delete right
150  * away, because the tuple is still visible until the deleting
151  * transaction commits or the statement ends (if it's our
152  * transaction). In either case, the lock on the VM buffer will have
153  * been released (acting as a write barrier) after clearing the bit.
154  * And for us to have a snapshot that includes the deleting
155  * transaction (making the tuple invisible), we must have acquired
156  * ProcArrayLock after that time, acting as a read barrier.
157  *
158  * It's worth going through this complexity to avoid needing to lock
159  * the VM buffer, which could cause significant contention.
160  */
161  if (!VM_ALL_VISIBLE(scandesc->heapRelation,
163  &node->ioss_VMBuffer))
164  {
165  /*
166  * Rats, we have to visit the heap to check visibility.
167  */
168  InstrCountTuples2(node, 1);
169  if (!index_fetch_heap(scandesc, node->ioss_TableSlot))
170  continue; /* no visible tuple, try next index entry */
171 
173 
174  /*
175  * Only MVCC snapshots are supported here, so there should be no
176  * need to keep following the HOT chain once a visible entry has
177  * been found. If we did want to allow that, we'd need to keep
178  * more state to remember not to call index_getnext_tid next time.
179  */
180  if (scandesc->xs_heap_continue)
181  elog(ERROR, "non-MVCC snapshots are not supported in index-only scans");
182 
183  /*
184  * Note: at this point we are holding a pin on the heap page, as
185  * recorded in scandesc->xs_cbuf. We could release that pin now,
186  * but it's not clear whether it's a win to do so. The next index
187  * entry might require a visit to the same heap page.
188  */
189 
190  tuple_from_heap = true;
191  }
192 
193  /*
194  * Fill the scan tuple slot with data from the index. This might be
195  * provided in either HeapTuple or IndexTuple format. Conceivably an
196  * index AM might fill both fields, in which case we prefer the heap
197  * format, since it's probably a bit cheaper to fill a slot from.
198  */
199  if (scandesc->xs_hitup)
200  {
201  /*
202  * We don't take the trouble to verify that the provided tuple has
203  * exactly the slot's format, but it seems worth doing a quick
204  * check on the number of fields.
205  */
207  scandesc->xs_hitupdesc->natts);
208  ExecForceStoreHeapTuple(scandesc->xs_hitup, slot, false);
209  }
210  else if (scandesc->xs_itup)
211  StoreIndexTuple(slot, scandesc->xs_itup, scandesc->xs_itupdesc);
212  else
213  elog(ERROR, "no data returned for index-only scan");
214 
215  /*
216  * If the index was lossy, we have to recheck the index quals.
217  * (Currently, this can never happen, but we should support the case
218  * for possible future use, eg with GiST indexes.)
219  */
220  if (scandesc->xs_recheck)
221  {
222  econtext->ecxt_scantuple = slot;
223  if (!ExecQualAndReset(node->indexqual, econtext))
224  {
225  /* Fails recheck, so drop it and loop back for another */
226  InstrCountFiltered2(node, 1);
227  continue;
228  }
229  }
230 
231  /*
232  * We don't currently support rechecking ORDER BY distances. (In
233  * principle, if the index can support retrieval of the originally
234  * indexed value, it should be able to produce an exact distance
235  * calculation too. So it's not clear that adding code here for
236  * recheck/re-sort would be worth the trouble. But we should at least
237  * throw an error if someone tries it.)
238  */
239  if (scandesc->numberOfOrderBys > 0 && scandesc->xs_recheckorderby)
240  ereport(ERROR,
241  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
242  errmsg("lossy distance functions are not supported in index-only scans")));
243 
244  /*
245  * If we didn't access the heap, then we'll need to take a predicate
246  * lock explicitly, as if we had. For now we do that at page level.
247  */
248  if (!tuple_from_heap)
251  estate->es_snapshot);
252 
253  return slot;
254  }
255 
256  /*
257  * if we get here it means the index scan failed so we are at the end of
258  * the scan..
259  */
260  return ExecClearTuple(slot);
261 }
262 
263 /*
264  * StoreIndexTuple
265  * Fill the slot with data from the index tuple.
266  *
267  * At some point this might be generally-useful functionality, but
268  * right now we don't need it elsewhere.
269  */
270 static void
272 {
273  /*
274  * Note: we must use the tupdesc supplied by the AM in index_deform_tuple,
275  * not the slot's tupdesc, in case the latter has different datatypes
276  * (this happens for btree name_ops in particular). They'd better have
277  * the same number of columns though, as well as being datatype-compatible
278  * which is something we can't so easily check.
279  */
280  Assert(slot->tts_tupleDescriptor->natts == itupdesc->natts);
281 
282  ExecClearTuple(slot);
283  index_deform_tuple(itup, itupdesc, slot->tts_values, slot->tts_isnull);
284  ExecStoreVirtualTuple(slot);
285 }
286 
287 /*
288  * IndexOnlyRecheck -- access method routine to recheck a tuple in EvalPlanQual
289  *
290  * This can't really happen, since an index can't supply CTID which would
291  * be necessary data for any potential EvalPlanQual target relation. If it
292  * did happen, the EPQ code would pass us the wrong data, namely a heap
293  * tuple not an index tuple. So throw an error.
294  */
295 static bool
297 {
298  elog(ERROR, "EvalPlanQual recheck is not supported in index-only scans");
299  return false; /* keep compiler quiet */
300 }
301 
302 /* ----------------------------------------------------------------
303  * ExecIndexOnlyScan(node)
304  * ----------------------------------------------------------------
305  */
306 static TupleTableSlot *
308 {
310 
311  /*
312  * If we have runtime keys and they've not already been set up, do it now.
313  */
314  if (node->ioss_NumRuntimeKeys != 0 && !node->ioss_RuntimeKeysReady)
315  ExecReScan((PlanState *) node);
316 
317  return ExecScan(&node->ss,
320 }
321 
322 /* ----------------------------------------------------------------
323  * ExecReScanIndexOnlyScan(node)
324  *
325  * Recalculates the values of any scan keys whose value depends on
326  * information known at runtime, then rescans the indexed relation.
327  *
328  * Updating the scan key was formerly done separately in
329  * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
330  * rescans of indices and relations/general streams more uniform.
331  * ----------------------------------------------------------------
332  */
333 void
335 {
336  /*
337  * If we are doing runtime key calculations (ie, any of the index key
338  * values weren't simple Consts), compute the new key values. But first,
339  * reset the context so we don't leak memory as each outer tuple is
340  * scanned. Note this assumes that we will recalculate *all* runtime keys
341  * on each call.
342  */
343  if (node->ioss_NumRuntimeKeys != 0)
344  {
345  ExprContext *econtext = node->ioss_RuntimeContext;
346 
347  ResetExprContext(econtext);
348  ExecIndexEvalRuntimeKeys(econtext,
349  node->ioss_RuntimeKeys,
350  node->ioss_NumRuntimeKeys);
351  }
352  node->ioss_RuntimeKeysReady = true;
353 
354  /* reset index scan */
355  if (node->ioss_ScanDesc)
357  node->ioss_ScanKeys, node->ioss_NumScanKeys,
359 
360  ExecScanReScan(&node->ss);
361 }
362 
363 
364 /* ----------------------------------------------------------------
365  * ExecEndIndexOnlyScan
366  * ----------------------------------------------------------------
367  */
368 void
370 {
371  Relation indexRelationDesc;
372  IndexScanDesc indexScanDesc;
373 
374  /*
375  * extract information from the node
376  */
377  indexRelationDesc = node->ioss_RelationDesc;
378  indexScanDesc = node->ioss_ScanDesc;
379 
380  /* Release VM buffer pin, if any. */
381  if (node->ioss_VMBuffer != InvalidBuffer)
382  {
385  }
386 
387  /*
388  * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
389  */
390 #ifdef NOT_USED
391  ExecFreeExprContext(&node->ss.ps);
392  if (node->ioss_RuntimeContext)
394 #endif
395 
396  /*
397  * clear out tuple table slots
398  */
399  if (node->ss.ps.ps_ResultTupleSlot)
402 
403  /*
404  * close the index relation (no-op if we didn't open it)
405  */
406  if (indexScanDesc)
407  index_endscan(indexScanDesc);
408  if (indexRelationDesc)
409  index_close(indexRelationDesc, NoLock);
410 }
411 
412 /* ----------------------------------------------------------------
413  * ExecIndexOnlyMarkPos
414  *
415  * Note: we assume that no caller attempts to set a mark before having read
416  * at least one tuple. Otherwise, ioss_ScanDesc might still be NULL.
417  * ----------------------------------------------------------------
418  */
419 void
421 {
422  EState *estate = node->ss.ps.state;
423  EPQState *epqstate = estate->es_epq_active;
424 
425  if (epqstate != NULL)
426  {
427  /*
428  * We are inside an EvalPlanQual recheck. If a test tuple exists for
429  * this relation, then we shouldn't access the index at all. We would
430  * instead need to save, and later restore, the state of the
431  * relsubs_done flag, so that re-fetching the test tuple is possible.
432  * However, given the assumption that no caller sets a mark at the
433  * start of the scan, we can only get here with relsubs_done[i]
434  * already set, and so no state need be saved.
435  */
436  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
437 
438  Assert(scanrelid > 0);
439  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
440  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
441  {
442  /* Verify the claim above */
443  if (!epqstate->relsubs_done[scanrelid - 1])
444  elog(ERROR, "unexpected ExecIndexOnlyMarkPos call in EPQ recheck");
445  return;
446  }
447  }
448 
450 }
451 
452 /* ----------------------------------------------------------------
453  * ExecIndexOnlyRestrPos
454  * ----------------------------------------------------------------
455  */
456 void
458 {
459  EState *estate = node->ss.ps.state;
460  EPQState *epqstate = estate->es_epq_active;
461 
462  if (estate->es_epq_active != NULL)
463  {
464  /* See comments in ExecIndexMarkPos */
465  Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
466 
467  Assert(scanrelid > 0);
468  if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
469  epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
470  {
471  /* Verify the claim above */
472  if (!epqstate->relsubs_done[scanrelid - 1])
473  elog(ERROR, "unexpected ExecIndexOnlyRestrPos call in EPQ recheck");
474  return;
475  }
476  }
477 
479 }
480 
481 /* ----------------------------------------------------------------
482  * ExecInitIndexOnlyScan
483  *
484  * Initializes the index scan's state information, creates
485  * scan keys, and opens the base and index relations.
486  *
487  * Note: index scans have 2 sets of state information because
488  * we have to keep track of the base relation and the
489  * index relation.
490  * ----------------------------------------------------------------
491  */
493 ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
494 {
495  IndexOnlyScanState *indexstate;
496  Relation currentRelation;
497  LOCKMODE lockmode;
498  TupleDesc tupDesc;
499 
500  /*
501  * create state structure
502  */
503  indexstate = makeNode(IndexOnlyScanState);
504  indexstate->ss.ps.plan = (Plan *) node;
505  indexstate->ss.ps.state = estate;
506  indexstate->ss.ps.ExecProcNode = ExecIndexOnlyScan;
507 
508  /*
509  * Miscellaneous initialization
510  *
511  * create expression context for node
512  */
513  ExecAssignExprContext(estate, &indexstate->ss.ps);
514 
515  /*
516  * open the scan relation
517  */
518  currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
519 
520  indexstate->ss.ss_currentRelation = currentRelation;
521  indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
522 
523  /*
524  * Build the scan tuple type using the indextlist generated by the
525  * planner. We use this, rather than the index's physical tuple
526  * descriptor, because the latter contains storage column types not the
527  * types of the original datums. (It's the AM's responsibility to return
528  * suitable data anyway.)
529  */
530  tupDesc = ExecTypeFromTL(node->indextlist);
531  ExecInitScanTupleSlot(estate, &indexstate->ss, tupDesc,
532  &TTSOpsVirtual);
533 
534  /*
535  * We need another slot, in a format that's suitable for the table AM, for
536  * when we need to fetch a tuple from the table for rechecking visibility.
537  */
538  indexstate->ioss_TableSlot =
540  RelationGetDescr(currentRelation),
541  table_slot_callbacks(currentRelation));
542 
543  /*
544  * Initialize result type and projection info. The node's targetlist will
545  * contain Vars with varno = INDEX_VAR, referencing the scan tuple.
546  */
547  ExecInitResultTypeTL(&indexstate->ss.ps);
549 
550  /*
551  * initialize child expressions
552  *
553  * Note: we don't initialize all of the indexorderby expression, only the
554  * sub-parts corresponding to runtime keys (see below).
555  */
556  indexstate->ss.ps.qual =
557  ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
558  indexstate->indexqual =
559  ExecInitQual(node->indexqual, (PlanState *) indexstate);
560 
561  /*
562  * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
563  * here. This allows an index-advisor plugin to EXPLAIN a plan containing
564  * references to nonexistent indexes.
565  */
566  if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
567  return indexstate;
568 
569  /* Open the index relation. */
570  lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
571  indexstate->ioss_RelationDesc = index_open(node->indexid, lockmode);
572 
573  /*
574  * Initialize index-specific scan state
575  */
576  indexstate->ioss_RuntimeKeysReady = false;
577  indexstate->ioss_RuntimeKeys = NULL;
578  indexstate->ioss_NumRuntimeKeys = 0;
579 
580  /*
581  * build the index scan keys from the index qualification
582  */
583  ExecIndexBuildScanKeys((PlanState *) indexstate,
584  indexstate->ioss_RelationDesc,
585  node->indexqual,
586  false,
587  &indexstate->ioss_ScanKeys,
588  &indexstate->ioss_NumScanKeys,
589  &indexstate->ioss_RuntimeKeys,
590  &indexstate->ioss_NumRuntimeKeys,
591  NULL, /* no ArrayKeys */
592  NULL);
593 
594  /*
595  * any ORDER BY exprs have to be turned into scankeys in the same way
596  */
597  ExecIndexBuildScanKeys((PlanState *) indexstate,
598  indexstate->ioss_RelationDesc,
599  node->indexorderby,
600  true,
601  &indexstate->ioss_OrderByKeys,
602  &indexstate->ioss_NumOrderByKeys,
603  &indexstate->ioss_RuntimeKeys,
604  &indexstate->ioss_NumRuntimeKeys,
605  NULL, /* no ArrayKeys */
606  NULL);
607 
608  /*
609  * If we have runtime keys, we need an ExprContext to evaluate them. The
610  * node's standard context won't do because we want to reset that context
611  * for every tuple. So, build another context just like the other one...
612  * -tgl 7/11/00
613  */
614  if (indexstate->ioss_NumRuntimeKeys != 0)
615  {
616  ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
617 
618  ExecAssignExprContext(estate, &indexstate->ss.ps);
619  indexstate->ioss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
620  indexstate->ss.ps.ps_ExprContext = stdecontext;
621  }
622  else
623  {
624  indexstate->ioss_RuntimeContext = NULL;
625  }
626 
627  /*
628  * all done.
629  */
630  return indexstate;
631 }
632 
633 /* ----------------------------------------------------------------
634  * Parallel Index-only Scan Support
635  * ----------------------------------------------------------------
636  */
637 
638 /* ----------------------------------------------------------------
639  * ExecIndexOnlyScanEstimate
640  *
641  * Compute the amount of space we'll need in the parallel
642  * query DSM, and inform pcxt->estimator about our needs.
643  * ----------------------------------------------------------------
644  */
645 void
647  ParallelContext *pcxt)
648 {
649  EState *estate = node->ss.ps.state;
650 
652  estate->es_snapshot);
654  shm_toc_estimate_keys(&pcxt->estimator, 1);
655 }
656 
657 /* ----------------------------------------------------------------
658  * ExecIndexOnlyScanInitializeDSM
659  *
660  * Set up a parallel index-only scan descriptor.
661  * ----------------------------------------------------------------
662  */
663 void
665  ParallelContext *pcxt)
666 {
667  EState *estate = node->ss.ps.state;
668  ParallelIndexScanDesc piscan;
669 
670  piscan = shm_toc_allocate(pcxt->toc, node->ioss_PscanLen);
672  node->ioss_RelationDesc,
673  estate->es_snapshot,
674  piscan);
675  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
676  node->ioss_ScanDesc =
678  node->ioss_RelationDesc,
679  node->ioss_NumScanKeys,
680  node->ioss_NumOrderByKeys,
681  piscan);
682  node->ioss_ScanDesc->xs_want_itup = true;
684 
685  /*
686  * If no run-time keys to calculate or they are ready, go ahead and pass
687  * the scankeys to the index AM.
688  */
689  if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
691  node->ioss_ScanKeys, node->ioss_NumScanKeys,
693 }
694 
695 /* ----------------------------------------------------------------
696  * ExecIndexOnlyScanReInitializeDSM
697  *
698  * Reset shared state before beginning a fresh scan.
699  * ----------------------------------------------------------------
700  */
701 void
703  ParallelContext *pcxt)
704 {
706 }
707 
708 /* ----------------------------------------------------------------
709  * ExecIndexOnlyScanInitializeWorker
710  *
711  * Copy relevant information from TOC into planstate.
712  * ----------------------------------------------------------------
713  */
714 void
716  ParallelWorkerContext *pwcxt)
717 {
718  ParallelIndexScanDesc piscan;
719 
720  piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
721  node->ioss_ScanDesc =
723  node->ioss_RelationDesc,
724  node->ioss_NumScanKeys,
725  node->ioss_NumOrderByKeys,
726  piscan);
727  node->ioss_ScanDesc->xs_want_itup = true;
728 
729  /*
730  * If no run-time keys to calculate or they are ready, go ahead and pass
731  * the scankeys to the index AM.
732  */
733  if (node->ioss_NumRuntimeKeys == 0 || node->ioss_RuntimeKeysReady)
735  node->ioss_ScanKeys, node->ioss_NumScanKeys,
737 }
bool ioss_RuntimeKeysReady
Definition: execnodes.h:1472
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1085
List * qual
Definition: plannodes.h:141
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition: predicate.c:2526
Plan plan
Definition: plannodes.h:340
TupleTableSlot * ioss_TableSlot
Definition: execnodes.h:1476
Index scanrelid
Definition: plannodes.h:341
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
IndexTuple xs_itup
Definition: relscan.h:127
#define RelationGetDescr(relation)
Definition: rel.h:445
int LOCKMODE
Definition: lockdefs.h:26
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
IndexScanDesc index_beginscan_parallel(Relation heaprel, Relation indexrel, int nkeys, int norderbys, ParallelIndexScanDesc pscan)
Definition: indexam.c:476
void ExecIndexOnlyRestrPos(IndexOnlyScanState *node)
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:158
void index_markpos(IndexScanDesc scan)
Definition: indexam.c:345
ExprContext * ps_ExprContext
Definition: execnodes.h:979
shm_toc_estimator estimator
Definition: parallel.h:41
struct TupleDescData * xs_itupdesc
Definition: relscan.h:128
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:130
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition: tableam.c:44
void ExecReScan(PlanState *node)
Definition: execAmi.c:77
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
int plan_node_id
Definition: plannodes.h:139
#define InvalidBuffer
Definition: buf.h:25
void index_rescan(IndexScanDesc scan, ScanKey keys, int nkeys, ScanKey orderbys, int norderbys)
Definition: indexam.c:289
struct TableScanDescData * ss_currentScanDesc
Definition: execnodes.h:1333
int errcode(int sqlerrcode)
Definition: elog.c:570
IndexRuntimeKeyInfo * ioss_RuntimeKeys
Definition: execnodes.h:1470
bool xs_recheckorderby
Definition: relscan.h:148
Snapshot es_snapshot
Definition: execnodes.h:503
Datum * tts_values
Definition: tuptable.h:126
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1334
void ExecReScanIndexOnlyScan(IndexOnlyScanState *node)
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
Relation ss_currentRelation
Definition: execnodes.h:1332
EState * state
Definition: execnodes.h:942
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
static bool IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:614
struct IndexScanDescData * ioss_ScanDesc
Definition: execnodes.h:1475
void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1434
struct EPQState * es_epq_active
Definition: execnodes.h:579
ScanDirection es_direction
Definition: execnodes.h:502
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:207
Size index_parallelscan_estimate(Relation indexRelation, Snapshot snapshot)
Definition: indexam.c:394
void index_parallelrescan(IndexScanDesc scan)
Definition: indexam.c:458
Relation heapRelation
Definition: relscan.h:102
void ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
Definition: execScan.c:285
void index_restrpos(IndexScanDesc scan)
Definition: indexam.c:369
PlanState ps
Definition: execnodes.h:1331
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
ItemPointer index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
Definition: indexam.c:509
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:978
void ExecIndexOnlyMarkPos(IndexOnlyScanState *node)
#define ERROR
Definition: elog.h:43
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:693
void ExecIndexOnlyScanEstimate(IndexOnlyScanState *node, ParallelContext *pcxt)
struct ScanKeyData * ioss_ScanKeys
Definition: execnodes.h:1466
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1776
ExprContext * ioss_RuntimeContext
Definition: execnodes.h:1473
#define NoLock
Definition: lockdefs.h:34
bool * tts_isnull
Definition: tuptable.h:128
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1720
ScanDirection
Definition: sdir.h:22
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition: executor.h:537
void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:433
bool * relsubs_done
Definition: execnodes.h:1119
#define InstrCountTuples2(node, delta)
Definition: execnodes.h:1037
struct ScanKeyData * ioss_OrderByKeys
Definition: execnodes.h:1468
void ExecEndIndexOnlyScan(IndexOnlyScanState *node)
void index_endscan(IndexScanDesc scan)
Definition: indexam.c:315
#define ereport(elevel, rest)
Definition: elog.h:141
TupleTableSlot * ExecAllocTableSlot(List **tupleTable, TupleDesc desc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1136
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:426
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:392
List * es_tupleTable
Definition: execnodes.h:552
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:946
void FreeExprContext(ExprContext *econtext, bool isCommit)
Definition: execUtils.c:375
unsigned int Index
Definition: c.h:475
Plan * plan
Definition: execnodes.h:940
Relation ioss_RelationDesc
Definition: execnodes.h:1474
List * indextlist
Definition: plannodes.h:433
List * indexorderby
Definition: plannodes.h:432
#define makeNode(_type_)
Definition: nodes.h:573
IndexOnlyScanState * ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
#define Assert(condition)
Definition: c.h:732
static TupleTableSlot * ExecIndexOnlyScan(PlanState *pstate)
static void StoreIndexTuple(TupleTableSlot *slot, IndexTuple itup, TupleDesc itupdesc)
static TupleTableSlot * IndexOnlyNext(IndexOnlyScanState *node)
#define InstrCountFiltered2(node, delta)
Definition: execnodes.h:1047
#define VM_ALL_VISIBLE(r, b, v)
Definition: visibilitymap.h:32
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:444
void ExecIndexBuildScanKeys(PlanState *planstate, Relation index, List *quals, bool isorderby, ScanKey *scanKeys, int *numScanKeys, IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys, IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
List * indexqual
Definition: plannodes.h:431
TupleDesc ExecTypeFromTL(List *targetList)
Definition: execTuples.c:1904
ExprState * indexqual
Definition: execnodes.h:1465
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:224
bool xs_heap_continue
Definition: relscan.h:133
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void ExecIndexOnlyScanInitializeWorker(IndexOnlyScanState *node, ParallelWorkerContext *pwcxt)
void ExecIndexOnlyScanReInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt)
void ExecIndexEvalRuntimeKeys(ExprContext *econtext, IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
ExprState * qual
Definition: execnodes.h:961
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
int errmsg(const char *fmt,...)
Definition: elog.c:784
HeapTuple xs_hitup
Definition: relscan.h:129
void index_parallelscan_initialize(Relation heapRelation, Relation indexRelation, Snapshot snapshot, ParallelIndexScanDesc target)
Definition: indexam.c:427
#define elog(elevel,...)
Definition: elog.h:226
void ExecScanReScan(ScanState *node)
Definition: execScan.c:299
bool index_fetch_heap(IndexScanDesc scan, TupleTableSlot *slot)
Definition: indexam.c:566
void ExecIndexOnlyScanInitializeDSM(IndexOnlyScanState *node, ParallelContext *pcxt)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int numberOfOrderBys
Definition: relscan.h:106
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:425
#define INDEX_VAR
Definition: primnodes.h:159
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1113
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:56
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
#define ResetExprContext(econtext)
Definition: executor.h:495
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1517
shm_toc * toc
Definition: parallel.h:44
IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, int norderbys)
Definition: indexam.c:197