1 /*-------------------------------------------------------------------------
2 *
3 * tlist.c
4 * Target list manipulation routines
5 *
6 * Portions Copyright (c) 1996-2016, 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/tlist.h"
20
21
22 /*****************************************************************************
23 * Target list creation and searching utilities
24 *****************************************************************************/
25
26 /*
27 * tlist_member
28 * Finds the (first) member of the given tlist whose expression is
29 * equal() to the given expression. Result is NULL if no such member.
30 */
31 TargetEntry *
tlist_member(Node * node,List * targetlist)32 tlist_member(Node *node, List *targetlist)
33 {
34 ListCell *temp;
35
36 foreach(temp, targetlist)
37 {
38 TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
39
40 if (equal(node, tlentry->expr))
41 return tlentry;
42 }
43 return NULL;
44 }
45
46 /*
47 * tlist_member_ignore_relabel
48 * Same as above, except that we ignore top-level RelabelType nodes
49 * while checking for a match. This is needed for some scenarios
50 * involving binary-compatible sort operations.
51 */
52 TargetEntry *
tlist_member_ignore_relabel(Node * node,List * targetlist)53 tlist_member_ignore_relabel(Node *node, List *targetlist)
54 {
55 ListCell *temp;
56
57 while (node && IsA(node, RelabelType))
58 node = (Node *) ((RelabelType *) node)->arg;
59
60 foreach(temp, targetlist)
61 {
62 TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
63 Expr *tlexpr = tlentry->expr;
64
65 while (tlexpr && IsA(tlexpr, RelabelType))
66 tlexpr = ((RelabelType *) tlexpr)->arg;
67
68 if (equal(node, tlexpr))
69 return tlentry;
70 }
71 return NULL;
72 }
73
74 /*
75 * tlist_member_match_var
76 * Same as above, except that we match the provided Var on the basis
77 * of varno/varattno/varlevelsup/vartype only, rather than full equal().
78 *
79 * This is needed in some cases where we can't be sure of an exact typmod
80 * match. For safety, though, we insist on vartype match.
81 */
82 static TargetEntry *
tlist_member_match_var(Var * var,List * targetlist)83 tlist_member_match_var(Var *var, List *targetlist)
84 {
85 ListCell *temp;
86
87 foreach(temp, targetlist)
88 {
89 TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
90 Var *tlvar = (Var *) tlentry->expr;
91
92 if (!tlvar || !IsA(tlvar, Var))
93 continue;
94 if (var->varno == tlvar->varno &&
95 var->varattno == tlvar->varattno &&
96 var->varlevelsup == tlvar->varlevelsup &&
97 var->vartype == tlvar->vartype)
98 return tlentry;
99 }
100 return NULL;
101 }
102
103 /*
104 * add_to_flat_tlist
105 * Add more items to a flattened tlist (if they're not already in it)
106 *
107 * 'tlist' is the flattened tlist
108 * 'exprs' is a list of expressions (usually, but not necessarily, Vars)
109 *
110 * Returns the extended tlist.
111 */
112 List *
add_to_flat_tlist(List * tlist,List * exprs)113 add_to_flat_tlist(List *tlist, List *exprs)
114 {
115 int next_resno = list_length(tlist) + 1;
116 ListCell *lc;
117
118 foreach(lc, exprs)
119 {
120 Node *expr = (Node *) lfirst(lc);
121
122 if (!tlist_member(expr, tlist))
123 {
124 TargetEntry *tle;
125
126 tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
127 next_resno++,
128 NULL,
129 false);
130 tlist = lappend(tlist, tle);
131 }
132 }
133 return tlist;
134 }
135
136
137 /*
138 * get_tlist_exprs
139 * Get just the expression subtrees of a tlist
140 *
141 * Resjunk columns are ignored unless includeJunk is true
142 */
143 List *
get_tlist_exprs(List * tlist,bool includeJunk)144 get_tlist_exprs(List *tlist, bool includeJunk)
145 {
146 List *result = NIL;
147 ListCell *l;
148
149 foreach(l, tlist)
150 {
151 TargetEntry *tle = (TargetEntry *) lfirst(l);
152
153 if (tle->resjunk && !includeJunk)
154 continue;
155
156 result = lappend(result, tle->expr);
157 }
158 return result;
159 }
160
161
162 /*
163 * count_nonjunk_tlist_entries
164 * What it says ...
165 */
166 int
count_nonjunk_tlist_entries(List * tlist)167 count_nonjunk_tlist_entries(List *tlist)
168 {
169 int len = 0;
170 ListCell *l;
171
172 foreach(l, tlist)
173 {
174 TargetEntry *tle = (TargetEntry *) lfirst(l);
175
176 if (!tle->resjunk)
177 len++;
178 }
179 return len;
180 }
181
182
183 /*
184 * tlist_same_exprs
185 * Check whether two target lists contain the same expressions
186 *
187 * Note: this function is used to decide whether it's safe to jam a new tlist
188 * into a non-projection-capable plan node. Obviously we can't do that unless
189 * the node's tlist shows it already returns the column values we want.
190 * However, we can ignore the TargetEntry attributes resname, ressortgroupref,
191 * resorigtbl, resorigcol, and resjunk, because those are only labelings that
192 * don't affect the row values computed by the node. (Moreover, if we didn't
193 * ignore them, we'd frequently fail to make the desired optimization, since
194 * the planner tends to not bother to make resname etc. valid in intermediate
195 * plan nodes.) Note that on success, the caller must still jam the desired
196 * tlist into the plan node, else it won't have the desired labeling fields.
197 */
198 bool
tlist_same_exprs(List * tlist1,List * tlist2)199 tlist_same_exprs(List *tlist1, List *tlist2)
200 {
201 ListCell *lc1,
202 *lc2;
203
204 if (list_length(tlist1) != list_length(tlist2))
205 return false; /* not same length, so can't match */
206
207 forboth(lc1, tlist1, lc2, tlist2)
208 {
209 TargetEntry *tle1 = (TargetEntry *) lfirst(lc1);
210 TargetEntry *tle2 = (TargetEntry *) lfirst(lc2);
211
212 if (!equal(tle1->expr, tle2->expr))
213 return false;
214 }
215
216 return true;
217 }
218
219
220 /*
221 * Does tlist have same output datatypes as listed in colTypes?
222 *
223 * Resjunk columns are ignored if junkOK is true; otherwise presence of
224 * a resjunk column will always cause a 'false' result.
225 *
226 * Note: currently no callers care about comparing typmods.
227 */
228 bool
tlist_same_datatypes(List * tlist,List * colTypes,bool junkOK)229 tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
230 {
231 ListCell *l;
232 ListCell *curColType = list_head(colTypes);
233
234 foreach(l, tlist)
235 {
236 TargetEntry *tle = (TargetEntry *) lfirst(l);
237
238 if (tle->resjunk)
239 {
240 if (!junkOK)
241 return false;
242 }
243 else
244 {
245 if (curColType == NULL)
246 return false; /* tlist longer than colTypes */
247 if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
248 return false;
249 curColType = lnext(curColType);
250 }
251 }
252 if (curColType != NULL)
253 return false; /* tlist shorter than colTypes */
254 return true;
255 }
256
257 /*
258 * Does tlist have same exposed collations as listed in colCollations?
259 *
260 * Identical logic to the above, but for collations.
261 */
262 bool
tlist_same_collations(List * tlist,List * colCollations,bool junkOK)263 tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
264 {
265 ListCell *l;
266 ListCell *curColColl = list_head(colCollations);
267
268 foreach(l, tlist)
269 {
270 TargetEntry *tle = (TargetEntry *) lfirst(l);
271
272 if (tle->resjunk)
273 {
274 if (!junkOK)
275 return false;
276 }
277 else
278 {
279 if (curColColl == NULL)
280 return false; /* tlist longer than colCollations */
281 if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
282 return false;
283 curColColl = lnext(curColColl);
284 }
285 }
286 if (curColColl != NULL)
287 return false; /* tlist shorter than colCollations */
288 return true;
289 }
290
291 /*
292 * apply_tlist_labeling
293 * Apply the TargetEntry labeling attributes of src_tlist to dest_tlist
294 *
295 * This is useful for reattaching column names etc to a plan's final output
296 * targetlist.
297 */
298 void
apply_tlist_labeling(List * dest_tlist,List * src_tlist)299 apply_tlist_labeling(List *dest_tlist, List *src_tlist)
300 {
301 ListCell *ld,
302 *ls;
303
304 Assert(list_length(dest_tlist) == list_length(src_tlist));
305 forboth(ld, dest_tlist, ls, src_tlist)
306 {
307 TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
308 TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
309
310 Assert(dest_tle->resno == src_tle->resno);
311 dest_tle->resname = src_tle->resname;
312 dest_tle->ressortgroupref = src_tle->ressortgroupref;
313 dest_tle->resorigtbl = src_tle->resorigtbl;
314 dest_tle->resorigcol = src_tle->resorigcol;
315 dest_tle->resjunk = src_tle->resjunk;
316 }
317 }
318
319
320 /*
321 * get_sortgroupref_tle
322 * Find the targetlist entry matching the given SortGroupRef index,
323 * and return it.
324 */
325 TargetEntry *
get_sortgroupref_tle(Index sortref,List * targetList)326 get_sortgroupref_tle(Index sortref, List *targetList)
327 {
328 ListCell *l;
329
330 foreach(l, targetList)
331 {
332 TargetEntry *tle = (TargetEntry *) lfirst(l);
333
334 if (tle->ressortgroupref == sortref)
335 return tle;
336 }
337
338 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
339 return NULL; /* keep compiler quiet */
340 }
341
342 /*
343 * get_sortgroupclause_tle
344 * Find the targetlist entry matching the given SortGroupClause
345 * by ressortgroupref, and return it.
346 */
347 TargetEntry *
get_sortgroupclause_tle(SortGroupClause * sgClause,List * targetList)348 get_sortgroupclause_tle(SortGroupClause *sgClause,
349 List *targetList)
350 {
351 return get_sortgroupref_tle(sgClause->tleSortGroupRef, targetList);
352 }
353
354 /*
355 * get_sortgroupclause_expr
356 * Find the targetlist entry matching the given SortGroupClause
357 * by ressortgroupref, and return its expression.
358 */
359 Node *
get_sortgroupclause_expr(SortGroupClause * sgClause,List * targetList)360 get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
361 {
362 TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
363
364 return (Node *) tle->expr;
365 }
366
367 /*
368 * get_sortgrouplist_exprs
369 * Given a list of SortGroupClauses, build a list
370 * of the referenced targetlist expressions.
371 */
372 List *
get_sortgrouplist_exprs(List * sgClauses,List * targetList)373 get_sortgrouplist_exprs(List *sgClauses, List *targetList)
374 {
375 List *result = NIL;
376 ListCell *l;
377
378 foreach(l, sgClauses)
379 {
380 SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
381 Node *sortexpr;
382
383 sortexpr = get_sortgroupclause_expr(sortcl, targetList);
384 result = lappend(result, sortexpr);
385 }
386 return result;
387 }
388
389
390 /*****************************************************************************
391 * Functions to extract data from a list of SortGroupClauses
392 *
393 * These don't really belong in tlist.c, but they are sort of related to the
394 * functions just above, and they don't seem to deserve their own file.
395 *****************************************************************************/
396
397 /*
398 * get_sortgroupref_clause
399 * Find the SortGroupClause matching the given SortGroupRef index,
400 * and return it.
401 */
402 SortGroupClause *
get_sortgroupref_clause(Index sortref,List * clauses)403 get_sortgroupref_clause(Index sortref, List *clauses)
404 {
405 ListCell *l;
406
407 foreach(l, clauses)
408 {
409 SortGroupClause *cl = (SortGroupClause *) lfirst(l);
410
411 if (cl->tleSortGroupRef == sortref)
412 return cl;
413 }
414
415 elog(ERROR, "ORDER/GROUP BY expression not found in list");
416 return NULL; /* keep compiler quiet */
417 }
418
419 /*
420 * get_sortgroupref_clause_noerr
421 * As above, but return NULL rather than throwing an error if not found.
422 */
423 SortGroupClause *
get_sortgroupref_clause_noerr(Index sortref,List * clauses)424 get_sortgroupref_clause_noerr(Index sortref, List *clauses)
425 {
426 ListCell *l;
427
428 foreach(l, clauses)
429 {
430 SortGroupClause *cl = (SortGroupClause *) lfirst(l);
431
432 if (cl->tleSortGroupRef == sortref)
433 return cl;
434 }
435
436 return NULL;
437 }
438
439 /*
440 * extract_grouping_ops - make an array of the equality operator OIDs
441 * for a SortGroupClause list
442 */
443 Oid *
extract_grouping_ops(List * groupClause)444 extract_grouping_ops(List *groupClause)
445 {
446 int numCols = list_length(groupClause);
447 int colno = 0;
448 Oid *groupOperators;
449 ListCell *glitem;
450
451 groupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
452
453 foreach(glitem, groupClause)
454 {
455 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
456
457 groupOperators[colno] = groupcl->eqop;
458 Assert(OidIsValid(groupOperators[colno]));
459 colno++;
460 }
461
462 return groupOperators;
463 }
464
465 /*
466 * extract_grouping_cols - make an array of the grouping column resnos
467 * for a SortGroupClause list
468 */
469 AttrNumber *
extract_grouping_cols(List * groupClause,List * tlist)470 extract_grouping_cols(List *groupClause, List *tlist)
471 {
472 AttrNumber *grpColIdx;
473 int numCols = list_length(groupClause);
474 int colno = 0;
475 ListCell *glitem;
476
477 grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
478
479 foreach(glitem, groupClause)
480 {
481 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
482 TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
483
484 grpColIdx[colno++] = tle->resno;
485 }
486
487 return grpColIdx;
488 }
489
490 /*
491 * grouping_is_sortable - is it possible to implement grouping list by sorting?
492 *
493 * This is easy since the parser will have included a sortop if one exists.
494 */
495 bool
grouping_is_sortable(List * groupClause)496 grouping_is_sortable(List *groupClause)
497 {
498 ListCell *glitem;
499
500 foreach(glitem, groupClause)
501 {
502 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
503
504 if (!OidIsValid(groupcl->sortop))
505 return false;
506 }
507 return true;
508 }
509
510 /*
511 * grouping_is_hashable - is it possible to implement grouping list by hashing?
512 *
513 * We rely on the parser to have set the hashable flag correctly.
514 */
515 bool
grouping_is_hashable(List * groupClause)516 grouping_is_hashable(List *groupClause)
517 {
518 ListCell *glitem;
519
520 foreach(glitem, groupClause)
521 {
522 SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
523
524 if (!groupcl->hashable)
525 return false;
526 }
527 return true;
528 }
529
530
531 /*****************************************************************************
532 * PathTarget manipulation functions
533 *
534 * PathTarget is a somewhat stripped-down version of a full targetlist; it
535 * omits all the TargetEntry decoration except (optionally) sortgroupref data,
536 * and it adds evaluation cost and output data width info.
537 *****************************************************************************/
538
539 /*
540 * make_pathtarget_from_tlist
541 * Construct a PathTarget equivalent to the given targetlist.
542 *
543 * This leaves the cost and width fields as zeroes. Most callers will want
544 * to use create_pathtarget(), so as to get those set.
545 */
546 PathTarget *
make_pathtarget_from_tlist(List * tlist)547 make_pathtarget_from_tlist(List *tlist)
548 {
549 PathTarget *target = makeNode(PathTarget);
550 int i;
551 ListCell *lc;
552
553 target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
554
555 i = 0;
556 foreach(lc, tlist)
557 {
558 TargetEntry *tle = (TargetEntry *) lfirst(lc);
559
560 target->exprs = lappend(target->exprs, tle->expr);
561 target->sortgrouprefs[i] = tle->ressortgroupref;
562 i++;
563 }
564
565 return target;
566 }
567
568 /*
569 * make_tlist_from_pathtarget
570 * Construct a targetlist from a PathTarget.
571 */
572 List *
make_tlist_from_pathtarget(PathTarget * target)573 make_tlist_from_pathtarget(PathTarget *target)
574 {
575 List *tlist = NIL;
576 int i;
577 ListCell *lc;
578
579 i = 0;
580 foreach(lc, target->exprs)
581 {
582 Expr *expr = (Expr *) lfirst(lc);
583 TargetEntry *tle;
584
585 tle = makeTargetEntry(expr,
586 i + 1,
587 NULL,
588 false);
589 if (target->sortgrouprefs)
590 tle->ressortgroupref = target->sortgrouprefs[i];
591 tlist = lappend(tlist, tle);
592 i++;
593 }
594
595 return tlist;
596 }
597
598 /*
599 * copy_pathtarget
600 * Copy a PathTarget.
601 *
602 * The new PathTarget has its own List cells, but shares the underlying
603 * target expression trees with the old one. We duplicate the List cells
604 * so that items can be added to one target without damaging the other.
605 */
606 PathTarget *
copy_pathtarget(PathTarget * src)607 copy_pathtarget(PathTarget *src)
608 {
609 PathTarget *dst = makeNode(PathTarget);
610
611 /* Copy scalar fields */
612 memcpy(dst, src, sizeof(PathTarget));
613 /* Shallow-copy the expression list */
614 dst->exprs = list_copy(src->exprs);
615 /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
616 if (src->sortgrouprefs)
617 {
618 Size nbytes = list_length(src->exprs) * sizeof(Index);
619
620 dst->sortgrouprefs = (Index *) palloc(nbytes);
621 memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
622 }
623 return dst;
624 }
625
626 /*
627 * create_empty_pathtarget
628 * Create an empty (zero columns, zero cost) PathTarget.
629 */
630 PathTarget *
create_empty_pathtarget(void)631 create_empty_pathtarget(void)
632 {
633 /* This is easy, but we don't want callers to hard-wire this ... */
634 return makeNode(PathTarget);
635 }
636
637 /*
638 * add_column_to_pathtarget
639 * Append a target column to the PathTarget.
640 *
641 * As with make_pathtarget_from_tlist, we leave it to the caller to update
642 * the cost and width fields.
643 */
644 void
add_column_to_pathtarget(PathTarget * target,Expr * expr,Index sortgroupref)645 add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
646 {
647 /* Updating the exprs list is easy ... */
648 target->exprs = lappend(target->exprs, expr);
649 /* ... the sortgroupref data, a bit less so */
650 if (target->sortgrouprefs)
651 {
652 int nexprs = list_length(target->exprs);
653
654 /* This might look inefficient, but actually it's usually cheap */
655 target->sortgrouprefs = (Index *)
656 repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
657 target->sortgrouprefs[nexprs - 1] = sortgroupref;
658 }
659 else if (sortgroupref)
660 {
661 /* Adding sortgroupref labeling to a previously unlabeled target */
662 int nexprs = list_length(target->exprs);
663
664 target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
665 target->sortgrouprefs[nexprs - 1] = sortgroupref;
666 }
667 }
668
669 /*
670 * add_new_column_to_pathtarget
671 * Append a target column to the PathTarget, but only if it's not
672 * equal() to any pre-existing target expression.
673 *
674 * The caller cannot specify a sortgroupref, since it would be unclear how
675 * to merge that with a pre-existing column.
676 *
677 * As with make_pathtarget_from_tlist, we leave it to the caller to update
678 * the cost and width fields.
679 */
680 void
add_new_column_to_pathtarget(PathTarget * target,Expr * expr)681 add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
682 {
683 if (!list_member(target->exprs, expr))
684 add_column_to_pathtarget(target, expr, 0);
685 }
686
687 /*
688 * add_new_columns_to_pathtarget
689 * Apply add_new_column_to_pathtarget() for each element of the list.
690 */
691 void
add_new_columns_to_pathtarget(PathTarget * target,List * exprs)692 add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
693 {
694 ListCell *lc;
695
696 foreach(lc, exprs)
697 {
698 Expr *expr = (Expr *) lfirst(lc);
699
700 add_new_column_to_pathtarget(target, expr);
701 }
702 }
703
704 /*
705 * apply_pathtarget_labeling_to_tlist
706 * Apply any sortgrouprefs in the PathTarget to matching tlist entries
707 *
708 * Here, we do not assume that the tlist entries are one-for-one with the
709 * PathTarget. The intended use of this function is to deal with cases
710 * where createplan.c has decided to use some other tlist and we have
711 * to identify what matches exist.
712 */
713 void
apply_pathtarget_labeling_to_tlist(List * tlist,PathTarget * target)714 apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target)
715 {
716 int i;
717 ListCell *lc;
718
719 /* Nothing to do if PathTarget has no sortgrouprefs data */
720 if (target->sortgrouprefs == NULL)
721 return;
722
723 i = 0;
724 foreach(lc, target->exprs)
725 {
726 Expr *expr = (Expr *) lfirst(lc);
727 TargetEntry *tle;
728
729 if (target->sortgrouprefs[i])
730 {
731 /*
732 * For Vars, use tlist_member_match_var's weakened matching rule;
733 * this allows us to deal with some cases where a set-returning
734 * function has been inlined, so that we now have more knowledge
735 * about what it returns than we did when the original Var was
736 * created. Otherwise, use regular equal() to find the matching
737 * TLE. (In current usage, only the Var case is actually needed;
738 * but it seems best to have sane behavior here for non-Vars too.)
739 */
740 if (expr && IsA(expr, Var))
741 tle = tlist_member_match_var((Var *) expr, tlist);
742 else
743 tle = tlist_member((Node *) expr, tlist);
744
745 /*
746 * Complain if noplace for the sortgrouprefs label, or if we'd
747 * have to label a column twice. (The case where it already has
748 * the desired label probably can't happen, but we may as well
749 * allow for it.)
750 */
751 if (!tle)
752 elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
753 if (tle->ressortgroupref != 0 &&
754 tle->ressortgroupref != target->sortgrouprefs[i])
755 elog(ERROR, "targetlist item has multiple sortgroupref labels");
756
757 tle->ressortgroupref = target->sortgrouprefs[i];
758 }
759 i++;
760 }
761 }
762