1
/*-------------------------------------------------------------------------
4
* Target list manipulation routines
6
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
13
*-------------------------------------------------------------------------
17
#include "nodes/makefuncs.h"
18
#include "nodes/nodeFuncs.h"
19
#include "optimizer/tlist.h"
20
#include "optimizer/var.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, true);
97
new_tlist = add_to_flat_tlist(NIL, vlist);
104
* Add more items to a flattened tlist (if they're not already in it)
106
* 'tlist' is the flattened tlist
107
* 'exprs' is a list of expressions (usually, but not necessarily, Vars)
109
* Returns the extended tlist.
112
add_to_flat_tlist(List *tlist, List *exprs)
114
int next_resno = list_length(tlist) + 1;
119
Node *expr = (Node *) lfirst(lc);
121
if (!tlist_member(expr, tlist))
125
tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
129
tlist = lappend(tlist, tle);
138
* Get just the expression subtrees of a tlist
140
* Resjunk columns are ignored unless includeJunk is true
143
get_tlist_exprs(List *tlist, bool includeJunk)
150
TargetEntry *tle = (TargetEntry *) lfirst(l);
152
if (tle->resjunk && !includeJunk)
155
result = lappend(result, tle->expr);
162
* Does tlist have same output datatypes as listed in colTypes?
164
* Resjunk columns are ignored if junkOK is true; otherwise presence of
165
* a resjunk column will always cause a 'false' result.
167
* Note: currently no callers care about comparing typmods.
170
tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
173
ListCell *curColType = list_head(colTypes);
177
TargetEntry *tle = (TargetEntry *) lfirst(l);
186
if (curColType == NULL)
187
return false; /* tlist longer than colTypes */
188
if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
190
curColType = lnext(curColType);
193
if (curColType != NULL)
194
return false; /* tlist shorter than colTypes */
200
* get_sortgroupref_tle
201
* Find the targetlist entry matching the given SortGroupRef index,
205
get_sortgroupref_tle(Index sortref, List *targetList)
209
foreach(l, targetList)
211
TargetEntry *tle = (TargetEntry *) lfirst(l);
213
if (tle->ressortgroupref == sortref)
217
elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
218
return NULL; /* keep compiler quiet */
222
* get_sortgroupclause_tle
223
* Find the targetlist entry matching the given SortGroupClause
224
* by ressortgroupref, and return it.
227
get_sortgroupclause_tle(SortGroupClause *sgClause,
230
return get_sortgroupref_tle(sgClause->tleSortGroupRef, targetList);
234
* get_sortgroupclause_expr
235
* Find the targetlist entry matching the given SortGroupClause
236
* by ressortgroupref, and return its expression.
239
get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
241
TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
243
return (Node *) tle->expr;
247
* get_sortgrouplist_exprs
248
* Given a list of SortGroupClauses, build a list
249
* of the referenced targetlist expressions.
252
get_sortgrouplist_exprs(List *sgClauses, List *targetList)
257
foreach(l, sgClauses)
259
SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
262
sortexpr = get_sortgroupclause_expr(sortcl, targetList);
263
result = lappend(result, sortexpr);
269
/*****************************************************************************
270
* Functions to extract data from a list of SortGroupClauses
272
* These don't really belong in tlist.c, but they are sort of related to the
273
* functions just above, and they don't seem to deserve their own file.
274
*****************************************************************************/
277
* extract_grouping_ops - make an array of the equality operator OIDs
278
* for a SortGroupClause list
281
extract_grouping_ops(List *groupClause)
283
int numCols = list_length(groupClause);
288
groupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
290
foreach(glitem, groupClause)
292
SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
294
groupOperators[colno] = groupcl->eqop;
295
Assert(OidIsValid(groupOperators[colno]));
299
return groupOperators;
303
* extract_grouping_cols - make an array of the grouping column resnos
304
* for a SortGroupClause list
307
extract_grouping_cols(List *groupClause, List *tlist)
309
AttrNumber *grpColIdx;
310
int numCols = list_length(groupClause);
314
grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
316
foreach(glitem, groupClause)
318
SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
319
TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
321
grpColIdx[colno++] = tle->resno;
328
* grouping_is_sortable - is it possible to implement grouping list by sorting?
330
* This is easy since the parser will have included a sortop if one exists.
333
grouping_is_sortable(List *groupClause)
337
foreach(glitem, groupClause)
339
SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
341
if (!OidIsValid(groupcl->sortop))
348
* grouping_is_hashable - is it possible to implement grouping list by hashing?
350
* We assume hashing is OK if the equality operators are marked oprcanhash.
351
* (If there isn't actually a supporting hash function, the executor will
352
* complain at runtime; but this is a misdeclaration of the operator, not
356
grouping_is_hashable(List *groupClause)
360
foreach(glitem, groupClause)
362
SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
364
if (!op_hashjoinable(groupcl->eqop))