Teach query_tree_walker, query_tree_mutator, and SS_finalize_plan to
authorTom Lane
Sat, 18 May 2002 18:49:41 +0000 (18:49 +0000)
committerTom Lane
Sat, 18 May 2002 18:49:41 +0000 (18:49 +0000)
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).

src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/util/clauses.c
src/backend/parser/parse_clause.c
src/include/optimizer/subselect.h

index a3eeced7bb13e3d062af8e8cbb027f306913e624..a28c088e8faeb78e71e012c5e400a3a970823cd7 100644 (file)
@@ -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
index 57930e9a5021b896c3d600da251b3ff856dde45f..556fe07b5cdf591e86800cbd8f5df86186fb8100 100644 (file)
@@ -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 */
 
index 972c7f94633df4d93b76810eec2a678a56dbb02a..9f059521f4d79b659d6eb393fc8b091bc7bd677e 100644 (file)
@@ -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);
    }
index a41182e9398636e9db4dd3d13cb8ac9929e35e0a..461e7c15cf18f34ac9a9b42b40325b4708fa5a13 100644 (file)
@@ -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
index 0b54f2e3fdb1f8fbc76b98df13c175c862dbe281..b504cd7bee67ce5381524560154ecdb1c712a246 100644 (file)
@@ -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);