typedefstruct
{
Relids varnos;
PlannerInfo *root; int sublevels_up;
} pull_varnos_context;
typedefstruct
{
Bitmapset *varattnos;
Index varno;
} pull_varattnos_context;
typedefstruct
{
List *vars; int sublevels_up;
} pull_vars_context;
typedefstruct
{ int var_location; int sublevels_up;
} locate_var_of_level_context;
typedefstruct
{
List *varlist; int flags;
} pull_var_clause_context;
typedefstruct
{
PlannerInfo *root; /* could be NULL! */
Query *query; /* outer Query */ int sublevels_up; bool possible_sublink; /* could aliases include a SubLink? */ bool inserted_sublink; /* have we inserted a SubLink? */
} flatten_join_alias_vars_context;
if (phv->phlevelsup == 0)
{ if (phv->phid < context->root->placeholder_array_size)
phinfo = context->root->placeholder_array[phv->phid];
} if (phinfo == NULL)
{ /* No PlaceHolderInfo yet, use phrels */
context->varnos = bms_add_members(context->varnos,
phv->phrels);
} elseif (bms_equal(phv->phrels, phinfo->ph_var->phrels))
{ /* Normal case: use ph_eval_at */
context->varnos = bms_add_members(context->varnos,
phinfo->ph_eval_at);
} else
{ /* Translated PlaceHolderVar: translate ph_eval_at to match */
Relids newevalat,
delta;
/* remove what was removed from phv->phrels ... */
delta = bms_difference(phinfo->ph_var->phrels, phv->phrels);
newevalat = bms_difference(phinfo->ph_eval_at, delta); /* ... then if that was in fact part of ph_eval_at ... */ if (!bms_equal(newevalat, phinfo->ph_eval_at))
{ /* ... add what was added */
delta = bms_difference(phv->phrels, phinfo->ph_var->phrels);
newevalat = bms_join(newevalat, delta);
}
context->varnos = bms_join(context->varnos,
newevalat);
}
staticbool
pull_vars_walker(Node *node, pull_vars_context *context)
{ if (node == NULL) returnfalse; if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up)
context->vars = lappend(context->vars, var); returnfalse;
} if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
if (phv->phlevelsup == context->sublevels_up)
context->vars = lappend(context->vars, phv); /* we don't want to look into the contained expression */ returnfalse;
} if (IsA(node, Query))
{ /* Recurse into RTE subquery or not-yet-planned sublink subquery */ bool result;
staticbool
contain_var_clause_walker(Node *node, void *context)
{ if (node == NULL) returnfalse; if (IsA(node, Var))
{ if (((Var *) node)->varlevelsup == 0) returntrue; /* abort the tree traversal and return true */ returnfalse;
} if (IsA(node, CurrentOfExpr)) returntrue; if (IsA(node, PlaceHolderVar))
{ if (((PlaceHolderVar *) node)->phlevelsup == 0) returntrue; /* abort the tree traversal and return true */ /* else fall through to check the contained expr */
} return expression_tree_walker(node, contain_var_clause_walker, context);
}
/* *contain_vars_of_level *RecursivelyscanaclausetodiscoverwhetheritcontainsanyVarnodes *ofthespecifiedquerylevel. * *ReturnstrueifanysuchVarfound. * *Willrecurseintosublinks.Also,maybeinvokeddirectlyonaQuery.
*/ bool
contain_vars_of_level(Node *node, int levelsup)
{ int sublevels_up = levelsup;
staticbool
contain_vars_of_level_walker(Node *node, int *sublevels_up)
{ if (node == NULL) returnfalse; if (IsA(node, Var))
{ if (((Var *) node)->varlevelsup == *sublevels_up) returntrue; /* abort tree traversal and return true */ returnfalse;
} if (IsA(node, CurrentOfExpr))
{ if (*sublevels_up == 0) returntrue; returnfalse;
} if (IsA(node, PlaceHolderVar))
{ if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up) returntrue; /* abort the tree traversal and return true */ /* else fall through to check the contained expr */
} if (IsA(node, Query))
{ /* Recurse into subselects */ bool result;
staticbool
locate_var_of_level_walker(Node *node,
locate_var_of_level_context *context)
{ if (node == NULL) returnfalse; if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->location >= 0)
{
context->var_location = var->location; returntrue; /* abort tree traversal and return true */
} returnfalse;
} if (IsA(node, CurrentOfExpr))
{ /* since CurrentOfExpr doesn't carry location, nothing we can do */ returnfalse;
} /* No extra code needed for PlaceHolderVar; just look in contained expr */ if (IsA(node, Query))
{ /* Recurse into subselects */ bool result;
staticbool
pull_var_clause_walker(Node *node, pull_var_clause_context *context)
{ if (node == NULL) returnfalse; if (IsA(node, Var))
{ if (((Var *) node)->varlevelsup != 0)
elog(ERROR, "Upper-level Var found where not expected");
context->varlist = lappend(context->varlist, node); returnfalse;
} elseif (IsA(node, Aggref))
{ if (((Aggref *) node)->agglevelsup != 0)
elog(ERROR, "Upper-level Aggref found where not expected"); if (context->flags & PVC_INCLUDE_AGGREGATES)
{
context->varlist = lappend(context->varlist, node); /* we do NOT descend into the contained expression */ returnfalse;
} elseif (context->flags & PVC_RECURSE_AGGREGATES)
{ /* fall through to recurse into the aggregate's arguments */
} else
elog(ERROR, "Aggref found where not expected");
} elseif (IsA(node, GroupingFunc))
{ if (((GroupingFunc *) node)->agglevelsup != 0)
elog(ERROR, "Upper-level GROUPING found where not expected"); if (context->flags & PVC_INCLUDE_AGGREGATES)
{
context->varlist = lappend(context->varlist, node); /* we do NOT descend into the contained expression */ returnfalse;
} elseif (context->flags & PVC_RECURSE_AGGREGATES)
{ /* fall through to recurse into the GroupingFunc's arguments */
} else
elog(ERROR, "GROUPING found where not expected");
} elseif (IsA(node, WindowFunc))
{ /* WindowFuncs have no levelsup field to check ... */ if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
{
context->varlist = lappend(context->varlist, node); /* we do NOT descend into the contained expressions */ returnfalse;
} elseif (context->flags & PVC_RECURSE_WINDOWFUNCS)
{ /* fall through to recurse into the windowfunc's arguments */
} else
elog(ERROR, "WindowFunc found where not expected");
} elseif (IsA(node, PlaceHolderVar))
{ if (((PlaceHolderVar *) node)->phlevelsup != 0)
elog(ERROR, "Upper-level PlaceHolderVar found where not expected"); if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
{
context->varlist = lappend(context->varlist, node); /* we do NOT descend into the contained expression */ returnfalse;
} elseif (context->flags & PVC_RECURSE_PLACEHOLDERS)
{ /* fall through to recurse into the placeholder's expression */
} else
elog(ERROR, "PlaceHolderVar found where not expected");
} return expression_tree_walker(node, pull_var_clause_walker, context);
}
context.root = root;
context.query = query;
context.sublevels_up = 0; /* flag whether join aliases could possibly contain SubLinks */
context.possible_sublink = query->hasSubLinks; /* if hasSubLinks is already true, no need to work hard */
context.inserted_sublink = query->hasSubLinks;
static Node *
flatten_join_alias_vars_mutator(Node *node,
flatten_join_alias_vars_context *context)
{ if (node == NULL) return NULL; if (IsA(node, Var))
{
Var *var = (Var *) node;
RangeTblEntry *rte;
Node *newvar;
/* No change unless Var belongs to a JOIN of the target level */ if (var->varlevelsup != context->sublevels_up) return node; /* no need to copy, really */
rte = rt_fetch(var->varno, context->query->rtable); if (rte->rtekind != RTE_JOIN) return node; if (var->varattno == InvalidAttrNumber)
{ /* Must expand whole-row reference */
RowExpr *rowexpr;
List *fields = NIL;
List *colnames = NIL;
ListCell *lv;
ListCell *ln;
/* *Ifweareexpandinganaliascarrieddownfromanupper *query,mustadjustitsvarlevelsupfields.
*/ if (context->sublevels_up != 0)
IncrementVarSublevelsUp(newvar, context->sublevels_up, 0); /* Preserve original Var's location, if possible */ if (IsA(newvar, Var))
((Var *) newvar)->location = var->location; /* Recurse in case join input is itself a join */ /* (also takes care of setting inserted_sublink if needed) */
newvar = flatten_join_alias_vars_mutator(newvar, context);
fields = lappend(fields, newvar); /* We need the names of non-dropped columns, too */
colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
}
rowexpr = makeNode(RowExpr);
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST; /* vartype will always be RECORDOID, so we always need colnames */
rowexpr->colnames = colnames;
rowexpr->location = var->location;
/* Lastly, add any varnullingrels to the replacement expression */ return add_nullingrels_if_needed(context->root, (Node *) rowexpr,
var);
}
/* Preserve original Var's location, if possible */ if (IsA(newvar, Var))
((Var *) newvar)->location = var->location;
/* Recurse in case join input is itself a join */
newvar = flatten_join_alias_vars_mutator(newvar, context);
/* Detect if we are adding a sublink to query */ if (context->possible_sublink && !context->inserted_sublink)
context->inserted_sublink = checkExprHasSubLink(newvar);
/* Lastly, add any varnullingrels to the replacement expression */ return add_nullingrels_if_needed(context->root, newvar, var);
} if (IsA(node, PlaceHolderVar))
{ /* Copy the PlaceHolderVar node with correct mutation of subnodes */
PlaceHolderVar *phv;
context.root = root;
context.query = query;
context.sublevels_up = 0; /* flag whether grouping expressions could possibly contain SubLinks */
context.possible_sublink = query->hasSubLinks; /* if hasSubLinks is already true, no need to work hard */
context.inserted_sublink = query->hasSubLinks;
static Node *
flatten_group_exprs_mutator(Node *node,
flatten_join_alias_vars_context *context)
{ if (node == NULL) return NULL; if (IsA(node, Var))
{
Var *var = (Var *) node;
RangeTblEntry *rte;
Node *newvar;
/* No change unless Var belongs to the GROUP of the target level */ if (var->varlevelsup != context->sublevels_up) return node; /* no need to copy, really */
rte = rt_fetch(var->varno, context->query->rtable); if (rte->rtekind != RTE_GROUP) return node;
/* Preserve original Var's location, if possible */ if (IsA(newvar, Var))
((Var *) newvar)->location = var->location;
/* Detect if we are adding a sublink to query */ if (context->possible_sublink && !context->inserted_sublink)
context->inserted_sublink = checkExprHasSubLink(newvar);
/* Lastly, add any varnullingrels to the replacement expression */ return mark_nullable_by_grouping(context->root, newvar, var);
}
if (IsA(node, Aggref))
{
Aggref *agg = (Aggref *) node;