diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-05-18 18:49:41 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-05-18 18:49:41 +0000 |
commit | a5b370943e1a7936e0118641f16acf6dbcc829cc (patch) | |
tree | 3c133b3fd1134cc9fb2ca711b58dda6bc3c7e5f0 /src/backend/parser/parse_clause.c | |
parent | 2c50f6344b4160dc8748b9a12db64fa2e94b46e0 (diff) | |
download | postgresql-a5b370943e1a7936e0118641f16acf6dbcc829cc.tar.gz postgresql-a5b370943e1a7936e0118641f16acf6dbcc829cc.zip |
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).
Diffstat (limited to 'src/backend/parser/parse_clause.c')
-rw-r--r-- | src/backend/parser/parse_clause.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index a41182e9398..461e7c15cf1 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 |