mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-01 19:45:33 +08:00
Change set_plan_references and join_references to take an rtable List
rather than a Query node; this allows set_plan_references to recurse into subplans correctly. Fixes core dump on full outer joins in subplans. Also, invoke preprocess_expression on function RTEs' function expressions. This seems to fix the planner's problems with outer-level Vars in function RTEs.
This commit is contained in:
parent
0a757154bd
commit
51fd22abdd
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.114 2002/05/12 20:10:03 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.115 2002/05/18 02:25:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -671,19 +671,19 @@ create_nestloop_plan(Query *root,
|
||||
|
||||
/* only refs to outer vars get changed in the inner indexqual */
|
||||
innerscan->indxqualorig = join_references(indxqualorig,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel);
|
||||
innerscan->indxqual = join_references(innerscan->indxqual,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel);
|
||||
/* fix the inner qpqual too, if it has join clauses */
|
||||
if (NumRelids((Node *) inner_plan->qual) > 1)
|
||||
inner_plan->qual = join_references(inner_plan->qual,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
NIL,
|
||||
innerrel);
|
||||
@ -694,7 +694,7 @@ create_nestloop_plan(Query *root,
|
||||
TidScan *innerscan = (TidScan *) inner_plan;
|
||||
|
||||
innerscan->tideval = join_references(innerscan->tideval,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
innerscan->scan.scanrelid);
|
||||
@ -716,12 +716,12 @@ create_nestloop_plan(Query *root,
|
||||
* Set quals to contain INNER/OUTER var references.
|
||||
*/
|
||||
joinclauses = join_references(joinclauses,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0);
|
||||
otherclauses = join_references(otherclauses,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0);
|
||||
@ -760,7 +760,7 @@ create_mergejoin_plan(Query *root,
|
||||
* clauses to contain INNER/OUTER var references.
|
||||
*/
|
||||
joinclauses = join_references(set_difference(joinclauses, mergeclauses),
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0);
|
||||
@ -769,7 +769,7 @@ create_mergejoin_plan(Query *root,
|
||||
* Fix the additional qpquals too.
|
||||
*/
|
||||
otherclauses = join_references(otherclauses,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0);
|
||||
@ -779,7 +779,7 @@ create_mergejoin_plan(Query *root,
|
||||
* that the outer variable is always on the left.
|
||||
*/
|
||||
mergeclauses = switch_outer(join_references(mergeclauses,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0));
|
||||
@ -886,7 +886,7 @@ create_hashjoin_plan(Query *root,
|
||||
* clauses to contain INNER/OUTER var references.
|
||||
*/
|
||||
joinclauses = join_references(set_difference(joinclauses, hashclauses),
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0);
|
||||
@ -895,7 +895,7 @@ create_hashjoin_plan(Query *root,
|
||||
* Fix the additional qpquals too.
|
||||
*/
|
||||
otherclauses = join_references(otherclauses,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0);
|
||||
@ -905,7 +905,7 @@ create_hashjoin_plan(Query *root,
|
||||
* that the outer variable is always on the left.
|
||||
*/
|
||||
hashclauses = switch_outer(join_references(hashclauses,
|
||||
root,
|
||||
root->rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0));
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.71 2002/05/17 22:35:12 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.72 2002/05/18 02:25:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -177,7 +177,7 @@ add_vars_to_targetlist(Query *root, List *vars)
|
||||
List *varsused;
|
||||
|
||||
expansion = flatten_join_alias_vars((Node *) var,
|
||||
root, true);
|
||||
root->rtable, true);
|
||||
varsused = pull_var_clause(expansion, false);
|
||||
add_vars_to_targetlist(root, varsused);
|
||||
freeList(varsused);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.117 2002/05/12 23:43:03 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.118 2002/05/18 02:25:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -101,7 +101,7 @@ planner(Query *parse)
|
||||
result_plan->nParamExec = length(PlannerParamVar);
|
||||
|
||||
/* final cleanup of the plan */
|
||||
set_plan_references(parse, result_plan);
|
||||
set_plan_references(result_plan, parse->rtable);
|
||||
|
||||
/* restore state for outer planner, if any */
|
||||
PlannerQueryLevel = save_PlannerQueryLevel;
|
||||
@ -175,6 +175,17 @@ subquery_planner(Query *parse, double tuple_fraction)
|
||||
parse->havingQual = preprocess_expression(parse, parse->havingQual,
|
||||
EXPRKIND_HAVING);
|
||||
|
||||
/* Also need to preprocess expressions for function RTEs */
|
||||
foreach(lst, parse->rtable)
|
||||
{
|
||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lst);
|
||||
|
||||
if (rte->rtekind == RTE_FUNCTION)
|
||||
rte->funcexpr = preprocess_expression(parse, rte->funcexpr,
|
||||
EXPRKIND_TARGET);
|
||||
/* These are not targetlist items, but close enough... */
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for ungrouped variables passed to subplans in targetlist and
|
||||
* HAVING clause (but not in WHERE or JOIN/ON clauses, since those are
|
||||
@ -737,7 +748,7 @@ preprocess_expression(Query *parse, Node *expr, int kind)
|
||||
}
|
||||
}
|
||||
if (has_join_rtes)
|
||||
expr = flatten_join_alias_vars(expr, parse, false);
|
||||
expr = flatten_join_alias_vars(expr, parse->rtable, false);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.77 2002/05/18 00:42:55 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.78 2002/05/18 02:25:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Query *root;
|
||||
List *rtable;
|
||||
List *outer_tlist;
|
||||
List *inner_tlist;
|
||||
Index acceptable_rel;
|
||||
@ -42,7 +42,7 @@ typedef struct
|
||||
} replace_vars_with_subplan_refs_context;
|
||||
|
||||
static void fix_expr_references(Plan *plan, Node *node);
|
||||
static void set_join_references(Query *root, Join *join);
|
||||
static void set_join_references(Join *join, List *rtable);
|
||||
static void set_uppernode_references(Plan *plan, Index subvarno);
|
||||
static Node *join_references_mutator(Node *node,
|
||||
join_references_context *context);
|
||||
@ -75,7 +75,7 @@ static bool fix_opids_walker(Node *node, void *context);
|
||||
* Returns nothing of interest, but modifies internal fields of nodes.
|
||||
*/
|
||||
void
|
||||
set_plan_references(Query *root, Plan *plan)
|
||||
set_plan_references(Plan *plan, List *rtable)
|
||||
{
|
||||
List *pl;
|
||||
|
||||
@ -110,16 +110,24 @@ set_plan_references(Query *root, Plan *plan)
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
break;
|
||||
case T_SubqueryScan:
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
|
||||
/*
|
||||
* We do not do set_uppernode_references() here, because a
|
||||
* SubqueryScan will always have been created with correct
|
||||
* references to its subplan's outputs to begin with.
|
||||
*/
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
/* Recurse into subplan too */
|
||||
set_plan_references(root, ((SubqueryScan *) plan)->subplan);
|
||||
/*
|
||||
* We do not do set_uppernode_references() here, because a
|
||||
* SubqueryScan will always have been created with correct
|
||||
* references to its subplan's outputs to begin with.
|
||||
*/
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
|
||||
/* Recurse into subplan too */
|
||||
rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid,
|
||||
rtable);
|
||||
Assert(rte->rtekind == RTE_SUBQUERY);
|
||||
set_plan_references(((SubqueryScan *) plan)->subplan,
|
||||
rte->subquery->rtable);
|
||||
}
|
||||
break;
|
||||
case T_FunctionScan:
|
||||
{
|
||||
@ -128,19 +136,19 @@ set_plan_references(Query *root, Plan *plan)
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
|
||||
root->rtable);
|
||||
rtable);
|
||||
Assert(rte->rtekind == RTE_FUNCTION);
|
||||
fix_expr_references(plan, rte->funcexpr);
|
||||
}
|
||||
break;
|
||||
case T_NestLoop:
|
||||
set_join_references(root, (Join *) plan);
|
||||
set_join_references((Join *) plan, rtable);
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
|
||||
break;
|
||||
case T_MergeJoin:
|
||||
set_join_references(root, (Join *) plan);
|
||||
set_join_references((Join *) plan, rtable);
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
|
||||
@ -148,7 +156,7 @@ set_plan_references(Query *root, Plan *plan)
|
||||
(Node *) ((MergeJoin *) plan)->mergeclauses);
|
||||
break;
|
||||
case T_HashJoin:
|
||||
set_join_references(root, (Join *) plan);
|
||||
set_join_references((Join *) plan, rtable);
|
||||
fix_expr_references(plan, (Node *) plan->targetlist);
|
||||
fix_expr_references(plan, (Node *) plan->qual);
|
||||
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
|
||||
@ -202,7 +210,7 @@ set_plan_references(Query *root, Plan *plan)
|
||||
* recurse into subplans.
|
||||
*/
|
||||
foreach(pl, ((Append *) plan)->appendplans)
|
||||
set_plan_references(root, (Plan *) lfirst(pl));
|
||||
set_plan_references((Plan *) lfirst(pl), rtable);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "set_plan_references: unknown plan type %d",
|
||||
@ -219,21 +227,21 @@ set_plan_references(Query *root, Plan *plan)
|
||||
* plan's var nodes against the already-modified nodes of the
|
||||
* subplans.
|
||||
*/
|
||||
set_plan_references(root, plan->lefttree);
|
||||
set_plan_references(root, plan->righttree);
|
||||
set_plan_references(plan->lefttree, rtable);
|
||||
set_plan_references(plan->righttree, rtable);
|
||||
foreach(pl, plan->initPlan)
|
||||
{
|
||||
SubPlan *sp = (SubPlan *) lfirst(pl);
|
||||
|
||||
Assert(IsA(sp, SubPlan));
|
||||
set_plan_references(root, sp->plan);
|
||||
set_plan_references(sp->plan, sp->rtable);
|
||||
}
|
||||
foreach(pl, plan->subPlan)
|
||||
{
|
||||
SubPlan *sp = (SubPlan *) lfirst(pl);
|
||||
|
||||
Assert(IsA(sp, SubPlan));
|
||||
set_plan_references(root, sp->plan);
|
||||
set_plan_references(sp->plan, sp->rtable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,10 +277,11 @@ fix_expr_references(Plan *plan, Node *node)
|
||||
* creation of a plan node by createplan.c and its fixing by this module.
|
||||
* Fortunately, there doesn't seem to be any need to do that.
|
||||
*
|
||||
* 'join' is a join plan node
|
||||
* 'join' is a join plan node
|
||||
* 'rtable' is the associated range table
|
||||
*/
|
||||
static void
|
||||
set_join_references(Query *root, Join *join)
|
||||
set_join_references(Join *join, List *rtable)
|
||||
{
|
||||
Plan *outer = join->plan.lefttree;
|
||||
Plan *inner = join->plan.righttree;
|
||||
@ -280,7 +289,7 @@ set_join_references(Query *root, Join *join)
|
||||
List *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
|
||||
|
||||
join->plan.targetlist = join_references(join->plan.targetlist,
|
||||
root,
|
||||
rtable,
|
||||
outer_tlist,
|
||||
inner_tlist,
|
||||
(Index) 0);
|
||||
@ -374,6 +383,7 @@ set_uppernode_references(Plan *plan, Index subvarno)
|
||||
* pass inner_tlist = NIL and acceptable_rel = the ID of the inner relation.
|
||||
*
|
||||
* 'clauses' is the targetlist or list of join clauses
|
||||
* 'rtable' is the current range table
|
||||
* 'outer_tlist' is the target list of the outer join relation
|
||||
* 'inner_tlist' is the target list of the inner join relation, or NIL
|
||||
* 'acceptable_rel' is either zero or the rangetable index of a relation
|
||||
@ -384,14 +394,14 @@ set_uppernode_references(Plan *plan, Index subvarno)
|
||||
*/
|
||||
List *
|
||||
join_references(List *clauses,
|
||||
Query *root,
|
||||
List *rtable,
|
||||
List *outer_tlist,
|
||||
List *inner_tlist,
|
||||
Index acceptable_rel)
|
||||
{
|
||||
join_references_context context;
|
||||
|
||||
context.root = root;
|
||||
context.rtable = rtable;
|
||||
context.outer_tlist = outer_tlist;
|
||||
context.inner_tlist = inner_tlist;
|
||||
context.acceptable_rel = acceptable_rel;
|
||||
@ -432,7 +442,7 @@ join_references_mutator(Node *node,
|
||||
|
||||
/* Perhaps it's a join alias that can be resolved to input vars? */
|
||||
newnode = flatten_join_alias_vars((Node *) var,
|
||||
context->root,
|
||||
context->rtable,
|
||||
true);
|
||||
if (!equal(newnode, (Node *) var))
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.36 2002/04/28 19:54:28 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.37 2002/05/18 02:25:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -41,7 +41,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Query *root;
|
||||
List *rtable;
|
||||
bool force;
|
||||
} flatten_join_alias_vars_context;
|
||||
|
||||
@ -328,11 +328,11 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
|
||||
* of sublinks to subplans!
|
||||
*/
|
||||
Node *
|
||||
flatten_join_alias_vars(Node *node, Query *root, bool force)
|
||||
flatten_join_alias_vars(Node *node, List *rtable, bool force)
|
||||
{
|
||||
flatten_join_alias_vars_context context;
|
||||
|
||||
context.root = root;
|
||||
context.rtable = rtable;
|
||||
context.force = force;
|
||||
|
||||
return flatten_join_alias_vars_mutator(node, &context);
|
||||
@ -352,7 +352,7 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
|
||||
if (var->varlevelsup != 0)
|
||||
return node; /* no need to copy, really */
|
||||
rte = rt_fetch(var->varno, context->root->rtable);
|
||||
rte = rt_fetch(var->varno, context->rtable);
|
||||
if (rte->rtekind != RTE_JOIN)
|
||||
return node;
|
||||
Assert(var->varattno > 0);
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: planmain.h,v 1.56 2002/04/28 19:54:28 tgl Exp $
|
||||
* $Id: planmain.h,v 1.57 2002/05/18 02:25:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -56,8 +56,8 @@ extern void process_implied_equality(Query *root, Node *item1, Node *item2,
|
||||
/*
|
||||
* prototypes for plan/setrefs.c
|
||||
*/
|
||||
extern void set_plan_references(Query *root, Plan *plan);
|
||||
extern List *join_references(List *clauses, Query *root,
|
||||
extern void set_plan_references(Plan *plan, List *rtable);
|
||||
extern List *join_references(List *clauses, List *rtable,
|
||||
List *outer_tlist, List *inner_tlist,
|
||||
Index acceptable_rel);
|
||||
extern void fix_opids(Node *node);
|
||||
|
@ -7,14 +7,14 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: var.h,v 1.19 2002/04/28 19:54:28 tgl Exp $
|
||||
* $Id: var.h,v 1.20 2002/05/18 02:25:50 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef VAR_H
|
||||
#define VAR_H
|
||||
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "nodes/primnodes.h"
|
||||
|
||||
|
||||
extern List *pull_varnos(Node *node);
|
||||
@ -23,6 +23,6 @@ extern bool contain_var_reference(Node *node, int varno, int varattno,
|
||||
extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup);
|
||||
extern bool contain_var_clause(Node *node);
|
||||
extern List *pull_var_clause(Node *node, bool includeUpperVars);
|
||||
extern Node *flatten_join_alias_vars(Node *node, Query *root, bool force);
|
||||
extern Node *flatten_join_alias_vars(Node *node, List *rtable, bool force);
|
||||
|
||||
#endif /* VAR_H */
|
||||
|
Loading…
Reference in New Issue
Block a user