mirror of https://github.com/postgres/postgres
Clean up some mistakes in handling of uplevel Vars in planner.
Most parts of the planner should ignore, or indeed never even see, uplevel Vars because they will be or have been replaced by Params. There were a couple of places that got it wrong though, probably my fault from recent changes...
This commit is contained in:
parent
5adebf83b6
commit
37d20eb855
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.38 1999/08/22 20:14:47 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.39 1999/08/26 05:07:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -50,7 +50,7 @@ static void check_hashjoinable(RestrictInfo *restrictinfo);
|
||||||
void
|
void
|
||||||
make_var_only_tlist(Query *root, List *tlist)
|
make_var_only_tlist(Query *root, List *tlist)
|
||||||
{
|
{
|
||||||
List *tlist_vars = pull_var_clause((Node *) tlist);
|
List *tlist_vars = pull_var_clause((Node *) tlist, false);
|
||||||
|
|
||||||
add_vars_to_targetlist(root, tlist_vars);
|
add_vars_to_targetlist(root, tlist_vars);
|
||||||
freeList(tlist_vars);
|
freeList(tlist_vars);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.65 1999/08/22 23:56:45 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.66 1999/08/26 05:07:41 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -296,26 +296,27 @@ union_planner(Query *parse)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a HAVING clause, do the necessary things with it.
|
* If we have a HAVING clause, do the necessary things with it.
|
||||||
|
* This code should parallel query_planner()'s initial processing
|
||||||
|
* of the WHERE clause.
|
||||||
*/
|
*/
|
||||||
if (parse->havingQual)
|
if (parse->havingQual)
|
||||||
{
|
{
|
||||||
List *ql;
|
List *ql;
|
||||||
|
|
||||||
/* convert the havingQual to conjunctive normal form (cnf) */
|
/* Replace uplevel Vars with Params */
|
||||||
parse->havingQual = (Node *) cnfify((Expr *) parse->havingQual, true);
|
if (PlannerQueryLevel > 1)
|
||||||
|
parse->havingQual = SS_replace_correlation_vars(parse->havingQual);
|
||||||
|
|
||||||
if (parse->hasSubLinks)
|
if (parse->hasSubLinks)
|
||||||
{
|
{
|
||||||
/*
|
/* Expand SubLinks to SubPlans */
|
||||||
* There may be a subselect in the havingQual, so we have to
|
|
||||||
* process it using the same function as for a subselect in
|
|
||||||
* 'where'
|
|
||||||
*/
|
|
||||||
parse->havingQual = SS_process_sublinks(parse->havingQual);
|
parse->havingQual = SS_process_sublinks(parse->havingQual);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for ungrouped variables passed to subplans. (Probably
|
* Check for ungrouped variables passed to subplans. (Probably
|
||||||
* this should be done for the targetlist as well???)
|
* this should be done for the targetlist as well??? But we
|
||||||
|
* should NOT do it for the WHERE qual, since WHERE is
|
||||||
|
* evaluated pre-GROUP.)
|
||||||
*/
|
*/
|
||||||
if (check_subplans_for_ungrouped_vars(parse->havingQual,
|
if (check_subplans_for_ungrouped_vars(parse->havingQual,
|
||||||
parse->groupClause,
|
parse->groupClause,
|
||||||
|
@ -323,6 +324,9 @@ union_planner(Query *parse)
|
||||||
elog(ERROR, "Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT");
|
elog(ERROR, "Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* convert the havingQual to conjunctive normal form (cnf) */
|
||||||
|
parse->havingQual = (Node *) cnfify((Expr *) parse->havingQual, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Require an aggregate function to appear in each clause of the
|
* Require an aggregate function to appear in each clause of the
|
||||||
* havingQual (else it could have been done as a WHERE constraint).
|
* havingQual (else it could have been done as a WHERE constraint).
|
||||||
|
@ -428,10 +432,11 @@ make_subplanTargetList(Query *parse,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Otherwise, start with a "flattened" tlist (having just the vars
|
* Otherwise, start with a "flattened" tlist (having just the vars
|
||||||
* mentioned in the targetlist and HAVING qual).
|
* mentioned in the targetlist and HAVING qual --- but not upper-
|
||||||
|
* level Vars; they will be replaced by Params later on).
|
||||||
*/
|
*/
|
||||||
sub_tlist = flatten_tlist(tlist);
|
sub_tlist = flatten_tlist(tlist);
|
||||||
extravars = pull_var_clause(parse->havingQual);
|
extravars = pull_var_clause(parse->havingQual, false);
|
||||||
sub_tlist = add_to_flat_tlist(sub_tlist, extravars);
|
sub_tlist = add_to_flat_tlist(sub_tlist, extravars);
|
||||||
freeList(extravars);
|
freeList(extravars);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.49 1999/08/25 23:21:41 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.50 1999/08/26 05:09:05 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
|
@ -339,7 +339,7 @@ make_ands_implicit(Expr *clause)
|
||||||
/*
|
/*
|
||||||
* pull_constant_clauses
|
* pull_constant_clauses
|
||||||
* Scans through a list of qualifications and find those that
|
* Scans through a list of qualifications and find those that
|
||||||
* contain no variables.
|
* contain no variables (of the current query level).
|
||||||
*
|
*
|
||||||
* Returns a list of the constant clauses in constantQual and the remaining
|
* Returns a list of the constant clauses in constantQual and the remaining
|
||||||
* quals as the return value.
|
* quals as the return value.
|
||||||
|
@ -480,11 +480,14 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
|
||||||
* Var nodes are considered distinct if they have different varno
|
* Var nodes are considered distinct if they have different varno
|
||||||
* or varattno values. If there are several occurrences of the same
|
* or varattno values. If there are several occurrences of the same
|
||||||
* varno/varattno, you get a randomly chosen one...
|
* varno/varattno, you get a randomly chosen one...
|
||||||
|
*
|
||||||
|
* Note that upper-level vars are ignored, since they normally will
|
||||||
|
* become Params with respect to this query level.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
|
clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
|
||||||
{
|
{
|
||||||
List *clvars = pull_var_clause(clause);
|
List *clvars = pull_var_clause(clause, false);
|
||||||
List *varno_list = NIL;
|
List *varno_list = NIL;
|
||||||
List *var_list = NIL;
|
List *var_list = NIL;
|
||||||
List *i;
|
List *i;
|
||||||
|
@ -494,7 +497,6 @@ clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
|
||||||
Var *var = (Var *) lfirst(i);
|
Var *var = (Var *) lfirst(i);
|
||||||
List *vi;
|
List *vi;
|
||||||
|
|
||||||
Assert(var->varlevelsup == 0);
|
|
||||||
if (!intMember(var->varno, varno_list))
|
if (!intMember(var->varno, varno_list))
|
||||||
varno_list = lconsi(var->varno, varno_list);
|
varno_list = lconsi(var->varno, varno_list);
|
||||||
foreach(vi, var_list)
|
foreach(vi, var_list)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.40 1999/08/22 20:14:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.41 1999/08/26 05:09:06 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -147,6 +147,10 @@ new_unsorted_tlist(List *targetlist)
|
||||||
* flatten_tlist
|
* flatten_tlist
|
||||||
* Create a target list that only contains unique variables.
|
* Create a target list that only contains unique variables.
|
||||||
*
|
*
|
||||||
|
* Note that Vars with varlevelsup > 0 are not included in the output
|
||||||
|
* tlist. We expect that those will eventually be replaced with Params,
|
||||||
|
* but that probably has not happened at the time this routine is called.
|
||||||
|
*
|
||||||
* 'tlist' is the current target list
|
* 'tlist' is the current target list
|
||||||
*
|
*
|
||||||
* Returns the "flattened" new target list.
|
* Returns the "flattened" new target list.
|
||||||
|
@ -157,7 +161,7 @@ new_unsorted_tlist(List *targetlist)
|
||||||
List *
|
List *
|
||||||
flatten_tlist(List *tlist)
|
flatten_tlist(List *tlist)
|
||||||
{
|
{
|
||||||
List *vlist = pull_var_clause((Node *) tlist);
|
List *vlist = pull_var_clause((Node *) tlist, false);
|
||||||
List *new_tlist;
|
List *new_tlist;
|
||||||
|
|
||||||
new_tlist = add_to_flat_tlist(NIL, vlist);
|
new_tlist = add_to_flat_tlist(NIL, vlist);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.23 1999/08/22 20:14:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.24 1999/08/26 05:09:06 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -19,16 +19,23 @@
|
||||||
#include "optimizer/var.h"
|
#include "optimizer/var.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
List *varlist;
|
||||||
|
bool includeUpperVars;
|
||||||
|
} pull_var_clause_context;
|
||||||
|
|
||||||
static bool pull_varnos_walker(Node *node, List **listptr);
|
static bool pull_varnos_walker(Node *node, List **listptr);
|
||||||
static bool contain_var_clause_walker(Node *node, void *context);
|
static bool contain_var_clause_walker(Node *node, void *context);
|
||||||
static bool pull_var_clause_walker(Node *node, List **listptr);
|
static bool pull_var_clause_walker(Node *node,
|
||||||
|
pull_var_clause_context *context);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pull_varnos
|
* pull_varnos
|
||||||
*
|
*
|
||||||
* Create a list of all the distinct varnos present in a parsetree
|
* Create a list of all the distinct varnos present in a parsetree
|
||||||
* (tlist or qual).
|
* (tlist or qual). Note that only varnos attached to level-zero
|
||||||
|
* Vars are considered --- upper Vars refer to some other rtable!
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
pull_varnos(Node *node)
|
pull_varnos(Node *node)
|
||||||
|
@ -47,7 +54,7 @@ pull_varnos_walker(Node *node, List **listptr)
|
||||||
if (IsA(node, Var))
|
if (IsA(node, Var))
|
||||||
{
|
{
|
||||||
Var *var = (Var *) node;
|
Var *var = (Var *) node;
|
||||||
if (!intMember(var->varno, *listptr))
|
if (var->varlevelsup == 0 && !intMember(var->varno, *listptr))
|
||||||
*listptr = lconsi(var->varno, *listptr);
|
*listptr = lconsi(var->varno, *listptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +63,8 @@ pull_varnos_walker(Node *node, List **listptr)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* contain_var_clause
|
* contain_var_clause
|
||||||
* Recursively scan a clause to discover whether it contains any Var nodes.
|
* Recursively scan a clause to discover whether it contains any Var nodes
|
||||||
|
* (of the current query level).
|
||||||
*
|
*
|
||||||
* Returns true if any varnode found.
|
* Returns true if any varnode found.
|
||||||
*/
|
*/
|
||||||
|
@ -72,7 +80,11 @@ contain_var_clause_walker(Node *node, void *context)
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return false;
|
return false;
|
||||||
if (IsA(node, Var))
|
if (IsA(node, Var))
|
||||||
return true; /* abort the tree traversal and return true */
|
{
|
||||||
|
if (((Var *) node)->varlevelsup == 0)
|
||||||
|
return true; /* abort the tree traversal and return true */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return expression_tree_walker(node, contain_var_clause_walker, context);
|
return expression_tree_walker(node, contain_var_clause_walker, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,28 +92,36 @@ contain_var_clause_walker(Node *node, void *context)
|
||||||
* pull_var_clause
|
* pull_var_clause
|
||||||
* Recursively pulls all var nodes from an expression clause.
|
* Recursively pulls all var nodes from an expression clause.
|
||||||
*
|
*
|
||||||
|
* Upper-level vars (with varlevelsup > 0) are included only
|
||||||
|
* if includeUpperVars is true. Most callers probably want
|
||||||
|
* to ignore upper-level vars.
|
||||||
|
*
|
||||||
* Returns list of varnodes found. Note the varnodes themselves are not
|
* Returns list of varnodes found. Note the varnodes themselves are not
|
||||||
* copied, only referenced.
|
* copied, only referenced.
|
||||||
*/
|
*/
|
||||||
List *
|
List *
|
||||||
pull_var_clause(Node *clause)
|
pull_var_clause(Node *clause, bool includeUpperVars)
|
||||||
{
|
{
|
||||||
List *result = NIL;
|
pull_var_clause_context context;
|
||||||
|
|
||||||
pull_var_clause_walker(clause, &result);
|
context.varlist = NIL;
|
||||||
return result;
|
context.includeUpperVars = includeUpperVars;
|
||||||
|
|
||||||
|
pull_var_clause_walker(clause, &context);
|
||||||
|
return context.varlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pull_var_clause_walker(Node *node, List **listptr)
|
pull_var_clause_walker(Node *node, pull_var_clause_context *context)
|
||||||
{
|
{
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return false;
|
return false;
|
||||||
if (IsA(node, Var))
|
if (IsA(node, Var))
|
||||||
{
|
{
|
||||||
*listptr = lappend(*listptr, node);
|
if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars)
|
||||||
|
context->varlist = lappend(context->varlist, node);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return expression_tree_walker(node, pull_var_clause_walker,
|
return expression_tree_walker(node, pull_var_clause_walker,
|
||||||
(void *) listptr);
|
(void *) context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: var.h,v 1.9 1999/08/22 20:14:57 tgl Exp $
|
* $Id: var.h,v 1.10 1999/08/26 05:06:17 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +17,6 @@
|
||||||
|
|
||||||
extern List *pull_varnos(Node *me);
|
extern List *pull_varnos(Node *me);
|
||||||
extern bool contain_var_clause(Node *clause);
|
extern bool contain_var_clause(Node *clause);
|
||||||
extern List *pull_var_clause(Node *clause);
|
extern List *pull_var_clause(Node *clause, bool includeUpperVars);
|
||||||
|
|
||||||
#endif /* VAR_H */
|
#endif /* VAR_H */
|
||||||
|
|
Loading…
Reference in New Issue