Skip to content

Commit e2159f3

Browse files
committed
Teach the planner to remove SubqueryScan nodes from the plan if they
aren't doing anything useful (ie, neither selection nor projection). Also, extend to SubqueryScan the hacks already in place to avoid unnecessary ExecProject calls when the result would just be the same tuple the subquery already delivered. This saves some overhead in UNION and other set operations, as well as avoiding overhead for unflatten-able subqueries. Per example from Sokolov Yura.
1 parent c61207b commit e2159f3

File tree

13 files changed

+603
-175
lines changed

13 files changed

+603
-175
lines changed

src/backend/executor/execMain.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.248 2005/05/06 17:24:53 tgl Exp $
29+
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.249 2005/05/22 22:30:19 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -353,16 +353,10 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
353353
AclId userid;
354354

355355
/*
356-
* If it's a subquery, recursively examine its rangetable.
357-
*/
358-
if (rte->rtekind == RTE_SUBQUERY)
359-
{
360-
ExecCheckRTPerms(rte->subquery->rtable);
361-
return;
362-
}
363-
364-
/*
365-
* Otherwise, only plain-relation RTEs need to be checked here.
356+
* Only plain-relation RTEs need to be checked here. Subquery RTEs
357+
* are checked by ExecInitSubqueryScan if the subquery is still a
358+
* separate subquery --- if it's been pulled up into our query level
359+
* then the RTEs are in our rangetable and will be checked here.
366360
* Function RTEs are checked by init_fcache when the function is
367361
* prepared for execution. Join and special RTEs need no checks.
368362
*/

src/backend/executor/execScan.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.35 2005/03/16 21:38:06 tgl Exp $
15+
* $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.36 2005/05/22 22:30:19 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -48,7 +48,6 @@ TupleTableSlot *
4848
ExecScan(ScanState *node,
4949
ExecScanAccessMtd accessMtd) /* function returning a tuple */
5050
{
51-
EState *estate;
5251
ExprContext *econtext;
5352
List *qual;
5453
ProjectionInfo *projInfo;
@@ -58,11 +57,16 @@ ExecScan(ScanState *node,
5857
/*
5958
* Fetch data from node
6059
*/
61-
estate = node->ps.state;
62-
econtext = node->ps.ps_ExprContext;
6360
qual = node->ps.qual;
6461
projInfo = node->ps.ps_ProjInfo;
6562

63+
/*
64+
* If we have neither a qual to check nor a projection to do,
65+
* just skip all the overhead and return the raw scan tuple.
66+
*/
67+
if (!qual && !projInfo)
68+
return (*accessMtd) (node);
69+
6670
/*
6771
* Check to see if we're still projecting out tuples from a previous
6872
* scan tuple (because there is a function-returning-set in the
@@ -83,6 +87,7 @@ ExecScan(ScanState *node,
8387
* storage allocated in the previous tuple cycle. Note this can't
8488
* happen until we're done projecting out tuples from a scan tuple.
8589
*/
90+
econtext = node->ps.ps_ExprContext;
8691
ResetExprContext(econtext);
8792

8893
/*

src/backend/executor/nodeAppend.c

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.63 2005/04/24 11:46:20 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.64 2005/05/22 22:30:19 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -251,67 +251,52 @@ ExecCountSlotsAppend(Append *node)
251251
/* ----------------------------------------------------------------
252252
* ExecAppend
253253
*
254-
* Handles the iteration over the multiple scans.
254+
* Handles iteration over multiple subplans.
255255
* ----------------------------------------------------------------
256256
*/
257257
TupleTableSlot *
258258
ExecAppend(AppendState *node)
259259
{
260-
EState *estate;
261-
int whichplan;
262-
PlanState *subnode;
263-
TupleTableSlot *result;
264-
TupleTableSlot *result_slot;
265-
ScanDirection direction;
266-
267-
/*
268-
* get information from the node
269-
*/
270-
estate = node->ps.state;
271-
direction = estate->es_direction;
272-
whichplan = node->as_whichplan;
273-
result_slot = node->ps.ps_ResultTupleSlot;
274-
275-
/*
276-
* figure out which subplan we are currently processing
277-
*/
278-
subnode = node->appendplans[whichplan];
279-
280-
/*
281-
* get a tuple from the subplan
282-
*/
283-
result = ExecProcNode(subnode);
284-
285-
if (!TupIsNull(result))
260+
for (;;)
286261
{
262+
PlanState *subnode;
263+
TupleTableSlot *result;
264+
287265
/*
288-
* if the subplan gave us something then return it as-is. We do
289-
* NOT make use of the result slot that was set up in ExecInitAppend,
290-
* first because there's no reason to and second because it may have
291-
* the wrong tuple descriptor in inherited-UPDATE cases.
266+
* figure out which subplan we are currently processing
292267
*/
293-
return result;
294-
}
295-
else
296-
{
268+
subnode = node->appendplans[node->as_whichplan];
269+
297270
/*
298-
* .. go on to the "next" subplan in the appropriate direction and
299-
* try processing again (recursively)
271+
* get a tuple from the subplan
300272
*/
301-
if (ScanDirectionIsForward(direction))
302-
node->as_whichplan++;
303-
else
304-
node->as_whichplan--;
273+
result = ExecProcNode(subnode);
274+
275+
if (!TupIsNull(result))
276+
{
277+
/*
278+
* If the subplan gave us something then return it as-is.
279+
* We do NOT make use of the result slot that was set up in
280+
* ExecInitAppend, first because there's no reason to and
281+
* second because it may have the wrong tuple descriptor in
282+
* inherited-UPDATE cases.
283+
*/
284+
return result;
285+
}
305286

306287
/*
307-
* return something from next node or an empty slot if all of our
308-
* subplans have been exhausted. The empty slot is the one set up
288+
* Go on to the "next" subplan in the appropriate direction.
289+
* If no more subplans, return the empty slot set up for us
309290
* by ExecInitAppend.
310291
*/
311-
if (exec_append_initialize_next(node))
312-
return ExecAppend(node);
292+
if (ScanDirectionIsForward(node->ps.state->es_direction))
293+
node->as_whichplan++;
313294
else
314-
return ExecClearTuple(result_slot);
295+
node->as_whichplan--;
296+
if (!exec_append_initialize_next(node))
297+
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
298+
299+
/* Else loop back and try to get a tuple from the new subplan */
315300
}
316301
}
317302

src/backend/executor/nodeFunctionscan.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.33 2005/04/14 22:09:40 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.34 2005/05/22 22:30:19 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -219,8 +219,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
219219
BlessTupleDesc(tupdesc);
220220

221221
scanstate->tupdesc = tupdesc;
222-
ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
223-
tupdesc, false);
222+
ExecAssignScanType(&scanstate->ss, tupdesc, false);
224223

225224
/*
226225
* Other node-specific setup
@@ -235,7 +234,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
235234
* Initialize result tuple type and projection info.
236235
*/
237236
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
238-
ExecAssignProjectionInfo(&scanstate->ss.ps);
237+
ExecAssignScanProjectionInfo(&scanstate->ss);
239238

240239
return scanstate;
241240
}

src/backend/executor/nodeSubqueryscan.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.25 2004/12/31 21:59:45 pgsql Exp $
15+
* $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.26 2005/05/22 22:30:19 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -78,6 +78,10 @@ SubqueryNext(SubqueryScanState *node)
7878

7979
MemoryContextSwitchTo(oldcontext);
8080

81+
/*
82+
* We just overwrite our ScanTupleSlot with the subplan's result slot,
83+
* rather than expending the cycles for ExecCopySlot().
84+
*/
8185
node->ss.ss_ScanTupleSlot = slot;
8286

8387
return slot;
@@ -144,12 +148,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
144148
ExecInitExpr((Expr *) node->scan.plan.qual,
145149
(PlanState *) subquerystate);
146150

147-
#define SUBQUERYSCAN_NSLOTS 1
151+
#define SUBQUERYSCAN_NSLOTS 2
148152

149153
/*
150154
* tuple table initialization
151155
*/
152156
ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
157+
ExecInitScanTupleSlot(estate, &subquerystate->ss);
153158

154159
/*
155160
* initialize subquery
@@ -159,6 +164,11 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
159164
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
160165
Assert(rte->rtekind == RTE_SUBQUERY);
161166

167+
/*
168+
* Do access checking on the rangetable entries in the subquery.
169+
*/
170+
ExecCheckRTPerms(rte->subquery->rtable);
171+
162172
/*
163173
* The subquery needs its own EState because it has its own
164174
* rangetable. It shares our Param ID space, however. XXX if
@@ -187,14 +197,20 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
187197

188198
MemoryContextSwitchTo(oldcontext);
189199

190-
subquerystate->ss.ss_ScanTupleSlot = NULL;
191200
subquerystate->ss.ps.ps_TupFromTlist = false;
192201

202+
/*
203+
* Initialize scan tuple type (needed by ExecAssignScanProjectionInfo)
204+
*/
205+
ExecAssignScanType(&subquerystate->ss,
206+
ExecGetResultType(subquerystate->subplan),
207+
false);
208+
193209
/*
194210
* Initialize result tuple type and projection info.
195211
*/
196212
ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
197-
ExecAssignProjectionInfo(&subquerystate->ss.ps);
213+
ExecAssignScanProjectionInfo(&subquerystate->ss);
198214

199215
return subquerystate;
200216
}
@@ -230,6 +246,7 @@ ExecEndSubqueryScan(SubqueryScanState *node)
230246
* clean out the upper tuple table
231247
*/
232248
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
249+
node->ss.ss_ScanTupleSlot = NULL; /* not ours to clear */
233250

234251
/*
235252
* close down subquery

src/backend/optimizer/plan/createplan.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.188 2005/04/25 04:27:12 tgl Exp $
13+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.189 2005/05/22 22:30:19 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -308,10 +308,11 @@ use_physical_tlist(RelOptInfo *rel)
308308
int i;
309309

310310
/*
311-
* Currently, can't do this for subquery or function scans. (This is
312-
* mainly because we don't have an equivalent of build_physical_tlist
313-
* for them; worth adding?)
311+
* OK for subquery scans, but not function scans. (This is mainly
312+
* because build_physical_tlist doesn't support them; worth adding?)
314313
*/
314+
if (rel->rtekind == RTE_SUBQUERY)
315+
return true;
315316
if (rel->rtekind != RTE_RELATION)
316317
return false;
317318

src/backend/optimizer/plan/planner.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.185 2005/04/28 21:47:13 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.186 2005/05/22 22:30:19 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -144,12 +144,12 @@ planner(Query *parse, bool isCursor, int cursorOptions,
144144
result_plan = materialize_finished_plan(result_plan);
145145
}
146146

147+
/* final cleanup of the plan */
148+
result_plan = set_plan_references(result_plan, parse->rtable);
149+
147150
/* executor wants to know total number of Params used overall */
148151
result_plan->nParamExec = list_length(PlannerParamList);
149152

150-
/* final cleanup of the plan */
151-
set_plan_references(result_plan, parse->rtable);
152-
153153
/* restore state for outer planner, if any */
154154
PlannerQueryLevel = save_PlannerQueryLevel;
155155
PlannerParamList = save_PlannerParamList;

0 commit comments

Comments
 (0)