提交 5efe3121 编写于 作者: T Tom Lane

Clean up tlist.c tree-walking routines with

expression_tree_mutator.
上级 14f84cd8
...@@ -7,21 +7,19 @@ ...@@ -7,21 +7,19 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.36 1999/07/16 04:59:27 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.37 1999/08/09 05:34:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/tlist.h" #include "optimizer/tlist.h"
#include "optimizer/var.h" #include "optimizer/var.h"
static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist); static Node *flatten_tlist_vars_mutator(Node *node, List *flat_tlist);
/***************************************************************************** /*****************************************************************************
* ---------- RELATION node target list routines ---------- * ---------- RELATION node target list routines ----------
...@@ -29,25 +27,19 @@ static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist); ...@@ -29,25 +27,19 @@ static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist);
/* /*
* tlistentry_member * tlistentry_member
* * Finds the (first) member of the given tlist whose expression is
* RETURNS: the leftmost member of sequence "targetlist" that satisfies * var_equal() to the given var. Result is NULL if no such member.
* the predicate "var_equal"
* MODIFIES: nothing
* REQUIRES: test = function which can operate on a lispval union
* var = valid var_node
* targetlist = valid sequence
*/ */
TargetEntry * TargetEntry *
tlistentry_member(Var *var, List *targetlist) tlistentry_member(Var *var, List *targetlist)
{ {
if (var) if (var && IsA(var, Var))
{ {
List *temp; List *temp;
foreach(temp, targetlist) foreach(temp, targetlist)
{ {
if (var_equal(var, if (var_equal(var, get_expr(lfirst(temp))))
get_expr(lfirst(temp))))
return (TargetEntry *) lfirst(temp); return (TargetEntry *) lfirst(temp);
} }
} }
...@@ -56,11 +48,8 @@ tlistentry_member(Var *var, List *targetlist) ...@@ -56,11 +48,8 @@ tlistentry_member(Var *var, List *targetlist)
/* /*
* matching_tlist_var * matching_tlist_var
* * Same as tlistentry_member(), except returns the tlist expression
* RETURNS: var node in a target list which is var_equal to 'var', * rather than its parent TargetEntry node.
* if one exists.
* REQUIRES: "test" operates on lispval unions,
*
*/ */
Expr * Expr *
matching_tlist_var(Var *var, List *targetlist) matching_tlist_var(Var *var, List *targetlist)
...@@ -74,54 +63,45 @@ matching_tlist_var(Var *var, List *targetlist) ...@@ -74,54 +63,45 @@ matching_tlist_var(Var *var, List *targetlist)
return (Expr *) NULL; return (Expr *) NULL;
} }
/*
* tlist_member
* Same as tlistentry_member(), except returns the Resdom node
* rather than its parent TargetEntry node.
*/
Resdom *
tlist_member(Var *var, List *tlist)
{
TargetEntry *tlentry;
tlentry = tlistentry_member(var, tlist);
if (tlentry)
return tlentry->resdom;
return (Resdom *) NULL;
}
/* /*
* add_var_to_tlist * add_var_to_tlist
* Creates a targetlist entry corresponding to the supplied var node * Creates a targetlist entry corresponding to the supplied var node
*
* 'var' and adds the new targetlist entry to the targetlist field of * 'var' and adds the new targetlist entry to the targetlist field of
* 'rel' * 'rel'. No entry is created if 'var' is already in the tlist.
*
* RETURNS: nothing
* MODIFIES: vartype and varid fields of leftmost varnode that matches
* argument "var" (sometimes).
* CREATES: new var_node iff no matching var_node exists in targetlist
*/ */
void void
add_var_to_tlist(RelOptInfo *rel, Var *var) add_var_to_tlist(RelOptInfo *rel, Var *var)
{ {
Expr *oldvar; if (tlistentry_member(var, rel->targetlist) == NULL)
oldvar = matching_tlist_var(var, rel->targetlist);
/*
* If 'var' is not already in 'rel's target list, add a new node.
*/
if (oldvar == NULL)
{ {
List *tlist = rel->targetlist; /* XXX is copyObject necessary here? */
Var *newvar = makeVar(var->varno, rel->targetlist = lappend(rel->targetlist,
var->varattno, create_tl_element((Var *) copyObject(var),
var->vartype, length(rel->targetlist) + 1));
var->vartypmod,
var->varlevelsup,
var->varno,
var->varoattno);
rel->targetlist = lappend(tlist,
create_tl_element(newvar,
length(tlist) + 1));
} }
} }
/* /*
* create_tl_element * create_tl_element
* Creates a target list entry node and its associated (resdom var) pair * Creates a target list entry node and its associated (resdom var) pair
* with its resdom number equal to 'resdomno' and the joinlist field set * with its resdom number equal to 'resdomno'.
* to 'joinlist'.
*
* RETURNS: newly created tlist_entry
* CREATES: new targetlist entry (always).
*/ */
TargetEntry * TargetEntry *
create_tl_element(Var *var, int resdomno) create_tl_element(Var *var, int resdomno)
...@@ -176,35 +156,6 @@ get_actual_tlist(List *tlist) ...@@ -176,35 +156,6 @@ get_actual_tlist(List *tlist)
* ---------- GENERAL target list routines ---------- * ---------- GENERAL target list routines ----------
*****************************************************************************/ *****************************************************************************/
/*
* tlist_member
* Determines whether a var node is already contained within a
* target list.
*
* 'var' is the var node
* 'tlist' is the target list
*
* Returns the resdom entry of the matching var node, or NULL if no match.
*
*/
Resdom *
tlist_member(Var *var, List *tlist)
{
if (var)
{
List *i;
foreach(i, tlist)
{
TargetEntry *tle = (TargetEntry *) lfirst(i);
if (var_equal(var, get_expr(tle)))
return tle->resdom;
}
}
return (Resdom *) NULL;
}
/* /*
* Routine to get the resdom out of a targetlist. * Routine to get the resdom out of a targetlist.
*/ */
...@@ -228,52 +179,37 @@ tlist_resdom(List *tlist, Resdom *resnode) ...@@ -228,52 +179,37 @@ tlist_resdom(List *tlist, Resdom *resnode)
/* /*
* match_varid * match_varid
* Searches a target list for an entry with some desired varid. * Searches a target list for an entry matching a given var.
*
* 'varid' is the desired id
* 'tlist' is the target list that is searched
*
* Returns the target list entry (resdom var) of the matching var.
* *
* Now checks to make sure array references (in addition to range * Returns the target list entry (resdom var) of the matching var,
* table indices) are identical - retrieve (a.b[1],a.b[2]) should * or NULL if no match.
* not be turned into retrieve (a.b[1],a.b[1]).
*
* [what used to be varid is now broken up into two fields varnoold and
* varoattno. Also, nested attnos are long gone. - ay 2/95]
*/ */
TargetEntry * TargetEntry *
match_varid(Var *test_var, List *tlist) match_varid(Var *test_var, List *tlist)
{ {
List *tl; List *tl;
Oid type_var;
type_var = (Oid) test_var->vartype; Assert(test_var->varlevelsup == 0); /* XXX why? */
Assert(test_var->varlevelsup == 0);
foreach(tl, tlist) foreach(tl, tlist)
{ {
TargetEntry *entry; TargetEntry *entry = lfirst(tl);
Var *tlvar; Var *tlvar = get_expr(entry);
entry = lfirst(tl);
tlvar = get_expr(entry);
if (!IsA(tlvar, Var)) if (!IsA(tlvar, Var))
continue; continue;
/* /*
* we test the original varno (instead of varno which might be * we test the original varno, instead of varno which might be
* changed to INNER/OUTER. * changed to INNER/OUTER. XXX is test on vartype necessary?
*/ */
Assert(tlvar->varlevelsup == 0); Assert(tlvar->varlevelsup == 0);
if (tlvar->varnoold == test_var->varnoold && if (tlvar->varnoold == test_var->varnoold &&
tlvar->varoattno == test_var->varoattno) tlvar->varoattno == test_var->varoattno &&
{ tlvar->vartype == test_var->vartype)
if (tlvar->vartype == type_var)
return entry; return entry;
} }
}
return NULL; return NULL;
} }
...@@ -321,11 +257,12 @@ List * ...@@ -321,11 +257,12 @@ List *
copy_vars(List *target, List *source) copy_vars(List *target, List *source)
{ {
List *result = NIL; List *result = NIL;
List *src = NIL; List *src;
List *dest = NIL; List *dest;
for (src = source, dest = target; src != NIL && for (src = source, dest = target;
dest != NIL; src = lnext(src), dest = lnext(dest)) src != NIL && dest != NIL;
src = lnext(src), dest = lnext(dest))
{ {
TargetEntry *temp = makeTargetEntry(((TargetEntry *) lfirst(dest))->resdom, TargetEntry *temp = makeTargetEntry(((TargetEntry *) lfirst(dest))->resdom,
(Node *) get_expr(lfirst(src))); (Node *) get_expr(lfirst(src)));
...@@ -350,50 +287,48 @@ flatten_tlist(List *tlist) ...@@ -350,50 +287,48 @@ flatten_tlist(List *tlist)
{ {
int last_resdomno = 1; int last_resdomno = 1;
List *new_tlist = NIL; List *new_tlist = NIL;
List *tlist_vars = NIL; List *tl;
List *temp;
foreach(temp, tlist) foreach(tl, tlist)
{ {
TargetEntry *temp_entry = (TargetEntry *) lfirst(temp); TargetEntry *tl_entry = (TargetEntry *) lfirst(tl);
List *vlist = pull_var_clause((Node *) get_expr(tl_entry));
List *v;
tlist_vars = nconc(tlist_vars, foreach(v, vlist)
pull_var_clause((Node *) get_expr(temp_entry)));
}
foreach(temp, tlist_vars)
{ {
Var *var = lfirst(temp); Var *var = lfirst(v);
if (!(tlist_member(var, new_tlist))) if (! tlistentry_member(var, new_tlist))
{ {
Resdom *r; Resdom *r;
r = makeResdom(last_resdomno, r = makeResdom(last_resdomno++,
var->vartype, var->vartype,
var->vartypmod, var->vartypmod,
NULL, NULL,
(Index) 0, (Index) 0,
(Oid) 0, (Oid) 0,
false); false);
last_resdomno++; new_tlist = lappend(new_tlist,
new_tlist = lappend(new_tlist, makeTargetEntry(r, (Node *) var)); makeTargetEntry(r, (Node *) var));
} }
} }
freeList(vlist);
}
return new_tlist; return new_tlist;
} }
/* /*
* flatten_tlist_vars * flatten_tlist_vars
* Redoes the target list of a query with no nested attributes by * Redoes the target list of a query by replacing vars within
* replacing vars within computational expressions with vars from * target expressions with vars from the 'flattened' target list.
* the 'flattened' target list of the query.
* *
* 'full_tlist' is the actual target list * 'full_tlist' is the original target list
* 'flat_tlist' is the flattened (var-only) target list * 'flat_tlist' is the flattened (var-only) target list
* *
* Returns the modified actual target list. * Returns the rebuilt target list. The original is not modified.
* *
*/ */
List * List *
...@@ -406,105 +341,25 @@ flatten_tlist_vars(List *full_tlist, List *flat_tlist) ...@@ -406,105 +341,25 @@ flatten_tlist_vars(List *full_tlist, List *flat_tlist)
{ {
TargetEntry *tle = lfirst(x); TargetEntry *tle = lfirst(x);
result = lappend(result, makeTargetEntry(tle->resdom, result = lappend(result,
flatten_tlistentry((Node *) get_expr(tle), makeTargetEntry(tle->resdom,
flatten_tlist_vars_mutator((Node *) get_expr(tle),
flat_tlist))); flat_tlist)));
} }
return result; return result;
} }
/*
* flatten_tlistentry
* Replaces vars within a target list entry with vars from a flattened
* target list.
*
* 'tlistentry' is the target list entry to be modified
* 'flat_tlist' is the flattened target list
*
* Returns the (modified) target_list entry from the target list.
*
*/
static Node * static Node *
flatten_tlistentry(Node *tlistentry, List *flat_tlist) flatten_tlist_vars_mutator(Node *node, List *flat_tlist)
{ {
List *temp; if (node == NULL)
if (tlistentry == NULL)
return NULL; return NULL;
else if (IsA(tlistentry, Var)) if (IsA(node, Var))
return (Node *) get_expr(match_varid((Var *) tlistentry, return (Node *) get_expr(match_varid((Var *) node,
flat_tlist)); flat_tlist));
else if (single_node(tlistentry)) return expression_tree_mutator(node, flatten_tlist_vars_mutator,
return tlistentry; (void *) flat_tlist);
else if (IsA(tlistentry, Iter))
{
((Iter *) tlistentry)->iterexpr =
flatten_tlistentry((Node *) ((Iter *) tlistentry)->iterexpr,
flat_tlist);
return tlistentry;
}
else if (is_subplan(tlistentry))
{
/* do we need to support this case? */
elog(ERROR, "flatten_tlistentry: subplan case not implemented");
return tlistentry;
}
else if (IsA(tlistentry, Expr))
{
/*
* Recursively scan the arguments of an expression. NOTE: this
* must come after is_subplan() case since subplan is a kind of
* Expr node.
*/
foreach(temp, ((Expr *) tlistentry)->args)
lfirst(temp) = flatten_tlistentry(lfirst(temp), flat_tlist);
return tlistentry;
}
else if (IsA(tlistentry, Aggref))
{
/*
* XXX shouldn't this be recursing into the agg's target? Seems to
* work though, so will leave it alone ... tgl 5/99
*/
return tlistentry;
}
else if (IsA(tlistentry, ArrayRef))
{
ArrayRef *aref = (ArrayRef *) tlistentry;
foreach(temp, aref->refupperindexpr)
lfirst(temp) = flatten_tlistentry(lfirst(temp), flat_tlist);
foreach(temp, aref->reflowerindexpr)
lfirst(temp) = flatten_tlistentry(lfirst(temp), flat_tlist);
aref->refexpr = flatten_tlistentry(aref->refexpr, flat_tlist);
aref->refassgnexpr = flatten_tlistentry(aref->refassgnexpr, flat_tlist);
return tlistentry;
}
else if (case_clause(tlistentry))
{
CaseExpr *cexpr = (CaseExpr *) tlistentry;
foreach(temp, cexpr->args)
{
CaseWhen *cwhen = (CaseWhen *) lfirst(temp);
cwhen->expr = flatten_tlistentry(cwhen->expr, flat_tlist);
cwhen->result = flatten_tlistentry(cwhen->result, flat_tlist);
}
cexpr->defresult = flatten_tlistentry(cexpr->defresult, flat_tlist);
return tlistentry;
}
else
{
elog(ERROR, "flatten_tlistentry: Cannot handle node type %d",
nodeTag(tlistentry));
return tlistentry;
}
} }
...@@ -522,11 +377,10 @@ Var * ...@@ -522,11 +377,10 @@ Var *
get_groupclause_expr(GroupClause *groupClause, List *targetList) get_groupclause_expr(GroupClause *groupClause, List *targetList)
{ {
List *l; List *l;
TargetEntry *tle;
foreach(l, targetList) foreach(l, targetList)
{ {
tle = (TargetEntry *) lfirst(l); TargetEntry *tle = (TargetEntry *) lfirst(l);
if (tle->resdom->resgroupref == groupClause->tleGroupref) if (tle->resdom->resgroupref == groupClause->tleGroupref)
return get_expr(tle); return get_expr(tle);
} }
...@@ -535,49 +389,3 @@ get_groupclause_expr(GroupClause *groupClause, List *targetList) ...@@ -535,49 +389,3 @@ get_groupclause_expr(GroupClause *groupClause, List *targetList)
"get_groupclause_expr: GROUP BY expression not found in targetlist"); "get_groupclause_expr: GROUP BY expression not found in targetlist");
return NULL; return NULL;
} }
/*****************************************************************************
*
*****************************************************************************/
/*
* AddGroupAttrToTlist -
* append the group attribute to the target list if it's not already
* in there.
*/
#ifdef NOT_USED
/*
* WARNING!!! If this ever get's used again, the new reference
* mechanism from group clause to targetlist entry must be implemented
* here too. Jan
*/
void
AddGroupAttrToTlist(List *tlist, List *grpCl)
{
List *gl;
int last_resdomno = length(tlist) + 1;
foreach(gl, grpCl)
{
GroupClause *gc = (GroupClause *) lfirst(gl);
Var *var = gc->grpAttr;
if (!(tlist_member(var, tlist)))
{
Resdom *r;
r = makeResdom(last_resdomno,
var->vartype,
var->vartypmod,
NULL,
(Index) 0,
(Oid) 0,
false);
last_resdomno++;
tlist = lappend(tlist, makeTargetEntry(r, (Node *) var));
}
}
}
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册