Teach query_tree_walker, query_tree_mutator, and SS_finalize_plan to

process function RTE expressions, which they were previously missing.
This allows outer-Var references and subselects to work correctly in
the arguments of a function RTE.  Install check to prevent function RTEs
from cross-referencing Vars of sibling FROM-items, which doesn't make
any sense (if you want to join, write a JOIN or WHERE clause).
This commit is contained in:
Tom Lane 2002-05-18 18:49:41 +00:00
parent 2c50f6344b
commit a5b370943e
5 changed files with 87 additions and 41 deletions

View file

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.118 2002/05/18 02:25:49 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.119 2002/05/18 18:49:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -246,7 +246,7 @@ subquery_planner(Query *parse, double tuple_fraction)
*/ */
if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1) if (PlannerPlanId != saved_planid || PlannerQueryLevel > 1)
{ {
(void) SS_finalize_plan(plan); (void) SS_finalize_plan(plan, parse->rtable);
/* /*
* At the moment, SS_finalize_plan doesn't handle initPlans and so * At the moment, SS_finalize_plan doesn't handle initPlans and so

View file

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.52 2002/05/12 20:10:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.53 2002/05/18 18:49:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -21,6 +21,7 @@
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/planner.h" #include "optimizer/planner.h"
#include "optimizer/subselect.h" #include "optimizer/subselect.h"
#include "parser/parsetree.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_oper.h" #include "parser/parse_oper.h"
#include "utils/syscache.h" #include "utils/syscache.h"
@ -586,7 +587,7 @@ process_sublinks_mutator(Node *node, void *context)
} }
List * List *
SS_finalize_plan(Plan *plan) SS_finalize_plan(Plan *plan, List *rtable)
{ {
List *extParam = NIL; List *extParam = NIL;
List *locParam = NIL; List *locParam = NIL;
@ -619,10 +620,20 @@ SS_finalize_plan(Plan *plan)
&results); &results);
break; break;
case T_Append: case T_IndexScan:
foreach(lst, ((Append *) plan)->appendplans) finalize_primnode((Node *) ((IndexScan *) plan)->indxqual,
results.paramids = set_unioni(results.paramids, &results);
SS_finalize_plan((Plan *) lfirst(lst)));
/*
* we need not look at indxqualorig, since it will have the
* same param references as indxqual, and we aren't really
* concerned yet about having a complete subplan list.
*/
break;
case T_TidScan:
finalize_primnode((Node *) ((TidScan *) plan)->tideval,
&results);
break; break;
case T_SubqueryScan: case T_SubqueryScan:
@ -638,15 +649,22 @@ SS_finalize_plan(Plan *plan)
((SubqueryScan *) plan)->subplan->extParam); ((SubqueryScan *) plan)->subplan->extParam);
break; break;
case T_IndexScan: case T_FunctionScan:
finalize_primnode((Node *) ((IndexScan *) plan)->indxqual, {
&results); RangeTblEntry *rte;
/* rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
* we need not look at indxqualorig, since it will have the rtable);
* same param references as indxqual, and we aren't really Assert(rte->rtekind == RTE_FUNCTION);
* concerned yet about having a complete subplan list. finalize_primnode(rte->funcexpr, &results);
*/ }
break;
case T_Append:
foreach(lst, ((Append *) plan)->appendplans)
results.paramids = set_unioni(results.paramids,
SS_finalize_plan((Plan *) lfirst(lst),
rtable));
break; break;
case T_NestLoop: case T_NestLoop:
@ -673,11 +691,6 @@ SS_finalize_plan(Plan *plan)
&results); &results);
break; break;
case T_TidScan:
finalize_primnode((Node *) ((TidScan *) plan)->tideval,
&results);
break;
case T_Agg: case T_Agg:
case T_SeqScan: case T_SeqScan:
case T_Material: case T_Material:
@ -686,7 +699,6 @@ SS_finalize_plan(Plan *plan)
case T_SetOp: case T_SetOp:
case T_Limit: case T_Limit:
case T_Group: case T_Group:
case T_FunctionScan:
break; break;
default: default:
@ -696,9 +708,11 @@ SS_finalize_plan(Plan *plan)
/* Process left and right subplans, if any */ /* Process left and right subplans, if any */
results.paramids = set_unioni(results.paramids, results.paramids = set_unioni(results.paramids,
SS_finalize_plan(plan->lefttree)); SS_finalize_plan(plan->lefttree,
rtable));
results.paramids = set_unioni(results.paramids, results.paramids = set_unioni(results.paramids,
SS_finalize_plan(plan->righttree)); SS_finalize_plan(plan->righttree,
rtable));
/* Now we have all the paramids and subplans */ /* Now we have all the paramids and subplans */

View file

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.99 2002/05/12 23:43:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.100 2002/05/18 18:49:41 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -1915,7 +1915,6 @@ query_tree_walker(Query *query,
{ {
case RTE_RELATION: case RTE_RELATION:
case RTE_SPECIAL: case RTE_SPECIAL:
case RTE_FUNCTION:
/* nothing to do */ /* nothing to do */
break; break;
case RTE_SUBQUERY: case RTE_SUBQUERY:
@ -1927,6 +1926,10 @@ query_tree_walker(Query *query,
if (walker(rte->joinaliasvars, context)) if (walker(rte->joinaliasvars, context))
return true; return true;
break; break;
case RTE_FUNCTION:
if (walker(rte->funcexpr, context))
return true;
break;
} }
} }
return false; return false;
@ -2293,7 +2296,6 @@ query_tree_mutator(Query *query,
{ {
case RTE_RELATION: case RTE_RELATION:
case RTE_SPECIAL: case RTE_SPECIAL:
case RTE_FUNCTION:
/* nothing to do, don't bother to make a copy */ /* nothing to do, don't bother to make a copy */
break; break;
case RTE_SUBQUERY: case RTE_SUBQUERY:
@ -2310,6 +2312,11 @@ query_tree_mutator(Query *query,
MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *); MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *);
rte = newrte; rte = newrte;
break; break;
case RTE_FUNCTION:
FLATCOPY(newrte, rte, RangeTblEntry);
MUTATE(newrte->funcexpr, rte->funcexpr, Node *);
rte = newrte;
break;
} }
newrt = lappend(newrt, rte); newrt = lappend(newrt, rte);
} }

View file

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.92 2002/05/12 23:43:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.93 2002/05/18 18:49:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -410,7 +410,9 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
*/ */
save_namespace = pstate->p_namespace; save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL; pstate->p_namespace = NIL;
parsetrees = parse_analyze(r->subquery, pstate); parsetrees = parse_analyze(r->subquery, pstate);
pstate->p_namespace = save_namespace; pstate->p_namespace = save_namespace;
/* /*
@ -455,26 +457,49 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
{ {
Node *funcexpr; Node *funcexpr;
char *funcname; char *funcname;
List *save_namespace;
RangeTblEntry *rte; RangeTblEntry *rte;
RangeTblRef *rtr; RangeTblRef *rtr;
/* /* Get function name for possible use as alias */
* Transform the raw FuncCall node
*/
funcexpr = transformExpr(pstate, r->funccallnode);
Assert(IsA(r->funccallnode, FuncCall)); Assert(IsA(r->funccallnode, FuncCall));
funcname = strVal(llast(((FuncCall *) r->funccallnode)->funcname)); funcname = strVal(llast(((FuncCall *) r->funccallnode)->funcname));
/* /*
* Disallow aggregate functions and subselects in the expression. * Transform the raw FuncCall node. This is a bit tricky because we don't
* (Aggregates clearly make no sense; perhaps later we could support * want the function expression to be able to see any FROM items already
* subselects, though.) * created in the current query (compare to transformRangeSubselect).
* But it does need to be able to see any further-up parent states.
* So, temporarily make the current query level have an empty namespace.
* NOTE: this code is OK only because the expression can't legally alter
* the namespace by causing implicit relation refs to be added.
*/ */
save_namespace = pstate->p_namespace;
pstate->p_namespace = NIL;
funcexpr = transformExpr(pstate, r->funccallnode);
pstate->p_namespace = save_namespace;
/*
* We still need to check that the function parameters don't refer
* to any other rels. That could happen despite our hack on the namespace
* if fully-qualified names are used. So, check there are no local
* Var references in the transformed expression. (Outer references
* are OK, and are ignored here.)
*/
if (pull_varnos(funcexpr) != NIL)
elog(ERROR, "FROM function expression may not refer to other relations of same query level");
/*
* Disallow aggregate functions in the expression. (No reason to postpone
* this check until parseCheckAggregates.)
*/
if (pstate->p_hasAggs)
{
if (contain_agg_clause(funcexpr)) if (contain_agg_clause(funcexpr))
elog(ERROR, "cannot use aggregate function in FROM function expression"); elog(ERROR, "cannot use aggregate function in FROM function expression");
if (contain_subplans(funcexpr)) }
elog(ERROR, "cannot use subselect in FROM function expression");
/* /*
* Insist we have a bare function call (explain.c is the only place * Insist we have a bare function call (explain.c is the only place

View file

@ -14,7 +14,7 @@ extern List *PlannerInitPlan; /* init subplans for current query */
extern List *PlannerParamVar; /* to get Var from Param->paramid */ extern List *PlannerParamVar; /* to get Var from Param->paramid */
extern int PlannerPlanId; /* to assign unique ID to subquery plans */ extern int PlannerPlanId; /* to assign unique ID to subquery plans */
extern List *SS_finalize_plan(Plan *plan); extern List *SS_finalize_plan(Plan *plan, List *rtable);
extern Node *SS_replace_correlation_vars(Node *expr); extern Node *SS_replace_correlation_vars(Node *expr);
extern Node *SS_process_sublinks(Node *expr); extern Node *SS_process_sublinks(Node *expr);