1 /*-------------------------------------------------------------------------
4 * Target list manipulation routines
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.80 2008/08/07 01:11:50 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "nodes/makefuncs.h"
18 #include "optimizer/tlist.h"
19 #include "optimizer/var.h"
20 #include "parser/parse_expr.h"
21 #include "utils/lsyscache.h"
24 /*****************************************************************************
25 * Target list creation and searching utilities
26 *****************************************************************************/
30 * Finds the (first) member of the given tlist whose expression is
31 * equal() to the given expression. Result is NULL if no such member.
34 tlist_member(Node *node, List *targetlist)
38 foreach(temp, targetlist)
40 TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
42 if (equal(node, tlentry->expr))
49 * tlist_member_ignore_relabel
50 * Same as above, except that we ignore top-level RelabelType nodes
51 * while checking for a match. This is needed for some scenarios
52 * involving binary-compatible sort operations.
55 tlist_member_ignore_relabel(Node *node, List *targetlist)
59 while (node && IsA(node, RelabelType))
60 node = (Node *) ((RelabelType *) node)->arg;
62 foreach(temp, targetlist)
64 TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
65 Expr *tlexpr = tlentry->expr;
67 while (tlexpr && IsA(tlexpr, RelabelType))
68 tlexpr = ((RelabelType *) tlexpr)->arg;
70 if (equal(node, tlexpr))
78 * Create a target list that only contains unique variables.
80 * Note that Vars with varlevelsup > 0 are not included in the output
81 * tlist. We expect that those will eventually be replaced with Params,
82 * but that probably has not happened at the time this routine is called.
84 * 'tlist' is the current target list
86 * Returns the "flattened" new target list.
88 * The result is entirely new structure sharing no nodes with the original.
89 * Copying the Var nodes is probably overkill, but be safe for now.
92 flatten_tlist(List *tlist)
94 List *vlist = pull_var_clause((Node *) tlist, false);
97 new_tlist = add_to_flat_tlist(NIL, vlist);
104 * Add more vars to a flattened tlist (if they're not already in it)
106 * 'tlist' is the flattened tlist
107 * 'vars' is a list of var nodes
109 * Returns the extended tlist.
112 add_to_flat_tlist(List *tlist, List *vars)
114 int next_resno = list_length(tlist) + 1;
119 Var *var = (Var *) lfirst(v);
121 if (!tlist_member((Node *) var, tlist))
125 tle = makeTargetEntry(copyObject(var), /* copy needed?? */
129 tlist = lappend(tlist, tle);
137 * get_sortgroupref_tle
138 * Find the targetlist entry matching the given SortGroupRef index,
142 get_sortgroupref_tle(Index sortref, List *targetList)
146 foreach(l, targetList)
148 TargetEntry *tle = (TargetEntry *) lfirst(l);
150 if (tle->ressortgroupref == sortref)
154 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
155 return NULL; /* keep compiler quiet */
159 * get_sortgroupclause_tle
160 * Find the targetlist entry matching the given SortGroupClause
161 * by ressortgroupref, and return it.
164 get_sortgroupclause_tle(SortGroupClause *sgClause,
167 return get_sortgroupref_tle(sgClause->tleSortGroupRef, targetList);
171 * get_sortgroupclause_expr
172 * Find the targetlist entry matching the given SortGroupClause
173 * by ressortgroupref, and return its expression.
176 get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
178 TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
180 return (Node *) tle->expr;
184 * get_sortgrouplist_exprs
185 * Given a list of SortGroupClauses, build a list
186 * of the referenced targetlist expressions.
189 get_sortgrouplist_exprs(List *sgClauses, List *targetList)
194 foreach(l, sgClauses)
196 SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
199 sortexpr = get_sortgroupclause_expr(sortcl, targetList);
200 result = lappend(result, sortexpr);
206 /*****************************************************************************
207 * Functions to extract data from a list of SortGroupClauses
209 * These don't really belong in tlist.c, but they are sort of related to the
210 * functions just above, and they don't seem to deserve their own file.
211 *****************************************************************************/
214 * extract_grouping_ops - make an array of the equality operator OIDs
215 * for a SortGroupClause list
218 extract_grouping_ops(List *groupClause)
220 int numCols = list_length(groupClause);
225 groupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
227 foreach(glitem, groupClause)
229 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
231 groupOperators[colno] = groupcl->eqop;
232 Assert(OidIsValid(groupOperators[colno]));
236 return groupOperators;
240 * extract_grouping_cols - make an array of the grouping column resnos
241 * for a SortGroupClause list
244 extract_grouping_cols(List *groupClause, List *tlist)
246 AttrNumber *grpColIdx;
247 int numCols = list_length(groupClause);
251 grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
253 foreach(glitem, groupClause)
255 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
256 TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
258 grpColIdx[colno++] = tle->resno;
265 * grouping_is_sortable - is it possible to implement grouping list by sorting?
267 * This is easy since the parser will have included a sortop if one exists.
270 grouping_is_sortable(List *groupClause)
274 foreach(glitem, groupClause)
276 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
278 if (!OidIsValid(groupcl->sortop))
285 * grouping_is_hashable - is it possible to implement grouping list by hashing?
287 * We assume hashing is OK if the equality operators are marked oprcanhash.
288 * (If there isn't actually a supporting hash function, the executor will
289 * complain at runtime; but this is a misdeclaration of the operator, not
293 grouping_is_hashable(List *groupClause)
297 foreach(glitem, groupClause)
299 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
301 if (!op_hashjoinable(groupcl->eqop))
310 * Does tlist have same output datatypes as listed in colTypes?
312 * Resjunk columns are ignored if junkOK is true; otherwise presence of
313 * a resjunk column will always cause a 'false' result.
315 * Note: currently no callers care about comparing typmods.
318 tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
321 ListCell *curColType = list_head(colTypes);
325 TargetEntry *tle = (TargetEntry *) lfirst(l);
334 if (curColType == NULL)
335 return false; /* tlist longer than colTypes */
336 if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
338 curColType = lnext(curColType);
341 if (curColType != NULL)
342 return false; /* tlist shorter than colTypes */