📄 setrefs.c
字号:
/*------------------------------------------------------------------------- * * setrefs.c * Routines to change varno/attno entries to contain references * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.50.2.1 1999/08/02 06:27:03 scrappy Exp $ * *------------------------------------------------------------------------- */#include <sys/types.h>#include "postgres.h"#include "nodes/makefuncs.h"#include "nodes/nodeFuncs.h"#include "optimizer/clauses.h"#include "optimizer/planmain.h"#include "optimizer/tlist.h"#include "optimizer/var.h"static void set_join_tlist_references(Join *join);static void set_nonamescan_tlist_references(SeqScan *nonamescan);static void set_noname_tlist_references(Noname *noname);static Node *replace_clause_joinvar_refs(Node *clause, List *outer_tlist, List *inner_tlist);static Var *replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist);static List *tlist_noname_references(Oid nonameid, List *tlist);static bool OperandIsInner(Node *opnd, int inner_relid);static List *pull_agg_clause(Node *clause);static void set_result_tlist_references(Result *resultNode);static void replace_vars_with_subplan_refs(Node *clause, Index subvarno, List *subplanTargetList);/***************************************************************************** * * SUBPLAN REFERENCES * *****************************************************************************//* * set_tlist_references * Modifies the target list of nodes in a plan to reference target lists * at lower levels. * * 'plan' is the plan whose target list and children's target lists will * be modified * * Returns nothing of interest, but modifies internal fields of nodes. * */voidset_tlist_references(Plan *plan){ if (plan == NULL) return; if (IsA_Join(plan)) set_join_tlist_references((Join *) plan); else if (IsA(plan, SeqScan) &&plan->lefttree && IsA_Noname(plan->lefttree)) set_nonamescan_tlist_references((SeqScan *) plan); else if (IsA(plan, Sort)) set_noname_tlist_references((Noname *) plan); else if (IsA(plan, Result)) set_result_tlist_references((Result *) plan); else if (IsA(plan, Hash)) set_tlist_references(plan->lefttree);}/* * set_join_tlist_references * Modifies the target list of a join node by setting the varnos and * varattnos to reference the target list of the outer and inner join * relations. * * Creates a target list for a join node to contain references by setting * varno values to OUTER or INNER and setting attno values to the * result domain number of either the corresponding outer or inner join * tuple. * * 'join' is a join plan node * * Returns nothing of interest, but modifies internal fields of nodes. * */static voidset_join_tlist_references(Join *join){ Plan *outer = ((Plan *) join)->lefttree; Plan *inner = ((Plan *) join)->righttree; List *outer_tlist = ((outer == NULL) ? NIL : outer->targetlist); List *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist); List *new_join_targetlist = NIL; List *qptlist = ((Plan *) join)->targetlist; List *entry; foreach(entry, qptlist) { TargetEntry *xtl = (TargetEntry *) lfirst(entry); Node *joinvar = replace_clause_joinvar_refs(xtl->expr, outer_tlist, inner_tlist); new_join_targetlist = lappend(new_join_targetlist, makeTargetEntry(xtl->resdom, joinvar)); } ((Plan *) join)->targetlist = new_join_targetlist; if (outer != NULL) set_tlist_references(outer); if (inner != NULL) set_tlist_references(inner);}/* * set_nonamescan_tlist_references * Modifies the target list of a node that scans a noname relation (i.e., a * sort or hash node) so that the varnos refer to the child noname. * * 'nonamescan' is a seqscan node * * Returns nothing of interest, but modifies internal fields of nodes. * */static voidset_nonamescan_tlist_references(SeqScan *nonamescan){ Noname *noname = (Noname *) ((Plan *) nonamescan)->lefttree; ((Plan *) nonamescan)->targetlist = tlist_noname_references(noname->nonameid, ((Plan *) nonamescan)->targetlist); set_noname_tlist_references(noname);}/* * set_noname_tlist_references * The noname's vars are made consistent with (actually, identical to) the * modified version of the target list of the node from which noname node * receives its tuples. * * 'noname' is a noname (e.g., sort, hash) plan node * * Returns nothing of interest, but modifies internal fields of nodes. * */static voidset_noname_tlist_references(Noname *noname){ Plan *source = ((Plan *) noname)->lefttree; if (source != NULL) { set_tlist_references(source); ((Plan *) noname)->targetlist = copy_vars(((Plan *) noname)->targetlist, (source)->targetlist); } else elog(ERROR, "calling set_noname_tlist_references with empty lefttree");}/* * join_references * Creates a new set of join clauses by changing the varno/varattno * values of variables in the clauses to reference target list values * from the outer and inner join relation target lists. * This is just an external interface for replace_clause_joinvar_refs. * * 'clauses' is the list of join clauses * 'outer_tlist' is the target list of the outer join relation * 'inner_tlist' is the target list of the inner join relation * * Returns the new join clauses. The original clause structure is * not modified. * */List *join_references(List *clauses, List *outer_tlist, List *inner_tlist){ return (List *) replace_clause_joinvar_refs((Node *) clauses, outer_tlist, inner_tlist);}/* * index_outerjoin_references * Given a list of join clauses, replace the operand corresponding to the * outer relation in the join with references to the corresponding target * list element in 'outer_tlist' (the outer is rather obscurely * identified as the side that doesn't contain a var whose varno equals * 'inner_relid'). * * As a side effect, the operator is replaced by the regproc id. * * 'inner_indxqual' is the list of join clauses (so-called because they * are used as qualifications for the inner (inbex) scan of a nestloop) * * Returns the new list of clauses. * */List *index_outerjoin_references(List *inner_indxqual, List *outer_tlist, Index inner_relid){ List *t_list = NIL; Expr *temp = NULL; List *t_clause = NIL; Expr *clause = NULL; foreach(t_clause, inner_indxqual) { clause = lfirst(t_clause); /* * if inner scan on the right. */ if (OperandIsInner((Node *) get_rightop(clause), inner_relid)) { Var *joinvar = (Var *) replace_clause_joinvar_refs((Node *) get_leftop(clause), outer_tlist, NIL); temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper), joinvar, get_rightop(clause)); t_list = lappend(t_list, temp); } else { /* inner scan on left */ Var *joinvar = (Var *) replace_clause_joinvar_refs((Node *) get_rightop(clause), outer_tlist, NIL); temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper), get_leftop(clause), joinvar); t_list = lappend(t_list, temp); } } return t_list;}/* * replace_clause_joinvar_refs * replace_joinvar_refs * * Replaces all variables within a join clause with a new var node * whose varno/varattno fields contain a reference to a target list * element from either the outer or inner join relation. * * 'clause' is the join clause * 'outer_tlist' is the target list of the outer join relation * 'inner_tlist' is the target list of the inner join relation * * Returns the new join clause. * NB: it is critical that the original clause structure not be modified! * The changes must be applied to a copy. * * XXX the current implementation does not copy unchanged primitive * nodes; they remain shared with the original. Is this safe? */static Node *replace_clause_joinvar_refs(Node *clause, List *outer_tlist, List *inner_tlist){ if (clause == NULL) return NULL; if (IsA(clause, Var)) { Var *temp = replace_joinvar_refs((Var *) clause, outer_tlist, inner_tlist); if (temp != NULL) return (Node *) temp; else return clause; } else if (single_node(clause)) return clause; else if (and_clause(clause)) { return (Node *) make_andclause((List *) replace_clause_joinvar_refs((Node *) ((Expr *) clause)->args, outer_tlist, inner_tlist)); } else if (or_clause(clause)) { return (Node *) make_orclause((List *) replace_clause_joinvar_refs((Node *) ((Expr *) clause)->args, outer_tlist, inner_tlist)); } else if (IsA(clause, ArrayRef)) { ArrayRef *oldnode = (ArrayRef *) clause; ArrayRef *newnode = makeNode(ArrayRef); newnode->refattrlength = oldnode->refattrlength; newnode->refelemlength = oldnode->refelemlength; newnode->refelemtype = oldnode->refelemtype; newnode->refelembyval = oldnode->refelembyval; newnode->refupperindexpr = (List *) replace_clause_joinvar_refs((Node *) oldnode->refupperindexpr, outer_tlist, inner_tlist); newnode->reflowerindexpr = (List *) replace_clause_joinvar_refs((Node *) oldnode->reflowerindexpr, outer_tlist, inner_tlist); newnode->refexpr = replace_clause_joinvar_refs(oldnode->refexpr, outer_tlist, inner_tlist); newnode->refassgnexpr = replace_clause_joinvar_refs(oldnode->refassgnexpr, outer_tlist, inner_tlist); return (Node *) newnode; } else if (is_funcclause(clause)) { return (Node *) make_funcclause( (Func *) ((Expr *) clause)->oper, (List *) replace_clause_joinvar_refs( (Node *) ((Expr *) clause)->args, outer_tlist, inner_tlist)); } else if (not_clause(clause)) { return (Node *) make_notclause((Expr *) replace_clause_joinvar_refs( (Node *) get_notclausearg((Expr *) clause), outer_tlist, inner_tlist)); } else if (is_opclause(clause)) { return (Node *) make_opclause( replace_opid((Oper *) ((Expr *) clause)->oper), (Var *) replace_clause_joinvar_refs( (Node *) get_leftop((Expr *) clause), outer_tlist, inner_tlist), (Var *) replace_clause_joinvar_refs( (Node *) get_rightop((Expr *) clause), outer_tlist, inner_tlist)); } else if (IsA(clause, List)) { List *t_list = NIL; List *subclause; foreach(subclause, (List *) clause) { t_list = lappend(t_list, replace_clause_joinvar_refs(lfirst(subclause), outer_tlist, inner_tlist)); } return (Node *) t_list; } else if (is_subplan(clause)) { /* This is a tad wasteful of space, but it works... */ Expr *newclause = (Expr *) copyObject(clause); newclause->args = (List *) replace_clause_joinvar_refs((Node *) newclause->args, outer_tlist, inner_tlist); ((SubPlan *) newclause->oper)->sublink->oper = (List *) replace_clause_joinvar_refs( (Node *) ((SubPlan *) newclause->oper)->sublink->oper, outer_tlist, inner_tlist); return (Node *) newclause; } else if (IsA(clause, CaseExpr)) { CaseExpr *oldnode = (CaseExpr *) clause; CaseExpr *newnode = makeNode(CaseExpr); newnode->casetype = oldnode->casetype; newnode->arg = oldnode->arg; /* XXX should always be null * anyway ... */ newnode->args = (List *) replace_clause_joinvar_refs((Node *) oldnode->args, outer_tlist, inner_tlist); newnode->defresult = replace_clause_joinvar_refs(oldnode->defresult, outer_tlist, inner_tlist); return (Node *) newnode; } else if (IsA(clause, CaseWhen)) { CaseWhen *oldnode = (CaseWhen *) clause; CaseWhen *newnode = makeNode(CaseWhen); newnode->expr = replace_clause_joinvar_refs(oldnode->expr, outer_tlist, inner_tlist); newnode->result = replace_clause_joinvar_refs(oldnode->result, outer_tlist, inner_tlist); return (Node *) newnode; } else { elog(ERROR, "replace_clause_joinvar_refs: unsupported clause %d", nodeTag(clause)); return NULL; }}static Var *replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist){ Resdom *outer_resdom; outer_resdom = tlist_member(var, outer_tlist); if (outer_resdom != NULL && IsA(outer_resdom, Resdom)) { return (makeVar(OUTER, outer_resdom->resno, var->vartype, var->vartypmod, 0, var->varnoold, var->varoattno)); } else { Resdom *inner_resdom; inner_resdom = tlist_member(var, inner_tlist); if (inner_resdom != NULL && IsA(inner_resdom, Resdom)) { return (makeVar(INNER, inner_resdom->resno, var->vartype, var->vartypmod, 0, var->varnoold, var->varoattno)); } } return (Var *) NULL;}/* * tlist_noname_references * Creates a new target list for a node that scans a noname relation, * setting the varnos to the id of the noname relation and setting varids * if necessary (varids are only needed if this is a targetlist internal * to the tree, in which case the targetlist entry always contains a var * node, so we can just copy it from the noname). * * 'nonameid' is the id of the noname relation * 'tlist' is the target list to be modified * * Returns new target list * */static List *tlist_noname_references(Oid nonameid, List *tlist){ List *t_list = NIL; TargetEntry *noname = (TargetEntry *) NULL; TargetEntry *xtl = NULL; List *entry;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -