/*------------------------------------------------------------------------- * * execScan.c * This code provides support for generalized relation scans. ExecScan * is passed a node and a pointer to a function to "do the right thing" * and return a tuple from the relation. ExecScan then does the tedious * stuff - checking the qualification and projecting the tuple * appropriately. * * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/backend/executor/execScan.c * *------------------------------------------------------------------------- */ #include "postgres.h" #include "executor/executor.h" #include "executor/execScan.h" #include "miscadmin.h" /* ---------------------------------------------------------------- * ExecScan * * Scans the relation using the 'access method' indicated and * returns the next qualifying tuple. * The access method returns the next tuple and ExecScan() is * responsible for checking the tuple returned against the qual-clause. * * A 'recheck method' must also be provided that can check an * arbitrary tuple of the relation against any qual conditions * that are implemented internal to the access method. * * Conditions: * -- the "cursor" maintained by the AMI is positioned at the tuple * returned previously. * * Initial States: * -- the relation indicated is opened for scanning so that the * "cursor" is positioned before the first qualifying tuple. * ---------------------------------------------------------------- */ TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, /* function returning a tuple */ ExecScanRecheckMtd recheckMtd) { EPQState *epqstate; ExprState *qual; ProjectionInfo *projInfo; epqstate = node->ps.state->es_epq_active; qual = node->ps.qual; projInfo = node->ps.ps_ProjInfo; return ExecScanExtended(node, accessMtd, recheckMtd, epqstate, qual, projInfo); } /* * ExecAssignScanProjectionInfo * Set up projection info for a scan node, if necessary. * * We can avoid a projection step if the requested tlist exactly matches * the underlying tuple type. If so, we just set ps_ProjInfo to NULL. * Note that this case occurs not only for simple "SELECT * FROM ...", but * also in most cases where there are joins or other processing nodes above * the scan node, because the planner will preferentially generate a matching * tlist. * * The scan slot's descriptor must have been set already. */ void ExecAssignScanProjectionInfo(ScanState *node) { Scan *scan = (Scan *) node->ps.plan; TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid); } /* * ExecAssignScanProjectionInfoWithVarno * As above, but caller can specify varno expected in Vars in the tlist. */ void ExecAssignScanProjectionInfoWithVarno(ScanState *node, int varno) { TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno); } /* * ExecScanReScan * * This must be called within the ReScan function of any plan node type * that uses ExecScan(). */ void ExecScanReScan(ScanState *node) { EState *estate = node->ps.state; /* * We must clear the scan tuple so that observers (e.g., execCurrent.c) * can tell that this plan node is not positioned on a tuple. */ ExecClearTuple(node->ss_ScanTupleSlot); /* * Rescan EvalPlanQual tuple(s) if we're inside an EvalPlanQual recheck. * But don't lose the "blocked" status of blocked target relations. */ if (estate->es_epq_active != NULL) { EPQState *epqstate = estate->es_epq_active; Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; if (scanrelid > 0) epqstate->relsubs_done[scanrelid - 1] = epqstate->relsubs_blocked[scanrelid - 1]; else { Bitmapset *relids; int rtindex = -1; /* * If an FDW or custom scan provider has replaced the join with a * scan, there are multiple RTIs; reset the epqScanDone flag for * all of them. */ if (IsA(node->ps.plan, ForeignScan)) relids = ((ForeignScan *) node->ps.plan)->fs_base_relids; else if (IsA(node->ps.plan, CustomScan)) relids = ((CustomScan *) node->ps.plan)->custom_relids; else elog(ERROR, "unexpected scan node: %d", (int) nodeTag(node->ps.plan)); while ((rtindex = bms_next_member(relids, rtindex)) >= 0) { Assert(rtindex > 0); epqstate->relsubs_done[rtindex - 1] = epqstate->relsubs_blocked[rtindex - 1]; } } } }