diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index a3eeced7bb13e3d062af8e8cbb027f306913e624..a28c088e8faeb78e71e012c5e400a3a970823cd7 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * 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) { - (void) SS_finalize_plan(plan); + (void) SS_finalize_plan(plan, parse->rtable); /* * At the moment, SS_finalize_plan doesn't handle initPlans and so diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 57930e9a5021b896c3d600da251b3ff856dde45f..556fe07b5cdf591e86800cbd8f5df86186fb8100 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * 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/planner.h" #include "optimizer/subselect.h" +#include "parser/parsetree.h" #include "parser/parse_expr.h" #include "parser/parse_oper.h" #include "utils/syscache.h" @@ -586,7 +587,7 @@ process_sublinks_mutator(Node *node, void *context) } List * -SS_finalize_plan(Plan *plan) +SS_finalize_plan(Plan *plan, List *rtable) { List *extParam = NIL; List *locParam = NIL; @@ -619,10 +620,20 @@ SS_finalize_plan(Plan *plan) &results); break; - case T_Append: - foreach(lst, ((Append *) plan)->appendplans) - results.paramids = set_unioni(results.paramids, - SS_finalize_plan((Plan *) lfirst(lst))); + case T_IndexScan: + finalize_primnode((Node *) ((IndexScan *) plan)->indxqual, + &results); + + /* + * 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; case T_SubqueryScan: @@ -638,15 +649,22 @@ SS_finalize_plan(Plan *plan) ((SubqueryScan *) plan)->subplan->extParam); break; - case T_IndexScan: - finalize_primnode((Node *) ((IndexScan *) plan)->indxqual, - &results); + case T_FunctionScan: + { + RangeTblEntry *rte; - /* - * 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. - */ + rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid, + rtable); + Assert(rte->rtekind == RTE_FUNCTION); + 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; case T_NestLoop: @@ -673,11 +691,6 @@ SS_finalize_plan(Plan *plan) &results); break; - case T_TidScan: - finalize_primnode((Node *) ((TidScan *) plan)->tideval, - &results); - break; - case T_Agg: case T_SeqScan: case T_Material: @@ -686,7 +699,6 @@ SS_finalize_plan(Plan *plan) case T_SetOp: case T_Limit: case T_Group: - case T_FunctionScan: break; default: @@ -696,9 +708,11 @@ SS_finalize_plan(Plan *plan) /* Process left and right subplans, if any */ results.paramids = set_unioni(results.paramids, - SS_finalize_plan(plan->lefttree)); + SS_finalize_plan(plan->lefttree, + rtable)); 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 */ diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 972c7f94633df4d93b76810eec2a678a56dbb02a..9f059521f4d79b659d6eb393fc8b091bc7bd677e 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * 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 * AUTHOR DATE MAJOR EVENT @@ -1915,7 +1915,6 @@ query_tree_walker(Query *query, { case RTE_RELATION: case RTE_SPECIAL: - case RTE_FUNCTION: /* nothing to do */ break; case RTE_SUBQUERY: @@ -1927,6 +1926,10 @@ query_tree_walker(Query *query, if (walker(rte->joinaliasvars, context)) return true; break; + case RTE_FUNCTION: + if (walker(rte->funcexpr, context)) + return true; + break; } } return false; @@ -2293,7 +2296,6 @@ query_tree_mutator(Query *query, { case RTE_RELATION: case RTE_SPECIAL: - case RTE_FUNCTION: /* nothing to do, don't bother to make a copy */ break; case RTE_SUBQUERY: @@ -2310,6 +2312,11 @@ query_tree_mutator(Query *query, MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *); rte = newrte; break; + case RTE_FUNCTION: + FLATCOPY(newrte, rte, RangeTblEntry); + MUTATE(newrte->funcexpr, rte->funcexpr, Node *); + rte = newrte; + break; } newrt = lappend(newrt, rte); } diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index a41182e9398636e9db4dd3d13cb8ac9929e35e0a..461e7c15cf18f34ac9a9b42b40325b4708fa5a13 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * 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; pstate->p_namespace = NIL; + parsetrees = parse_analyze(r->subquery, pstate); + pstate->p_namespace = save_namespace; /* @@ -455,26 +457,49 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) { Node *funcexpr; char *funcname; + List *save_namespace; RangeTblEntry *rte; RangeTblRef *rtr; + /* Get function name for possible use as alias */ + Assert(IsA(r->funccallnode, FuncCall)); + funcname = strVal(llast(((FuncCall *) r->funccallnode)->funcname)); + /* - * Transform the raw FuncCall node + * Transform the raw FuncCall node. This is a bit tricky because we don't + * want the function expression to be able to see any FROM items already + * 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); - Assert(IsA(r->funccallnode, FuncCall)); - funcname = strVal(llast(((FuncCall *) r->funccallnode)->funcname)); + 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 and subselects in the expression. - * (Aggregates clearly make no sense; perhaps later we could support - * subselects, though.) + * Disallow aggregate functions in the expression. (No reason to postpone + * this check until parseCheckAggregates.) */ - if (contain_agg_clause(funcexpr)) - elog(ERROR, "cannot use aggregate function in FROM function expression"); - if (contain_subplans(funcexpr)) - elog(ERROR, "cannot use subselect in FROM function expression"); + if (pstate->p_hasAggs) + { + if (contain_agg_clause(funcexpr)) + elog(ERROR, "cannot use aggregate function in FROM function expression"); + } /* * Insist we have a bare function call (explain.c is the only place diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h index 0b54f2e3fdb1f8fbc76b98df13c175c862dbe281..b504cd7bee67ce5381524560154ecdb1c712a246 100644 --- a/src/include/optimizer/subselect.h +++ b/src/include/optimizer/subselect.h @@ -14,7 +14,7 @@ extern List *PlannerInitPlan; /* init subplans for current query */ extern List *PlannerParamVar; /* to get Var from Param->paramid */ 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_process_sublinks(Node *expr);