diff options
Diffstat (limited to 'src/backend/executor/nodeSubqueryscan.c')
-rw-r--r-- | src/backend/executor/nodeSubqueryscan.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c new file mode 100644 index 0000000..c09f628 --- /dev/null +++ b/src/backend/executor/nodeSubqueryscan.c @@ -0,0 +1,213 @@ +/*------------------------------------------------------------------------- + * + * nodeSubqueryscan.c + * Support routines for scanning subqueries (subselects in rangetable). + * + * This is just enough different from sublinks (nodeSubplan.c) to mean that + * we need two sets of code. Ought to look at trying to unify the cases. + * + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/executor/nodeSubqueryscan.c + * + *------------------------------------------------------------------------- + */ +/* + * INTERFACE ROUTINES + * ExecSubqueryScan scans a subquery. + * ExecSubqueryNext retrieve next tuple in sequential order. + * ExecInitSubqueryScan creates and initializes a subqueryscan node. + * ExecEndSubqueryScan releases any storage allocated. + * ExecReScanSubqueryScan rescans the relation + * + */ +#include "postgres.h" + +#include "executor/execdebug.h" +#include "executor/nodeSubqueryscan.h" + +static TupleTableSlot *SubqueryNext(SubqueryScanState *node); + +/* ---------------------------------------------------------------- + * Scan Support + * ---------------------------------------------------------------- + */ +/* ---------------------------------------------------------------- + * SubqueryNext + * + * This is a workhorse for ExecSubqueryScan + * ---------------------------------------------------------------- + */ +static TupleTableSlot * +SubqueryNext(SubqueryScanState *node) +{ + TupleTableSlot *slot; + + /* + * Get the next tuple from the sub-query. + */ + slot = ExecProcNode(node->subplan); + + /* + * We just return the subplan's result slot, rather than expending extra + * cycles for ExecCopySlot(). (Our own ScanTupleSlot is used only for + * EvalPlanQual rechecks.) + */ + return slot; +} + +/* + * SubqueryRecheck -- access method routine to recheck a tuple in EvalPlanQual + */ +static bool +SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot) +{ + /* nothing to check */ + return true; +} + +/* ---------------------------------------------------------------- + * ExecSubqueryScan(node) + * + * Scans the subquery sequentially and returns the next qualifying + * tuple. + * We call the ExecScan() routine and pass it the appropriate + * access method functions. + * ---------------------------------------------------------------- + */ +static TupleTableSlot * +ExecSubqueryScan(PlanState *pstate) +{ + SubqueryScanState *node = castNode(SubqueryScanState, pstate); + + return ExecScan(&node->ss, + (ExecScanAccessMtd) SubqueryNext, + (ExecScanRecheckMtd) SubqueryRecheck); +} + +/* ---------------------------------------------------------------- + * ExecInitSubqueryScan + * ---------------------------------------------------------------- + */ +SubqueryScanState * +ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) +{ + SubqueryScanState *subquerystate; + + /* check for unsupported flags */ + Assert(!(eflags & EXEC_FLAG_MARK)); + + /* SubqueryScan should not have any "normal" children */ + Assert(outerPlan(node) == NULL); + Assert(innerPlan(node) == NULL); + + /* + * create state structure + */ + subquerystate = makeNode(SubqueryScanState); + subquerystate->ss.ps.plan = (Plan *) node; + subquerystate->ss.ps.state = estate; + subquerystate->ss.ps.ExecProcNode = ExecSubqueryScan; + + /* + * Miscellaneous initialization + * + * create expression context for node + */ + ExecAssignExprContext(estate, &subquerystate->ss.ps); + + /* + * initialize subquery + */ + subquerystate->subplan = ExecInitNode(node->subplan, estate, eflags); + + /* + * Initialize scan slot and type (needed by ExecAssignScanProjectionInfo) + */ + ExecInitScanTupleSlot(estate, &subquerystate->ss, + ExecGetResultType(subquerystate->subplan), + ExecGetResultSlotOps(subquerystate->subplan, NULL)); + + /* + * The slot used as the scantuple isn't the slot above (outside of EPQ), + * but the one from the node below. + */ + subquerystate->ss.ps.scanopsset = true; + subquerystate->ss.ps.scanops = ExecGetResultSlotOps(subquerystate->subplan, + &subquerystate->ss.ps.scanopsfixed); + subquerystate->ss.ps.resultopsset = true; + subquerystate->ss.ps.resultops = subquerystate->ss.ps.scanops; + subquerystate->ss.ps.resultopsfixed = subquerystate->ss.ps.scanopsfixed; + + /* + * Initialize result type and projection. + */ + ExecInitResultTypeTL(&subquerystate->ss.ps); + ExecAssignScanProjectionInfo(&subquerystate->ss); + + /* + * initialize child expressions + */ + subquerystate->ss.ps.qual = + ExecInitQual(node->scan.plan.qual, (PlanState *) subquerystate); + + return subquerystate; +} + +/* ---------------------------------------------------------------- + * ExecEndSubqueryScan + * + * frees any storage allocated through C routines. + * ---------------------------------------------------------------- + */ +void +ExecEndSubqueryScan(SubqueryScanState *node) +{ + /* + * Free the exprcontext + */ + ExecFreeExprContext(&node->ss.ps); + + /* + * clean out the upper tuple table + */ + if (node->ss.ps.ps_ResultTupleSlot) + ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); + ExecClearTuple(node->ss.ss_ScanTupleSlot); + + /* + * close down subquery + */ + ExecEndNode(node->subplan); +} + +/* ---------------------------------------------------------------- + * ExecReScanSubqueryScan + * + * Rescans the relation. + * ---------------------------------------------------------------- + */ +void +ExecReScanSubqueryScan(SubqueryScanState *node) +{ + ExecScanReScan(&node->ss); + + /* + * ExecReScan doesn't know about my subplan, so I have to do + * changed-parameter signaling myself. This is just as well, because the + * subplan has its own memory context in which its chgParam state lives. + */ + if (node->ss.ps.chgParam != NULL) + UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam); + + /* + * if chgParam of subnode is not null then plan will be re-scanned by + * first ExecProcNode. + */ + if (node->subplan->chgParam == NULL) + ExecReScan(node->subplan); +} |