nodeResult.c 7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * nodeResult.c
4
 *	  support for constant nodes needing special code.
5
 *
6
 * DESCRIPTION
7
 *
8 9
 *		Result nodes are used in queries where no relations are scanned.
 *		Examples of such queries are:
10
 *
11 12 13
 *				retrieve (x = 1)
 *		and
 *				append emp (name = "mike", salary = 15000)
14
 *
15 16 17
 *		Result nodes are also used to optimise queries with constant
 *		qualifications (ie, quals that do not depend on the scanned data),
 *		such as:
18
 *
19
 *				retrieve (emp.all) where 2 > 1
20
 *
21
 *		In this case, the plan generated is
22
 *
23 24 25
 *						Result	(with 2 > 1 qual)
 *						/
 *				   SeqScan (emp.all)
26
 *
27 28 29 30 31 32
 *		At runtime, the Result node evaluates the constant qual once.
 *		If it's false, we can return an empty result set without running
 *		the controlled plan at all.  If it's true, we run the controlled
 *		plan normally and pass back the results.
 *
 *
Bruce Momjian's avatar
Bruce Momjian committed
33
 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
34 35
 * Portions Copyright (c) 1994, Regents of the University of California
 *
36
 * IDENTIFICATION
37
 *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.22 2002/12/05 15:50:33 tgl Exp $
38 39 40
 *
 *-------------------------------------------------------------------------
 */
41

42
#include "postgres.h"
43 44 45

#include "executor/executor.h"
#include "executor/nodeResult.h"
46 47
#include "utils/memutils.h"

48 49

/* ----------------------------------------------------------------
50
 *		ExecResult(node)
51
 *
52
 *		returns the tuples from the outer plan which satisfy the
53 54 55
 *		qualification clause.  Since result nodes with right
 *		subtrees are never planned, we ignore the right subtree
 *		entirely (for now).. -cim 10/7/89
56
 *
57 58 59
 *		The qualification containing only constant clauses are
 *		checked first before any processing is done. It always returns
 *		'nil' if the constant qualification is not satisfied.
60 61 62
 * ----------------------------------------------------------------
 */
TupleTableSlot *
63
ExecResult(ResultState *node)
64
{
65 66
	TupleTableSlot *outerTupleSlot;
	TupleTableSlot *resultSlot;
67
	PlanState   *outerPlan;
68
	ExprContext *econtext;
69
	ExprDoneCond isDone;
70

71
	econtext = node->ps.ps_ExprContext;
72

73 74
	/*
	 * check constant qualifications like (2 > 1), if not already done
75
	 */
76
	if (node->rs_checkqual)
77
	{
78 79 80
		bool		qualResult = ExecQual((List *) node->resconstantqual,
										  econtext,
										  false);
81

82 83
		node->rs_checkqual = false;
		if (!qualResult)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
84
		{
85
			node->rs_done = true;
86
			return NULL;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
87
		}
88 89
	}

90 91 92 93
	/*
	 * 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.
94
	 */
95
	if (node->ps.ps_TupFromTlist)
96
	{
97
		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
98
		if (isDone == ExprMultipleResult)
99
			return resultSlot;
100
		/* Done with that source tuple... */
101
		node->ps.ps_TupFromTlist = false;
102 103
	}

104 105 106 107
	/*
	 * 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.
108 109 110
	 */
	ResetExprContext(econtext);

111 112 113 114 115
	/*
	 * if rs_done is true then it means that we were asked to return a
	 * constant tuple and we already did the last time ExecResult() was
	 * called, OR that we failed the constant qual check. Either way, now
	 * we are through.
116
	 */
117
	while (!node->rs_done)
118
	{
119
		outerPlan = outerPlanState(node);
120 121 122

		if (outerPlan != NULL)
		{
123 124 125
			/*
			 * retrieve tuples from the outer plan until there are no
			 * more.
126
			 */
127
			outerTupleSlot = ExecProcNode(outerPlan);
128 129 130

			if (TupIsNull(outerTupleSlot))
				return NULL;
131

132
			node->ps.ps_OuterTupleSlot = outerTupleSlot;
133

134 135 136
			/*
			 * XXX gross hack. use outer tuple as scan tuple for
			 * projection
137 138 139
			 */
			econtext->ecxt_outertuple = outerTupleSlot;
			econtext->ecxt_scantuple = outerTupleSlot;
140 141 142
		}
		else
		{
143 144 145
			/*
			 * if we don't have an outer plan, then we are just generating
			 * the results from a constant target list.  Do it only once.
146
			 */
147
			node->rs_done = true;
148 149
		}

150 151 152 153
		/*
		 * form the result tuple using ExecProject(), and return it ---
		 * unless the projection produces an empty set, in which case we
		 * must loop back to see if there are more outerPlan tuples.
154
		 */
155
		resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
156 157 158

		if (isDone != ExprEndResult)
		{
159
			node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
160 161
			return resultSlot;
		}
162 163 164
	}

	return NULL;
165 166 167
}

/* ----------------------------------------------------------------
168 169 170 171 172
 *		ExecInitResult
 *
 *		Creates the run-time state information for the result node
 *		produced by the planner and initailizes outer relations
 *		(child nodes).
173 174
 * ----------------------------------------------------------------
 */
175 176
ResultState *
ExecInitResult(Result *node, EState *estate)
177
{
178
	ResultState *resstate;
179

180
	/*
181
	 * create state structure
182 183
	 */
	resstate = makeNode(ResultState);
184 185 186
	resstate->ps.plan = (Plan *) node;
	resstate->ps.state = estate;

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
187 188
	resstate->rs_done = false;
	resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
189

190 191
	/*
	 * Miscellaneous initialization
192
	 *
193
	 * create expression context for node
194
	 */
195
	ExecAssignExprContext(estate, &resstate->ps);
196

197
#define RESULT_NSLOTS 1
198 199 200

	/*
	 * tuple table initialization
201
	 */
202
	ExecInitResultTupleSlot(estate, &resstate->ps);
203

204
	/*
205
	 * initialize child expressions
206
	 */
207 208 209 210 211 212 213 214 215 216 217 218 219
	resstate->ps.targetlist = (List *)
		ExecInitExpr((Node *) node->plan.targetlist,
					 (PlanState *) resstate);
	resstate->ps.qual = (List *)
		ExecInitExpr((Node *) node->plan.qual,
					 (PlanState *) resstate);
	resstate->resconstantqual = ExecInitExpr(node->resconstantqual,
											 (PlanState *) resstate);

	/*
	 * initialize child nodes
	 */
	outerPlanState(resstate) = ExecInitNode(outerPlan(node), estate);
220 221 222 223 224 225

	/*
	 * we don't use inner plan
	 */
	Assert(innerPlan(node) == NULL);

226 227
	/*
	 * initialize tuple type and projection info
228
	 */
229 230
	ExecAssignResultTypeFromTL(&resstate->ps);
	ExecAssignProjectionInfo(&resstate->ps);
231

232
	return resstate;
233 234 235
}

int
236
ExecCountSlotsResult(Result *node)
237
{
238
	return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
239 240 241
}

/* ----------------------------------------------------------------
242 243
 *		ExecEndResult
 *
244
 *		frees up storage allocated through C routines
245 246 247
 * ----------------------------------------------------------------
 */
void
248
ExecEndResult(ResultState *node)
249
{
250 251
	/*
	 * Free the projection info
252
	 */
253 254
	ExecFreeProjectionInfo(&node->ps);
	ExecFreeExprContext(&node->ps);
255

256
	/*
257
	 * clean out the tuple table
258
	 */
259
	ExecClearTuple(node->ps.ps_ResultTupleSlot);
260

261
	/*
262
	 * shut down subplans
263
	 */
264
	ExecEndNode(outerPlanState(node));
265
}
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
266 267

void
268
ExecReScanResult(ResultState *node, ExprContext *exprCtxt)
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
269
{
270 271 272
	node->rs_done = false;
	node->ps.ps_TupFromTlist = false;
	node->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
273 274 275 276

	/*
	 * if chgParam of subnode is not null then plan will be re-scanned by
	 * first ExecProcNode.
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
277
	 */
278 279 280
	if (((PlanState *) node)->lefttree &&
		((PlanState *) node)->lefttree->chgParam == NULL)
		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
281
}