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-2005, PostgreSQL Global Development Group
11
* Portions Copyright (c) 1994, Regents of the University of California
15
* $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.25 2004-12-31 21:59:45 pgsql 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;
56
MemoryContext oldcontext;
59
* get information from the estate and scan state
61
estate = node->ss.ps.state;
62
direction = estate->es_direction;
65
* We need not support EvalPlanQual here, since we are not scanning a
70
* Get the next tuple from the sub-query. We have to be careful to
71
* run it in its appropriate memory context.
73
node->sss_SubEState->es_direction = direction;
75
oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
77
slot = ExecProcNode(node->subplan);
79
MemoryContextSwitchTo(oldcontext);
81
node->ss.ss_ScanTupleSlot = slot;
86
/* ----------------------------------------------------------------
87
* ExecSubqueryScan(node)
89
* Scans the subquery sequentially and returns the next qualifying
91
* It calls the ExecScan() routine and passes it the access method
92
* which retrieve tuples sequentially.
97
ExecSubqueryScan(SubqueryScanState *node)
100
* use SubqueryNext as access method
102
return ExecScan(&node->ss, (ExecScanAccessMtd) SubqueryNext);
105
/* ----------------------------------------------------------------
106
* ExecInitSubqueryScan
107
* ----------------------------------------------------------------
110
ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
112
SubqueryScanState *subquerystate;
115
MemoryContext oldcontext;
118
* SubqueryScan should not have any "normal" children.
120
Assert(outerPlan(node) == NULL);
121
Assert(innerPlan(node) == NULL);
124
* create state structure
126
subquerystate = makeNode(SubqueryScanState);
127
subquerystate->ss.ps.plan = (Plan *) node;
128
subquerystate->ss.ps.state = estate;
131
* Miscellaneous initialization
133
* create expression context for node
135
ExecAssignExprContext(estate, &subquerystate->ss.ps);
138
* initialize child expressions
140
subquerystate->ss.ps.targetlist = (List *)
141
ExecInitExpr((Expr *) node->scan.plan.targetlist,
142
(PlanState *) subquerystate);
143
subquerystate->ss.ps.qual = (List *)
144
ExecInitExpr((Expr *) node->scan.plan.qual,
145
(PlanState *) subquerystate);
147
#define SUBQUERYSCAN_NSLOTS 1
150
* tuple table initialization
152
ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
155
* initialize subquery
157
* This should agree with ExecInitSubPlan
159
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
160
Assert(rte->rtekind == RTE_SUBQUERY);
163
* The subquery needs its own EState because it has its own
164
* rangetable. It shares our Param ID space, however. XXX if
165
* rangetable access were done differently, the subquery could share
166
* our EState, which would eliminate some thrashing about in this
169
sp_estate = CreateExecutorState();
170
subquerystate->sss_SubEState = sp_estate;
172
oldcontext = MemoryContextSwitchTo(sp_estate->es_query_cxt);
174
sp_estate->es_range_table = rte->subquery->rtable;
175
sp_estate->es_param_list_info = estate->es_param_list_info;
176
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
177
sp_estate->es_tupleTable =
178
ExecCreateTupleTable(ExecCountSlotsNode(node->subplan) + 10);
179
sp_estate->es_snapshot = estate->es_snapshot;
180
sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
181
sp_estate->es_instrument = estate->es_instrument;
184
* Start up the subplan (this is a very cut-down form of InitPlan())
186
subquerystate->subplan = ExecInitNode(node->subplan, sp_estate);
188
MemoryContextSwitchTo(oldcontext);
190
subquerystate->ss.ss_ScanTupleSlot = NULL;
191
subquerystate->ss.ps.ps_TupFromTlist = false;
194
* Initialize result tuple type and projection info.
196
ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
197
ExecAssignProjectionInfo(&subquerystate->ss.ps);
199
return subquerystate;
203
ExecCountSlotsSubqueryScan(SubqueryScan *node)
206
* The subplan has its own tuple table and must not be counted here!
208
return ExecCountSlotsNode(outerPlan(node)) +
209
ExecCountSlotsNode(innerPlan(node)) +
213
/* ----------------------------------------------------------------
214
* ExecEndSubqueryScan
216
* frees any storage allocated through C routines.
217
* ----------------------------------------------------------------
220
ExecEndSubqueryScan(SubqueryScanState *node)
222
MemoryContext oldcontext;
225
* Free the exprcontext
227
ExecFreeExprContext(&node->ss.ps);
230
* clean out the upper tuple table
232
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
235
* close down subquery
237
oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
239
ExecEndPlan(node->subplan, node->sss_SubEState);
241
MemoryContextSwitchTo(oldcontext);
243
FreeExecutorState(node->sss_SubEState);
246
/* ----------------------------------------------------------------
249
* Rescans the relation.
250
* ----------------------------------------------------------------
253
ExecSubqueryReScan(SubqueryScanState *node, ExprContext *exprCtxt)
256
MemoryContext oldcontext;
258
estate = node->ss.ps.state;
260
oldcontext = MemoryContextSwitchTo(node->sss_SubEState->es_query_cxt);
263
* ExecReScan doesn't know about my subplan, so I have to do
264
* changed-parameter signaling myself. This is just as well, because
265
* the subplan has its own memory context in which its chgParam state
268
if (node->ss.ps.chgParam != NULL)
269
UpdateChangedParamSet(node->subplan, node->ss.ps.chgParam);
272
* if chgParam of subnode is not null then plan will be re-scanned by
273
* first ExecProcNode.
275
if (node->subplan->chgParam == NULL)
276
ExecReScan(node->subplan, NULL);
278
MemoryContextSwitchTo(oldcontext);
280
node->ss.ss_ScanTupleSlot = NULL;