mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
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:
parent
2c50f6344b
commit
a5b370943e
@ -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
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
if (contain_agg_clause(funcexpr))
|
save_namespace = pstate->p_namespace;
|
||||||
elog(ERROR, "cannot use aggregate function in FROM function expression");
|
pstate->p_namespace = NIL;
|
||||||
if (contain_subplans(funcexpr))
|
|
||||||
elog(ERROR, "cannot use subselect in FROM function expression");
|
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))
|
||||||
|
elog(ERROR, "cannot use aggregate function 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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user