📄 var.c
字号:
} return expression_tree_walker(node, contain_vars_above_level_walker, (void *) sublevels_up);}/* * find_minimum_var_level * Recursively scan a clause to find the lowest variable level it * contains --- for example, zero is returned if there are any local * variables, one if there are no local variables but there are * one-level-up outer references, etc. Subqueries are scanned to see * if they possess relevant outer references. (But any local variables * within subqueries are not relevant.) * * -1 is returned if the clause has no variables at all. * * Will recurse into sublinks. Also, may be invoked directly on a Query. */intfind_minimum_var_level(Node *node){ find_minimum_var_level_context context; context.min_varlevel = -1; /* signifies nothing found yet */ context.sublevels_up = 0; (void) query_or_expression_tree_walker(node, find_minimum_var_level_walker, (void *) &context, 0); return context.min_varlevel;}static boolfind_minimum_var_level_walker(Node *node, find_minimum_var_level_context *context){ if (node == NULL) return false; if (IsA(node, Var)) { int varlevelsup = ((Var *) node)->varlevelsup; /* convert levelsup to frame of reference of original query */ varlevelsup -= context->sublevels_up; /* ignore local vars of subqueries */ if (varlevelsup >= 0) { if (context->min_varlevel < 0 || context->min_varlevel > varlevelsup) { context->min_varlevel = varlevelsup; /* * As soon as we find a local variable, we can abort the tree * traversal, since min_varlevel is then certainly 0. */ if (varlevelsup == 0) return true; } } } /* * An Aggref must be treated like a Var of its level. Normally we'd get * the same result from looking at the Vars in the aggregate's argument, * but this fails in the case of a Var-less aggregate call (COUNT(*)). */ if (IsA(node, Aggref)) { int agglevelsup = ((Aggref *) node)->agglevelsup; /* convert levelsup to frame of reference of original query */ agglevelsup -= context->sublevels_up; /* ignore local aggs of subqueries */ if (agglevelsup >= 0) { if (context->min_varlevel < 0 || context->min_varlevel > agglevelsup) { context->min_varlevel = agglevelsup; /* * As soon as we find a local aggregate, we can abort the tree * traversal, since min_varlevel is then certainly 0. */ if (agglevelsup == 0) return true; } } } if (IsA(node, Query)) { /* Recurse into subselects */ bool result; context->sublevels_up++; result = query_tree_walker((Query *) node, find_minimum_var_level_walker, (void *) context, 0); context->sublevels_up--; return result; } return expression_tree_walker(node, find_minimum_var_level_walker, (void *) context);}/* * pull_var_clause * Recursively pulls all var nodes from an expression clause. * * Upper-level vars (with varlevelsup > 0) are included only * if includeUpperVars is true. Most callers probably want * to ignore upper-level vars. * * Returns list of varnodes found. Note the varnodes themselves are not * copied, only referenced. * * Does not examine subqueries, therefore must only be used after reduction * of sublinks to subplans! */List *pull_var_clause(Node *node, bool includeUpperVars){ pull_var_clause_context context; context.varlist = NIL; context.includeUpperVars = includeUpperVars; pull_var_clause_walker(node, &context); return context.varlist;}static boolpull_var_clause_walker(Node *node, pull_var_clause_context *context){ if (node == NULL) return false; if (IsA(node, Var)) { if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars) context->varlist = lappend(context->varlist, node); return false; } return expression_tree_walker(node, pull_var_clause_walker, (void *) context);}/* * flatten_join_alias_vars * Replace Vars that reference JOIN outputs with references to the original * relation variables instead. This allows quals involving such vars to be * pushed down. Whole-row Vars that reference JOIN relations are expanded * into RowExpr constructs that name the individual output Vars. This * is necessary since we will not scan the JOIN as a base relation, which * is the only way that the executor can directly handle whole-row Vars. * * NOTE: this is used on not-yet-planned expressions. We do not expect it * to be applied directly to a Query node. */Node *flatten_join_alias_vars(PlannerInfo *root, Node *node){ flatten_join_alias_vars_context context; context.root = root; context.sublevels_up = 0; return flatten_join_alias_vars_mutator(node, &context);}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->root->parse->rtable); if (rte->rtekind != RTE_JOIN) return node; if (var->varattno == InvalidAttrNumber) { /* Must expand whole-row reference */ RowExpr *rowexpr; List *fields = NIL; AttrNumber attnum; ListCell *l; attnum = 0; foreach(l, rte->joinaliasvars) { newvar = (Node *) lfirst(l); attnum++; /* Ignore dropped columns */ if (IsA(newvar, Const)) continue; /* * If we are expanding an alias carried down from an upper * query, must adjust its varlevelsup fields. */ if (context->sublevels_up != 0) { newvar = copyObject(newvar); IncrementVarSublevelsUp(newvar, context->sublevels_up, 0); } /* Recurse in case join input is itself a join */ newvar = flatten_join_alias_vars_mutator(newvar, context); fields = lappend(fields, newvar); } rowexpr = makeNode(RowExpr); rowexpr->args = fields; rowexpr->row_typeid = var->vartype; rowexpr->row_format = COERCE_IMPLICIT_CAST; return (Node *) rowexpr; } /* Expand join alias reference */ Assert(var->varattno > 0); newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1); /* * If we are expanding an alias carried down from an upper query, must * adjust its varlevelsup fields. */ if (context->sublevels_up != 0) { newvar = copyObject(newvar); IncrementVarSublevelsUp(newvar, context->sublevels_up, 0); } /* Recurse in case join input is itself a join */ return flatten_join_alias_vars_mutator(newvar, context); } if (IsA(node, InClauseInfo)) { /* Copy the InClauseInfo node with correct mutation of subnodes */ InClauseInfo *ininfo; ininfo = (InClauseInfo *) expression_tree_mutator(node, flatten_join_alias_vars_mutator, (void *) context); /* now fix InClauseInfo's relid sets */ if (context->sublevels_up == 0) { ininfo->lefthand = alias_relid_set(context->root, ininfo->lefthand); ininfo->righthand = alias_relid_set(context->root, ininfo->righthand); } return (Node *) ininfo; } if (IsA(node, Query)) { /* Recurse into RTE subquery or not-yet-planned sublink subquery */ Query *newnode; context->sublevels_up++; newnode = query_tree_mutator((Query *) node, flatten_join_alias_vars_mutator, (void *) context, QTW_IGNORE_JOINALIASES); context->sublevels_up--; return (Node *) newnode; } /* Already-planned tree not supported */ Assert(!is_subplan(node)); return expression_tree_mutator(node, flatten_join_alias_vars_mutator, (void *) context);}/* * alias_relid_set: in a set of RT indexes, replace joins by their * underlying base relids */static Relidsalias_relid_set(PlannerInfo *root, Relids relids){ Relids result = NULL; Relids tmprelids; int rtindex; tmprelids = bms_copy(relids); while ((rtindex = bms_first_member(tmprelids)) >= 0) { RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable); if (rte->rtekind == RTE_JOIN) result = bms_join(result, get_relids_for_join(root, rtindex)); else result = bms_add_member(result, rtindex); } bms_free(tmprelids); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -