Commit e2159f38 authored by Tom Lane's avatar Tom Lane

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.
parent c61207b0
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.248 2005/05/06 17:24:53 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.249 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -353,16 +353,10 @@ ExecCheckRTEPerms(RangeTblEntry *rte) ...@@ -353,16 +353,10 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
AclId userid; AclId userid;
/* /*
* If it's a subquery, recursively examine its rangetable. * Only plain-relation RTEs need to be checked here. Subquery RTEs
*/ * are checked by ExecInitSubqueryScan if the subquery is still a
if (rte->rtekind == RTE_SUBQUERY) * separate subquery --- if it's been pulled up into our query level
{ * then the RTEs are in our rangetable and will be checked here.
ExecCheckRTPerms(rte->subquery->rtable);
return;
}
/*
* Otherwise, only plain-relation RTEs need to be checked here.
* Function RTEs are checked by init_fcache when the function is * Function RTEs are checked by init_fcache when the function is
* prepared for execution. Join and special RTEs need no checks. * prepared for execution. Join and special RTEs need no checks.
*/ */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.35 2005/03/16 21:38:06 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.36 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -48,7 +48,6 @@ TupleTableSlot * ...@@ -48,7 +48,6 @@ TupleTableSlot *
ExecScan(ScanState *node, ExecScan(ScanState *node,
ExecScanAccessMtd accessMtd) /* function returning a tuple */ ExecScanAccessMtd accessMtd) /* function returning a tuple */
{ {
EState *estate;
ExprContext *econtext; ExprContext *econtext;
List *qual; List *qual;
ProjectionInfo *projInfo; ProjectionInfo *projInfo;
...@@ -58,11 +57,16 @@ ExecScan(ScanState *node, ...@@ -58,11 +57,16 @@ ExecScan(ScanState *node,
/* /*
* Fetch data from node * Fetch data from node
*/ */
estate = node->ps.state;
econtext = node->ps.ps_ExprContext;
qual = node->ps.qual; qual = node->ps.qual;
projInfo = node->ps.ps_ProjInfo; projInfo = node->ps.ps_ProjInfo;
/*
* If we have neither a qual to check nor a projection to do,
* just skip all the overhead and return the raw scan tuple.
*/
if (!qual && !projInfo)
return (*accessMtd) (node);
/* /*
* Check to see if we're still projecting out tuples from a previous * Check to see if we're still projecting out tuples from a previous
* scan tuple (because there is a function-returning-set in the * scan tuple (because there is a function-returning-set in the
...@@ -83,6 +87,7 @@ ExecScan(ScanState *node, ...@@ -83,6 +87,7 @@ ExecScan(ScanState *node,
* storage allocated in the previous tuple cycle. Note this can't * storage allocated in the previous tuple cycle. Note this can't
* happen until we're done projecting out tuples from a scan tuple. * happen until we're done projecting out tuples from a scan tuple.
*/ */
econtext = node->ps.ps_ExprContext;
ResetExprContext(econtext); ResetExprContext(econtext);
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.63 2005/04/24 11:46:20 neilc Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeAppend.c,v 1.64 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -251,31 +251,21 @@ ExecCountSlotsAppend(Append *node) ...@@ -251,31 +251,21 @@ ExecCountSlotsAppend(Append *node)
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecAppend * ExecAppend
* *
* Handles the iteration over the multiple scans. * Handles iteration over multiple subplans.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
TupleTableSlot * TupleTableSlot *
ExecAppend(AppendState *node) ExecAppend(AppendState *node)
{ {
EState *estate; for (;;)
int whichplan; {
PlanState *subnode; PlanState *subnode;
TupleTableSlot *result; TupleTableSlot *result;
TupleTableSlot *result_slot;
ScanDirection direction;
/*
* get information from the node
*/
estate = node->ps.state;
direction = estate->es_direction;
whichplan = node->as_whichplan;
result_slot = node->ps.ps_ResultTupleSlot;
/* /*
* figure out which subplan we are currently processing * figure out which subplan we are currently processing
*/ */
subnode = node->appendplans[whichplan]; subnode = node->appendplans[node->as_whichplan];
/* /*
* get a tuple from the subplan * get a tuple from the subplan
...@@ -285,33 +275,28 @@ ExecAppend(AppendState *node) ...@@ -285,33 +275,28 @@ ExecAppend(AppendState *node)
if (!TupIsNull(result)) if (!TupIsNull(result))
{ {
/* /*
* if the subplan gave us something then return it as-is. We do * If the subplan gave us something then return it as-is.
* NOT make use of the result slot that was set up in ExecInitAppend, * We do NOT make use of the result slot that was set up in
* first because there's no reason to and second because it may have * ExecInitAppend, first because there's no reason to and
* the wrong tuple descriptor in inherited-UPDATE cases. * second because it may have the wrong tuple descriptor in
* inherited-UPDATE cases.
*/ */
return result; return result;
} }
else
{
/* /*
* .. go on to the "next" subplan in the appropriate direction and * Go on to the "next" subplan in the appropriate direction.
* try processing again (recursively) * If no more subplans, return the empty slot set up for us
* by ExecInitAppend.
*/ */
if (ScanDirectionIsForward(direction)) if (ScanDirectionIsForward(node->ps.state->es_direction))
node->as_whichplan++; node->as_whichplan++;
else else
node->as_whichplan--; node->as_whichplan--;
if (!exec_append_initialize_next(node))
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
/* /* Else loop back and try to get a tuple from the new subplan */
* return something from next node or an empty slot if all of our
* subplans have been exhausted. The empty slot is the one set up
* by ExecInitAppend.
*/
if (exec_append_initialize_next(node))
return ExecAppend(node);
else
return ExecClearTuple(result_slot);
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.33 2005/04/14 22:09:40 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.34 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -219,8 +219,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) ...@@ -219,8 +219,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
BlessTupleDesc(tupdesc); BlessTupleDesc(tupdesc);
scanstate->tupdesc = tupdesc; scanstate->tupdesc = tupdesc;
ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot, ExecAssignScanType(&scanstate->ss, tupdesc, false);
tupdesc, false);
/* /*
* Other node-specific setup * Other node-specific setup
...@@ -235,7 +234,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) ...@@ -235,7 +234,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */
ExecAssignResultTypeFromTL(&scanstate->ss.ps); ExecAssignResultTypeFromTL(&scanstate->ss.ps);
ExecAssignProjectionInfo(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss);
return scanstate; return scanstate;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.25 2004/12/31 21:59:45 pgsql Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.26 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -78,6 +78,10 @@ SubqueryNext(SubqueryScanState *node) ...@@ -78,6 +78,10 @@ SubqueryNext(SubqueryScanState *node)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
/*
* We just overwrite our ScanTupleSlot with the subplan's result slot,
* rather than expending the cycles for ExecCopySlot().
*/
node->ss.ss_ScanTupleSlot = slot; node->ss.ss_ScanTupleSlot = slot;
return slot; return slot;
...@@ -144,12 +148,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate) ...@@ -144,12 +148,13 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
ExecInitExpr((Expr *) node->scan.plan.qual, ExecInitExpr((Expr *) node->scan.plan.qual,
(PlanState *) subquerystate); (PlanState *) subquerystate);
#define SUBQUERYSCAN_NSLOTS 1 #define SUBQUERYSCAN_NSLOTS 2
/* /*
* tuple table initialization * tuple table initialization
*/ */
ExecInitResultTupleSlot(estate, &subquerystate->ss.ps); ExecInitResultTupleSlot(estate, &subquerystate->ss.ps);
ExecInitScanTupleSlot(estate, &subquerystate->ss);
/* /*
* initialize subquery * initialize subquery
...@@ -159,6 +164,11 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate) ...@@ -159,6 +164,11 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table); rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
Assert(rte->rtekind == RTE_SUBQUERY); Assert(rte->rtekind == RTE_SUBQUERY);
/*
* Do access checking on the rangetable entries in the subquery.
*/
ExecCheckRTPerms(rte->subquery->rtable);
/* /*
* The subquery needs its own EState because it has its own * The subquery needs its own EState because it has its own
* rangetable. It shares our Param ID space, however. XXX if * rangetable. It shares our Param ID space, however. XXX if
...@@ -187,14 +197,20 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate) ...@@ -187,14 +197,20 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate)
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
subquerystate->ss.ss_ScanTupleSlot = NULL;
subquerystate->ss.ps.ps_TupFromTlist = false; subquerystate->ss.ps.ps_TupFromTlist = false;
/*
* Initialize scan tuple type (needed by ExecAssignScanProjectionInfo)
*/
ExecAssignScanType(&subquerystate->ss,
ExecGetResultType(subquerystate->subplan),
false);
/* /*
* Initialize result tuple type and projection info. * Initialize result tuple type and projection info.
*/ */
ExecAssignResultTypeFromTL(&subquerystate->ss.ps); ExecAssignResultTypeFromTL(&subquerystate->ss.ps);
ExecAssignProjectionInfo(&subquerystate->ss.ps); ExecAssignScanProjectionInfo(&subquerystate->ss);
return subquerystate; return subquerystate;
} }
...@@ -230,6 +246,7 @@ ExecEndSubqueryScan(SubqueryScanState *node) ...@@ -230,6 +246,7 @@ ExecEndSubqueryScan(SubqueryScanState *node)
* clean out the upper tuple table * clean out the upper tuple table
*/ */
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
node->ss.ss_ScanTupleSlot = NULL; /* not ours to clear */
/* /*
* close down subquery * close down subquery
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.188 2005/04/25 04:27:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.189 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -308,10 +308,11 @@ use_physical_tlist(RelOptInfo *rel) ...@@ -308,10 +308,11 @@ use_physical_tlist(RelOptInfo *rel)
int i; int i;
/* /*
* Currently, can't do this for subquery or function scans. (This is * OK for subquery scans, but not function scans. (This is mainly
* mainly because we don't have an equivalent of build_physical_tlist * because build_physical_tlist doesn't support them; worth adding?)
* for them; worth adding?)
*/ */
if (rel->rtekind == RTE_SUBQUERY)
return true;
if (rel->rtekind != RTE_RELATION) if (rel->rtekind != RTE_RELATION)
return false; return false;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.185 2005/04/28 21:47:13 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.186 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -144,12 +144,12 @@ planner(Query *parse, bool isCursor, int cursorOptions, ...@@ -144,12 +144,12 @@ planner(Query *parse, bool isCursor, int cursorOptions,
result_plan = materialize_finished_plan(result_plan); result_plan = materialize_finished_plan(result_plan);
} }
/* final cleanup of the plan */
result_plan = set_plan_references(result_plan, parse->rtable);
/* executor wants to know total number of Params used overall */ /* executor wants to know total number of Params used overall */
result_plan->nParamExec = list_length(PlannerParamList); result_plan->nParamExec = list_length(PlannerParamList);
/* final cleanup of the plan */
set_plan_references(result_plan, parse->rtable);
/* restore state for outer planner, if any */ /* restore state for outer planner, if any */
PlannerQueryLevel = save_PlannerQueryLevel; PlannerQueryLevel = save_PlannerQueryLevel;
PlannerParamList = save_PlannerParamList; PlannerParamList = save_PlannerParamList;
......
This diff is collapsed.
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.120 2005/04/06 16:34:06 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.121 2005/05/22 22:30:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,6 +61,7 @@ static List *recurse_union_children(Node *setOp, Query *parse, ...@@ -61,6 +61,7 @@ static List *recurse_union_children(Node *setOp, Query *parse,
SetOperationStmt *top_union, SetOperationStmt *top_union,
List *refnames_tlist); List *refnames_tlist);
static List *generate_setop_tlist(List *colTypes, int flag, static List *generate_setop_tlist(List *colTypes, int flag,
Index varno,
bool hack_constants, bool hack_constants,
List *input_tlist, List *input_tlist,
List *refnames_tlist); List *refnames_tlist);
...@@ -119,8 +120,8 @@ plan_set_operations(Query *parse, List **sortClauses) ...@@ -119,8 +120,8 @@ plan_set_operations(Query *parse, List **sortClauses)
/* /*
* Recurse on setOperations tree to generate plans for set ops. The * Recurse on setOperations tree to generate plans for set ops. The
* final output plan should have just the column types shown as the * final output plan should have just the column types shown as the
* output from the top-level node, plus possibly a resjunk working * output from the top-level node, plus possibly resjunk working
* column (we can rely on upper-level nodes to deal with that). * columns (we can rely on upper-level nodes to deal with that).
*/ */
return recurse_set_operations((Node *) topop, parse, return recurse_set_operations((Node *) topop, parse,
topop->colTypes, true, -1, topop->colTypes, true, -1,
...@@ -163,7 +164,9 @@ recurse_set_operations(Node *setOp, Query *parse, ...@@ -163,7 +164,9 @@ recurse_set_operations(Node *setOp, Query *parse,
* Add a SubqueryScan with the caller-requested targetlist * Add a SubqueryScan with the caller-requested targetlist
*/ */
plan = (Plan *) plan = (Plan *)
make_subqueryscan(generate_setop_tlist(colTypes, flag, true, make_subqueryscan(generate_setop_tlist(colTypes, flag,
rtr->rtindex,
true,
subplan->targetlist, subplan->targetlist,
refnames_tlist), refnames_tlist),
NIL, NIL,
...@@ -202,13 +205,15 @@ recurse_set_operations(Node *setOp, Query *parse, ...@@ -202,13 +205,15 @@ recurse_set_operations(Node *setOp, Query *parse,
* the subplan. However, since the subplan was generated by * the subplan. However, since the subplan was generated by
* generate_union_plan() or generate_nonunion_plan(), and hence * generate_union_plan() or generate_nonunion_plan(), and hence
* its tlist was generated by generate_append_tlist(), this will * its tlist was generated by generate_append_tlist(), this will
* work. * work. We just tell generate_setop_tlist() to use varno 0.
*/ */
if (flag >= 0 || if (flag >= 0 ||
!tlist_same_datatypes(plan->targetlist, colTypes, junkOK)) !tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
{ {
plan = (Plan *) plan = (Plan *)
make_result(generate_setop_tlist(colTypes, flag, false, make_result(generate_setop_tlist(colTypes, flag,
0,
false,
plan->targetlist, plan->targetlist,
refnames_tlist), refnames_tlist),
NULL, NULL,
...@@ -415,12 +420,14 @@ recurse_union_children(Node *setOp, Query *parse, ...@@ -415,12 +420,14 @@ recurse_union_children(Node *setOp, Query *parse,
* *
* colTypes: column datatypes for non-junk columns * colTypes: column datatypes for non-junk columns
* flag: -1 if no flag column needed, 0 or 1 to create a const flag column * flag: -1 if no flag column needed, 0 or 1 to create a const flag column
* varno: varno to use in generated Vars
* hack_constants: true to copy up constants (see comments in code) * hack_constants: true to copy up constants (see comments in code)
* input_tlist: targetlist of this node's input node * input_tlist: targetlist of this node's input node
* refnames_tlist: targetlist to take column names from * refnames_tlist: targetlist to take column names from
*/ */
static List * static List *
generate_setop_tlist(List *colTypes, int flag, generate_setop_tlist(List *colTypes, int flag,
Index varno,
bool hack_constants, bool hack_constants,
List *input_tlist, List *input_tlist,
List *refnames_tlist) List *refnames_tlist)
...@@ -462,7 +469,7 @@ generate_setop_tlist(List *colTypes, int flag, ...@@ -462,7 +469,7 @@ generate_setop_tlist(List *colTypes, int flag,
if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const)) if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
expr = (Node *) inputtle->expr; expr = (Node *) inputtle->expr;
else else
expr = (Node *) makeVar(0, expr = (Node *) makeVar(varno,
inputtle->resno, inputtle->resno,
exprType((Node *) inputtle->expr), exprType((Node *) inputtle->expr),
exprTypmod((Node *) inputtle->expr), exprTypmod((Node *) inputtle->expr),
...@@ -513,6 +520,7 @@ generate_setop_tlist(List *colTypes, int flag, ...@@ -513,6 +520,7 @@ generate_setop_tlist(List *colTypes, int flag,
* *
* The entries in the Append's targetlist should always be simple Vars; * The entries in the Append's targetlist should always be simple Vars;
* we just have to make sure they have the right datatypes and typmods. * we just have to make sure they have the right datatypes and typmods.
* The Vars are always generated with varno 0.
*/ */
static List * static List *
generate_append_tlist(List *colTypes, bool flag, generate_append_tlist(List *colTypes, bool flag,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.196 2005/04/23 04:42:53 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.197 2005/05/22 22:30:20 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -3026,8 +3026,6 @@ query_tree_walker(Query *query, ...@@ -3026,8 +3026,6 @@ query_tree_walker(Query *query,
void *context, void *context,
int flags) int flags)
{ {
ListCell *rt;
Assert(query != NULL && IsA(query, Query)); Assert(query != NULL && IsA(query, Query));
if (walker((Node *) query->targetList, context)) if (walker((Node *) query->targetList, context))
...@@ -3044,7 +3042,25 @@ query_tree_walker(Query *query, ...@@ -3044,7 +3042,25 @@ query_tree_walker(Query *query,
return true; return true;
if (walker(query->in_info_list, context)) if (walker(query->in_info_list, context))
return true; return true;
foreach(rt, query->rtable) if (range_table_walker(query->rtable, walker, context, flags))
return true;
return false;
}
/*
* range_table_walker is just the part of query_tree_walker that scans
* a query's rangetable. This is split out since it can be useful on
* its own.
*/
bool
range_table_walker(List *rtable,
bool (*walker) (),
void *context,
int flags)
{
ListCell *rt;
foreach(rt, rtable)
{ {
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
...@@ -3532,9 +3548,6 @@ query_tree_mutator(Query *query, ...@@ -3532,9 +3548,6 @@ query_tree_mutator(Query *query,
void *context, void *context,
int flags) int flags)
{ {
List *newrt;
ListCell *rt;
Assert(query != NULL && IsA(query, Query)); Assert(query != NULL && IsA(query, Query));
if (!(flags & QTW_DONT_COPY_QUERY)) if (!(flags & QTW_DONT_COPY_QUERY))
...@@ -3552,8 +3565,26 @@ query_tree_mutator(Query *query, ...@@ -3552,8 +3565,26 @@ query_tree_mutator(Query *query,
MUTATE(query->limitOffset, query->limitOffset, Node *); MUTATE(query->limitOffset, query->limitOffset, Node *);
MUTATE(query->limitCount, query->limitCount, Node *); MUTATE(query->limitCount, query->limitCount, Node *);
MUTATE(query->in_info_list, query->in_info_list, List *); MUTATE(query->in_info_list, query->in_info_list, List *);
newrt = NIL; query->rtable = range_table_mutator(query->rtable,
foreach(rt, query->rtable) mutator, context, flags);
return query;
}
/*
* range_table_mutator is just the part of query_tree_mutator that processes
* a query's rangetable. This is split out since it can be useful on
* its own.
*/
List *
range_table_mutator(List *rtable,
Node *(*mutator) (),
void *context,
int flags)
{
List *newrt = NIL;
ListCell *rt;
foreach(rt, rtable)
{ {
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
RangeTblEntry *newrte; RangeTblEntry *newrte;
...@@ -3592,8 +3623,7 @@ query_tree_mutator(Query *query, ...@@ -3592,8 +3623,7 @@ query_tree_mutator(Query *query,
} }
newrt = lappend(newrt, newrte); newrt = lappend(newrt, newrte);
} }
query->rtable = newrt; return newrt;
return query;
} }
/* /*
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.106 2005/04/22 21:58:31 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.107 2005/05/22 22:30:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "optimizer/plancat.h" #include "optimizer/plancat.h"
#include "optimizer/tlist.h" #include "optimizer/tlist.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_expr.h"
#include "rewrite/rewriteManip.h" #include "rewrite/rewriteManip.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
...@@ -353,27 +354,32 @@ estimate_rel_size(Relation rel, int32 *attr_widths, ...@@ -353,27 +354,32 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
* relation, but that data is not readily available to ExecTypeFromTL. * relation, but that data is not readily available to ExecTypeFromTL.
* For now, we don't apply the physical-tlist optimization when there are * For now, we don't apply the physical-tlist optimization when there are
* dropped cols. * dropped cols.
*
* We also support building a "physical" tlist for subqueries, since the
* same optimization can occur in SubqueryScan nodes.
*/ */
List * List *
build_physical_tlist(Query *root, RelOptInfo *rel) build_physical_tlist(Query *root, RelOptInfo *rel)
{ {
List *tlist = NIL;
Index varno = rel->relid; Index varno = rel->relid;
RangeTblEntry *rte = rt_fetch(varno, root->rtable); RangeTblEntry *rte = rt_fetch(varno, root->rtable);
Relation relation; Relation relation;
List *tlist = NIL; Query *subquery;
Var *var;
ListCell *l;
int attrno, int attrno,
numattrs; numattrs;
Assert(rte->rtekind == RTE_RELATION); switch (rte->rtekind)
{
case RTE_RELATION:
relation = heap_open(rte->relid, AccessShareLock); relation = heap_open(rte->relid, AccessShareLock);
numattrs = RelationGetNumberOfAttributes(relation); numattrs = RelationGetNumberOfAttributes(relation);
for (attrno = 1; attrno <= numattrs; attrno++) for (attrno = 1; attrno <= numattrs; attrno++)
{ {
Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1]; Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1];
Var *var;
if (att_tup->attisdropped) if (att_tup->attisdropped)
{ {
...@@ -396,6 +402,34 @@ build_physical_tlist(Query *root, RelOptInfo *rel) ...@@ -396,6 +402,34 @@ build_physical_tlist(Query *root, RelOptInfo *rel)
} }
heap_close(relation, AccessShareLock); heap_close(relation, AccessShareLock);
break;
case RTE_SUBQUERY:
subquery = rte->subquery;
foreach(l, subquery->targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(l);
var = makeVar(varno,
tle->resno,
exprType((Node *) tle->expr),
exprTypmod((Node *) tle->expr),
0);
tlist = lappend(tlist,
makeTargetEntry((Expr *) var,
tle->resno,
NULL,
tle->resjunk));
}
break;
default:
/* caller error */
elog(ERROR, "unsupported RTE kind %d in build_physical_tlist",
(int) rte->rtekind);
break;
}
return tlist; return tlist;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.78 2005/01/28 19:34:28 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.79 2005/05/22 22:30:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -91,6 +91,11 @@ extern bool query_tree_walker(Query *query, bool (*walker) (), ...@@ -91,6 +91,11 @@ extern bool query_tree_walker(Query *query, bool (*walker) (),
extern Query *query_tree_mutator(Query *query, Node *(*mutator) (), extern Query *query_tree_mutator(Query *query, Node *(*mutator) (),
void *context, int flags); void *context, int flags);
extern bool range_table_walker(List *rtable, bool (*walker) (),
void *context, int flags);
extern List *range_table_mutator(List *rtable, Node *(*mutator) (),
void *context, int flags);
extern bool query_or_expression_tree_walker(Node *node, bool (*walker) (), extern bool query_or_expression_tree_walker(Node *node, bool (*walker) (),
void *context, int flags); void *context, int flags);
extern Node *query_or_expression_tree_mutator(Node *node, Node *(*mutator) (), extern Node *query_or_expression_tree_mutator(Node *node, Node *(*mutator) (),
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.84 2005/04/25 02:14:48 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.85 2005/05/22 22:30:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -74,7 +74,7 @@ extern void process_implied_equality(Query *root, ...@@ -74,7 +74,7 @@ extern void process_implied_equality(Query *root,
/* /*
* prototypes for plan/setrefs.c * prototypes for plan/setrefs.c
*/ */
extern void set_plan_references(Plan *plan, List *rtable); extern Plan *set_plan_references(Plan *plan, List *rtable);
extern void fix_opfuncids(Node *node); extern void fix_opfuncids(Node *node);
extern void set_opfuncid(OpExpr *opexpr); extern void set_opfuncid(OpExpr *opexpr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment