PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
var.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.h"
#include "optimizer/placeholder.h"
#include "optimizer/prep.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
Include dependency graph for var.c:

Go to the source code of this file.

Data Structures

struct  pull_varnos_context
 
struct  pull_varattnos_context
 
struct  pull_vars_context
 
struct  locate_var_of_level_context
 
struct  pull_var_clause_context
 
struct  flatten_join_alias_vars_context
 

Functions

static bool pull_varnos_walker (Node *node, pull_varnos_context *context)
 
static bool pull_varattnos_walker (Node *node, pull_varattnos_context *context)
 
static bool pull_vars_walker (Node *node, pull_vars_context *context)
 
static bool contain_var_clause_walker (Node *node, void *context)
 
static bool contain_vars_of_level_walker (Node *node, int *sublevels_up)
 
static bool locate_var_of_level_walker (Node *node, locate_var_of_level_context *context)
 
static bool pull_var_clause_walker (Node *node, pull_var_clause_context *context)
 
static Nodeflatten_join_alias_vars_mutator (Node *node, flatten_join_alias_vars_context *context)
 
static Nodeflatten_group_exprs_mutator (Node *node, flatten_join_alias_vars_context *context)
 
static Nodemark_nullable_by_grouping (PlannerInfo *root, Node *newnode, Var *oldvar)
 
static Nodeadd_nullingrels_if_needed (PlannerInfo *root, Node *newnode, Var *oldvar)
 
static bool is_standard_join_alias_expression (Node *newnode, Var *oldvar)
 
static void adjust_standard_join_alias_expression (Node *newnode, Var *oldvar)
 
static Relids alias_relid_set (Query *query, Relids relids)
 
Relids pull_varnos (PlannerInfo *root, Node *node)
 
Relids pull_varnos_of_level (PlannerInfo *root, Node *node, int levelsup)
 
void pull_varattnos (Node *node, Index varno, Bitmapset **varattnos)
 
Listpull_vars_of_level (Node *node, int levelsup)
 
bool contain_var_clause (Node *node)
 
bool contain_vars_of_level (Node *node, int levelsup)
 
int locate_var_of_level (Node *node, int levelsup)
 
Listpull_var_clause (Node *node, int flags)
 
Nodeflatten_join_alias_vars (PlannerInfo *root, Query *query, Node *node)
 
Nodeflatten_group_exprs (PlannerInfo *root, Query *query, Node *node)
 

Function Documentation

◆ add_nullingrels_if_needed()

static Node * add_nullingrels_if_needed ( PlannerInfo root,
Node newnode,
Var oldvar 
)
static

Definition at line 1134 of file var.c.

1135 {
1136  if (oldvar->varnullingrels == NULL)
1137  return newnode; /* nothing to do */
1138  /* If possible, do it by adding to existing nullingrel fields */
1139  if (is_standard_join_alias_expression(newnode, oldvar))
1140  adjust_standard_join_alias_expression(newnode, oldvar);
1141  else if (root)
1142  {
1143  /*
1144  * We can insert a PlaceHolderVar to carry the nullingrels. However,
1145  * deciding where to evaluate the PHV is slightly tricky. We first
1146  * try to evaluate it at the natural semantic level of the new
1147  * expression; but if that expression is variable-free, fall back to
1148  * evaluating it at the join that the oldvar is an alias Var for.
1149  */
1150  PlaceHolderVar *newphv;
1151  Index levelsup = oldvar->varlevelsup;
1152  Relids phrels = pull_varnos_of_level(root, newnode, levelsup);
1153 
1154  if (bms_is_empty(phrels)) /* variable-free? */
1155  {
1156  if (levelsup != 0) /* this won't work otherwise */
1157  elog(ERROR, "unsupported join alias expression");
1158  phrels = get_relids_for_join(root->parse, oldvar->varno);
1159  /* If it's an outer join, eval below not above the join */
1160  phrels = bms_del_member(phrels, oldvar->varno);
1161  Assert(!bms_is_empty(phrels));
1162  }
1163  newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
1164  /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
1165  newphv->phlevelsup = levelsup;
1166  newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
1167  newnode = (Node *) newphv;
1168  }
1169  else
1170  {
1171  /* ooops, we're missing support for something the parser can make */
1172  elog(ERROR, "unsupported join alias expression");
1173  }
1174  return newnode;
1175 }
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
#define bms_is_empty(a)
Definition: bitmapset.h:118
#define Assert(condition)
Definition: c.h:863
unsigned int Index
Definition: c.h:619
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
PlaceHolderVar * make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
Definition: placeholder.c:54
Relids get_relids_for_join(Query *query, int joinrelid)
tree ctl root
Definition: radixtree.h:1886
Definition: nodes.h:129
Relids phnullingrels
Definition: pathnodes.h:2801
Index phlevelsup
Definition: pathnodes.h:2807
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
Relids pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
Definition: var.c:139
static bool is_standard_join_alias_expression(Node *newnode, Var *oldvar)
Definition: var.c:1186
static void adjust_standard_join_alias_expression(Node *newnode, Var *oldvar)
Definition: var.c:1260

References adjust_standard_join_alias_expression(), Assert, bms_copy(), bms_del_member(), bms_is_empty, elog, ERROR, get_relids_for_join(), is_standard_join_alias_expression(), make_placeholder_expr(), PlaceHolderVar::phlevelsup, PlaceHolderVar::phnullingrels, pull_varnos_of_level(), root, Var::varlevelsup, and Var::varno.

Referenced by flatten_join_alias_vars_mutator().

◆ adjust_standard_join_alias_expression()

static void adjust_standard_join_alias_expression ( Node newnode,
Var oldvar 
)
static

Definition at line 1260 of file var.c.

1261 {
1262  if (IsA(newnode, Var) &&
1263  ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
1264  {
1265  Var *newvar = (Var *) newnode;
1266 
1267  newvar->varnullingrels = bms_add_members(newvar->varnullingrels,
1268  oldvar->varnullingrels);
1269  }
1270  else if (IsA(newnode, PlaceHolderVar) &&
1271  ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
1272  {
1273  PlaceHolderVar *newphv = (PlaceHolderVar *) newnode;
1274 
1275  newphv->phnullingrels = bms_add_members(newphv->phnullingrels,
1276  oldvar->varnullingrels);
1277  }
1278  else if (IsA(newnode, FuncExpr))
1279  {
1280  FuncExpr *fexpr = (FuncExpr *) newnode;
1281 
1283  }
1284  else if (IsA(newnode, RelabelType))
1285  {
1286  RelabelType *relabel = (RelabelType *) newnode;
1287 
1288  adjust_standard_join_alias_expression((Node *) relabel->arg, oldvar);
1289  }
1290  else if (IsA(newnode, CoerceViaIO))
1291  {
1292  CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
1293 
1294  adjust_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
1295  }
1296  else if (IsA(newnode, ArrayCoerceExpr))
1297  {
1298  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
1299 
1300  adjust_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
1301  }
1302  else if (IsA(newnode, CoalesceExpr))
1303  {
1304  CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
1305  ListCell *lc;
1306 
1307  Assert(cexpr->args != NIL);
1308  foreach(lc, cexpr->args)
1309  {
1311  }
1312  }
1313  else
1314  Assert(false);
1315 }
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:917
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define linitial(l)
Definition: pg_list.h:178
List * args
Definition: primnodes.h:1492
Expr * arg
Definition: primnodes.h:1207
List * args
Definition: primnodes.h:768
Expr * arg
Definition: primnodes.h:1184
Definition: primnodes.h:248

References RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, FuncExpr::args, CoalesceExpr::args, Assert, bms_add_members(), IsA, lfirst, linitial, NIL, PlaceHolderVar::phnullingrels, and Var::varlevelsup.

Referenced by add_nullingrels_if_needed().

◆ alias_relid_set()

static Relids alias_relid_set ( Query query,
Relids  relids 
)
static

Definition at line 1322 of file var.c.

1323 {
1324  Relids result = NULL;
1325  int rtindex;
1326 
1327  rtindex = -1;
1328  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1329  {
1330  RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
1331 
1332  if (rte->rtekind == RTE_JOIN)
1333  result = bms_join(result, get_relids_for_join(query, rtindex));
1334  else
1335  result = bms_add_member(result, rtindex);
1336  }
1337  return result;
1338 }
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1230
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
@ RTE_JOIN
Definition: parsenodes.h:1019
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * rtable
Definition: parsenodes.h:170
RTEKind rtekind
Definition: parsenodes.h:1047

References bms_add_member(), bms_join(), bms_next_member(), get_relids_for_join(), rt_fetch, Query::rtable, RTE_JOIN, and RangeTblEntry::rtekind.

Referenced by flatten_join_alias_vars_mutator().

◆ contain_var_clause()

◆ contain_var_clause_walker()

static bool contain_var_clause_walker ( Node node,
void *  context 
)
static

Definition at line 414 of file var.c.

415 {
416  if (node == NULL)
417  return false;
418  if (IsA(node, Var))
419  {
420  if (((Var *) node)->varlevelsup == 0)
421  return true; /* abort the tree traversal and return true */
422  return false;
423  }
424  if (IsA(node, CurrentOfExpr))
425  return true;
426  if (IsA(node, PlaceHolderVar))
427  {
428  if (((PlaceHolderVar *) node)->phlevelsup == 0)
429  return true; /* abort the tree traversal and return true */
430  /* else fall through to check the contained expr */
431  }
433 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
tree context
Definition: radixtree.h:1835

References context, expression_tree_walker, and IsA.

Referenced by contain_var_clause().

◆ contain_vars_of_level()

bool contain_vars_of_level ( Node node,
int  levelsup 
)

Definition at line 446 of file var.c.

447 {
448  int sublevels_up = levelsup;
449 
452  (void *) &sublevels_up,
453  0);
454 }
#define query_or_expression_tree_walker(n, w, c, f)
Definition: nodeFuncs.h:171
static bool contain_vars_of_level_walker(Node *node, int *sublevels_up)
Definition: var.c:457

References contain_vars_of_level_walker(), and query_or_expression_tree_walker.

Referenced by apply_child_basequals(), checkExprIsVarFree(), convert_EXISTS_sublink_to_join(), convert_EXISTS_to_ANY(), pull_up_simple_values(), pullup_replace_vars_callback(), rewriteRuleAction(), transformAExprIn(), transformJsonTable(), transformRangeFunction(), transformRangeTableFunc(), transformSetOperationTree(), and transformValuesClause().

◆ contain_vars_of_level_walker()

static bool contain_vars_of_level_walker ( Node node,
int *  sublevels_up 
)
static

Definition at line 457 of file var.c.

458 {
459  if (node == NULL)
460  return false;
461  if (IsA(node, Var))
462  {
463  if (((Var *) node)->varlevelsup == *sublevels_up)
464  return true; /* abort tree traversal and return true */
465  return false;
466  }
467  if (IsA(node, CurrentOfExpr))
468  {
469  if (*sublevels_up == 0)
470  return true;
471  return false;
472  }
473  if (IsA(node, PlaceHolderVar))
474  {
475  if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
476  return true; /* abort the tree traversal and return true */
477  /* else fall through to check the contained expr */
478  }
479  if (IsA(node, Query))
480  {
481  /* Recurse into subselects */
482  bool result;
483 
484  (*sublevels_up)++;
485  result = query_tree_walker((Query *) node,
487  (void *) sublevels_up,
488  0);
489  (*sublevels_up)--;
490  return result;
491  }
492  return expression_tree_walker(node,
494  (void *) sublevels_up);
495 }
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:158

References expression_tree_walker, IsA, and query_tree_walker.

Referenced by contain_vars_of_level().

◆ flatten_group_exprs()

Node* flatten_group_exprs ( PlannerInfo root,
Query query,
Node node 
)

Definition at line 929 of file var.c.

930 {
932 
933  /*
934  * We do not expect this to be applied to the whole Query, only to
935  * expressions or LATERAL subqueries. Hence, if the top node is a Query,
936  * it's okay to immediately increment sublevels_up.
937  */
938  Assert(node != (Node *) query);
939 
940  context.root = root;
941  context.query = query;
942  context.sublevels_up = 0;
943  /* flag whether grouping expressions could possibly contain SubLinks */
944  context.possible_sublink = query->hasSubLinks;
945  /* if hasSubLinks is already true, no need to work hard */
946  context.inserted_sublink = query->hasSubLinks;
947 
948  return flatten_group_exprs_mutator(node, &context);
949 }
static Node * flatten_group_exprs_mutator(Node *node, flatten_join_alias_vars_context *context)
Definition: var.c:952

References Assert, context, flatten_group_exprs_mutator(), and root.

Referenced by get_query_def(), and subquery_planner().

◆ flatten_group_exprs_mutator()

static Node * flatten_group_exprs_mutator ( Node node,
flatten_join_alias_vars_context context 
)
static

Definition at line 952 of file var.c.

954 {
955  if (node == NULL)
956  return NULL;
957  if (IsA(node, Var))
958  {
959  Var *var = (Var *) node;
960  RangeTblEntry *rte;
961  Node *newvar;
962 
963  /* No change unless Var belongs to the GROUP of the target level */
964  if (var->varlevelsup != context->sublevels_up)
965  return node; /* no need to copy, really */
966  rte = rt_fetch(var->varno, context->query->rtable);
967  if (rte->rtekind != RTE_GROUP)
968  return node;
969 
970  /* Expand group exprs reference */
971  Assert(var->varattno > 0);
972  newvar = (Node *) list_nth(rte->groupexprs, var->varattno - 1);
973  Assert(newvar != NULL);
974  newvar = copyObject(newvar);
975 
976  /*
977  * If we are expanding an expr carried down from an upper query, must
978  * adjust its varlevelsup fields.
979  */
980  if (context->sublevels_up != 0)
981  IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
982 
983  /* Preserve original Var's location, if possible */
984  if (IsA(newvar, Var))
985  ((Var *) newvar)->location = var->location;
986 
987  /* Detect if we are adding a sublink to query */
988  if (context->possible_sublink && !context->inserted_sublink)
989  context->inserted_sublink = checkExprHasSubLink(newvar);
990 
991  /* Lastly, add any varnullingrels to the replacement expression */
992  return mark_nullable_by_grouping(context->root, newvar, var);
993  }
994 
995  if (IsA(node, Aggref))
996  {
997  Aggref *agg = (Aggref *) node;
998 
999  if ((int) agg->agglevelsup == context->sublevels_up)
1000  {
1001  /*
1002  * If we find an aggregate call of the original level, do not
1003  * recurse into its normal arguments, ORDER BY arguments, or
1004  * filter; there are no grouped vars there. But we should check
1005  * direct arguments as though they weren't in an aggregate.
1006  */
1007  agg = copyObject(agg);
1008  agg->aggdirectargs = (List *)
1010 
1011  return (Node *) agg;
1012  }
1013 
1014  /*
1015  * We can skip recursing into aggregates of higher levels altogether,
1016  * since they could not possibly contain Vars of concern to us (see
1017  * transformAggregateCall). We do need to look at aggregates of lower
1018  * levels, however.
1019  */
1020  if ((int) agg->agglevelsup > context->sublevels_up)
1021  return node;
1022  }
1023 
1024  if (IsA(node, GroupingFunc))
1025  {
1026  GroupingFunc *grp = (GroupingFunc *) node;
1027 
1028  /*
1029  * If we find a GroupingFunc node of the original or higher level, do
1030  * not recurse into its arguments; there are no grouped vars there.
1031  */
1032  if ((int) grp->agglevelsup >= context->sublevels_up)
1033  return node;
1034  }
1035 
1036  if (IsA(node, Query))
1037  {
1038  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1039  Query *newnode;
1040  bool save_inserted_sublink;
1041 
1042  context->sublevels_up++;
1043  save_inserted_sublink = context->inserted_sublink;
1044  context->inserted_sublink = ((Query *) node)->hasSubLinks;
1045  newnode = query_tree_mutator((Query *) node,
1047  (void *) context,
1049  newnode->hasSubLinks |= context->inserted_sublink;
1050  context->inserted_sublink = save_inserted_sublink;
1051  context->sublevels_up--;
1052  return (Node *) newnode;
1053  }
1054 
1056  (void *) context);
1057 }
#define expression_tree_mutator(n, m, c)
Definition: nodeFuncs.h:155
#define QTW_IGNORE_GROUPEXPRS
Definition: nodeFuncs.h:32
#define query_tree_mutator(q, m, c, f)
Definition: nodeFuncs.h:160
#define copyObject(obj)
Definition: nodes.h:224
@ RTE_GROUP
Definition: parsenodes.h:1028
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:295
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:849
List * aggdirectargs
Definition: primnodes.h:465
Index agglevelsup
Definition: primnodes.h:551
Definition: pg_list.h:54
ParseLoc location
Definition: primnodes.h:293
AttrNumber varattno
Definition: primnodes.h:260
static Node * mark_nullable_by_grouping(PlannerInfo *root, Node *newnode, Var *oldvar)
Definition: var.c:1064

References Aggref::aggdirectargs, GroupingFunc::agglevelsup, Assert, checkExprHasSubLink(), context, copyObject, expression_tree_mutator, IncrementVarSublevelsUp(), IsA, list_nth(), Var::location, mark_nullable_by_grouping(), QTW_IGNORE_GROUPEXPRS, query_tree_mutator, rt_fetch, RTE_GROUP, RangeTblEntry::rtekind, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by flatten_group_exprs().

◆ flatten_join_alias_vars()

Node* flatten_join_alias_vars ( PlannerInfo root,
Query query,
Node node 
)

Definition at line 749 of file var.c.

750 {
752 
753  /*
754  * We do not expect this to be applied to the whole Query, only to
755  * expressions or LATERAL subqueries. Hence, if the top node is a Query,
756  * it's okay to immediately increment sublevels_up.
757  */
758  Assert(node != (Node *) query);
759 
760  context.root = root;
761  context.query = query;
762  context.sublevels_up = 0;
763  /* flag whether join aliases could possibly contain SubLinks */
764  context.possible_sublink = query->hasSubLinks;
765  /* if hasSubLinks is already true, no need to work hard */
766  context.inserted_sublink = query->hasSubLinks;
767 
769 }
static Node * flatten_join_alias_vars_mutator(Node *node, flatten_join_alias_vars_context *context)
Definition: var.c:772

References Assert, context, flatten_join_alias_vars_mutator(), and root.

Referenced by finalize_grouping_exprs_walker(), parseCheckAggregates(), preprocess_expression(), pull_up_simple_subquery(), and subquery_planner().

◆ flatten_join_alias_vars_mutator()

static Node * flatten_join_alias_vars_mutator ( Node node,
flatten_join_alias_vars_context context 
)
static

Definition at line 772 of file var.c.

774 {
775  if (node == NULL)
776  return NULL;
777  if (IsA(node, Var))
778  {
779  Var *var = (Var *) node;
780  RangeTblEntry *rte;
781  Node *newvar;
782 
783  /* No change unless Var belongs to a JOIN of the target level */
784  if (var->varlevelsup != context->sublevels_up)
785  return node; /* no need to copy, really */
786  rte = rt_fetch(var->varno, context->query->rtable);
787  if (rte->rtekind != RTE_JOIN)
788  return node;
789  if (var->varattno == InvalidAttrNumber)
790  {
791  /* Must expand whole-row reference */
792  RowExpr *rowexpr;
793  List *fields = NIL;
794  List *colnames = NIL;
795  ListCell *lv;
796  ListCell *ln;
797 
798  Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
799  forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
800  {
801  newvar = (Node *) lfirst(lv);
802  /* Ignore dropped columns */
803  if (newvar == NULL)
804  continue;
805  newvar = copyObject(newvar);
806 
807  /*
808  * If we are expanding an alias carried down from an upper
809  * query, must adjust its varlevelsup fields.
810  */
811  if (context->sublevels_up != 0)
812  IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
813  /* Preserve original Var's location, if possible */
814  if (IsA(newvar, Var))
815  ((Var *) newvar)->location = var->location;
816  /* Recurse in case join input is itself a join */
817  /* (also takes care of setting inserted_sublink if needed) */
818  newvar = flatten_join_alias_vars_mutator(newvar, context);
819  fields = lappend(fields, newvar);
820  /* We need the names of non-dropped columns, too */
821  colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
822  }
823  rowexpr = makeNode(RowExpr);
824  rowexpr->args = fields;
825  rowexpr->row_typeid = var->vartype;
826  rowexpr->row_format = COERCE_IMPLICIT_CAST;
827  /* vartype will always be RECORDOID, so we always need colnames */
828  rowexpr->colnames = colnames;
829  rowexpr->location = var->location;
830 
831  /* Lastly, add any varnullingrels to the replacement expression */
832  return add_nullingrels_if_needed(context->root, (Node *) rowexpr,
833  var);
834  }
835 
836  /* Expand join alias reference */
837  Assert(var->varattno > 0);
838  newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
839  Assert(newvar != NULL);
840  newvar = copyObject(newvar);
841 
842  /*
843  * If we are expanding an alias carried down from an upper query, must
844  * adjust its varlevelsup fields.
845  */
846  if (context->sublevels_up != 0)
847  IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
848 
849  /* Preserve original Var's location, if possible */
850  if (IsA(newvar, Var))
851  ((Var *) newvar)->location = var->location;
852 
853  /* Recurse in case join input is itself a join */
854  newvar = flatten_join_alias_vars_mutator(newvar, context);
855 
856  /* Detect if we are adding a sublink to query */
857  if (context->possible_sublink && !context->inserted_sublink)
858  context->inserted_sublink = checkExprHasSubLink(newvar);
859 
860  /* Lastly, add any varnullingrels to the replacement expression */
861  return add_nullingrels_if_needed(context->root, newvar, var);
862  }
863  if (IsA(node, PlaceHolderVar))
864  {
865  /* Copy the PlaceHolderVar node with correct mutation of subnodes */
866  PlaceHolderVar *phv;
867 
870  (void *) context);
871  /* now fix PlaceHolderVar's relid sets */
872  if (phv->phlevelsup == context->sublevels_up)
873  {
874  phv->phrels = alias_relid_set(context->query,
875  phv->phrels);
876  /* we *don't* change phnullingrels */
877  }
878  return (Node *) phv;
879  }
880 
881  if (IsA(node, Query))
882  {
883  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
884  Query *newnode;
885  bool save_inserted_sublink;
886 
887  context->sublevels_up++;
888  save_inserted_sublink = context->inserted_sublink;
889  context->inserted_sublink = ((Query *) node)->hasSubLinks;
890  newnode = query_tree_mutator((Query *) node,
892  (void *) context,
894  newnode->hasSubLinks |= context->inserted_sublink;
895  context->inserted_sublink = save_inserted_sublink;
896  context->sublevels_up--;
897  return (Node *) newnode;
898  }
899  /* Already-planned tree not supported */
900  Assert(!IsA(node, SubPlan));
901  Assert(!IsA(node, AlternativeSubPlan));
902  /* Shouldn't need to handle these planner auxiliary nodes here */
903  Assert(!IsA(node, SpecialJoinInfo));
904  Assert(!IsA(node, PlaceHolderInfo));
905  Assert(!IsA(node, MinMaxAggInfo));
906 
908  (void *) context);
909 }
#define InvalidAttrNumber
Definition: attnum.h:23
List * lappend(List *list, void *datum)
Definition: list.c:339
#define QTW_IGNORE_JOINALIASES
Definition: nodeFuncs.h:25
#define makeNode(_type_)
Definition: nodes.h:155
static int list_length(const List *l)
Definition: pg_list.h:152
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
List * args
Definition: primnodes.h:1411
ParseLoc location
Definition: primnodes.h:1435
static Node * add_nullingrels_if_needed(PlannerInfo *root, Node *newnode, Var *oldvar)
Definition: var.c:1134
static Relids alias_relid_set(Query *query, Relids relids)
Definition: var.c:1322

References add_nullingrels_if_needed(), alias_relid_set(), RowExpr::args, Assert, checkExprHasSubLink(), COERCE_IMPLICIT_CAST, context, copyObject, expression_tree_mutator, forboth, IncrementVarSublevelsUp(), InvalidAttrNumber, IsA, lappend(), lfirst, list_length(), list_nth(), Var::location, RowExpr::location, makeNode, NIL, PlaceHolderVar::phlevelsup, QTW_IGNORE_JOINALIASES, query_tree_mutator, rt_fetch, RTE_JOIN, RangeTblEntry::rtekind, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by flatten_join_alias_vars().

◆ is_standard_join_alias_expression()

static bool is_standard_join_alias_expression ( Node newnode,
Var oldvar 
)
static

Definition at line 1186 of file var.c.

1187 {
1188  if (newnode == NULL)
1189  return false;
1190  if (IsA(newnode, Var) &&
1191  ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
1192  return true;
1193  else if (IsA(newnode, PlaceHolderVar) &&
1194  ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
1195  return true;
1196  else if (IsA(newnode, FuncExpr))
1197  {
1198  FuncExpr *fexpr = (FuncExpr *) newnode;
1199 
1200  /*
1201  * We need to assume that the function wouldn't produce non-NULL from
1202  * NULL, which is reasonable for implicit coercions but otherwise not
1203  * so much. (Looking at its strictness is likely overkill, and anyway
1204  * it would cause us to fail if someone forgot to mark an implicit
1205  * coercion as strict.)
1206  */
1207  if (fexpr->funcformat != COERCE_IMPLICIT_CAST ||
1208  fexpr->args == NIL)
1209  return false;
1210 
1211  /*
1212  * Examine only the first argument --- coercions might have additional
1213  * arguments that are constants.
1214  */
1215  return is_standard_join_alias_expression(linitial(fexpr->args), oldvar);
1216  }
1217  else if (IsA(newnode, RelabelType))
1218  {
1219  RelabelType *relabel = (RelabelType *) newnode;
1220 
1221  /* This definitely won't produce non-NULL from NULL */
1222  return is_standard_join_alias_expression((Node *) relabel->arg, oldvar);
1223  }
1224  else if (IsA(newnode, CoerceViaIO))
1225  {
1226  CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
1227 
1228  /* This definitely won't produce non-NULL from NULL */
1229  return is_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
1230  }
1231  else if (IsA(newnode, ArrayCoerceExpr))
1232  {
1233  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
1234 
1235  /* This definitely won't produce non-NULL from NULL (at array level) */
1236  return is_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
1237  }
1238  else if (IsA(newnode, CoalesceExpr))
1239  {
1240  CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
1241  ListCell *lc;
1242 
1243  Assert(cexpr->args != NIL);
1244  foreach(lc, cexpr->args)
1245  {
1246  if (!is_standard_join_alias_expression(lfirst(lc), oldvar))
1247  return false;
1248  }
1249  return true;
1250  }
1251  else
1252  return false;
1253 }

References RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, FuncExpr::args, CoalesceExpr::args, Assert, COERCE_IMPLICIT_CAST, IsA, lfirst, linitial, NIL, and Var::varlevelsup.

Referenced by add_nullingrels_if_needed().

◆ locate_var_of_level()

int locate_var_of_level ( Node node,
int  levelsup 
)

Definition at line 514 of file var.c.

515 {
517 
518  context.var_location = -1; /* in case we find nothing */
519  context.sublevels_up = levelsup;
520 
523  (void *) &context,
524  0);
525 
526  return context.var_location;
527 }
static bool locate_var_of_level_walker(Node *node, locate_var_of_level_context *context)
Definition: var.c:530

References context, locate_var_of_level_walker(), and query_or_expression_tree_walker.

Referenced by check_agg_arguments(), checkExprIsVarFree(), and transformSetOperationTree().

◆ locate_var_of_level_walker()

static bool locate_var_of_level_walker ( Node node,
locate_var_of_level_context context 
)
static

Definition at line 530 of file var.c.

532 {
533  if (node == NULL)
534  return false;
535  if (IsA(node, Var))
536  {
537  Var *var = (Var *) node;
538 
539  if (var->varlevelsup == context->sublevels_up &&
540  var->location >= 0)
541  {
542  context->var_location = var->location;
543  return true; /* abort tree traversal and return true */
544  }
545  return false;
546  }
547  if (IsA(node, CurrentOfExpr))
548  {
549  /* since CurrentOfExpr doesn't carry location, nothing we can do */
550  return false;
551  }
552  /* No extra code needed for PlaceHolderVar; just look in contained expr */
553  if (IsA(node, Query))
554  {
555  /* Recurse into subselects */
556  bool result;
557 
558  context->sublevels_up++;
559  result = query_tree_walker((Query *) node,
561  (void *) context,
562  0);
563  context->sublevels_up--;
564  return result;
565  }
566  return expression_tree_walker(node,
568  (void *) context);
569 }

References context, expression_tree_walker, IsA, Var::location, query_tree_walker, and Var::varlevelsup.

Referenced by locate_var_of_level().

◆ mark_nullable_by_grouping()

static Node * mark_nullable_by_grouping ( PlannerInfo root,
Node newnode,
Var oldvar 
)
static

Definition at line 1064 of file var.c.

1065 {
1066  Relids relids;
1067 
1068  if (root == NULL)
1069  return newnode;
1070  if (oldvar->varnullingrels == NULL)
1071  return newnode; /* nothing to do */
1072 
1073  Assert(bms_equal(oldvar->varnullingrels,
1074  bms_make_singleton(root->group_rtindex)));
1075 
1076  relids = pull_varnos_of_level(root, newnode, oldvar->varlevelsup);
1077 
1078  if (!bms_is_empty(relids))
1079  {
1080  /*
1081  * If the newnode is not variable-free, we set the nullingrels of Vars
1082  * or PHVs that are contained in the expression. This is not really
1083  * 'correct' in theory, because it is the whole expression that can be
1084  * nullable by grouping sets, not its individual vars. But it works
1085  * in practice, because what we need is that the expression can be
1086  * somehow distinguished from the same expression in ECs, and marking
1087  * its vars is sufficient for this purpose.
1088  */
1089  newnode = add_nulling_relids(newnode,
1090  relids,
1091  oldvar->varnullingrels);
1092  }
1093  else /* variable-free? */
1094  {
1095  /*
1096  * If the newnode is variable-free and does not contain volatile
1097  * functions or set-returning functions, it can be treated as a member
1098  * of EC that is redundant. So wrap it in a new PlaceHolderVar to
1099  * carry the nullingrels. Otherwise we do not bother to make any
1100  * changes.
1101  *
1102  * Aggregate functions and window functions are not allowed in
1103  * grouping expressions.
1104  */
1105  Assert(!contain_agg_clause(newnode));
1106  Assert(!contain_window_function(newnode));
1107 
1108  if (!contain_volatile_functions(newnode) &&
1109  !expression_returns_set(newnode))
1110  {
1111  PlaceHolderVar *newphv;
1112  Relids phrels;
1113 
1114  phrels = get_relids_in_jointree((Node *) root->parse->jointree,
1115  true, false);
1116  Assert(!bms_is_empty(phrels));
1117 
1118  newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
1119  /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
1120  newphv->phlevelsup = oldvar->varlevelsup;
1121  newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
1122  newnode = (Node *) newphv;
1123  }
1124  }
1125 
1126  return newnode;
1127 }
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
bool contain_agg_clause(Node *clause)
Definition: clauses.c:177
bool contain_window_function(Node *clause)
Definition: clauses.c:214
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:538
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:758
Relids get_relids_in_jointree(Node *jtnode, bool include_outer_joins, bool include_inner_joins)
Node * add_nulling_relids(Node *node, const Bitmapset *target_relids, const Bitmapset *added_relids)

References add_nulling_relids(), Assert, bms_copy(), bms_equal(), bms_is_empty, bms_make_singleton(), contain_agg_clause(), contain_volatile_functions(), contain_window_function(), expression_returns_set(), get_relids_in_jointree(), make_placeholder_expr(), PlaceHolderVar::phlevelsup, PlaceHolderVar::phnullingrels, pull_varnos_of_level(), root, and Var::varlevelsup.

Referenced by flatten_group_exprs_mutator().

◆ pull_var_clause()

List* pull_var_clause ( Node node,
int  flags 
)

Definition at line 612 of file var.c.

613 {
615 
616  /* Assert that caller has not specified inconsistent flags */
623 
624  context.varlist = NIL;
625  context.flags = flags;
626 
628  return context.varlist;
629 }
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
#define PVC_RECURSE_PLACEHOLDERS
Definition: optimizer.h:191
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
#define PVC_INCLUDE_WINDOWFUNCS
Definition: optimizer.h:188
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
#define PVC_INCLUDE_AGGREGATES
Definition: optimizer.h:186
static bool pull_var_clause_walker(Node *node, pull_var_clause_context *context)
Definition: var.c:632

References Assert, context, NIL, pull_var_clause_walker(), PVC_INCLUDE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS, PVC_INCLUDE_WINDOWFUNCS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS, and PVC_RECURSE_WINDOWFUNCS.

Referenced by add_paths_with_pathkeys_for_rel(), AddRelationNewConstraints(), build_base_rel_tlists(), build_remote_returning(), build_tlist_to_deparse(), CreateTriggerFiringOn(), distribute_qual_to_rels(), estimate_num_groups(), find_computable_ec_member(), find_placeholders_in_expr(), fix_placeholder_input_needed_levels(), foreign_grouping_ok(), generate_base_implied_equalities_no_const(), make_group_input_target(), make_partial_grouping_target(), make_sort_input_target(), make_window_input_target(), preprocess_targetlist(), process_implied_equality(), qual_is_pushdown_safe(), rebuild_eclass_attr_needed(), rebuild_joinclause_attr_needed(), rebuild_placeholder_attr_needed(), semijoin_target_ok(), and StoreRelCheck().

◆ pull_var_clause_walker()

static bool pull_var_clause_walker ( Node node,
pull_var_clause_context context 
)
static

Definition at line 632 of file var.c.

633 {
634  if (node == NULL)
635  return false;
636  if (IsA(node, Var))
637  {
638  if (((Var *) node)->varlevelsup != 0)
639  elog(ERROR, "Upper-level Var found where not expected");
640  context->varlist = lappend(context->varlist, node);
641  return false;
642  }
643  else if (IsA(node, Aggref))
644  {
645  if (((Aggref *) node)->agglevelsup != 0)
646  elog(ERROR, "Upper-level Aggref found where not expected");
647  if (context->flags & PVC_INCLUDE_AGGREGATES)
648  {
649  context->varlist = lappend(context->varlist, node);
650  /* we do NOT descend into the contained expression */
651  return false;
652  }
653  else if (context->flags & PVC_RECURSE_AGGREGATES)
654  {
655  /* fall through to recurse into the aggregate's arguments */
656  }
657  else
658  elog(ERROR, "Aggref found where not expected");
659  }
660  else if (IsA(node, GroupingFunc))
661  {
662  if (((GroupingFunc *) node)->agglevelsup != 0)
663  elog(ERROR, "Upper-level GROUPING found where not expected");
664  if (context->flags & PVC_INCLUDE_AGGREGATES)
665  {
666  context->varlist = lappend(context->varlist, node);
667  /* we do NOT descend into the contained expression */
668  return false;
669  }
670  else if (context->flags & PVC_RECURSE_AGGREGATES)
671  {
672  /* fall through to recurse into the GroupingFunc's arguments */
673  }
674  else
675  elog(ERROR, "GROUPING found where not expected");
676  }
677  else if (IsA(node, WindowFunc))
678  {
679  /* WindowFuncs have no levelsup field to check ... */
680  if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
681  {
682  context->varlist = lappend(context->varlist, node);
683  /* we do NOT descend into the contained expressions */
684  return false;
685  }
686  else if (context->flags & PVC_RECURSE_WINDOWFUNCS)
687  {
688  /* fall through to recurse into the windowfunc's arguments */
689  }
690  else
691  elog(ERROR, "WindowFunc found where not expected");
692  }
693  else if (IsA(node, PlaceHolderVar))
694  {
695  if (((PlaceHolderVar *) node)->phlevelsup != 0)
696  elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
697  if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
698  {
699  context->varlist = lappend(context->varlist, node);
700  /* we do NOT descend into the contained expression */
701  return false;
702  }
703  else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
704  {
705  /* fall through to recurse into the placeholder's expression */
706  }
707  else
708  elog(ERROR, "PlaceHolderVar found where not expected");
709  }
711  (void *) context);
712 }

References context, elog, ERROR, expression_tree_walker, IsA, lappend(), PVC_INCLUDE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS, PVC_INCLUDE_WINDOWFUNCS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_PLACEHOLDERS, and PVC_RECURSE_WINDOWFUNCS.

Referenced by pull_var_clause().

◆ pull_varattnos()

void pull_varattnos ( Node node,
Index  varno,
Bitmapset **  varattnos 
)

◆ pull_varattnos_walker()

static bool pull_varattnos_walker ( Node node,
pull_varattnos_context context 
)
static

Definition at line 309 of file var.c.

310 {
311  if (node == NULL)
312  return false;
313  if (IsA(node, Var))
314  {
315  Var *var = (Var *) node;
316 
317  if (var->varno == context->varno && var->varlevelsup == 0)
318  context->varattnos =
319  bms_add_member(context->varattnos,
321  return false;
322  }
323 
324  /* Should not find an unplanned subquery */
325  Assert(!IsA(node, Query));
326 
328  (void *) context);
329 }
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27

References Assert, bms_add_member(), context, expression_tree_walker, FirstLowInvalidHeapAttributeNumber, IsA, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by pull_varattnos().

◆ pull_varnos()

Relids pull_varnos ( PlannerInfo root,
Node node 
)

Definition at line 113 of file var.c.

114 {
116 
117  context.varnos = NULL;
118  context.root = root;
119  context.sublevels_up = 0;
120 
121  /*
122  * Must be prepared to start with a Query or a bare expression tree; if
123  * it's a Query, we don't want to increment sublevels_up.
124  */
127  (void *) &context,
128  0);
129 
130  return context.varnos;
131 }
static bool pull_varnos_walker(Node *node, pull_varnos_context *context)
Definition: var.c:160

References context, pull_varnos_walker(), query_or_expression_tree_walker, and root.

Referenced by compute_semijoin_info(), convert_ANY_sublink_to_join(), convert_EXISTS_sublink_to_join(), cost_incremental_sort(), distribute_qual_to_rels(), examine_variable(), expand_indexqual_rowcompare(), extract_lateral_vars_from_PHVs(), find_placeholder_info(), get_eclass_for_sort_expr(), is_pseudo_constant_for_index(), IsTidEqualAnyClause(), join_is_removable(), make_outerjoininfo(), make_plain_restrictinfo(), match_rowcompare_to_indexcol(), match_saopclause_to_indexcol(), NumRelids(), pg_get_expr_worker(), process_implied_equality(), pullup_replace_vars_callback(), remove_rel_from_query(), and subquery_planner().

◆ pull_varnos_of_level()

Relids pull_varnos_of_level ( PlannerInfo root,
Node node,
int  levelsup 
)

Definition at line 139 of file var.c.

140 {
142 
143  context.varnos = NULL;
144  context.root = root;
145  context.sublevels_up = levelsup;
146 
147  /*
148  * Must be prepared to start with a Query or a bare expression tree; if
149  * it's a Query, we don't want to increment sublevels_up.
150  */
153  (void *) &context,
154  0);
155 
156  return context.varnos;
157 }

References context, pull_varnos_walker(), query_or_expression_tree_walker, and root.

Referenced by add_nullingrels_if_needed(), convert_ANY_sublink_to_join(), is_simple_subquery(), jointree_contains_lateral_outer_refs(), and mark_nullable_by_grouping().

◆ pull_varnos_walker()

static bool pull_varnos_walker ( Node node,
pull_varnos_context context 
)
static

Definition at line 160 of file var.c.

161 {
162  if (node == NULL)
163  return false;
164  if (IsA(node, Var))
165  {
166  Var *var = (Var *) node;
167 
168  if (var->varlevelsup == context->sublevels_up)
169  {
170  context->varnos = bms_add_member(context->varnos, var->varno);
171  context->varnos = bms_add_members(context->varnos,
172  var->varnullingrels);
173  }
174  return false;
175  }
176  if (IsA(node, CurrentOfExpr))
177  {
178  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
179 
180  if (context->sublevels_up == 0)
181  context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
182  return false;
183  }
184  if (IsA(node, PlaceHolderVar))
185  {
186  PlaceHolderVar *phv = (PlaceHolderVar *) node;
187 
188  /*
189  * If a PlaceHolderVar is not of the target query level, ignore it,
190  * instead recursing into its expression to see if it contains any
191  * vars that are of the target level. We'll also do that when the
192  * caller doesn't pass a "root" pointer. (We probably shouldn't see
193  * PlaceHolderVars at all in such cases, but if we do, this is a
194  * reasonable behavior.)
195  */
196  if (phv->phlevelsup == context->sublevels_up &&
197  context->root != NULL)
198  {
199  /*
200  * Ideally, the PHV's contribution to context->varnos is its
201  * ph_eval_at set. However, this code can be invoked before
202  * that's been computed. If we cannot find a PlaceHolderInfo,
203  * fall back to the conservative assumption that the PHV will be
204  * evaluated at its syntactic level (phv->phrels).
205  *
206  * Another problem is that a PlaceHolderVar can appear in quals or
207  * tlists that have been translated for use in a child appendrel.
208  * Typically such a PHV is a parameter expression sourced by some
209  * other relation, so that the translation from parent appendrel
210  * to child doesn't change its phrels, and we should still take
211  * ph_eval_at at face value. But in corner cases, the PHV's
212  * original phrels can include the parent appendrel itself, in
213  * which case the translated PHV will have the child appendrel in
214  * phrels, and we must translate ph_eval_at to match.
215  */
216  PlaceHolderInfo *phinfo = NULL;
217 
218  if (phv->phlevelsup == 0)
219  {
220  if (phv->phid < context->root->placeholder_array_size)
221  phinfo = context->root->placeholder_array[phv->phid];
222  }
223  if (phinfo == NULL)
224  {
225  /* No PlaceHolderInfo yet, use phrels */
226  context->varnos = bms_add_members(context->varnos,
227  phv->phrels);
228  }
229  else if (bms_equal(phv->phrels, phinfo->ph_var->phrels))
230  {
231  /* Normal case: use ph_eval_at */
232  context->varnos = bms_add_members(context->varnos,
233  phinfo->ph_eval_at);
234  }
235  else
236  {
237  /* Translated PlaceHolderVar: translate ph_eval_at to match */
238  Relids newevalat,
239  delta;
240 
241  /* remove what was removed from phv->phrels ... */
242  delta = bms_difference(phinfo->ph_var->phrels, phv->phrels);
243  newevalat = bms_difference(phinfo->ph_eval_at, delta);
244  /* ... then if that was in fact part of ph_eval_at ... */
245  if (!bms_equal(newevalat, phinfo->ph_eval_at))
246  {
247  /* ... add what was added */
248  delta = bms_difference(phv->phrels, phinfo->ph_var->phrels);
249  newevalat = bms_join(newevalat, delta);
250  }
251  context->varnos = bms_join(context->varnos,
252  newevalat);
253  }
254 
255  /*
256  * In all three cases, include phnullingrels in the result. We
257  * don't worry about possibly needing to translate it, because
258  * appendrels only translate varnos of baserels, not outer joins.
259  */
260  context->varnos = bms_add_members(context->varnos,
261  phv->phnullingrels);
262  return false; /* don't recurse into expression */
263  }
264  }
265  else if (IsA(node, Query))
266  {
267  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
268  bool result;
269 
270  context->sublevels_up++;
271  result = query_tree_walker((Query *) node, pull_varnos_walker,
272  (void *) context, 0);
273  context->sublevels_up--;
274  return result;
275  }
277  (void *) context);
278 }
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:346
Relids ph_eval_at
Definition: pathnodes.h:3098
PlaceHolderVar * ph_var
Definition: pathnodes.h:3095

References bms_add_member(), bms_add_members(), bms_difference(), bms_equal(), bms_join(), context, CurrentOfExpr::cvarno, expression_tree_walker, IsA, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_var, PlaceHolderVar::phid, PlaceHolderVar::phlevelsup, PlaceHolderVar::phnullingrels, query_tree_walker, Var::varlevelsup, and Var::varno.

Referenced by pull_varnos(), and pull_varnos_of_level().

◆ pull_vars_of_level()

List* pull_vars_of_level ( Node node,
int  levelsup 
)

Definition at line 340 of file var.c.

341 {
343 
344  context.vars = NIL;
345  context.sublevels_up = levelsup;
346 
347  /*
348  * Must be prepared to start with a Query or a bare expression tree; if
349  * it's a Query, we don't want to increment sublevels_up.
350  */
353  (void *) &context,
354  0);
355 
356  return context.vars;
357 }
static bool pull_vars_walker(Node *node, pull_vars_context *context)
Definition: var.c:360

References context, NIL, pull_vars_walker(), and query_or_expression_tree_walker.

Referenced by extract_lateral_references(), and extract_lateral_vars_from_PHVs().

◆ pull_vars_walker()

static bool pull_vars_walker ( Node node,
pull_vars_context context 
)
static

Definition at line 360 of file var.c.

361 {
362  if (node == NULL)
363  return false;
364  if (IsA(node, Var))
365  {
366  Var *var = (Var *) node;
367 
368  if (var->varlevelsup == context->sublevels_up)
369  context->vars = lappend(context->vars, var);
370  return false;
371  }
372  if (IsA(node, PlaceHolderVar))
373  {
374  PlaceHolderVar *phv = (PlaceHolderVar *) node;
375 
376  if (phv->phlevelsup == context->sublevels_up)
377  context->vars = lappend(context->vars, phv);
378  /* we don't want to look into the contained expression */
379  return false;
380  }
381  if (IsA(node, Query))
382  {
383  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
384  bool result;
385 
386  context->sublevels_up++;
387  result = query_tree_walker((Query *) node, pull_vars_walker,
388  (void *) context, 0);
389  context->sublevels_up--;
390  return result;
391  }
393  (void *) context);
394 }

References context, expression_tree_walker, IsA, lappend(), PlaceHolderVar::phlevelsup, query_tree_walker, and Var::varlevelsup.

Referenced by pull_vars_of_level().