Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * tlist.c
4 : : * Target list manipulation routines
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/optimizer/util/tlist.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "nodes/makefuncs.h"
18 : : #include "nodes/nodeFuncs.h"
19 : : #include "optimizer/cost.h"
20 : : #include "optimizer/optimizer.h"
21 : : #include "optimizer/tlist.h"
22 : : #include "rewrite/rewriteManip.h"
23 : :
24 : :
25 : : /*
26 : : * Test if an expression node represents a SRF call. Beware multiple eval!
27 : : *
28 : : * Please note that this is only meant for use in split_pathtarget_at_srfs();
29 : : * if you use it anywhere else, your code is almost certainly wrong for SRFs
30 : : * nested within expressions. Use expression_returns_set() instead.
31 : : */
32 : : #define IS_SRF_CALL(node) \
33 : : ((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
34 : : (IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
35 : :
36 : : /*
37 : : * Data structures for split_pathtarget_at_srfs(). To preserve the identity
38 : : * of sortgroupref items even if they are textually equal(), what we track is
39 : : * not just bare expressions but expressions plus their sortgroupref indexes.
40 : : */
41 : : typedef struct
42 : : {
43 : : Node *expr; /* some subexpression of a PathTarget */
44 : : Index sortgroupref; /* its sortgroupref, or 0 if none */
45 : : } split_pathtarget_item;
46 : :
47 : : typedef struct
48 : : {
49 : : PlannerInfo *root;
50 : : bool is_grouping_target; /* true if processing grouping target */
51 : : /* This is a List of bare expressions: */
52 : : List *input_target_exprs; /* exprs available from input */
53 : : /* These are Lists of Lists of split_pathtarget_items: */
54 : : List *level_srfs; /* SRF exprs to evaluate at each level */
55 : : List *level_input_vars; /* input vars needed at each level */
56 : : List *level_input_srfs; /* input SRFs needed at each level */
57 : : /* These are Lists of split_pathtarget_items: */
58 : : List *current_input_vars; /* vars needed in current subexpr */
59 : : List *current_input_srfs; /* SRFs needed in current subexpr */
60 : : /* Auxiliary data for current split_pathtarget_walker traversal: */
61 : : int current_depth; /* max SRF depth in current subexpr */
62 : : Index current_sgref; /* current subexpr's sortgroupref, or 0 */
63 : : } split_pathtarget_context;
64 : :
65 : : static void split_pathtarget_at_srfs_extended(PlannerInfo *root,
66 : : PathTarget *target,
67 : : PathTarget *input_target,
68 : : List **targets,
69 : : List **targets_contain_srfs,
70 : : bool is_grouping_target);
71 : : static bool split_pathtarget_walker(Node *node,
72 : : split_pathtarget_context *context);
73 : : static void add_sp_item_to_pathtarget(PathTarget *target,
74 : : split_pathtarget_item *item);
75 : : static void add_sp_items_to_pathtarget(PathTarget *target, List *items);
76 : :
77 : :
78 : : /*****************************************************************************
79 : : * Target list creation and searching utilities
80 : : *****************************************************************************/
81 : :
82 : : /*
83 : : * tlist_member
84 : : * Finds the (first) member of the given tlist whose expression is
85 : : * equal() to the given expression. Result is NULL if no such member.
86 : : */
87 : : TargetEntry *
3293 peter_e@gmx.net 88 :CBC 27094 : tlist_member(Expr *node, List *targetlist)
89 : : {
90 : : ListCell *temp;
91 : :
9702 tgl@sss.pgh.pa.us 92 [ + + + + : 94977 : foreach(temp, targetlist)
+ + ]
93 : : {
9468 bruce@momjian.us 94 : 74975 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
95 : :
9702 tgl@sss.pgh.pa.us 96 [ + + ]: 74975 : if (equal(node, tlentry->expr))
97 : 7092 : return tlentry;
98 : : }
10057 bruce@momjian.us 99 : 20002 : return NULL;
100 : : }
101 : :
102 : : /*
103 : : * tlist_member_match_var
104 : : * Same as above, except that we match the provided Var on the basis
105 : : * of varno/varattno/varlevelsup/vartype only, rather than full equal().
106 : : *
107 : : * This is needed in some cases where we can't be sure of an exact typmod
108 : : * match. For safety, though, we insist on vartype match.
109 : : */
110 : : static TargetEntry *
4587 tgl@sss.pgh.pa.us 111 : 1377 : tlist_member_match_var(Var *var, List *targetlist)
112 : : {
113 : : ListCell *temp;
114 : :
115 [ + - + - : 3805 : foreach(temp, targetlist)
+ - ]
116 : : {
117 : 3805 : TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
118 : 3805 : Var *tlvar = (Var *) tlentry->expr;
119 : :
120 [ + - - + ]: 3805 : if (!tlvar || !IsA(tlvar, Var))
4587 tgl@sss.pgh.pa.us 121 :UBC 0 : continue;
4587 tgl@sss.pgh.pa.us 122 [ + - ]:CBC 3805 : if (var->varno == tlvar->varno &&
123 [ + + ]: 3805 : var->varattno == tlvar->varattno &&
3660 124 [ + - ]: 1377 : var->varlevelsup == tlvar->varlevelsup &&
125 [ + - ]: 1377 : var->vartype == tlvar->vartype)
4587 126 : 1377 : return tlentry;
127 : : }
4587 tgl@sss.pgh.pa.us 128 :UBC 0 : return NULL;
129 : : }
130 : :
131 : : /*
132 : : * add_to_flat_tlist
133 : : * Add more items to a flattened tlist (if they're not already in it)
134 : : *
135 : : * 'tlist' is the flattened tlist
136 : : * 'exprs' is a list of expressions (usually, but not necessarily, Vars)
137 : : *
138 : : * Returns the extended tlist.
139 : : */
140 : : List *
6286 tgl@sss.pgh.pa.us 141 :CBC 859 : add_to_flat_tlist(List *tlist, List *exprs)
142 : : {
7648 143 : 859 : int next_resno = list_length(tlist) + 1;
144 : : ListCell *lc;
145 : :
6286 146 [ + + + + : 4698 : foreach(lc, exprs)
+ + ]
147 : : {
3293 peter_e@gmx.net 148 : 3839 : Expr *expr = (Expr *) lfirst(lc);
149 : :
6286 tgl@sss.pgh.pa.us 150 [ + + ]: 3839 : if (!tlist_member(expr, tlist))
151 : : {
152 : : TargetEntry *tle;
153 : :
3189 154 : 3819 : tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
7648 155 : 3819 : next_resno++,
156 : : NULL,
157 : : false);
158 : 3819 : tlist = lappend(tlist, tle);
159 : : }
160 : : }
9703 161 : 859 : return tlist;
162 : : }
163 : :
164 : :
165 : : /*
166 : : * get_tlist_exprs
167 : : * Get just the expression subtrees of a tlist
168 : : *
169 : : * Resjunk columns are ignored unless includeJunk is true
170 : : */
171 : : List *
6429 172 : 725 : get_tlist_exprs(List *tlist, bool includeJunk)
173 : : {
174 : 725 : List *result = NIL;
175 : : ListCell *l;
176 : :
177 [ + + + + : 3432 : foreach(l, tlist)
+ + ]
178 : : {
179 : 2707 : TargetEntry *tle = (TargetEntry *) lfirst(l);
180 : :
181 [ - + - - ]: 2707 : if (tle->resjunk && !includeJunk)
6429 tgl@sss.pgh.pa.us 182 :UBC 0 : continue;
183 : :
6429 tgl@sss.pgh.pa.us 184 :CBC 2707 : result = lappend(result, tle->expr);
185 : : }
186 : 725 : return result;
187 : : }
188 : :
189 : :
190 : : /*
191 : : * count_nonjunk_tlist_entries
192 : : * What it says ...
193 : : */
194 : : int
4288 195 : 19909 : count_nonjunk_tlist_entries(List *tlist)
196 : : {
197 : 19909 : int len = 0;
198 : : ListCell *l;
199 : :
200 [ + + + + : 41244 : foreach(l, tlist)
+ + ]
201 : : {
202 : 21335 : TargetEntry *tle = (TargetEntry *) lfirst(l);
203 : :
204 [ + + ]: 21335 : if (!tle->resjunk)
205 : 19989 : len++;
206 : : }
207 : 19909 : return len;
208 : : }
209 : :
210 : :
211 : : /*
212 : : * tlist_same_exprs
213 : : * Check whether two target lists contain the same expressions
214 : : *
215 : : * Note: this function is used to decide whether it's safe to jam a new tlist
216 : : * into a non-projection-capable plan node. Obviously we can't do that unless
217 : : * the node's tlist shows it already returns the column values we want.
218 : : * However, we can ignore the TargetEntry attributes resname, ressortgroupref,
219 : : * resorigtbl, resorigcol, and resjunk, because those are only labelings that
220 : : * don't affect the row values computed by the node. (Moreover, if we didn't
221 : : * ignore them, we'd frequently fail to make the desired optimization, since
222 : : * the planner tends to not bother to make resname etc. valid in intermediate
223 : : * plan nodes.) Note that on success, the caller must still jam the desired
224 : : * tlist into the plan node, else it won't have the desired labeling fields.
225 : : */
226 : : bool
4749 227 : 1026 : tlist_same_exprs(List *tlist1, List *tlist2)
228 : : {
229 : : ListCell *lc1,
230 : : *lc2;
231 : :
232 [ + + ]: 1026 : if (list_length(tlist1) != list_length(tlist2))
233 : 455 : return false; /* not same length, so can't match */
234 : :
235 [ + - + + : 765 : forboth(lc1, tlist1, lc2, tlist2)
+ - + + +
+ + - +
+ ]
236 : : {
237 : 679 : TargetEntry *tle1 = (TargetEntry *) lfirst(lc1);
238 : 679 : TargetEntry *tle2 = (TargetEntry *) lfirst(lc2);
239 : :
240 [ + + ]: 679 : if (!equal(tle1->expr, tle2->expr))
241 : 485 : return false;
242 : : }
243 : :
244 : 86 : return true;
245 : : }
246 : :
247 : :
248 : : /*
249 : : * Does tlist have same output datatypes as listed in colTypes?
250 : : *
251 : : * Resjunk columns are ignored if junkOK is true; otherwise presence of
252 : : * a resjunk column will always cause a 'false' result.
253 : : *
254 : : * Note: currently no callers care about comparing typmods.
255 : : */
256 : : bool
6429 257 : 12934 : tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
258 : : {
259 : : ListCell *l;
260 : 12934 : ListCell *curColType = list_head(colTypes);
261 : :
262 [ + + + + : 59817 : foreach(l, tlist)
+ + ]
263 : : {
264 : 47374 : TargetEntry *tle = (TargetEntry *) lfirst(l);
265 : :
266 [ + + ]: 47374 : if (tle->resjunk)
267 : : {
268 [ - + ]: 6 : if (!junkOK)
269 : 491 : return false;
270 : : }
271 : : else
272 : : {
273 [ - + ]: 47368 : if (curColType == NULL)
6429 tgl@sss.pgh.pa.us 274 :UBC 0 : return false; /* tlist longer than colTypes */
6429 tgl@sss.pgh.pa.us 275 [ + + ]:CBC 47368 : if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
276 : 491 : return false;
2435 277 : 46877 : curColType = lnext(colTypes, curColType);
278 : : }
279 : : }
6429 280 [ - + ]: 12443 : if (curColType != NULL)
6429 tgl@sss.pgh.pa.us 281 :UBC 0 : return false; /* tlist shorter than colTypes */
6429 tgl@sss.pgh.pa.us 282 :CBC 12443 : return true;
283 : : }
284 : :
285 : : /*
286 : : * Does tlist have same exposed collations as listed in colCollations?
287 : : *
288 : : * Identical logic to the above, but for collations.
289 : : */
290 : : bool
5447 291 : 2833 : tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
292 : : {
293 : : ListCell *l;
294 : 2833 : ListCell *curColColl = list_head(colCollations);
295 : :
296 [ + + + + : 11349 : foreach(l, tlist)
+ + ]
297 : : {
298 : 8516 : TargetEntry *tle = (TargetEntry *) lfirst(l);
299 : :
300 [ - + ]: 8516 : if (tle->resjunk)
301 : : {
5447 tgl@sss.pgh.pa.us 302 [ # # ]:UBC 0 : if (!junkOK)
303 : 0 : return false;
304 : : }
305 : : else
306 : : {
5447 tgl@sss.pgh.pa.us 307 [ - + ]:CBC 8516 : if (curColColl == NULL)
5447 tgl@sss.pgh.pa.us 308 :UBC 0 : return false; /* tlist longer than colCollations */
5447 tgl@sss.pgh.pa.us 309 [ - + ]:CBC 8516 : if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
5447 tgl@sss.pgh.pa.us 310 :UBC 0 : return false;
2435 tgl@sss.pgh.pa.us 311 :CBC 8516 : curColColl = lnext(colCollations, curColColl);
312 : : }
313 : : }
5447 314 [ - + ]: 2833 : if (curColColl != NULL)
5447 tgl@sss.pgh.pa.us 315 :UBC 0 : return false; /* tlist shorter than colCollations */
5447 tgl@sss.pgh.pa.us 316 :CBC 2833 : return true;
317 : : }
318 : :
319 : : /*
320 : : * apply_tlist_labeling
321 : : * Apply the TargetEntry labeling attributes of src_tlist to dest_tlist
322 : : *
323 : : * This is useful for reattaching column names etc to a plan's final output
324 : : * targetlist.
325 : : */
326 : : void
3660 327 : 298530 : apply_tlist_labeling(List *dest_tlist, List *src_tlist)
328 : : {
329 : : ListCell *ld,
330 : : *ls;
331 : :
332 [ - + ]: 298530 : Assert(list_length(dest_tlist) == list_length(src_tlist));
333 [ + + + + : 1120393 : forboth(ld, dest_tlist, ls, src_tlist)
+ + + + +
+ + - +
+ ]
334 : : {
335 : 821863 : TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
336 : 821863 : TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
337 : :
338 [ - + ]: 821863 : Assert(dest_tle->resno == src_tle->resno);
339 : 821863 : dest_tle->resname = src_tle->resname;
340 : 821863 : dest_tle->ressortgroupref = src_tle->ressortgroupref;
341 : 821863 : dest_tle->resorigtbl = src_tle->resorigtbl;
342 : 821863 : dest_tle->resorigcol = src_tle->resorigcol;
343 : 821863 : dest_tle->resjunk = src_tle->resjunk;
344 : : }
345 : 298530 : }
346 : :
347 : :
348 : : /*
349 : : * get_sortgroupref_tle
350 : : * Find the targetlist entry matching the given SortGroupRef index,
351 : : * and return it.
352 : : */
353 : : TargetEntry *
6702 354 : 145905 : get_sortgroupref_tle(Index sortref, List *targetList)
355 : : {
356 : : ListCell *l;
357 : :
9804 JanWieck@Yahoo.com 358 [ + - + - : 370224 : foreach(l, targetList)
+ - ]
359 : : {
9715 tgl@sss.pgh.pa.us 360 : 370224 : TargetEntry *tle = (TargetEntry *) lfirst(l);
361 : :
6702 362 [ + + ]: 370224 : if (tle->ressortgroupref == sortref)
9544 363 : 145905 : return tle;
364 : : }
365 : :
8269 tgl@sss.pgh.pa.us 366 [ # # ]:UBC 0 : elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
367 : : return NULL; /* keep compiler quiet */
368 : : }
369 : :
370 : : /*
371 : : * get_sortgroupclause_tle
372 : : * Find the targetlist entry matching the given SortGroupClause
373 : : * by ressortgroupref, and return it.
374 : : */
375 : : TargetEntry *
6434 tgl@sss.pgh.pa.us 376 :CBC 145023 : get_sortgroupclause_tle(SortGroupClause *sgClause,
377 : : List *targetList)
378 : : {
379 : 145023 : return get_sortgroupref_tle(sgClause->tleSortGroupRef, targetList);
380 : : }
381 : :
382 : : /*
383 : : * get_sortgroupclause_expr
384 : : * Find the targetlist entry matching the given SortGroupClause
385 : : * by ressortgroupref, and return its expression.
386 : : */
387 : : Node *
388 : 118933 : get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
389 : : {
390 : 118933 : TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
391 : :
8494 392 : 118933 : return (Node *) tle->expr;
393 : : }
394 : :
395 : : /*
396 : : * get_sortgrouplist_exprs
397 : : * Given a list of SortGroupClauses, build a list
398 : : * of the referenced targetlist expressions.
399 : : */
400 : : List *
6434 401 : 9271 : get_sortgrouplist_exprs(List *sgClauses, List *targetList)
402 : : {
8259 bruce@momjian.us 403 : 9271 : List *result = NIL;
404 : : ListCell *l;
405 : :
6434 tgl@sss.pgh.pa.us 406 [ + + + + : 21675 : foreach(l, sgClauses)
+ + ]
407 : : {
408 : 12404 : SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
409 : : Node *sortexpr;
410 : :
8455 411 : 12404 : sortexpr = get_sortgroupclause_expr(sortcl, targetList);
412 : 12404 : result = lappend(result, sortexpr);
413 : : }
414 : 9271 : return result;
415 : : }
416 : :
417 : :
418 : : /*****************************************************************************
419 : : * Functions to extract data from a list of SortGroupClauses
420 : : *
421 : : * These don't really belong in tlist.c, but they are sort of related to the
422 : : * functions just above, and they don't seem to deserve their own file.
423 : : *****************************************************************************/
424 : :
425 : : /*
426 : : * get_sortgroupref_clause
427 : : * Find the SortGroupClause matching the given SortGroupRef index,
428 : : * and return it.
429 : : */
430 : : SortGroupClause *
3956 andres@anarazel.de 431 : 5618 : get_sortgroupref_clause(Index sortref, List *clauses)
432 : : {
433 : : ListCell *l;
434 : :
435 [ + - + - : 8722 : foreach(l, clauses)
+ - ]
436 : : {
437 : 8722 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
438 : :
439 [ + + ]: 8722 : if (cl->tleSortGroupRef == sortref)
440 : 5618 : return cl;
441 : : }
442 : :
3956 andres@anarazel.de 443 [ # # ]:UBC 0 : elog(ERROR, "ORDER/GROUP BY expression not found in list");
444 : : return NULL; /* keep compiler quiet */
445 : : }
446 : :
447 : : /*
448 : : * get_sortgroupref_clause_noerr
449 : : * As above, but return NULL rather than throwing an error if not found.
450 : : */
451 : : SortGroupClause *
3659 tgl@sss.pgh.pa.us 452 :CBC 7852 : get_sortgroupref_clause_noerr(Index sortref, List *clauses)
453 : : {
454 : : ListCell *l;
455 : :
456 [ + + + + : 13361 : foreach(l, clauses)
+ + ]
457 : : {
458 : 11400 : SortGroupClause *cl = (SortGroupClause *) lfirst(l);
459 : :
460 [ + + ]: 11400 : if (cl->tleSortGroupRef == sortref)
461 : 5891 : return cl;
462 : : }
463 : :
464 : 1961 : return NULL;
465 : : }
466 : :
467 : : /*
468 : : * extract_grouping_ops - make an array of the equality operator OIDs
469 : : * for a SortGroupClause list
470 : : */
471 : : Oid *
6429 472 : 26030 : extract_grouping_ops(List *groupClause)
473 : : {
474 : 26030 : int numCols = list_length(groupClause);
475 : 26030 : int colno = 0;
476 : : Oid *groupOperators;
477 : : ListCell *glitem;
478 : :
95 michael@paquier.xyz 479 :GNC 26030 : groupOperators = palloc_array(Oid, numCols);
480 : :
6429 tgl@sss.pgh.pa.us 481 [ + + + + :CBC 33393 : foreach(glitem, groupClause)
+ + ]
482 : : {
483 : 7363 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
484 : :
485 : 7363 : groupOperators[colno] = groupcl->eqop;
486 [ - + ]: 7363 : Assert(OidIsValid(groupOperators[colno]));
487 : 7363 : colno++;
488 : : }
489 : :
490 : 26030 : return groupOperators;
491 : : }
492 : :
493 : : /*
494 : : * extract_grouping_collations - make an array of the grouping column collations
495 : : * for a SortGroupClause list
496 : : */
497 : : Oid *
2550 peter@eisentraut.org 498 : 26030 : extract_grouping_collations(List *groupClause, List *tlist)
499 : : {
500 : 26030 : int numCols = list_length(groupClause);
501 : 26030 : int colno = 0;
502 : : Oid *grpCollations;
503 : : ListCell *glitem;
504 : :
95 michael@paquier.xyz 505 :GNC 26030 : grpCollations = palloc_array(Oid, numCols);
506 : :
2550 peter@eisentraut.org 507 [ + + + + :CBC 33393 : foreach(glitem, groupClause)
+ + ]
508 : : {
509 : 7363 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
510 : 7363 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
511 : :
512 : 7363 : grpCollations[colno++] = exprCollation((Node *) tle->expr);
513 : : }
514 : :
515 : 26030 : return grpCollations;
516 : : }
517 : :
518 : : /*
519 : : * extract_grouping_cols - make an array of the grouping column resnos
520 : : * for a SortGroupClause list
521 : : */
522 : : AttrNumber *
6429 tgl@sss.pgh.pa.us 523 : 24980 : extract_grouping_cols(List *groupClause, List *tlist)
524 : : {
525 : : AttrNumber *grpColIdx;
526 : 24980 : int numCols = list_length(groupClause);
527 : 24980 : int colno = 0;
528 : : ListCell *glitem;
529 : :
95 michael@paquier.xyz 530 :GNC 24980 : grpColIdx = palloc_array(AttrNumber, numCols);
531 : :
6429 tgl@sss.pgh.pa.us 532 [ + + + + :CBC 30995 : foreach(glitem, groupClause)
+ + ]
533 : : {
534 : 6015 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
535 : 6015 : TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
536 : :
537 : 6015 : grpColIdx[colno++] = tle->resno;
538 : : }
539 : :
540 : 24980 : return grpColIdx;
541 : : }
542 : :
543 : : /*
544 : : * grouping_is_sortable - is it possible to implement grouping list by sorting?
545 : : *
546 : : * This is easy since the parser will have included a sortop if one exists.
547 : : */
548 : : bool
549 : 35868 : grouping_is_sortable(List *groupClause)
550 : : {
551 : : ListCell *glitem;
552 : :
553 [ + + + + : 58205 : foreach(glitem, groupClause)
+ + ]
554 : : {
555 : 22447 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
556 : :
557 [ + + ]: 22447 : if (!OidIsValid(groupcl->sortop))
558 : 110 : return false;
559 : : }
560 : 35758 : return true;
561 : : }
562 : :
563 : : /*
564 : : * grouping_is_hashable - is it possible to implement grouping list by hashing?
565 : : *
566 : : * We rely on the parser to have set the hashable flag correctly.
567 : : */
568 : : bool
569 : 6561 : grouping_is_hashable(List *groupClause)
570 : : {
571 : : ListCell *glitem;
572 : :
573 [ + + + + : 19848 : foreach(glitem, groupClause)
+ + ]
574 : : {
575 : 13359 : SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
576 : :
5615 577 [ + + ]: 13359 : if (!groupcl->hashable)
6429 578 : 72 : return false;
579 : : }
580 : 6489 : return true;
581 : : }
582 : :
583 : :
584 : : /*****************************************************************************
585 : : * PathTarget manipulation functions
586 : : *
587 : : * PathTarget is a somewhat stripped-down version of a full targetlist; it
588 : : * omits all the TargetEntry decoration except (optionally) sortgroupref data,
589 : : * and it adds evaluation cost and output data width info.
590 : : *****************************************************************************/
591 : :
592 : : /*
593 : : * make_pathtarget_from_tlist
594 : : * Construct a PathTarget equivalent to the given targetlist.
595 : : *
596 : : * This leaves the cost and width fields as zeroes. Most callers will want
597 : : * to use create_pathtarget(), so as to get those set.
598 : : */
599 : : PathTarget *
3660 600 : 297042 : make_pathtarget_from_tlist(List *tlist)
601 : : {
3653 602 : 297042 : PathTarget *target = makeNode(PathTarget);
603 : : int i;
604 : : ListCell *lc;
605 : :
3660 606 : 297042 : target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
607 : :
608 : 297042 : i = 0;
609 [ + + + + : 1116430 : foreach(lc, tlist)
+ + ]
610 : : {
611 : 819388 : TargetEntry *tle = (TargetEntry *) lfirst(lc);
612 : :
613 : 819388 : target->exprs = lappend(target->exprs, tle->expr);
614 : 819388 : target->sortgrouprefs[i] = tle->ressortgroupref;
615 : 819388 : i++;
616 : : }
617 : :
618 : : /*
619 : : * Mark volatility as unknown. The contain_volatile_functions function
620 : : * will determine if there are any volatile functions when called for the
621 : : * first time with this PathTarget.
622 : : */
1812 drowley@postgresql.o 623 : 297042 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
624 : :
3660 tgl@sss.pgh.pa.us 625 : 297042 : return target;
626 : : }
627 : :
628 : : /*
629 : : * make_tlist_from_pathtarget
630 : : * Construct a targetlist from a PathTarget.
631 : : */
632 : : List *
633 : 37373 : make_tlist_from_pathtarget(PathTarget *target)
634 : : {
635 : 37373 : List *tlist = NIL;
636 : : int i;
637 : : ListCell *lc;
638 : :
639 : 37373 : i = 0;
640 [ + + + + : 171591 : foreach(lc, target->exprs)
+ + ]
641 : : {
642 : 134218 : Expr *expr = (Expr *) lfirst(lc);
643 : : TargetEntry *tle;
644 : :
645 : 134218 : tle = makeTargetEntry(expr,
646 : 134218 : i + 1,
647 : : NULL,
648 : : false);
649 [ + + ]: 134218 : if (target->sortgrouprefs)
650 : 130678 : tle->ressortgroupref = target->sortgrouprefs[i];
651 : 134218 : tlist = lappend(tlist, tle);
652 : 134218 : i++;
653 : : }
654 : :
655 : 37373 : return tlist;
656 : : }
657 : :
658 : : /*
659 : : * copy_pathtarget
660 : : * Copy a PathTarget.
661 : : *
662 : : * The new PathTarget has its own exprs List, but shares the underlying
663 : : * target expression trees with the old one.
664 : : */
665 : : PathTarget *
3658 666 : 14066 : copy_pathtarget(PathTarget *src)
667 : : {
3653 668 : 14066 : PathTarget *dst = makeNode(PathTarget);
669 : :
670 : : /* Copy scalar fields */
3658 671 : 14066 : memcpy(dst, src, sizeof(PathTarget));
672 : : /* Shallow-copy the expression list */
673 : 14066 : dst->exprs = list_copy(src->exprs);
674 : : /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
675 [ + + ]: 14066 : if (src->sortgrouprefs)
676 : : {
677 : 13415 : Size nbytes = list_length(src->exprs) * sizeof(Index);
678 : :
679 : 13415 : dst->sortgrouprefs = (Index *) palloc(nbytes);
680 : 13415 : memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
681 : : }
682 : 14066 : return dst;
683 : : }
684 : :
685 : : /*
686 : : * create_empty_pathtarget
687 : : * Create an empty (zero columns, zero cost) PathTarget.
688 : : */
689 : : PathTarget *
3656 690 : 965312 : create_empty_pathtarget(void)
691 : : {
692 : : /* This is easy, but we don't want callers to hard-wire this ... */
3653 693 : 965312 : return makeNode(PathTarget);
694 : : }
695 : :
696 : : /*
697 : : * add_column_to_pathtarget
698 : : * Append a target column to the PathTarget.
699 : : *
700 : : * As with make_pathtarget_from_tlist, we leave it to the caller to update
701 : : * the cost and width fields.
702 : : */
703 : : void
3658 704 : 42162 : add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
705 : : {
706 : : /* Updating the exprs list is easy ... */
707 : 42162 : target->exprs = lappend(target->exprs, expr);
708 : : /* ... the sortgroupref data, a bit less so */
709 [ + + ]: 42162 : if (target->sortgrouprefs)
710 : : {
711 : 13263 : int nexprs = list_length(target->exprs);
712 : :
713 : : /* This might look inefficient, but actually it's usually cheap */
714 : 13263 : target->sortgrouprefs = (Index *)
715 : 13263 : repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
716 : 13263 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
717 : : }
718 [ + + ]: 28899 : else if (sortgroupref)
719 : : {
720 : : /* Adding sortgroupref labeling to a previously unlabeled target */
721 : 9838 : int nexprs = list_length(target->exprs);
722 : :
723 : 9838 : target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
724 : 9838 : target->sortgrouprefs[nexprs - 1] = sortgroupref;
725 : : }
726 : :
727 : : /*
728 : : * Reset has_volatile_expr to UNKNOWN. We just leave it up to
729 : : * contain_volatile_functions to set this properly again. Technically we
730 : : * could save some effort here and just check the new Expr, but it seems
731 : : * better to keep the logic for setting this flag in one location rather
732 : : * than duplicating the logic here.
733 : : */
1812 drowley@postgresql.o 734 [ - + ]: 42162 : if (target->has_volatile_expr == VOLATILITY_NOVOLATILE)
1812 drowley@postgresql.o 735 :UBC 0 : target->has_volatile_expr = VOLATILITY_UNKNOWN;
3658 tgl@sss.pgh.pa.us 736 :CBC 42162 : }
737 : :
738 : : /*
739 : : * add_new_column_to_pathtarget
740 : : * Append a target column to the PathTarget, but only if it's not
741 : : * equal() to any pre-existing target expression.
742 : : *
743 : : * The caller cannot specify a sortgroupref, since it would be unclear how
744 : : * to merge that with a pre-existing column.
745 : : *
746 : : * As with make_pathtarget_from_tlist, we leave it to the caller to update
747 : : * the cost and width fields.
748 : : */
749 : : void
3656 750 : 28307 : add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
751 : : {
752 [ + + ]: 28307 : if (!list_member(target->exprs, expr))
753 : 23152 : add_column_to_pathtarget(target, expr, 0);
754 : 28307 : }
755 : :
756 : : /*
757 : : * add_new_columns_to_pathtarget
758 : : * Apply add_new_column_to_pathtarget() for each element of the list.
759 : : */
760 : : void
761 : 26993 : add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
762 : : {
763 : : ListCell *lc;
764 : :
765 [ + + + + : 52928 : foreach(lc, exprs)
+ + ]
766 : : {
767 : 25935 : Expr *expr = (Expr *) lfirst(lc);
768 : :
769 : 25935 : add_new_column_to_pathtarget(target, expr);
770 : : }
771 : 26993 : }
772 : :
773 : : /*
774 : : * apply_pathtarget_labeling_to_tlist
775 : : * Apply any sortgrouprefs in the PathTarget to matching tlist entries
776 : : *
777 : : * Here, we do not assume that the tlist entries are one-for-one with the
778 : : * PathTarget. The intended use of this function is to deal with cases
779 : : * where createplan.c has decided to use some other tlist and we have
780 : : * to identify what matches exist.
781 : : */
782 : : void
3660 783 : 11678 : apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
784 : : {
785 : : int i;
786 : : ListCell *lc;
787 : :
788 : : /* Nothing to do if PathTarget has no sortgrouprefs data */
789 [ + + ]: 11678 : if (target->sortgrouprefs == NULL)
790 : 10683 : return;
791 : :
792 : 995 : i = 0;
793 [ + - + + : 2731 : foreach(lc, target->exprs)
+ + ]
794 : : {
795 : 1736 : Expr *expr = (Expr *) lfirst(lc);
796 : : TargetEntry *tle;
797 : :
798 [ + + ]: 1736 : if (target->sortgrouprefs[i])
799 : : {
800 : : /*
801 : : * For Vars, use tlist_member_match_var's weakened matching rule;
802 : : * this allows us to deal with some cases where a set-returning
803 : : * function has been inlined, so that we now have more knowledge
804 : : * about what it returns than we did when the original Var was
805 : : * created. Otherwise, use regular equal() to find the matching
806 : : * TLE. (In current usage, only the Var case is actually needed;
807 : : * but it seems best to have sane behavior here for non-Vars too.)
808 : : */
809 [ + - + - ]: 1377 : if (expr && IsA(expr, Var))
810 : 1377 : tle = tlist_member_match_var((Var *) expr, tlist);
811 : : else
3293 peter_e@gmx.net 812 :UBC 0 : tle = tlist_member(expr, tlist);
813 : :
814 : : /*
815 : : * Complain if noplace for the sortgrouprefs label, or if we'd
816 : : * have to label a column twice. (The case where it already has
817 : : * the desired label probably can't happen, but we may as well
818 : : * allow for it.)
819 : : */
3580 tgl@sss.pgh.pa.us 820 [ - + ]:CBC 1377 : if (!tle)
3580 tgl@sss.pgh.pa.us 821 [ # # ]:UBC 0 : elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
3580 tgl@sss.pgh.pa.us 822 [ + + ]:CBC 1377 : if (tle->ressortgroupref != 0 &&
3580 tgl@sss.pgh.pa.us 823 [ - + ]:GBC 6 : tle->ressortgroupref != target->sortgrouprefs[i])
3580 tgl@sss.pgh.pa.us 824 [ # # ]:UBC 0 : elog(ERROR, "targetlist item has multiple sortgroupref labels");
825 : :
3580 tgl@sss.pgh.pa.us 826 :CBC 1377 : tle->ressortgroupref = target->sortgrouprefs[i];
827 : : }
3660 828 : 1736 : i++;
829 : : }
830 : : }
831 : :
832 : : /*
833 : : * split_pathtarget_at_srfs
834 : : * Split given PathTarget into multiple levels to position SRFs safely,
835 : : * performing exact matching against input_target.
836 : : *
837 : : * This is a wrapper for split_pathtarget_at_srfs_extended() that is used when
838 : : * both targets are on the same side of the grouping boundary (i.e., both are
839 : : * pre-grouping or both are post-grouping). In this case, no special handling
840 : : * for the grouping nulling bit is required.
841 : : *
842 : : * See split_pathtarget_at_srfs_extended() for more details.
843 : : */
844 : : void
80 rguo@postgresql.org 845 : 19557 : split_pathtarget_at_srfs(PlannerInfo *root,
846 : : PathTarget *target, PathTarget *input_target,
847 : : List **targets, List **targets_contain_srfs)
848 : : {
849 : 19557 : split_pathtarget_at_srfs_extended(root, target, input_target,
850 : : targets, targets_contain_srfs,
851 : : false);
852 : 19557 : }
853 : :
854 : : /*
855 : : * split_pathtarget_at_srfs_grouping
856 : : * Split given PathTarget into multiple levels to position SRFs safely,
857 : : * ignoring the grouping nulling bit when matching against input_target.
858 : : *
859 : : * This variant is used when the targets cross the grouping boundary (i.e.,
860 : : * target is post-grouping while input_target is pre-grouping). In this case,
861 : : * we need to ignore the grouping nulling bit when checking for expression
862 : : * availability to avoid incorrectly re-evaluating SRFs that have already been
863 : : * computed in input_target.
864 : : *
865 : : * See split_pathtarget_at_srfs_extended() for more details.
866 : : */
867 : : void
868 : 6519 : split_pathtarget_at_srfs_grouping(PlannerInfo *root,
869 : : PathTarget *target, PathTarget *input_target,
870 : : List **targets, List **targets_contain_srfs)
871 : : {
872 : 6519 : split_pathtarget_at_srfs_extended(root, target, input_target,
873 : : targets, targets_contain_srfs,
874 : : true);
875 : 6519 : }
876 : :
877 : : /*
878 : : * split_pathtarget_at_srfs_extended
879 : : * Split given PathTarget into multiple levels to position SRFs safely
880 : : *
881 : : * The executor can only handle set-returning functions that appear at the
882 : : * top level of the targetlist of a ProjectSet plan node. If we have any SRFs
883 : : * that are not at top level, we need to split up the evaluation into multiple
884 : : * plan levels in which each level satisfies this constraint. This function
885 : : * creates appropriate PathTarget(s) for each level.
886 : : *
887 : : * As an example, consider the tlist expression
888 : : * x + srf1(srf2(y + z))
889 : : * This expression should appear as-is in the top PathTarget, but below that
890 : : * we must have a PathTarget containing
891 : : * x, srf1(srf2(y + z))
892 : : * and below that, another PathTarget containing
893 : : * x, srf2(y + z)
894 : : * and below that, another PathTarget containing
895 : : * x, y, z
896 : : * When these tlists are processed by setrefs.c, subexpressions that match
897 : : * output expressions of the next lower tlist will be replaced by Vars,
898 : : * so that what the executor gets are tlists looking like
899 : : * Var1 + Var2
900 : : * Var1, srf1(Var2)
901 : : * Var1, srf2(Var2 + Var3)
902 : : * x, y, z
903 : : * which satisfy the desired property.
904 : : *
905 : : * Another example is
906 : : * srf1(x), srf2(srf3(y))
907 : : * That must appear as-is in the top PathTarget, but below that we need
908 : : * srf1(x), srf3(y)
909 : : * That is, each SRF must be computed at a level corresponding to the nesting
910 : : * depth of SRFs within its arguments.
911 : : *
912 : : * In some cases, a SRF has already been evaluated in some previous plan level
913 : : * and we shouldn't expand it again (that is, what we see in the target is
914 : : * already meant as a reference to a lower subexpression). So, don't expand
915 : : * any tlist expressions that appear in input_target, if that's not NULL.
916 : : *
917 : : * This check requires extra care when processing the grouping target
918 : : * (indicated by the is_grouping_target flag). In this case input_target is
919 : : * pre-grouping while target is post-grouping, so the latter may carry
920 : : * nullingrels bits from the grouping step that are absent in the former. We
921 : : * must ignore those bits to correctly recognize that the tlist expressions are
922 : : * available in input_target.
923 : : *
924 : : * It's also important that we preserve any sortgroupref annotation appearing
925 : : * in the given target, especially on expressions matching input_target items.
926 : : *
927 : : * The outputs of this function are two parallel lists, one a list of
928 : : * PathTargets and the other an integer list of bool flags indicating
929 : : * whether the corresponding PathTarget contains any evaluable SRFs.
930 : : * The lists are given in the order they'd need to be evaluated in, with
931 : : * the "lowest" PathTarget first. So the last list entry is always the
932 : : * originally given PathTarget, and any entries before it indicate evaluation
933 : : * levels that must be inserted below it. The first list entry must not
934 : : * contain any SRFs (other than ones duplicating input_target entries), since
935 : : * it will typically be attached to a plan node that cannot evaluate SRFs.
936 : : *
937 : : * Note: using a list for the flags may seem like overkill, since there
938 : : * are only a few possible patterns for which levels contain SRFs.
939 : : * But this representation decouples callers from that knowledge.
940 : : */
941 : : static void
942 : 26076 : split_pathtarget_at_srfs_extended(PlannerInfo *root,
943 : : PathTarget *target, PathTarget *input_target,
944 : : List **targets, List **targets_contain_srfs,
945 : : bool is_grouping_target)
946 : : {
947 : : split_pathtarget_context context;
948 : : int max_depth;
949 : : bool need_extra_projection;
950 : : List *prev_level_tlist;
951 : : int lci;
952 : : ListCell *lc,
953 : : *lc1,
954 : : *lc2,
955 : : *lc3;
956 : :
957 : : /*
958 : : * It's not unusual for planner.c to pass us two physically identical
959 : : * targets, in which case we can conclude without further ado that all
960 : : * expressions are available from the input. (The logic below would
961 : : * arrive at the same conclusion, but much more tediously.)
962 : : */
3328 tgl@sss.pgh.pa.us 963 [ + + ]: 26076 : if (target == input_target)
964 : : {
965 : 19272 : *targets = list_make1(target);
966 : 19272 : *targets_contain_srfs = list_make1_int(false);
967 : 19272 : return;
968 : : }
969 : :
970 : : /*
971 : : * Pass 'root', the is_grouping_target flag, and any input_target exprs
972 : : * down to split_pathtarget_walker().
973 : : */
80 rguo@postgresql.org 974 : 6804 : context.root = root;
975 : 6804 : context.is_grouping_target = is_grouping_target;
3328 tgl@sss.pgh.pa.us 976 [ + + ]: 6804 : context.input_target_exprs = input_target ? input_target->exprs : NIL;
977 : :
978 : : /*
979 : : * Initialize with empty level-zero lists, and no levels after that.
980 : : * (Note: we could dispense with representing level zero explicitly, since
981 : : * it will never receive any SRFs, but then we'd have to special-case that
982 : : * level when we get to building result PathTargets. Level zero describes
983 : : * the SRF-free PathTarget that will be given to the input plan node.)
984 : : */
985 : 6804 : context.level_srfs = list_make1(NIL);
986 : 6804 : context.level_input_vars = list_make1(NIL);
987 : 6804 : context.level_input_srfs = list_make1(NIL);
988 : :
989 : : /* Initialize data we'll accumulate across all the target expressions */
990 : 6804 : context.current_input_vars = NIL;
991 : 6804 : context.current_input_srfs = NIL;
992 : 6804 : max_depth = 0;
993 : 6804 : need_extra_projection = false;
994 : :
995 : : /* Scan each expression in the PathTarget looking for SRFs */
2824 996 : 6804 : lci = 0;
3328 997 [ + - + + : 15762 : foreach(lc, target->exprs)
+ + ]
998 : : {
999 : 8958 : Node *node = (Node *) lfirst(lc);
1000 : :
1001 : : /* Tell split_pathtarget_walker about this expr's sortgroupref */
2824 1002 [ + + ]: 8958 : context.current_sgref = get_pathtarget_sortgroupref(target, lci);
1003 : 8958 : lci++;
1004 : :
1005 : : /*
1006 : : * Find all SRFs and Vars (and Var-like nodes) in this expression, and
1007 : : * enter them into appropriate lists within the context struct.
1008 : : */
3328 1009 : 8958 : context.current_depth = 0;
1010 : 8958 : split_pathtarget_walker(node, &context);
1011 : :
1012 : : /* An expression containing no SRFs is of no further interest */
1013 [ + + ]: 8958 : if (context.current_depth == 0)
1014 : 1462 : continue;
1015 : :
1016 : : /*
1017 : : * Track max SRF nesting depth over the whole PathTarget. Also, if
1018 : : * this expression establishes a new max depth, we no longer care
1019 : : * whether previous expressions contained nested SRFs; we can handle
1020 : : * any required projection for them in the final ProjectSet node.
1021 : : */
1022 [ + + ]: 7496 : if (max_depth < context.current_depth)
1023 : : {
1024 : 6525 : max_depth = context.current_depth;
1025 : 6525 : need_extra_projection = false;
1026 : : }
1027 : :
1028 : : /*
1029 : : * If any maximum-depth SRF is not at the top level of its expression,
1030 : : * we'll need an extra Result node to compute the top-level scalar
1031 : : * expression.
1032 : : */
1033 [ + + + + : 7496 : if (max_depth == context.current_depth && !IS_SRF_CALL(node))
+ + + + +
+ ]
1034 : 1248 : need_extra_projection = true;
1035 : : }
1036 : :
1037 : : /*
1038 : : * If we found no SRFs needing evaluation (maybe they were all present in
1039 : : * input_target, or maybe they were all removed by const-simplification),
1040 : : * then no ProjectSet is needed; fall out.
1041 : : */
1042 [ + + ]: 6804 : if (max_depth == 0)
1043 : : {
1044 : 285 : *targets = list_make1(target);
1045 : 285 : *targets_contain_srfs = list_make1_int(false);
1046 : 285 : return;
1047 : : }
1048 : :
1049 : : /*
1050 : : * The Vars and SRF outputs needed at top level can be added to the last
1051 : : * level_input lists if we don't need an extra projection step. If we do
1052 : : * need one, add a SRF-free level to the lists.
1053 : : */
1054 [ + + ]: 6519 : if (need_extra_projection)
1055 : : {
1056 : 567 : context.level_srfs = lappend(context.level_srfs, NIL);
1057 : 1134 : context.level_input_vars = lappend(context.level_input_vars,
1058 : 567 : context.current_input_vars);
1059 : 567 : context.level_input_srfs = lappend(context.level_input_srfs,
1060 : 567 : context.current_input_srfs);
1061 : : }
1062 : : else
1063 : : {
1064 : 5952 : lc = list_nth_cell(context.level_input_vars, max_depth);
1065 : 5952 : lfirst(lc) = list_concat(lfirst(lc), context.current_input_vars);
1066 : 5952 : lc = list_nth_cell(context.level_input_srfs, max_depth);
1067 : 5952 : lfirst(lc) = list_concat(lfirst(lc), context.current_input_srfs);
1068 : : }
1069 : :
1070 : : /*
1071 : : * Now construct the output PathTargets. The original target can be used
1072 : : * as-is for the last one, but we need to construct a new SRF-free target
1073 : : * representing what the preceding plan node has to emit, as well as a
1074 : : * target for each intermediate ProjectSet node.
1075 : : */
1076 : 6519 : *targets = *targets_contain_srfs = NIL;
1077 : 6519 : prev_level_tlist = NIL;
1078 : :
1079 [ + - + + : 20154 : forthree(lc1, context.level_srfs,
+ - + + +
- + + + +
+ - + - +
+ ]
1080 : : lc2, context.level_input_vars,
1081 : : lc3, context.level_input_srfs)
1082 : : {
1083 : 13635 : List *level_srfs = (List *) lfirst(lc1);
1084 : : PathTarget *ntarget;
1085 : :
2435 1086 [ + + ]: 13635 : if (lnext(context.level_srfs, lc1) == NULL)
1087 : : {
3328 1088 : 6519 : ntarget = target;
1089 : : }
1090 : : else
1091 : : {
1092 : 7116 : ntarget = create_empty_pathtarget();
1093 : :
1094 : : /*
1095 : : * This target should actually evaluate any SRFs of the current
1096 : : * level, and it needs to propagate forward any Vars needed by
1097 : : * later levels, as well as SRFs computed earlier and needed by
1098 : : * later levels.
1099 : : */
2824 1100 : 7116 : add_sp_items_to_pathtarget(ntarget, level_srfs);
2435 1101 [ + - + + : 14847 : for_each_cell(lc, context.level_input_vars,
+ + ]
1102 : : lnext(context.level_input_vars, lc2))
1103 : : {
3328 1104 : 7731 : List *input_vars = (List *) lfirst(lc);
1105 : :
2824 1106 : 7731 : add_sp_items_to_pathtarget(ntarget, input_vars);
1107 : : }
2435 1108 [ + - + + : 14847 : for_each_cell(lc, context.level_input_srfs,
+ + ]
1109 : : lnext(context.level_input_srfs, lc3))
1110 : : {
3328 1111 : 7731 : List *input_srfs = (List *) lfirst(lc);
1112 : : ListCell *lcx;
1113 : :
1114 [ + + + + : 16652 : foreach(lcx, input_srfs)
+ + ]
1115 : : {
2824 1116 : 8921 : split_pathtarget_item *item = lfirst(lcx);
1117 : :
1118 [ + + ]: 8921 : if (list_member(prev_level_tlist, item->expr))
1119 : 18 : add_sp_item_to_pathtarget(ntarget, item);
1120 : : }
1121 : : }
3328 1122 : 7116 : set_pathtarget_cost_width(root, ntarget);
1123 : : }
1124 : :
1125 : : /*
1126 : : * Add current target and does-it-compute-SRFs flag to output lists.
1127 : : */
1128 : 13635 : *targets = lappend(*targets, ntarget);
1129 : 13635 : *targets_contain_srfs = lappend_int(*targets_contain_srfs,
1130 : : (level_srfs != NIL));
1131 : :
1132 : : /* Remember this level's output for next pass */
1133 : 13635 : prev_level_tlist = ntarget->exprs;
1134 : : }
1135 : : }
1136 : :
1137 : : /*
1138 : : * Recursively examine expressions for split_pathtarget_at_srfs.
1139 : : *
1140 : : * Note we make no effort here to prevent duplicate entries in the output
1141 : : * lists. Duplicates will be gotten rid of later.
1142 : : */
1143 : : static bool
3343 andres@anarazel.de 1144 : 27461 : split_pathtarget_walker(Node *node, split_pathtarget_context *context)
1145 : : {
80 rguo@postgresql.org 1146 : 27461 : Node *sanitized_node = node;
1147 : :
3343 andres@anarazel.de 1148 [ + + ]: 27461 : if (node == NULL)
1149 : 53 : return false;
1150 : :
1151 : : /*
1152 : : * If we are crossing the grouping boundary (post-grouping target vs
1153 : : * pre-grouping input_target), we must ignore the grouping nulling bit to
1154 : : * correctly check if the subexpression is available in input_target. This
1155 : : * aligns with the matching logic in set_upper_references().
1156 : : */
80 rguo@postgresql.org 1157 [ + + ]: 27408 : if (context->is_grouping_target &&
1158 [ + + ]: 2280 : context->root->parse->hasGroupRTE &&
1159 [ + + ]: 303 : context->root->parse->groupingSets != NIL)
1160 : : {
1161 : : sanitized_node =
1162 : 117 : remove_nulling_relids(node,
1163 : 117 : bms_make_singleton(context->root->group_rtindex),
1164 : : NULL);
1165 : : }
1166 : :
1167 : : /*
1168 : : * A subexpression that matches an expression already computed in
1169 : : * input_target can be treated like a Var (which indeed it will be after
1170 : : * setrefs.c gets done with it), even if it's actually a SRF. Record it
1171 : : * as being needed for the current expression, and ignore any
1172 : : * substructure. (Note in particular that this preserves the identity of
1173 : : * any expressions that appear as sortgrouprefs in input_target.)
1174 : : */
1175 [ + + ]: 27408 : if (list_member(context->input_target_exprs, sanitized_node))
1176 : : {
95 michael@paquier.xyz 1177 :GNC 216 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1178 : :
2824 tgl@sss.pgh.pa.us 1179 :CBC 216 : item->expr = node;
1180 : 216 : item->sortgroupref = context->current_sgref;
3328 1181 : 216 : context->current_input_vars = lappend(context->current_input_vars,
1182 : : item);
1183 : 216 : return false;
1184 : : }
1185 : :
1186 : : /*
1187 : : * Vars and Var-like constructs are expected to be gotten from the input,
1188 : : * too. We assume that these constructs cannot contain any SRFs (if one
1189 : : * does, there will be an executor failure from a misplaced SRF).
1190 : : */
3343 andres@anarazel.de 1191 [ + + ]: 27192 : if (IsA(node, Var) ||
1192 [ + + ]: 25151 : IsA(node, PlaceHolderVar) ||
1193 [ + + ]: 25127 : IsA(node, Aggref) ||
1194 [ + - ]: 24392 : IsA(node, GroupingFunc) ||
1195 [ + + ]: 24392 : IsA(node, WindowFunc))
1196 : : {
95 michael@paquier.xyz 1197 :GNC 2809 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
1198 : :
2824 tgl@sss.pgh.pa.us 1199 :CBC 2809 : item->expr = node;
1200 : 2809 : item->sortgroupref = context->current_sgref;
3328 1201 : 2809 : context->current_input_vars = lappend(context->current_input_vars,
1202 : : item);
3343 andres@anarazel.de 1203 : 2809 : return false;
1204 : : }
1205 : :
1206 : : /*
1207 : : * If it's a SRF, recursively examine its inputs, determine its level, and
1208 : : * make appropriate entries in the output lists.
1209 : : */
3328 tgl@sss.pgh.pa.us 1210 [ + + + + : 24383 : if (IS_SRF_CALL(node))
+ + + + ]
1211 : : {
95 michael@paquier.xyz 1212 :GNC 7529 : split_pathtarget_item *item = palloc_object(split_pathtarget_item);
3328 tgl@sss.pgh.pa.us 1213 :CBC 7529 : List *save_input_vars = context->current_input_vars;
1214 : 7529 : List *save_input_srfs = context->current_input_srfs;
1215 : 7529 : int save_current_depth = context->current_depth;
1216 : : int srf_depth;
1217 : : ListCell *lc;
1218 : :
2824 1219 : 7529 : item->expr = node;
1220 : 7529 : item->sortgroupref = context->current_sgref;
1221 : :
3328 1222 : 7529 : context->current_input_vars = NIL;
1223 : 7529 : context->current_input_srfs = NIL;
1224 : 7529 : context->current_depth = 0;
2824 1225 : 7529 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
1226 : :
472 peter@eisentraut.org 1227 : 7529 : (void) expression_tree_walker(node, split_pathtarget_walker, context);
1228 : :
1229 : : /* Depth is one more than any SRF below it */
3328 tgl@sss.pgh.pa.us 1230 : 7529 : srf_depth = context->current_depth + 1;
1231 : :
1232 : : /* If new record depth, initialize another level of output lists */
1233 [ + + ]: 7529 : if (srf_depth >= list_length(context->level_srfs))
1234 : : {
1235 : 6549 : context->level_srfs = lappend(context->level_srfs, NIL);
1236 : 6549 : context->level_input_vars = lappend(context->level_input_vars, NIL);
1237 : 6549 : context->level_input_srfs = lappend(context->level_input_srfs, NIL);
1238 : : }
1239 : :
1240 : : /* Record this SRF as needing to be evaluated at appropriate level */
1241 : 7529 : lc = list_nth_cell(context->level_srfs, srf_depth);
2824 1242 : 7529 : lfirst(lc) = lappend(lfirst(lc), item);
1243 : :
1244 : : /* Record its inputs as being needed at the same level */
3328 1245 : 7529 : lc = list_nth_cell(context->level_input_vars, srf_depth);
1246 : 7529 : lfirst(lc) = list_concat(lfirst(lc), context->current_input_vars);
1247 : 7529 : lc = list_nth_cell(context->level_input_srfs, srf_depth);
1248 : 7529 : lfirst(lc) = list_concat(lfirst(lc), context->current_input_srfs);
1249 : :
1250 : : /*
1251 : : * Restore caller-level state and update it for presence of this SRF.
1252 : : * Notice we report the SRF itself as being needed for evaluation of
1253 : : * surrounding expression.
1254 : : */
1255 : 7529 : context->current_input_vars = save_input_vars;
2824 1256 : 7529 : context->current_input_srfs = lappend(save_input_srfs, item);
3328 1257 : 7529 : context->current_depth = Max(save_current_depth, srf_depth);
1258 : :
1259 : : /* We're done here */
3343 andres@anarazel.de 1260 : 7529 : return false;
1261 : : }
1262 : :
1263 : : /*
1264 : : * Otherwise, the node is a scalar (non-set) expression, so recurse to
1265 : : * examine its inputs.
1266 : : */
2824 tgl@sss.pgh.pa.us 1267 : 16854 : context->current_sgref = 0; /* subexpressions are not sortgroup items */
472 peter@eisentraut.org 1268 : 16854 : return expression_tree_walker(node, split_pathtarget_walker, context);
1269 : : }
1270 : :
1271 : : /*
1272 : : * Add a split_pathtarget_item to the PathTarget, unless a matching item is
1273 : : * already present. This is like add_new_column_to_pathtarget, but allows
1274 : : * for sortgrouprefs to be handled. An item having zero sortgroupref can
1275 : : * be merged with one that has a sortgroupref, acquiring the latter's
1276 : : * sortgroupref.
1277 : : *
1278 : : * Note that we don't worry about possibly adding duplicate sortgrouprefs
1279 : : * to the PathTarget. That would be bad, but it should be impossible unless
1280 : : * the target passed to split_pathtarget_at_srfs already had duplicates.
1281 : : * As long as it didn't, we can have at most one split_pathtarget_item with
1282 : : * any particular nonzero sortgroupref.
1283 : : */
1284 : : static void
2824 tgl@sss.pgh.pa.us 1285 : 4156 : add_sp_item_to_pathtarget(PathTarget *target, split_pathtarget_item *item)
1286 : : {
1287 : : int lci;
1288 : : ListCell *lc;
1289 : :
1290 : : /*
1291 : : * Look for a pre-existing entry that is equal() and does not have a
1292 : : * conflicting sortgroupref already.
1293 : : */
1294 : 4156 : lci = 0;
1295 [ + + + + : 5672 : foreach(lc, target->exprs)
+ + ]
1296 : : {
1297 : 3124 : Node *node = (Node *) lfirst(lc);
1298 [ + + ]: 3124 : Index sgref = get_pathtarget_sortgroupref(target, lci);
1299 : :
1300 [ + + ]: 3124 : if ((item->sortgroupref == sgref ||
1301 [ + + + + ]: 150 : item->sortgroupref == 0 ||
1302 [ + + ]: 3097 : sgref == 0) &&
1303 : 3097 : equal(item->expr, node))
1304 : : {
1305 : : /* Found a match. Assign item's sortgroupref if it has one. */
1306 [ + + ]: 1608 : if (item->sortgroupref)
1307 : : {
1308 [ + + ]: 12 : if (target->sortgrouprefs == NULL)
1309 : : {
1310 : 6 : target->sortgrouprefs = (Index *)
1311 : 6 : palloc0(list_length(target->exprs) * sizeof(Index));
1312 : : }
1313 : 12 : target->sortgrouprefs[lci] = item->sortgroupref;
1314 : : }
1315 : 1608 : return;
1316 : : }
1317 : 1516 : lci++;
1318 : : }
1319 : :
1320 : : /*
1321 : : * No match, so add item to PathTarget. Copy the expr for safety.
1322 : : */
1323 : 2548 : add_column_to_pathtarget(target, (Expr *) copyObject(item->expr),
1324 : : item->sortgroupref);
1325 : : }
1326 : :
1327 : : /*
1328 : : * Apply add_sp_item_to_pathtarget to each element of list.
1329 : : */
1330 : : static void
1331 : 14847 : add_sp_items_to_pathtarget(PathTarget *target, List *items)
1332 : : {
1333 : : ListCell *lc;
1334 : :
1335 [ + + + + : 18985 : foreach(lc, items)
+ + ]
1336 : : {
1337 : 4138 : split_pathtarget_item *item = lfirst(lc);
1338 : :
1339 : 4138 : add_sp_item_to_pathtarget(target, item);
1340 : : }
1341 : 14847 : }
|