aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-05-18 18:49:41 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-05-18 18:49:41 +0000
commita5b370943e1a7936e0118641f16acf6dbcc829cc (patch)
tree3c133b3fd1134cc9fb2ca711b58dda6bc3c7e5f0
parent2c50f6344b4160dc8748b9a12db64fa2e94b46e0 (diff)
downloadpostgresql-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).
-rw-r--r--src/backend/optimizer/plan/planner.c4
-rw-r--r--src/backend/optimizer/plan/subselect.c58
-rw-r--r--src/backend/optimizer/util/clauses.c13
-rw-r--r--src/backend/parser/parse_clause.c47
-rw-r--r--src/include/optimizer/subselect.h2
5 files changed, 85 insertions, 39 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a3eeced7bb1..a28c088e8fa 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 57930e9a502..556fe07b5cd 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 972c7f94633..9f059521f4d 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 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
diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h
index 0b54f2e3fdb..b504cd7bee6 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);