📄 setrefs.c
字号:
foreach(entry, tlist) { AttrNumber oattno; xtl = lfirst(entry); if (IsA(get_expr(xtl), Var)) oattno = ((Var *) xtl->expr)->varoattno; else oattno = 0; noname = makeTargetEntry(xtl->resdom, (Node *) makeVar(nonameid, xtl->resdom->resno, xtl->resdom->restype, xtl->resdom->restypmod, 0, nonameid, oattno)); t_list = lappend(t_list, noname); } return t_list;}/*--------------------------------------------------------- * * set_result_tlist_references * * Change the target list of a Result node, so that it correctly * addresses the tuples returned by its left tree subplan. * * NOTE: * 1) we ignore the right tree! (in the current implementation * it is always nil * 2) this routine will probably *NOT* work with nested dot * fields.... */static voidset_result_tlist_references(Result *resultNode){ Plan *subplan; List *resultTargetList; List *subplanTargetList; resultTargetList = ((Plan *) resultNode)->targetlist; /* * NOTE: we only consider the left tree subplan. This is usually a seq * scan. */ subplan = ((Plan *) resultNode)->lefttree; if (subplan != NULL) subplanTargetList = subplan->targetlist; else subplanTargetList = NIL; replace_tlist_with_subplan_refs(resultTargetList, (Index) OUTER, subplanTargetList);}/*--------------------------------------------------------- * * replace_tlist_with_subplan_refs * * Applies replace_vars_with_subplan_refs() to each entry of a targetlist. */voidreplace_tlist_with_subplan_refs(List *tlist, Index subvarno, List *subplanTargetList){ List *t; foreach(t, tlist) { TargetEntry *entry = (TargetEntry *) lfirst(t); replace_vars_with_subplan_refs((Node *) get_expr(entry), subvarno, subplanTargetList); }}/*--------------------------------------------------------- * * replace_vars_with_subplan_refs * * This routine modifies (destructively!) an expression tree so that all * Var nodes reference target nodes of a subplan. It is used to fix up * target expressions of upper-level plan nodes. * * 'clause': the tree to be fixed * 'subvarno': varno to be assigned to all Vars * 'subplanTargetList': target list for subplan * * Afterwards, all Var nodes have varno = subvarno, varattno = resno * of corresponding subplan target. */static voidreplace_vars_with_subplan_refs(Node *clause, Index subvarno, List *subplanTargetList){ List *t; if (clause == NULL) return; if (IsA(clause, Var)) { /* * Ha! A Var node! * * It could be that this varnode has been created by make_groupplan * and is already set up to reference the subplan target list. We * recognize that case by varno = 1, varnoold = -1, varattno = * varoattno, and varlevelsup = 0. (Probably ought to have an * explicit flag, but this should do for now.) */ Var *var = (Var *) clause; TargetEntry *subplanVar; if (var->varno == (Index) 1 && var->varnoold == ((Index) -1) && var->varattno == var->varoattno && var->varlevelsup == 0) return; /* OK to leave it alone */ /* Otherwise it had better be in the subplan list. */ subplanVar = match_varid(var, subplanTargetList); if (!subplanVar) elog(ERROR, "replace_vars_with_subplan_refs: variable not in target list"); /* * Change the varno & varattno fields of the var node. */ var->varno = subvarno; var->varattno = subplanVar->resdom->resno; } else if (single_node(clause)) { /* do nothing! */ } else if (IsA(clause, Iter)) replace_vars_with_subplan_refs(((Iter *) clause)->iterexpr, subvarno, subplanTargetList); else if (is_subplan(clause)) { foreach(t, ((Expr *) clause)->args) replace_vars_with_subplan_refs(lfirst(t), subvarno, subplanTargetList); foreach(t, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper) replace_vars_with_subplan_refs(lfirst(((Expr *) lfirst(t))->args), subvarno, subplanTargetList); } else if (IsA(clause, Expr)) { /* * Recursively scan the arguments of an expression. NOTE: this * must come after is_subplan() case since subplan is a kind of * Expr node. */ foreach(t, ((Expr *) clause)->args) replace_vars_with_subplan_refs(lfirst(t), subvarno, subplanTargetList); } else if (IsA(clause, Aggref)) replace_vars_with_subplan_refs(((Aggref *) clause)->target, subvarno, subplanTargetList); else if (IsA(clause, ArrayRef)) { ArrayRef *aref = (ArrayRef *) clause; foreach(t, aref->refupperindexpr) replace_vars_with_subplan_refs(lfirst(t), subvarno, subplanTargetList); foreach(t, aref->reflowerindexpr) replace_vars_with_subplan_refs(lfirst(t), subvarno, subplanTargetList); replace_vars_with_subplan_refs(aref->refexpr, subvarno, subplanTargetList); replace_vars_with_subplan_refs(aref->refassgnexpr, subvarno, subplanTargetList); } else if (case_clause(clause)) { foreach(t, ((CaseExpr *) clause)->args) { CaseWhen *when = (CaseWhen *) lfirst(t); replace_vars_with_subplan_refs(when->expr, subvarno, subplanTargetList); replace_vars_with_subplan_refs(when->result, subvarno, subplanTargetList); } replace_vars_with_subplan_refs(((CaseExpr *) clause)->defresult, subvarno, subplanTargetList); } else { elog(ERROR, "replace_vars_with_subplan_refs: Cannot handle node type %d", nodeTag(clause)); }}static boolOperandIsInner(Node *opnd, int inner_relid){ /* * Can be the inner scan if its a varnode or a function and the * inner_relid is equal to the varnode's var number or in the case of * a function the first argument's var number (all args in a * functional index are from the same relation). */ if (IsA(opnd, Var) && (inner_relid == ((Var *) opnd)->varno)) return true; if (is_funcclause(opnd)) { List *firstArg = lfirst(((Expr *) opnd)->args); if (IsA(firstArg, Var) && (inner_relid == ((Var *) firstArg)->varno)) return true; } return false;}/***************************************************************************** * *****************************************************************************//*--------------------------------------------------------- * * set_agg_tlist_references - * This routine has several responsibilities: * * Update the target list of an Agg node so that it points to * the tuples returned by its left tree subplan. * * If there is a qual list (from a HAVING clause), similarly update * vars in it to point to the subplan target list. * * Generate the aggNode->aggs list of Aggref nodes contained in the Agg. * * The return value is TRUE if all qual clauses include Aggrefs, or FALSE * if any do not (caller may choose to raise an error condition). */boolset_agg_tlist_references(Agg *aggNode){ List *subplanTargetList; List *tl; List *ql; bool all_quals_ok; subplanTargetList = aggNode->plan.lefttree->targetlist; aggNode->aggs = NIL; foreach(tl, aggNode->plan.targetlist) { TargetEntry *tle = lfirst(tl); replace_vars_with_subplan_refs(tle->expr, (Index) 0, subplanTargetList); aggNode->aggs = nconc(pull_agg_clause(tle->expr), aggNode->aggs); } all_quals_ok = true; foreach(ql, aggNode->plan.qual) { Node *qual = lfirst(ql); List *qualaggs; replace_vars_with_subplan_refs(qual, (Index) 0, subplanTargetList); qualaggs = pull_agg_clause(qual); if (qualaggs == NIL) all_quals_ok = false; /* this qual clause has no agg * functions! */ else aggNode->aggs = nconc(qualaggs, aggNode->aggs); } return all_quals_ok;}/* * Make a list of all Aggref nodes contained in the given expression. */static List *pull_agg_clause(Node *clause){ List *agg_list = NIL; List *t; if (clause == NULL) return NIL; else if (single_node(clause)) return NIL; else if (IsA(clause, Iter)) return pull_agg_clause(((Iter *) clause)->iterexpr); else if (is_subplan(clause)) { SubLink *sublink = ((SubPlan *) ((Expr *) clause)->oper)->sublink; /* * Only the lefthand side of the sublink should be checked for * aggregates to be attached to the aggs list */ foreach(t, sublink->lefthand) agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list); /* The first argument of ...->oper has also to be checked */ foreach(t, sublink->oper) agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list); } else if (IsA(clause, Expr)) { /* * Recursively scan the arguments of an expression. NOTE: this * must come after is_subplan() case since subplan is a kind of * Expr node. */ foreach(t, ((Expr *) clause)->args) agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list); } else if (IsA(clause, Aggref)) { return lcons(clause, pull_agg_clause(((Aggref *) clause)->target)); } else if (IsA(clause, ArrayRef)) { ArrayRef *aref = (ArrayRef *) clause; foreach(t, aref->refupperindexpr) agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list); foreach(t, aref->reflowerindexpr) agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list); agg_list = nconc(pull_agg_clause(aref->refexpr), agg_list); agg_list = nconc(pull_agg_clause(aref->refassgnexpr), agg_list); } else if (case_clause(clause)) { foreach(t, ((CaseExpr *) clause)->args) { CaseWhen *when = (CaseWhen *) lfirst(t); agg_list = nconc(agg_list, pull_agg_clause(when->expr)); agg_list = nconc(agg_list, pull_agg_clause(when->result)); } agg_list = nconc(pull_agg_clause(((CaseExpr *) clause)->defresult), agg_list); } else { elog(ERROR, "pull_agg_clause: Cannot handle node type %d", nodeTag(clause)); } return agg_list;}/* * check_having_for_ungrouped_vars takes the havingQual and the list of * GROUP BY clauses and checks for subplans in the havingQual that are being * passed ungrouped variables as parameters. In other contexts, ungrouped * vars in the havingQual will be detected by the parser (see parse_agg.c, * exprIsAggOrGroupCol()). But that routine currently does not check subplans, * because the necessary info is not computed until the planner runs. * This ought to be cleaned up someday. * * NOTE: the havingClause has been cnf-ified, so AND subclauses have been * turned into a plain List. Thus, this routine has to cope with List nodes * where the routine above does not... */voidcheck_having_for_ungrouped_vars(Node *clause, List *groupClause, List *targetList){ List *t; if (clause == NULL) return; if (IsA(clause, Var)) { /* * Ignore vars elsewhere in the having clause, since the parser * already checked 'em. */ } else if (single_node(clause)) { /* ignore */ } else if (IsA(clause, Iter)) { check_having_for_ungrouped_vars(((Iter *) clause)->iterexpr, groupClause, targetList); } else if (is_subplan(clause)) { /* * The args list of the subplan node represents attributes from * outside passed into the sublink. */ foreach(t, ((Expr *) clause)->args) { bool contained_in_group_clause = false; List *gl; foreach(gl, groupClause) { if (var_equal(lfirst(t), get_groupclause_expr((GroupClause *) lfirst(gl), targetList))) { contained_in_group_clause = true; break; } } if (!contained_in_group_clause) elog(ERROR, "Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT"); } } else if (IsA(clause, Expr)) { /* * Recursively scan the arguments of an expression. NOTE: this * must come after is_subplan() case since subplan is a kind of * Expr node. */ foreach(t, ((Expr *) clause)->args) check_having_for_ungrouped_vars(lfirst(t), groupClause, targetList); } else if (IsA(clause, List)) { /* * Recursively scan AND subclauses (see NOTE above). */ foreach(t, ((List *) clause)) check_having_for_ungrouped_vars(lfirst(t), groupClause, targetList); } else if (IsA(clause, Aggref)) { check_having_for_ungrouped_vars(((Aggref *) clause)->target, groupClause, targetList); } else if (IsA(clause, ArrayRef)) { ArrayRef *aref = (ArrayRef *) clause; /* * This is an arrayref. Recursively call this routine for its * expression and its index expression... */ foreach(t, aref->refupperindexpr) check_having_for_ungrouped_vars(lfirst(t), groupClause, targetList); foreach(t, aref->reflowerindexpr) check_having_for_ungrouped_vars(lfirst(t), groupClause, targetList); check_having_for_ungrouped_vars(aref->refexpr, groupClause, targetList); check_having_for_ungrouped_vars(aref->refassgnexpr, groupClause, targetList); } else if (case_clause(clause)) { foreach(t, ((CaseExpr *) clause)->args) { CaseWhen *when = (CaseWhen *) lfirst(t); check_having_for_ungrouped_vars(when->expr, groupClause, targetList); check_having_for_ungrouped_vars(when->result, groupClause, targetList); } check_having_for_ungrouped_vars(((CaseExpr *) clause)->defresult, groupClause, targetList); } else { elog(ERROR, "check_having_for_ungrouped_vars: Cannot handle node type %d", nodeTag(clause)); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -