mirror of
https://github.com/postgres/postgres.git
synced 2025-07-23 03:21:12 +03:00
Clean up tlist.c tree-walking routines with
expression_tree_mutator.
This commit is contained in:
@ -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);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
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'. No entry is created if 'var' is already in the tlist.
|
||||||
* 'rel'
|
|
||||||
*
|
|
||||||
* 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)
|
|||||||
* ---------- 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,51 +179,36 @@ 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
|
* Returns the target list entry (resdom var) of the matching var,
|
||||||
* 'tlist' is the target list that is searched
|
* or NULL if no match.
|
||||||
*
|
|
||||||
* Returns the target list entry (resdom var) of the matching var.
|
|
||||||
*
|
|
||||||
* Now checks to make sure array references (in addition to range
|
|
||||||
* table indices) are identical - retrieve (a.b[1],a.b[2]) should
|
|
||||||
* 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 *
|
|||||||
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,35 +287,34 @@ 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);
|
|
||||||
|
|
||||||
if (!(tlist_member(var, new_tlist)))
|
|
||||||
{
|
{
|
||||||
Resdom *r;
|
Var *var = lfirst(v);
|
||||||
|
|
||||||
r = makeResdom(last_resdomno,
|
if (! tlistentry_member(var, new_tlist))
|
||||||
var->vartype,
|
{
|
||||||
var->vartypmod,
|
Resdom *r;
|
||||||
NULL,
|
|
||||||
(Index) 0,
|
r = makeResdom(last_resdomno++,
|
||||||
(Oid) 0,
|
var->vartype,
|
||||||
false);
|
var->vartypmod,
|
||||||
last_resdomno++;
|
NULL,
|
||||||
new_tlist = lappend(new_tlist, makeTargetEntry(r, (Node *) var));
|
(Index) 0,
|
||||||
|
(Oid) 0,
|
||||||
|
false);
|
||||||
|
new_tlist = lappend(new_tlist,
|
||||||
|
makeTargetEntry(r, (Node *) var));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
freeList(vlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_tlist;
|
return new_tlist;
|
||||||
@ -386,14 +322,13 @@ flatten_tlist(List *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)
|
|||||||
{
|
{
|
||||||
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,
|
||||||
flat_tlist)));
|
flatten_tlist_vars_mutator((Node *) get_expr(tle),
|
||||||
|
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 *
|
|||||||
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)
|
|||||||
"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
|
|
||||||
|
Reference in New Issue
Block a user