#include "postgres.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "utils/memutils.h"
Go to the source code of this file.
Functions | |
static bool | tlist_matches_tupdesc (PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc) |
static TupleTableSlot * | ExecScanFetch (ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd) |
TupleTableSlot * | ExecScan (ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd) |
void | ExecAssignScanProjectionInfo (ScanState *node) |
void | ExecScanReScan (ScanState *node) |
void ExecAssignScanProjectionInfo | ( | ScanState * | node | ) |
Definition at line 246 of file execScan.c.
References ExecAssignProjectionInfo(), INDEX_VAR, IsA, NULL, Scan::plan, PlanState::plan, ScanState::ps, PlanState::ps_ProjInfo, Scan::scanrelid, ScanState::ss_ScanTupleSlot, Plan::targetlist, tlist_matches_tupdesc(), and TupleTableSlot::tts_tupleDescriptor.
Referenced by ExecInitBitmapHeapScan(), ExecInitCteScan(), ExecInitForeignScan(), ExecInitFunctionScan(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), ExecInitSeqScan(), ExecInitSubqueryScan(), ExecInitTidScan(), ExecInitValuesScan(), and ExecWorkTableScan().
{ Scan *scan = (Scan *) node->ps.plan; Index varno; /* Vars in an index-only scan's tlist should be INDEX_VAR */ if (IsA(scan, IndexOnlyScan)) varno = INDEX_VAR; else varno = scan->scanrelid; if (tlist_matches_tupdesc(&node->ps, scan->plan.targetlist, varno, node->ss_ScanTupleSlot->tts_tupleDescriptor)) node->ps.ps_ProjInfo = NULL; else ExecAssignProjectionInfo(&node->ps, node->ss_ScanTupleSlot->tts_tupleDescriptor); }
TupleTableSlot* ExecScan | ( | ScanState * | node, | |
ExecScanAccessMtd | accessMtd, | |||
ExecScanRecheckMtd | recheckMtd | |||
) |
Definition at line 108 of file execScan.c.
References Assert, CHECK_FOR_INTERRUPTS, ExprContext::ecxt_scantuple, ExecClearTuple(), ExecProject(), ExecQual(), ExecScanFetch(), ExprEndResult, ExprMultipleResult, InstrCountFiltered1, ProjectionInfo::pi_slot, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_ProjInfo, PlanState::ps_TupFromTlist, PlanState::qual, ResetExprContext, and TupIsNull.
Referenced by ExecBitmapHeapScan(), ExecCteScan(), ExecForeignScan(), ExecFunctionScan(), ExecIndexOnlyScan(), ExecIndexScan(), ExecSeqScan(), ExecSubqueryScan(), ExecTidScan(), ExecValuesScan(), and ExecWorkTableScan().
{ ExprContext *econtext; List *qual; ProjectionInfo *projInfo; ExprDoneCond isDone; TupleTableSlot *resultSlot; /* * Fetch data from node */ qual = node->ps.qual; projInfo = node->ps.ps_ProjInfo; econtext = node->ps.ps_ExprContext; /* * If we have neither a qual to check nor a projection to do, just skip * all the overhead and return the raw scan tuple. */ if (!qual && !projInfo) { ResetExprContext(econtext); return ExecScanFetch(node, accessMtd, recheckMtd); } /* * Check to see if we're still projecting out tuples from a previous scan * tuple (because there is a function-returning-set in the projection * expressions). If so, try to project another one. */ if (node->ps.ps_TupFromTlist) { Assert(projInfo); /* can't get here if not projecting */ resultSlot = ExecProject(projInfo, &isDone); if (isDone == ExprMultipleResult) return resultSlot; /* Done with that source tuple... */ node->ps.ps_TupFromTlist = false; } /* * Reset per-tuple memory context to free any expression evaluation * storage allocated in the previous tuple cycle. Note this can't happen * until we're done projecting out tuples from a scan tuple. */ ResetExprContext(econtext); /* * get a tuple from the access method. Loop until we obtain a tuple that * passes the qualification. */ for (;;) { TupleTableSlot *slot; CHECK_FOR_INTERRUPTS(); slot = ExecScanFetch(node, accessMtd, recheckMtd); /* * if the slot returned by the accessMtd contains NULL, then it means * there is nothing more to scan so we just return an empty slot, * being careful to use the projection result slot so it has correct * tupleDesc. */ if (TupIsNull(slot)) { if (projInfo) return ExecClearTuple(projInfo->pi_slot); else return slot; } /* * place the current tuple into the expr context */ econtext->ecxt_scantuple = slot; /* * check that the current tuple satisfies the qual-clause * * check for non-nil qual here to avoid a function call to ExecQual() * when the qual is nil ... saves only a few cycles, but they add up * ... */ if (!qual || ExecQual(qual, econtext, false)) { /* * Found a satisfactory scan tuple. */ if (projInfo) { /* * Form a projection tuple, store it in the result tuple slot * and return it --- unless we find we can project no tuples * from this scan tuple, in which case continue scan. */ resultSlot = ExecProject(projInfo, &isDone); if (isDone != ExprEndResult) { node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult); return resultSlot; } } else { /* * Here, we aren't projecting, so just return scan tuple. */ return slot; } } else InstrCountFiltered1(node, 1); /* * Tuple fails qual, so free per-tuple memory and try again. */ ResetExprContext(econtext); } }
static TupleTableSlot* ExecScanFetch | ( | ScanState * | node, | |
ExecScanAccessMtd | accessMtd, | |||
ExecScanRecheckMtd | recheckMtd | |||
) | [inline, static] |
Definition at line 37 of file execScan.c.
References Assert, EState::es_epqScanDone, EState::es_epqTuple, EState::es_epqTupleSet, ExecClearTuple(), ExecStoreTuple(), InvalidBuffer, NULL, PlanState::plan, ScanState::ps, ScanState::ss_ScanTupleSlot, and PlanState::state.
Referenced by ExecScan().
{ EState *estate = node->ps.state; if (estate->es_epqTuple != NULL) { /* * We are inside an EvalPlanQual recheck. Return the test tuple if * one is available, after rechecking any access-method-specific * conditions. */ Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; Assert(scanrelid > 0); if (estate->es_epqTupleSet[scanrelid - 1]) { TupleTableSlot *slot = node->ss_ScanTupleSlot; /* Return empty slot if we already returned a tuple */ if (estate->es_epqScanDone[scanrelid - 1]) return ExecClearTuple(slot); /* Else mark to remember that we shouldn't return more */ estate->es_epqScanDone[scanrelid - 1] = true; /* Return empty slot if we haven't got a test tuple */ if (estate->es_epqTuple[scanrelid - 1] == NULL) return ExecClearTuple(slot); /* Store test tuple in the plan node's scan slot */ ExecStoreTuple(estate->es_epqTuple[scanrelid - 1], slot, InvalidBuffer, false); /* Check if it meets the access-method conditions */ if (!(*recheckMtd) (node, slot)) ExecClearTuple(slot); /* would not be returned by scan */ return slot; } } /* * Run the node-type-specific access method function to get the next tuple */ return (*accessMtd) (node); }
void ExecScanReScan | ( | ScanState * | node | ) |
Definition at line 333 of file execScan.c.
References Assert, EState::es_epqScanDone, NULL, PlanState::plan, ScanState::ps, PlanState::ps_TupFromTlist, and PlanState::state.
Referenced by ExecReScanBitmapHeapScan(), ExecReScanCteScan(), ExecReScanForeignScan(), ExecReScanFunctionScan(), ExecReScanIndexOnlyScan(), ExecReScanIndexScan(), ExecReScanSeqScan(), ExecReScanSubqueryScan(), ExecReScanTidScan(), ExecReScanValuesScan(), and ExecReScanWorkTableScan().
{ EState *estate = node->ps.state; /* Stop projecting any tuples from SRFs in the targetlist */ node->ps.ps_TupFromTlist = false; /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */ if (estate->es_epqScanDone != NULL) { Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; Assert(scanrelid > 0); estate->es_epqScanDone[scanrelid - 1] = false; } }
static bool tlist_matches_tupdesc | ( | PlanState * | ps, | |
List * | tlist, | |||
Index | varno, | |||
TupleDesc | tupdesc | |||
) | [static] |
Definition at line 268 of file execScan.c.
References Assert, tupleDesc::attrs, ExecContextForcesOids(), IsA, lfirst, list_head(), lnext, tupleDesc::natts, NULL, tupleDesc::tdhasoid, Var::varattno, Var::varlevelsup, Var::varno, Var::vartype, and Var::vartypmod.
Referenced by ExecAssignScanProjectionInfo().
{ int numattrs = tupdesc->natts; int attrno; bool hasoid; ListCell *tlist_item = list_head(tlist); /* Check the tlist attributes */ for (attrno = 1; attrno <= numattrs; attrno++) { Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1]; Var *var; if (tlist_item == NULL) return false; /* tlist too short */ var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr; if (!var || !IsA(var, Var)) return false; /* tlist item not a Var */ /* if these Asserts fail, planner messed up */ Assert(var->varno == varno); Assert(var->varlevelsup == 0); if (var->varattno != attrno) return false; /* out of order */ if (att_tup->attisdropped) return false; /* table contains dropped columns */ /* * Note: usually the Var's type should match the tupdesc exactly, but * in situations involving unions of columns that have different * typmods, the Var may have come from above the union and hence have * typmod -1. This is a legitimate situation since the Var still * describes the column, just not as exactly as the tupdesc does. We * could change the planner to prevent it, but it'd then insert * projection steps just to convert from specific typmod to typmod -1, * which is pretty silly. */ if (var->vartype != att_tup->atttypid || (var->vartypmod != att_tup->atttypmod && var->vartypmod != -1)) return false; /* type mismatch */ tlist_item = lnext(tlist_item); } if (tlist_item) return false; /* tlist too long */ /* * If the plan context requires a particular hasoid setting, then that has * to match, too. */ if (ExecContextForcesOids(ps, &hasoid) && hasoid != tupdesc->tdhasoid) return false; return true; }