1 /*-------------------------------------------------------------------------
4 * Support routines for scanning subqueries (subselects in rangetable).
6 * This is just enough different from sublinks (nodeSubplan.c) to mean that
7 * we need two sets of code. Ought to look at trying to unify the cases.
10 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
15 * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.14 2002/12/05 15:50:33 tgl Exp $
17 *-------------------------------------------------------------------------
21 * ExecSubqueryScan scans a subquery.
22 * ExecSubqueryNext retrieve next tuple in sequential order.
23 * ExecInitSubqueryScan creates and initializes a subqueryscan node.
24 * ExecEndSubqueryScan releases any storage allocated.
25 * ExecSubqueryReScan rescans the relation
30 #include "catalog/pg_type.h"
31 #include "executor/execdebug.h"
32 #include "executor/execdefs.h"
33 #include "executor/execdesc.h"
34 #include "executor/nodeSubqueryscan.h"
35 #include "parser/parsetree.h"
36 #include "tcop/pquery.h"
38 static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
40 /* ----------------------------------------------------------------
42 * ----------------------------------------------------------------
44 /* ----------------------------------------------------------------
47 * This is a workhorse for ExecSubqueryScan
48 * ----------------------------------------------------------------
50 static TupleTableSlot *
51 SubqueryNext(SubqueryScanState *node)
54 ScanDirection direction;
58 * get information from the estate and scan state
60 estate = node->ss.ps.state;
61 direction = estate->es_direction;
64 * We need not support EvalPlanQual here, since we are not scanning a
69 * get the next tuple from the sub-query
71 node->sss_SubEState->es_direction = direction;
73 slot = ExecProcNode(node->subplan);
75 node->ss.ss_ScanTupleSlot = slot;
80 /* ----------------------------------------------------------------
81 * ExecSubqueryScan(node)
83 * Scans the subquery sequentially and returns the next qualifying
85 * It calls the ExecScan() routine and passes it the access method
86 * which retrieve tuples sequentially.
91 ExecSubqueryScan(SubqueryScanState *node)
94 * use SubqueryNext as access method
96 return ExecScan(&node->ss, (ExecScanAccessMtd) SubqueryNext);
99 /* ----------------------------------------------------------------
100 * ExecInitSubqueryScan
101 * ----------------------------------------------------------------
104 ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
106 SubqueryScanState *subquerystate;
111 * SubqueryScan should not have any "normal" children.
113 Assert(outerPlan(node) == NULL);
114 Assert(innerPlan(node) == NULL);
117 * create state structure
119 subquerystate = makeNode(SubqueryScanState);
120 subquerystate->ss.ps.plan = (Plan *) node;
121 subquerystate->ss.ps.state = estate;
124 * Miscellaneous initialization
126 * create expression context for node
128 ExecAssignExprContext(estate, &subquerystate->ss.ps);
131 * initialize child expressions
133 subquerystate->ss.ps.targetlist = (List *)
134 ExecInitExpr((Node *) node->scan.plan.targetlist,
135 (PlanState *) subquerystate);
136 subquerystate->ss.ps.qual = (List *)
137 ExecInitExpr((Node *) node->scan.plan.qual,
138 (PlanState *) subquerystate);
140 #define SUBQUERYSCAN_NSLOTS 1
143 * tuple table initialization
145 ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
148 * initialize subquery
150 * This should agree with ExecInitSubPlan
152 rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
153 Assert(rte->rtekind == RTE_SUBQUERY);
155 sp_estate = CreateExecutorState();
156 subquerystate->sss_SubEState = sp_estate;
158 sp_estate->es_range_table = rte->subquery->rtable;
159 sp_estate->es_param_list_info = estate->es_param_list_info;
160 sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
161 sp_estate->es_tupleTable =
162 ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
163 sp_estate->es_snapshot = estate->es_snapshot;
164 sp_estate->es_instrument = estate->es_instrument;
166 subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
168 subquerystate->ss.ss_ScanTupleSlot = NULL;
169 subquerystate->ss.ps.ps_TupFromTlist = false;
172 * initialize tuple type
174 ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
175 ExecAssignProjectionInfo(&subquerystate->ss.ps);
177 return subquerystate;
181 ExecCountSlotsSubqueryScan(SubqueryScan *node)
184 * The subplan has its own tuple table and must not be counted here!
186 return ExecCountSlotsNode(outerPlan(node)) +
187 ExecCountSlotsNode(innerPlan(node)) +
191 /* ----------------------------------------------------------------
192 * ExecEndSubqueryScan
194 * frees any storage allocated through C routines.
195 * ----------------------------------------------------------------
198 ExecEndSubqueryScan(SubqueryScanState *node)
201 * Free the projection info and the scan attribute info
203 ExecFreeProjectionInfo(&node->ss.ps);
204 ExecFreeExprContext(&node->ss.ps);
207 * clean out the upper tuple table
209 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
212 * close down subquery
214 ExecEndNode(node->subplan);
217 * clean up subquery's tuple table
219 node->ss.ss_ScanTupleSlot = NULL;
220 ExecDropTupleTable(node->sss_SubEState->es_tupleTable, true);
222 /* XXX we seem to be leaking the sub-EState... */
225 /* ----------------------------------------------------------------
228 * Rescans the relation.
229 * ----------------------------------------------------------------
232 ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
236 estate = node->ss.ps.state;
239 * ExecReScan doesn't know about my subplan, so I have to do
240 * changed-parameter signaling myself.
242 if (node->ss.ps.chgParam != NULL)
243 SetChangedParamList(node->subplan, node->ss.ps.chgParam);
246 * if chgParam of subnode is not null then plan will be re-scanned by
247 * first ExecProcNode.
249 if (node->subplan->chgParam == NULL)
250 ExecReScan(node->subplan, NULL);
252 node->ss.ss_ScanTupleSlot = NULL;