PostgreSQL Source Code  git master
tlist.c File Reference
#include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/tlist.h"
Include dependency graph for tlist.c:

Go to the source code of this file.

Data Structures

struct  split_pathtarget_item
 
struct  split_pathtarget_context
 

Macros

#define IS_SRF_CALL(node)
 

Functions

static bool split_pathtarget_walker (Node *node, split_pathtarget_context *context)
 
static void add_sp_item_to_pathtarget (PathTarget *target, split_pathtarget_item *item)
 
static void add_sp_items_to_pathtarget (PathTarget *target, List *items)
 
TargetEntrytlist_member (Expr *node, List *targetlist)
 
static TargetEntrytlist_member_match_var (Var *var, List *targetlist)
 
Listadd_to_flat_tlist (List *tlist, List *exprs)
 
Listget_tlist_exprs (List *tlist, bool includeJunk)
 
int count_nonjunk_tlist_entries (List *tlist)
 
bool tlist_same_exprs (List *tlist1, List *tlist2)
 
bool tlist_same_datatypes (List *tlist, List *colTypes, bool junkOK)
 
bool tlist_same_collations (List *tlist, List *colCollations, bool junkOK)
 
void apply_tlist_labeling (List *dest_tlist, List *src_tlist)
 
TargetEntryget_sortgroupref_tle (Index sortref, List *targetList)
 
TargetEntryget_sortgroupclause_tle (SortGroupClause *sgClause, List *targetList)
 
Nodeget_sortgroupclause_expr (SortGroupClause *sgClause, List *targetList)
 
Listget_sortgrouplist_exprs (List *sgClauses, List *targetList)
 
SortGroupClauseget_sortgroupref_clause (Index sortref, List *clauses)
 
SortGroupClauseget_sortgroupref_clause_noerr (Index sortref, List *clauses)
 
Oidextract_grouping_ops (List *groupClause)
 
Oidextract_grouping_collations (List *groupClause, List *tlist)
 
AttrNumberextract_grouping_cols (List *groupClause, List *tlist)
 
bool grouping_is_sortable (List *groupClause)
 
bool grouping_is_hashable (List *groupClause)
 
PathTargetmake_pathtarget_from_tlist (List *tlist)
 
Listmake_tlist_from_pathtarget (PathTarget *target)
 
PathTargetcopy_pathtarget (PathTarget *src)
 
PathTargetcreate_empty_pathtarget (void)
 
void add_column_to_pathtarget (PathTarget *target, Expr *expr, Index sortgroupref)
 
void add_new_column_to_pathtarget (PathTarget *target, Expr *expr)
 
void add_new_columns_to_pathtarget (PathTarget *target, List *exprs)
 
void apply_pathtarget_labeling_to_tlist (List *tlist, PathTarget *target)
 
void split_pathtarget_at_srfs (PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs)
 

Macro Definition Documentation

◆ IS_SRF_CALL

#define IS_SRF_CALL (   node)
Value:
((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
(IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
#define IsA(nodeptr, _type_)
Definition: nodes.h:158

Definition at line 31 of file tlist.c.

Function Documentation

◆ add_column_to_pathtarget()

void add_column_to_pathtarget ( PathTarget target,
Expr expr,
Index  sortgroupref 
)

Definition at line 695 of file tlist.c.

696 {
697  /* Updating the exprs list is easy ... */
698  target->exprs = lappend(target->exprs, expr);
699  /* ... the sortgroupref data, a bit less so */
700  if (target->sortgrouprefs)
701  {
702  int nexprs = list_length(target->exprs);
703 
704  /* This might look inefficient, but actually it's usually cheap */
705  target->sortgrouprefs = (Index *)
706  repalloc(target->sortgrouprefs, nexprs * sizeof(Index));
707  target->sortgrouprefs[nexprs - 1] = sortgroupref;
708  }
709  else if (sortgroupref)
710  {
711  /* Adding sortgroupref labeling to a previously unlabeled target */
712  int nexprs = list_length(target->exprs);
713 
714  target->sortgrouprefs = (Index *) palloc0(nexprs * sizeof(Index));
715  target->sortgrouprefs[nexprs - 1] = sortgroupref;
716  }
717 
718  /*
719  * Reset has_volatile_expr to UNKNOWN. We just leave it up to
720  * contain_volatile_functions to set this properly again. Technically we
721  * could save some effort here and just check the new Expr, but it seems
722  * better to keep the logic for setting this flag in one location rather
723  * than duplicating the logic here.
724  */
727 }
unsigned int Index
Definition: c.h:601
List * lappend(List *list, void *datum)
Definition: list.c:339
void * palloc0(Size size)
Definition: mcxt.c:1334
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1528
@ VOLATILITY_NOVOLATILE
Definition: pathnodes.h:1480
@ VOLATILITY_UNKNOWN
Definition: pathnodes.h:1478
static int list_length(const List *l)
Definition: pg_list.h:152
VolatileFunctionStatus has_volatile_expr
Definition: pathnodes.h:1525
List * exprs
Definition: pathnodes.h:1513

References PathTarget::exprs, PathTarget::has_volatile_expr, lappend(), list_length(), palloc0(), repalloc(), VOLATILITY_NOVOLATILE, and VOLATILITY_UNKNOWN.

Referenced by add_new_column_to_pathtarget(), add_sp_item_to_pathtarget(), create_one_window_path(), make_group_input_target(), make_partial_grouping_target(), make_sort_input_target(), and make_window_input_target().

◆ add_new_column_to_pathtarget()

void add_new_column_to_pathtarget ( PathTarget target,
Expr expr 
)

Definition at line 741 of file tlist.c.

742 {
743  if (!list_member(target->exprs, expr))
744  add_column_to_pathtarget(target, expr, 0);
745 }
bool list_member(const List *list, const void *datum)
Definition: list.c:661
void add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
Definition: tlist.c:695

References add_column_to_pathtarget(), PathTarget::exprs, and list_member().

Referenced by add_new_columns_to_pathtarget().

◆ add_new_columns_to_pathtarget()

void add_new_columns_to_pathtarget ( PathTarget target,
List exprs 
)

Definition at line 752 of file tlist.c.

753 {
754  ListCell *lc;
755 
756  foreach(lc, exprs)
757  {
758  Expr *expr = (Expr *) lfirst(lc);
759 
760  add_new_column_to_pathtarget(target, expr);
761  }
762 }
#define lfirst(lc)
Definition: pg_list.h:172
void add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
Definition: tlist.c:741

References add_new_column_to_pathtarget(), and lfirst.

Referenced by add_paths_with_pathkeys_for_rel(), make_group_input_target(), make_partial_grouping_target(), make_sort_input_target(), and make_window_input_target().

◆ add_sp_item_to_pathtarget()

static void add_sp_item_to_pathtarget ( PathTarget target,
split_pathtarget_item item 
)
static

Definition at line 1202 of file tlist.c.

1203 {
1204  int lci;
1205  ListCell *lc;
1206 
1207  /*
1208  * Look for a pre-existing entry that is equal() and does not have a
1209  * conflicting sortgroupref already.
1210  */
1211  lci = 0;
1212  foreach(lc, target->exprs)
1213  {
1214  Node *node = (Node *) lfirst(lc);
1215  Index sgref = get_pathtarget_sortgroupref(target, lci);
1216 
1217  if ((item->sortgroupref == sgref ||
1218  item->sortgroupref == 0 ||
1219  sgref == 0) &&
1220  equal(item->expr, node))
1221  {
1222  /* Found a match. Assign item's sortgroupref if it has one. */
1223  if (item->sortgroupref)
1224  {
1225  if (target->sortgrouprefs == NULL)
1226  {
1227  target->sortgrouprefs = (Index *)
1228  palloc0(list_length(target->exprs) * sizeof(Index));
1229  }
1230  target->sortgrouprefs[lci] = item->sortgroupref;
1231  }
1232  return;
1233  }
1234  lci++;
1235  }
1236 
1237  /*
1238  * No match, so add item to PathTarget. Copy the expr for safety.
1239  */
1240  add_column_to_pathtarget(target, (Expr *) copyObject(item->expr),
1241  item->sortgroupref);
1242 }
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
#define copyObject(obj)
Definition: nodes.h:223
#define get_pathtarget_sortgroupref(target, colno)
Definition: pathnodes.h:1529
Definition: nodes.h:129
Index sortgroupref
Definition: tlist.c:43

References add_column_to_pathtarget(), copyObject, equal(), split_pathtarget_item::expr, PathTarget::exprs, get_pathtarget_sortgroupref, lfirst, list_length(), palloc0(), and split_pathtarget_item::sortgroupref.

Referenced by add_sp_items_to_pathtarget(), and split_pathtarget_at_srfs().

◆ add_sp_items_to_pathtarget()

static void add_sp_items_to_pathtarget ( PathTarget target,
List items 
)
static

Definition at line 1248 of file tlist.c.

1249 {
1250  ListCell *lc;
1251 
1252  foreach(lc, items)
1253  {
1254  split_pathtarget_item *item = lfirst(lc);
1255 
1256  add_sp_item_to_pathtarget(target, item);
1257  }
1258 }
static void add_sp_item_to_pathtarget(PathTarget *target, split_pathtarget_item *item)
Definition: tlist.c:1202

References add_sp_item_to_pathtarget(), and lfirst.

Referenced by split_pathtarget_at_srfs().

◆ add_to_flat_tlist()

List* add_to_flat_tlist ( List tlist,
List exprs 
)

Definition at line 132 of file tlist.c.

133 {
134  int next_resno = list_length(tlist) + 1;
135  ListCell *lc;
136 
137  foreach(lc, exprs)
138  {
139  Expr *expr = (Expr *) lfirst(lc);
140 
141  if (!tlist_member(expr, tlist))
142  {
143  TargetEntry *tle;
144 
145  tle = makeTargetEntry(copyObject(expr), /* copy needed?? */
146  next_resno++,
147  NULL,
148  false);
149  tlist = lappend(tlist, tle);
150  }
151  }
152  return tlist;
153 }
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:240
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79

References copyObject, lappend(), lfirst, list_length(), makeTargetEntry(), and tlist_member().

Referenced by build_tlist_to_deparse(), and foreign_grouping_ok().

◆ apply_pathtarget_labeling_to_tlist()

void apply_pathtarget_labeling_to_tlist ( List tlist,
PathTarget target 
)

Definition at line 774 of file tlist.c.

775 {
776  int i;
777  ListCell *lc;
778 
779  /* Nothing to do if PathTarget has no sortgrouprefs data */
780  if (target->sortgrouprefs == NULL)
781  return;
782 
783  i = 0;
784  foreach(lc, target->exprs)
785  {
786  Expr *expr = (Expr *) lfirst(lc);
787  TargetEntry *tle;
788 
789  if (target->sortgrouprefs[i])
790  {
791  /*
792  * For Vars, use tlist_member_match_var's weakened matching rule;
793  * this allows us to deal with some cases where a set-returning
794  * function has been inlined, so that we now have more knowledge
795  * about what it returns than we did when the original Var was
796  * created. Otherwise, use regular equal() to find the matching
797  * TLE. (In current usage, only the Var case is actually needed;
798  * but it seems best to have sane behavior here for non-Vars too.)
799  */
800  if (expr && IsA(expr, Var))
801  tle = tlist_member_match_var((Var *) expr, tlist);
802  else
803  tle = tlist_member(expr, tlist);
804 
805  /*
806  * Complain if noplace for the sortgrouprefs label, or if we'd
807  * have to label a column twice. (The case where it already has
808  * the desired label probably can't happen, but we may as well
809  * allow for it.)
810  */
811  if (!tle)
812  elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
813  if (tle->ressortgroupref != 0 &&
814  tle->ressortgroupref != target->sortgrouprefs[i])
815  elog(ERROR, "targetlist item has multiple sortgroupref labels");
816 
817  tle->ressortgroupref = target->sortgrouprefs[i];
818  }
819  i++;
820  }
821 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
int i
Definition: isn.c:73
Index ressortgroupref
Definition: primnodes.h:1949
Definition: primnodes.h:234
static TargetEntry * tlist_member_match_var(Var *var, List *targetlist)
Definition: tlist.c:102

References elog, ERROR, PathTarget::exprs, i, IsA, lfirst, TargetEntry::ressortgroupref, tlist_member(), and tlist_member_match_var().

Referenced by create_projection_plan(), and create_scan_plan().

◆ apply_tlist_labeling()

void apply_tlist_labeling ( List dest_tlist,
List src_tlist 
)

Definition at line 318 of file tlist.c.

319 {
320  ListCell *ld,
321  *ls;
322 
323  Assert(list_length(dest_tlist) == list_length(src_tlist));
324  forboth(ld, dest_tlist, ls, src_tlist)
325  {
326  TargetEntry *dest_tle = (TargetEntry *) lfirst(ld);
327  TargetEntry *src_tle = (TargetEntry *) lfirst(ls);
328 
329  Assert(dest_tle->resno == src_tle->resno);
330  dest_tle->resname = src_tle->resname;
331  dest_tle->ressortgroupref = src_tle->ressortgroupref;
332  dest_tle->resorigtbl = src_tle->resorigtbl;
333  dest_tle->resorigcol = src_tle->resorigcol;
334  dest_tle->resjunk = src_tle->resjunk;
335  }
336 }
Assert(fmt[strlen(fmt) - 1] !='\n')
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
AttrNumber resno
Definition: primnodes.h:1945

References Assert(), forboth, lfirst, list_length(), TargetEntry::resno, and TargetEntry::ressortgroupref.

Referenced by clean_up_removed_plan_level(), create_modifytable_plan(), and create_plan().

◆ copy_pathtarget()

PathTarget* copy_pathtarget ( PathTarget src)

Definition at line 657 of file tlist.c.

658 {
660 
661  /* Copy scalar fields */
662  memcpy(dst, src, sizeof(PathTarget));
663  /* Shallow-copy the expression list */
664  dst->exprs = list_copy(src->exprs);
665  /* Duplicate sortgrouprefs if any (if not, the memcpy handled this) */
666  if (src->sortgrouprefs)
667  {
668  Size nbytes = list_length(src->exprs) * sizeof(Index);
669 
670  dst->sortgrouprefs = (Index *) palloc(nbytes);
671  memcpy(dst->sortgrouprefs, src->sortgrouprefs, nbytes);
672  }
673  return dst;
674 }
size_t Size
Definition: c.h:592
List * list_copy(const List *oldlist)
Definition: list.c:1573
void * palloc(Size size)
Definition: mcxt.c:1304
#define makeNode(_type_)
Definition: nodes.h:155

References PathTarget::exprs, list_copy(), list_length(), makeNode, and palloc().

Referenced by add_paths_with_pathkeys_for_rel(), apply_scanjoin_target_to_paths(), create_one_window_path(), create_partitionwise_grouping_paths(), and reparameterize_path_by_child().

◆ count_nonjunk_tlist_entries()

int count_nonjunk_tlist_entries ( List tlist)

Definition at line 186 of file tlist.c.

187 {
188  int len = 0;
189  ListCell *l;
190 
191  foreach(l, tlist)
192  {
193  TargetEntry *tle = (TargetEntry *) lfirst(l);
194 
195  if (!tle->resjunk)
196  len++;
197  }
198  return len;
199 }
const void size_t len

References len, and lfirst.

Referenced by get_update_query_targetlist_def(), transformJsonArrayQueryConstructor(), transformMultiAssignRef(), and transformSubLink().

◆ create_empty_pathtarget()

PathTarget* create_empty_pathtarget ( void  )

Definition at line 681 of file tlist.c.

682 {
683  /* This is easy, but we don't want callers to hard-wire this ... */
684  return makeNode(PathTarget);
685 }

References makeNode.

Referenced by build_child_join_rel(), build_join_rel(), build_simple_rel(), fetch_upper_rel(), make_group_input_target(), make_partial_grouping_target(), make_sort_input_target(), make_window_input_target(), and split_pathtarget_at_srfs().

◆ extract_grouping_collations()

Oid* extract_grouping_collations ( List groupClause,
List tlist 
)

Definition at line 489 of file tlist.c.

490 {
491  int numCols = list_length(groupClause);
492  int colno = 0;
493  Oid *grpCollations;
494  ListCell *glitem;
495 
496  grpCollations = (Oid *) palloc(sizeof(Oid) * numCols);
497 
498  foreach(glitem, groupClause)
499  {
500  SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
501  TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
502 
503  grpCollations[colno++] = exprCollation((Node *) tle->expr);
504  }
505 
506  return grpCollations;
507 }
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:788
unsigned int Oid
Definition: postgres_ext.h:31
Expr * expr
Definition: primnodes.h:1943
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:367

References TargetEntry::expr, exprCollation(), get_sortgroupclause_tle(), lfirst, list_length(), and palloc().

Referenced by create_agg_plan(), create_group_plan(), and create_groupingsets_plan().

◆ extract_grouping_cols()

AttrNumber* extract_grouping_cols ( List groupClause,
List tlist 
)

Definition at line 514 of file tlist.c.

515 {
516  AttrNumber *grpColIdx;
517  int numCols = list_length(groupClause);
518  int colno = 0;
519  ListCell *glitem;
520 
521  grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
522 
523  foreach(glitem, groupClause)
524  {
525  SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
526  TargetEntry *tle = get_sortgroupclause_tle(groupcl, tlist);
527 
528  grpColIdx[colno++] = tle->resno;
529  }
530 
531  return grpColIdx;
532 }
int16 AttrNumber
Definition: attnum.h:21

References get_sortgroupclause_tle(), lfirst, list_length(), palloc(), and TargetEntry::resno.

Referenced by create_agg_plan(), and create_group_plan().

◆ extract_grouping_ops()

Oid* extract_grouping_ops ( List groupClause)

Definition at line 463 of file tlist.c.

464 {
465  int numCols = list_length(groupClause);
466  int colno = 0;
467  Oid *groupOperators;
468  ListCell *glitem;
469 
470  groupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
471 
472  foreach(glitem, groupClause)
473  {
474  SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
475 
476  groupOperators[colno] = groupcl->eqop;
477  Assert(OidIsValid(groupOperators[colno]));
478  colno++;
479  }
480 
481  return groupOperators;
482 }
#define OidIsValid(objectId)
Definition: c.h:762

References Assert(), SortGroupClause::eqop, lfirst, list_length(), OidIsValid, and palloc().

Referenced by create_agg_plan(), create_group_plan(), and create_groupingsets_plan().

◆ get_sortgroupclause_expr()

Node* get_sortgroupclause_expr ( SortGroupClause sgClause,
List targetList 
)

Definition at line 379 of file tlist.c.

380 {
381  TargetEntry *tle = get_sortgroupclause_tle(sgClause, targetList);
382 
383  return (Node *) tle->expr;
384 }

References TargetEntry::expr, and get_sortgroupclause_tle().

Referenced by get_sortgrouplist_exprs(), make_pathkeys_for_sortclauses_extended(), transformAggregateCall(), and transformWindowDefinitions().

◆ get_sortgroupclause_tle()

◆ get_sortgrouplist_exprs()

List* get_sortgrouplist_exprs ( List sgClauses,
List targetList 
)

Definition at line 392 of file tlist.c.

393 {
394  List *result = NIL;
395  ListCell *l;
396 
397  foreach(l, sgClauses)
398  {
399  SortGroupClause *sortcl = (SortGroupClause *) lfirst(l);
400  Node *sortexpr;
401 
402  sortexpr = get_sortgroupclause_expr(sortcl, targetList);
403  result = lappend(result, sortexpr);
404  }
405  return result;
406 }
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
Node * get_sortgroupclause_expr(SortGroupClause *sgClause, List *targetList)
Definition: tlist.c:379

References get_sortgroupclause_expr(), lappend(), lfirst, and NIL.

Referenced by create_final_distinct_paths(), create_partial_distinct_paths(), estimate_path_cost_size(), get_number_of_groups(), get_windowclause_startup_tuples(), and group_by_has_partkey().

◆ get_sortgroupref_clause()

SortGroupClause* get_sortgroupref_clause ( Index  sortref,
List clauses 
)

Definition at line 422 of file tlist.c.

423 {
424  ListCell *l;
425 
426  foreach(l, clauses)
427  {
429 
430  if (cl->tleSortGroupRef == sortref)
431  return cl;
432  }
433 
434  elog(ERROR, "ORDER/GROUP BY expression not found in list");
435  return NULL; /* keep compiler quiet */
436 }

References elog, ERROR, lfirst, and SortGroupClause::tleSortGroupRef.

Referenced by groupclause_apply_groupingset().

◆ get_sortgroupref_clause_noerr()

SortGroupClause* get_sortgroupref_clause_noerr ( Index  sortref,
List clauses 
)

Definition at line 443 of file tlist.c.

444 {
445  ListCell *l;
446 
447  foreach(l, clauses)
448  {
450 
451  if (cl->tleSortGroupRef == sortref)
452  return cl;
453  }
454 
455  return NULL;
456 }

References lfirst, and SortGroupClause::tleSortGroupRef.

Referenced by find_em_for_rel_target(), foreign_grouping_ok(), group_keys_reorder_by_pathkeys(), make_group_input_target(), and make_partial_grouping_target().

◆ get_sortgroupref_tle()

TargetEntry* get_sortgroupref_tle ( Index  sortref,
List targetList 
)

Definition at line 345 of file tlist.c.

346 {
347  ListCell *l;
348 
349  foreach(l, targetList)
350  {
351  TargetEntry *tle = (TargetEntry *) lfirst(l);
352 
353  if (tle->ressortgroupref == sortref)
354  return tle;
355  }
356 
357  elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
358  return NULL; /* keep compiler quiet */
359 }

References elog, ERROR, lfirst, and TargetEntry::ressortgroupref.

Referenced by convert_subquery_pathkeys(), deparseSortGroupClause(), foreign_expr_walker(), get_rule_sortgroupclause(), get_sortgroupclause_tle(), make_unique_from_pathkeys(), prepare_sort_from_pathkeys(), and transformDistinctOnClause().

◆ get_tlist_exprs()

List* get_tlist_exprs ( List tlist,
bool  includeJunk 
)

Definition at line 163 of file tlist.c.

164 {
165  List *result = NIL;
166  ListCell *l;
167 
168  foreach(l, tlist)
169  {
170  TargetEntry *tle = (TargetEntry *) lfirst(l);
171 
172  if (tle->resjunk && !includeJunk)
173  continue;
174 
175  result = lappend(result, tle->expr);
176  }
177  return result;
178 }

References TargetEntry::expr, lappend(), lfirst, and NIL.

Referenced by recurse_set_operations().

◆ grouping_is_hashable()

bool grouping_is_hashable ( List groupClause)

Definition at line 560 of file tlist.c.

561 {
562  ListCell *glitem;
563 
564  foreach(glitem, groupClause)
565  {
566  SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
567 
568  if (!groupcl->hashable)
569  return false;
570  }
571  return true;
572 }

References lfirst.

Referenced by choose_hashed_setop(), create_final_distinct_paths(), create_grouping_paths(), create_partial_distinct_paths(), and generate_recursion_path().

◆ grouping_is_sortable()

bool grouping_is_sortable ( List groupClause)

Definition at line 540 of file tlist.c.

541 {
542  ListCell *glitem;
543 
544  foreach(glitem, groupClause)
545  {
546  SortGroupClause *groupcl = (SortGroupClause *) lfirst(glitem);
547 
548  if (!OidIsValid(groupcl->sortop))
549  return false;
550  }
551  return true;
552 }

References lfirst, OidIsValid, and SortGroupClause::sortop.

Referenced by adjust_foreign_grouping_path_cost(), choose_hashed_setop(), create_final_distinct_paths(), create_grouping_paths(), create_partial_distinct_paths(), make_pathkeys_for_window(), and standard_qp_callback().

◆ make_pathtarget_from_tlist()

PathTarget* make_pathtarget_from_tlist ( List tlist)

Definition at line 591 of file tlist.c.

592 {
593  PathTarget *target = makeNode(PathTarget);
594  int i;
595  ListCell *lc;
596 
597  target->sortgrouprefs = (Index *) palloc(list_length(tlist) * sizeof(Index));
598 
599  i = 0;
600  foreach(lc, tlist)
601  {
602  TargetEntry *tle = (TargetEntry *) lfirst(lc);
603 
604  target->exprs = lappend(target->exprs, tle->expr);
605  target->sortgrouprefs[i] = tle->ressortgroupref;
606  i++;
607  }
608 
609  /*
610  * Mark volatility as unknown. The contain_volatile_functions function
611  * will determine if there are any volatile functions when called for the
612  * first time with this PathTarget.
613  */
615 
616  return target;
617 }

References TargetEntry::expr, PathTarget::exprs, PathTarget::has_volatile_expr, i, lappend(), lfirst, list_length(), makeNode, palloc(), TargetEntry::ressortgroupref, and VOLATILITY_UNKNOWN.

◆ make_tlist_from_pathtarget()

List* make_tlist_from_pathtarget ( PathTarget target)

Definition at line 624 of file tlist.c.

625 {
626  List *tlist = NIL;
627  int i;
628  ListCell *lc;
629 
630  i = 0;
631  foreach(lc, target->exprs)
632  {
633  Expr *expr = (Expr *) lfirst(lc);
634  TargetEntry *tle;
635 
636  tle = makeTargetEntry(expr,
637  i + 1,
638  NULL,
639  false);
640  if (target->sortgrouprefs)
641  tle->ressortgroupref = target->sortgrouprefs[i];
642  tlist = lappend(tlist, tle);
643  i++;
644  }
645 
646  return tlist;
647 }

References PathTarget::exprs, i, lappend(), lfirst, makeTargetEntry(), NIL, and TargetEntry::ressortgroupref.

Referenced by set_subquery_pathlist().

◆ split_pathtarget_at_srfs()

void split_pathtarget_at_srfs ( PlannerInfo root,
PathTarget target,
PathTarget input_target,
List **  targets,
List **  targets_contain_srfs 
)

Definition at line 881 of file tlist.c.

884 {
885  split_pathtarget_context context;
886  int max_depth;
887  bool need_extra_projection;
888  List *prev_level_tlist;
889  int lci;
890  ListCell *lc,
891  *lc1,
892  *lc2,
893  *lc3;
894 
895  /*
896  * It's not unusual for planner.c to pass us two physically identical
897  * targets, in which case we can conclude without further ado that all
898  * expressions are available from the input. (The logic below would
899  * arrive at the same conclusion, but much more tediously.)
900  */
901  if (target == input_target)
902  {
903  *targets = list_make1(target);
904  *targets_contain_srfs = list_make1_int(false);
905  return;
906  }
907 
908  /* Pass any input_target exprs down to split_pathtarget_walker() */
909  context.input_target_exprs = input_target ? input_target->exprs : NIL;
910 
911  /*
912  * Initialize with empty level-zero lists, and no levels after that.
913  * (Note: we could dispense with representing level zero explicitly, since
914  * it will never receive any SRFs, but then we'd have to special-case that
915  * level when we get to building result PathTargets. Level zero describes
916  * the SRF-free PathTarget that will be given to the input plan node.)
917  */
918  context.level_srfs = list_make1(NIL);
919  context.level_input_vars = list_make1(NIL);
920  context.level_input_srfs = list_make1(NIL);
921 
922  /* Initialize data we'll accumulate across all the target expressions */
923  context.current_input_vars = NIL;
924  context.current_input_srfs = NIL;
925  max_depth = 0;
926  need_extra_projection = false;
927 
928  /* Scan each expression in the PathTarget looking for SRFs */
929  lci = 0;
930  foreach(lc, target->exprs)
931  {
932  Node *node = (Node *) lfirst(lc);
933 
934  /* Tell split_pathtarget_walker about this expr's sortgroupref */
935  context.current_sgref = get_pathtarget_sortgroupref(target, lci);
936  lci++;
937 
938  /*
939  * Find all SRFs and Vars (and Var-like nodes) in this expression, and
940  * enter them into appropriate lists within the context struct.
941  */
942  context.current_depth = 0;
943  split_pathtarget_walker(node, &context);
944 
945  /* An expression containing no SRFs is of no further interest */
946  if (context.current_depth == 0)
947  continue;
948 
949  /*
950  * Track max SRF nesting depth over the whole PathTarget. Also, if
951  * this expression establishes a new max depth, we no longer care
952  * whether previous expressions contained nested SRFs; we can handle
953  * any required projection for them in the final ProjectSet node.
954  */
955  if (max_depth < context.current_depth)
956  {
957  max_depth = context.current_depth;
958  need_extra_projection = false;
959  }
960 
961  /*
962  * If any maximum-depth SRF is not at the top level of its expression,
963  * we'll need an extra Result node to compute the top-level scalar
964  * expression.
965  */
966  if (max_depth == context.current_depth && !IS_SRF_CALL(node))
967  need_extra_projection = true;
968  }
969 
970  /*
971  * If we found no SRFs needing evaluation (maybe they were all present in
972  * input_target, or maybe they were all removed by const-simplification),
973  * then no ProjectSet is needed; fall out.
974  */
975  if (max_depth == 0)
976  {
977  *targets = list_make1(target);
978  *targets_contain_srfs = list_make1_int(false);
979  return;
980  }
981 
982  /*
983  * The Vars and SRF outputs needed at top level can be added to the last
984  * level_input lists if we don't need an extra projection step. If we do
985  * need one, add a SRF-free level to the lists.
986  */
987  if (need_extra_projection)
988  {
989  context.level_srfs = lappend(context.level_srfs, NIL);
990  context.level_input_vars = lappend(context.level_input_vars,
991  context.current_input_vars);
992  context.level_input_srfs = lappend(context.level_input_srfs,
993  context.current_input_srfs);
994  }
995  else
996  {
997  lc = list_nth_cell(context.level_input_vars, max_depth);
998  lfirst(lc) = list_concat(lfirst(lc), context.current_input_vars);
999  lc = list_nth_cell(context.level_input_srfs, max_depth);
1000  lfirst(lc) = list_concat(lfirst(lc), context.current_input_srfs);
1001  }
1002 
1003  /*
1004  * Now construct the output PathTargets. The original target can be used
1005  * as-is for the last one, but we need to construct a new SRF-free target
1006  * representing what the preceding plan node has to emit, as well as a
1007  * target for each intermediate ProjectSet node.
1008  */
1009  *targets = *targets_contain_srfs = NIL;
1010  prev_level_tlist = NIL;
1011 
1012  forthree(lc1, context.level_srfs,
1013  lc2, context.level_input_vars,
1014  lc3, context.level_input_srfs)
1015  {
1016  List *level_srfs = (List *) lfirst(lc1);
1017  PathTarget *ntarget;
1018 
1019  if (lnext(context.level_srfs, lc1) == NULL)
1020  {
1021  ntarget = target;
1022  }
1023  else
1024  {
1025  ntarget = create_empty_pathtarget();
1026 
1027  /*
1028  * This target should actually evaluate any SRFs of the current
1029  * level, and it needs to propagate forward any Vars needed by
1030  * later levels, as well as SRFs computed earlier and needed by
1031  * later levels.
1032  */
1033  add_sp_items_to_pathtarget(ntarget, level_srfs);
1034  for_each_cell(lc, context.level_input_vars,
1035  lnext(context.level_input_vars, lc2))
1036  {
1037  List *input_vars = (List *) lfirst(lc);
1038 
1039  add_sp_items_to_pathtarget(ntarget, input_vars);
1040  }
1041  for_each_cell(lc, context.level_input_srfs,
1042  lnext(context.level_input_srfs, lc3))
1043  {
1044  List *input_srfs = (List *) lfirst(lc);
1045  ListCell *lcx;
1046 
1047  foreach(lcx, input_srfs)
1048  {
1049  split_pathtarget_item *item = lfirst(lcx);
1050 
1051  if (list_member(prev_level_tlist, item->expr))
1052  add_sp_item_to_pathtarget(ntarget, item);
1053  }
1054  }
1055  set_pathtarget_cost_width(root, ntarget);
1056  }
1057 
1058  /*
1059  * Add current target and does-it-compute-SRFs flag to output lists.
1060  */
1061  *targets = lappend(*targets, ntarget);
1062  *targets_contain_srfs = lappend_int(*targets_contain_srfs,
1063  (level_srfs != NIL));
1064 
1065  /* Remember this level's output for next pass */
1066  prev_level_tlist = ntarget->exprs;
1067  }
1068 }
PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
Definition: costsize.c:6286
List * lappend_int(List *list, int datum)
Definition: list.c:357
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
#define list_make1(x1)
Definition: pg_list.h:212
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:563
#define for_each_cell(cell, lst, initcell)
Definition: pg_list.h:438
static ListCell * list_nth_cell(const List *list, int n)
Definition: pg_list.h:277
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define list_make1_int(x1)
Definition: pg_list.h:227
List * level_input_srfs
Definition: tlist.c:53
List * current_input_srfs
Definition: tlist.c:56
List * input_target_exprs
Definition: tlist.c:49
List * current_input_vars
Definition: tlist.c:55
List * level_input_vars
Definition: tlist.c:52
#define IS_SRF_CALL(node)
Definition: tlist.c:31
static bool split_pathtarget_walker(Node *node, split_pathtarget_context *context)
Definition: tlist.c:1077
PathTarget * create_empty_pathtarget(void)
Definition: tlist.c:681
static void add_sp_items_to_pathtarget(PathTarget *target, List *items)
Definition: tlist.c:1248

References add_sp_item_to_pathtarget(), add_sp_items_to_pathtarget(), create_empty_pathtarget(), split_pathtarget_context::current_depth, split_pathtarget_context::current_input_srfs, split_pathtarget_context::current_input_vars, split_pathtarget_context::current_sgref, split_pathtarget_item::expr, PathTarget::exprs, for_each_cell, forthree, get_pathtarget_sortgroupref, split_pathtarget_context::input_target_exprs, IS_SRF_CALL, lappend(), lappend_int(), split_pathtarget_context::level_input_srfs, split_pathtarget_context::level_input_vars, split_pathtarget_context::level_srfs, lfirst, list_concat(), list_make1, list_make1_int, list_member(), list_nth_cell(), lnext(), NIL, set_pathtarget_cost_width(), and split_pathtarget_walker().

Referenced by grouping_planner().

◆ split_pathtarget_walker()

static bool split_pathtarget_walker ( Node node,
split_pathtarget_context context 
)
static

Definition at line 1077 of file tlist.c.

1078 {
1079  if (node == NULL)
1080  return false;
1081 
1082  /*
1083  * A subexpression that matches an expression already computed in
1084  * input_target can be treated like a Var (which indeed it will be after
1085  * setrefs.c gets done with it), even if it's actually a SRF. Record it
1086  * as being needed for the current expression, and ignore any
1087  * substructure. (Note in particular that this preserves the identity of
1088  * any expressions that appear as sortgrouprefs in input_target.)
1089  */
1090  if (list_member(context->input_target_exprs, node))
1091  {
1093 
1094  item->expr = node;
1095  item->sortgroupref = context->current_sgref;
1096  context->current_input_vars = lappend(context->current_input_vars,
1097  item);
1098  return false;
1099  }
1100 
1101  /*
1102  * Vars and Var-like constructs are expected to be gotten from the input,
1103  * too. We assume that these constructs cannot contain any SRFs (if one
1104  * does, there will be an executor failure from a misplaced SRF).
1105  */
1106  if (IsA(node, Var) ||
1107  IsA(node, PlaceHolderVar) ||
1108  IsA(node, Aggref) ||
1109  IsA(node, GroupingFunc) ||
1110  IsA(node, WindowFunc))
1111  {
1113 
1114  item->expr = node;
1115  item->sortgroupref = context->current_sgref;
1116  context->current_input_vars = lappend(context->current_input_vars,
1117  item);
1118  return false;
1119  }
1120 
1121  /*
1122  * If it's a SRF, recursively examine its inputs, determine its level, and
1123  * make appropriate entries in the output lists.
1124  */
1125  if (IS_SRF_CALL(node))
1126  {
1128  List *save_input_vars = context->current_input_vars;
1129  List *save_input_srfs = context->current_input_srfs;
1130  int save_current_depth = context->current_depth;
1131  int srf_depth;
1132  ListCell *lc;
1133 
1134  item->expr = node;
1135  item->sortgroupref = context->current_sgref;
1136 
1137  context->current_input_vars = NIL;
1138  context->current_input_srfs = NIL;
1139  context->current_depth = 0;
1140  context->current_sgref = 0; /* subexpressions are not sortgroup items */
1141 
1143  (void *) context);
1144 
1145  /* Depth is one more than any SRF below it */
1146  srf_depth = context->current_depth + 1;
1147 
1148  /* If new record depth, initialize another level of output lists */
1149  if (srf_depth >= list_length(context->level_srfs))
1150  {
1151  context->level_srfs = lappend(context->level_srfs, NIL);
1152  context->level_input_vars = lappend(context->level_input_vars, NIL);
1153  context->level_input_srfs = lappend(context->level_input_srfs, NIL);
1154  }
1155 
1156  /* Record this SRF as needing to be evaluated at appropriate level */
1157  lc = list_nth_cell(context->level_srfs, srf_depth);
1158  lfirst(lc) = lappend(lfirst(lc), item);
1159 
1160  /* Record its inputs as being needed at the same level */
1161  lc = list_nth_cell(context->level_input_vars, srf_depth);
1162  lfirst(lc) = list_concat(lfirst(lc), context->current_input_vars);
1163  lc = list_nth_cell(context->level_input_srfs, srf_depth);
1164  lfirst(lc) = list_concat(lfirst(lc), context->current_input_srfs);
1165 
1166  /*
1167  * Restore caller-level state and update it for presence of this SRF.
1168  * Notice we report the SRF itself as being needed for evaluation of
1169  * surrounding expression.
1170  */
1171  context->current_input_vars = save_input_vars;
1172  context->current_input_srfs = lappend(save_input_srfs, item);
1173  context->current_depth = Max(save_current_depth, srf_depth);
1174 
1175  /* We're done here */
1176  return false;
1177  }
1178 
1179  /*
1180  * Otherwise, the node is a scalar (non-set) expression, so recurse to
1181  * examine its inputs.
1182  */
1183  context->current_sgref = 0; /* subexpressions are not sortgroup items */
1185  (void *) context);
1186 }
#define Max(x, y)
Definition: c.h:985
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151

References split_pathtarget_context::current_depth, split_pathtarget_context::current_input_srfs, split_pathtarget_context::current_input_vars, split_pathtarget_context::current_sgref, split_pathtarget_item::expr, expression_tree_walker, split_pathtarget_context::input_target_exprs, IS_SRF_CALL, IsA, lappend(), split_pathtarget_context::level_input_srfs, split_pathtarget_context::level_input_vars, split_pathtarget_context::level_srfs, lfirst, list_concat(), list_length(), list_member(), list_nth_cell(), Max, NIL, palloc(), and split_pathtarget_item::sortgroupref.

Referenced by split_pathtarget_at_srfs().

◆ tlist_member()

TargetEntry* tlist_member ( Expr node,
List targetlist 
)

Definition at line 79 of file tlist.c.

80 {
81  ListCell *temp;
82 
83  foreach(temp, targetlist)
84  {
85  TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
86 
87  if (equal(node, tlentry->expr))
88  return tlentry;
89  }
90  return NULL;
91 }

References equal(), TargetEntry::expr, and lfirst.

Referenced by add_to_flat_tlist(), apply_pathtarget_labeling_to_tlist(), build_remote_returning(), create_unique_plan(), preprocess_targetlist(), rebuild_fdw_scan_tlist(), and search_indexed_tlist_for_non_var().

◆ tlist_member_match_var()

static TargetEntry* tlist_member_match_var ( Var var,
List targetlist 
)
static

Definition at line 102 of file tlist.c.

103 {
104  ListCell *temp;
105 
106  foreach(temp, targetlist)
107  {
108  TargetEntry *tlentry = (TargetEntry *) lfirst(temp);
109  Var *tlvar = (Var *) tlentry->expr;
110 
111  if (!tlvar || !IsA(tlvar, Var))
112  continue;
113  if (var->varno == tlvar->varno &&
114  var->varattno == tlvar->varattno &&
115  var->varlevelsup == tlvar->varlevelsup &&
116  var->vartype == tlvar->vartype)
117  return tlentry;
118  }
119  return NULL;
120 }
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
AttrNumber varattno
Definition: primnodes.h:246
int varno
Definition: primnodes.h:241
Index varlevelsup
Definition: primnodes.h:266

References TargetEntry::expr, if(), IsA, lfirst, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by apply_pathtarget_labeling_to_tlist().

◆ tlist_same_collations()

bool tlist_same_collations ( List tlist,
List colCollations,
bool  junkOK 
)

Definition at line 282 of file tlist.c.

283 {
284  ListCell *l;
285  ListCell *curColColl = list_head(colCollations);
286 
287  foreach(l, tlist)
288  {
289  TargetEntry *tle = (TargetEntry *) lfirst(l);
290 
291  if (tle->resjunk)
292  {
293  if (!junkOK)
294  return false;
295  }
296  else
297  {
298  if (curColColl == NULL)
299  return false; /* tlist longer than colCollations */
300  if (exprCollation((Node *) tle->expr) != lfirst_oid(curColColl))
301  return false;
302  curColColl = lnext(colCollations, curColColl);
303  }
304  }
305  if (curColColl != NULL)
306  return false; /* tlist shorter than colCollations */
307  return true;
308 }
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
#define lfirst_oid(lc)
Definition: pg_list.h:174

References TargetEntry::expr, exprCollation(), lfirst, lfirst_oid, list_head(), and lnext().

Referenced by recurse_set_operations().

◆ tlist_same_datatypes()

bool tlist_same_datatypes ( List tlist,
List colTypes,
bool  junkOK 
)

Definition at line 248 of file tlist.c.

249 {
250  ListCell *l;
251  ListCell *curColType = list_head(colTypes);
252 
253  foreach(l, tlist)
254  {
255  TargetEntry *tle = (TargetEntry *) lfirst(l);
256 
257  if (tle->resjunk)
258  {
259  if (!junkOK)
260  return false;
261  }
262  else
263  {
264  if (curColType == NULL)
265  return false; /* tlist longer than colTypes */
266  if (exprType((Node *) tle->expr) != lfirst_oid(curColType))
267  return false;
268  curColType = lnext(colTypes, curColType);
269  }
270  }
271  if (curColType != NULL)
272  return false; /* tlist shorter than colTypes */
273  return true;
274 }
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42

References TargetEntry::expr, exprType(), lfirst, lfirst_oid, list_head(), and lnext().

Referenced by is_simple_union_all_recurse(), and recurse_set_operations().

◆ tlist_same_exprs()

bool tlist_same_exprs ( List tlist1,
List tlist2 
)

Definition at line 218 of file tlist.c.

219 {
220  ListCell *lc1,
221  *lc2;
222 
223  if (list_length(tlist1) != list_length(tlist2))
224  return false; /* not same length, so can't match */
225 
226  forboth(lc1, tlist1, lc2, tlist2)
227  {
228  TargetEntry *tle1 = (TargetEntry *) lfirst(lc1);
229  TargetEntry *tle2 = (TargetEntry *) lfirst(lc2);
230 
231  if (!equal(tle1->expr, tle2->expr))
232  return false;
233  }
234 
235  return true;
236 }

References equal(), TargetEntry::expr, forboth, lfirst, and list_length().

Referenced by apply_scanjoin_target_to_paths(), change_plan_targetlist(), and create_projection_plan().