prepjointree.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,329 行 · 第 1/3 页
C
1,329 行
JoinExpr *j = (JoinExpr *) jtnode; resolvenew_in_jointree(j->larg, varno, rte, subtlist); resolvenew_in_jointree(j->rarg, varno, rte, subtlist); j->quals = ResolveNew(j->quals, varno, 0, rte, subtlist, CMD_SELECT, 0); /* * We don't bother to update the colvars list, since it won't be used * again ... */ } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode));}/* * reduce_outer_joins * Attempt to reduce outer joins to plain inner joins. * * The idea here is that given a query like * SELECT ... FROM a LEFT JOIN b ON (...) WHERE b.y = 42; * we can reduce the LEFT JOIN to a plain JOIN if the "=" operator in WHERE * is strict. The strict operator will always return NULL, causing the outer * WHERE to fail, on any row where the LEFT JOIN filled in NULLs for b's * columns. Therefore, there's no need for the join to produce null-extended * rows in the first place --- which makes it a plain join not an outer join. * (This scenario may not be very likely in a query written out by hand, but * it's reasonably likely when pushing quals down into complex views.) * * More generally, an outer join can be reduced in strength if there is a * strict qual above it in the qual tree that constrains a Var from the * nullable side of the join to be non-null. (For FULL joins this applies * to each side separately.) * * To ease recognition of strict qual clauses, we require this routine to be * run after expression preprocessing (i.e., qual canonicalization and JOIN * alias-var expansion). */voidreduce_outer_joins(PlannerInfo *root){ reduce_outer_joins_state *state; /* * To avoid doing strictness checks on more quals than necessary, we want * to stop descending the jointree as soon as there are no outer joins * below our current point. This consideration forces a two-pass process. * The first pass gathers information about which base rels appear below * each side of each join clause, and about whether there are outer * join(s) below each side of each join clause. The second pass examines * qual clauses and changes join types as it descends the tree. */ state = reduce_outer_joins_pass1((Node *) root->parse->jointree); /* planner.c shouldn't have called me if no outer joins */ if (state == NULL || !state->contains_outer) elog(ERROR, "so where are the outer joins?"); reduce_outer_joins_pass2((Node *) root->parse->jointree, state, root, NULL);}/* * reduce_outer_joins_pass1 - phase 1 data collection * * Returns a state node describing the given jointree node. */static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode){ reduce_outer_joins_state *result; result = (reduce_outer_joins_state *) palloc(sizeof(reduce_outer_joins_state)); result->relids = NULL; result->contains_outer = false; result->sub_states = NIL; if (jtnode == NULL) return result; if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; result->relids = bms_make_singleton(varno); } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; foreach(l, f->fromlist) { reduce_outer_joins_state *sub_state; sub_state = reduce_outer_joins_pass1(lfirst(l)); result->relids = bms_add_members(result->relids, sub_state->relids); result->contains_outer |= sub_state->contains_outer; result->sub_states = lappend(result->sub_states, sub_state); } } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; reduce_outer_joins_state *sub_state; /* join's own RT index is not wanted in result->relids */ if (IS_OUTER_JOIN(j->jointype)) result->contains_outer = true; sub_state = reduce_outer_joins_pass1(j->larg); result->relids = bms_add_members(result->relids, sub_state->relids); result->contains_outer |= sub_state->contains_outer; result->sub_states = lappend(result->sub_states, sub_state); sub_state = reduce_outer_joins_pass1(j->rarg); result->relids = bms_add_members(result->relids, sub_state->relids); result->contains_outer |= sub_state->contains_outer; result->sub_states = lappend(result->sub_states, sub_state); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); return result;}/* * reduce_outer_joins_pass2 - phase 2 processing * * jtnode: current jointree node * state: state data collected by phase 1 for this node * root: toplevel planner state * nonnullable_rels: set of base relids forced non-null by upper quals */static voidreduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_state *state, PlannerInfo *root, Relids nonnullable_rels){ /* * pass 2 should never descend as far as an empty subnode or base rel, * because it's only called on subtrees marked as contains_outer. */ if (jtnode == NULL) elog(ERROR, "reached empty jointree"); if (IsA(jtnode, RangeTblRef)) elog(ERROR, "reached base rel"); else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; ListCell *s; Relids pass_nonnullable; /* Scan quals to see if we can add any nonnullability constraints */ pass_nonnullable = find_nonnullable_rels(f->quals); pass_nonnullable = bms_add_members(pass_nonnullable, nonnullable_rels); /* And recurse --- but only into interesting subtrees */ Assert(list_length(f->fromlist) == list_length(state->sub_states)); forboth(l, f->fromlist, s, state->sub_states) { reduce_outer_joins_state *sub_state = lfirst(s); if (sub_state->contains_outer) reduce_outer_joins_pass2(lfirst(l), sub_state, root, pass_nonnullable); } bms_free(pass_nonnullable); } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; int rtindex = j->rtindex; JoinType jointype = j->jointype; reduce_outer_joins_state *left_state = linitial(state->sub_states); reduce_outer_joins_state *right_state = lsecond(state->sub_states); /* Can we simplify this join? */ switch (jointype) { case JOIN_LEFT: if (bms_overlap(nonnullable_rels, right_state->relids)) jointype = JOIN_INNER; break; case JOIN_RIGHT: if (bms_overlap(nonnullable_rels, left_state->relids)) jointype = JOIN_INNER; break; case JOIN_FULL: if (bms_overlap(nonnullable_rels, left_state->relids)) { if (bms_overlap(nonnullable_rels, right_state->relids)) jointype = JOIN_INNER; else jointype = JOIN_LEFT; } else { if (bms_overlap(nonnullable_rels, right_state->relids)) jointype = JOIN_RIGHT; } break; default: break; } if (jointype != j->jointype) { /* apply the change to both jointree node and RTE */ RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable); Assert(rte->rtekind == RTE_JOIN); Assert(rte->jointype == j->jointype); rte->jointype = j->jointype = jointype; } /* Only recurse if there's more to do below here */ if (left_state->contains_outer || right_state->contains_outer) { Relids local_nonnullable; Relids pass_nonnullable; /* * If this join is (now) inner, we can add any nonnullability * constraints its quals provide to those we got from above. But * if it is outer, we can only pass down the local constraints * into the nullable side, because an outer join never eliminates * any rows from its non-nullable side. If it's a FULL join then * it doesn't eliminate anything from either side. */ if (jointype != JOIN_FULL) { local_nonnullable = find_nonnullable_rels(j->quals); local_nonnullable = bms_add_members(local_nonnullable, nonnullable_rels); } else local_nonnullable = NULL; /* no use in calculating it */ if (left_state->contains_outer) { if (jointype == JOIN_INNER || jointype == JOIN_RIGHT) pass_nonnullable = local_nonnullable; else pass_nonnullable = nonnullable_rels; reduce_outer_joins_pass2(j->larg, left_state, root, pass_nonnullable); } if (right_state->contains_outer) { if (jointype == JOIN_INNER || jointype == JOIN_LEFT) pass_nonnullable = local_nonnullable; else pass_nonnullable = nonnullable_rels; reduce_outer_joins_pass2(j->rarg, right_state, root, pass_nonnullable); } bms_free(local_nonnullable); } } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode));}/* * fix_in_clause_relids: update RT-index sets of InClauseInfo nodes * * When we pull up a subquery, any InClauseInfo references to the subquery's * RT index have to be replaced by the set of substituted relids. * * We assume we may modify the InClauseInfo nodes in-place. */static voidfix_in_clause_relids(List *in_info_list, int varno, Relids subrelids){ ListCell *l; foreach(l, in_info_list) { InClauseInfo *ininfo = (InClauseInfo *) lfirst(l); if (bms_is_member(varno, ininfo->lefthand)) { ininfo->lefthand = bms_del_member(ininfo->lefthand, varno); ininfo->lefthand = bms_add_members(ininfo->lefthand, subrelids); } if (bms_is_member(varno, ininfo->righthand)) { ininfo->righthand = bms_del_member(ininfo->righthand, varno); ininfo->righthand = bms_add_members(ininfo->righthand, subrelids); } }}/* * fix_append_rel_relids: update RT-index fields of AppendRelInfo nodes * * When we pull up a subquery, any AppendRelInfo references to the subquery's * RT index have to be replaced by the substituted relid (and there had better * be only one). * * We assume we may modify the AppendRelInfo nodes in-place. */static voidfix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids){ ListCell *l; int subvarno = -1; /* * We only want to extract the member relid once, but we mustn't fail * immediately if there are multiple members; it could be that none of the * AppendRelInfo nodes refer to it. So compute it on first use. Note that * bms_singleton_member will complain if set is not singleton. */ foreach(l, append_rel_list) { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); /* The parent_relid shouldn't ever be a pullup target */ Assert(appinfo->parent_relid != varno); if (appinfo->child_relid == varno) { if (subvarno < 0) subvarno = bms_singleton_member(subrelids); appinfo->child_relid = subvarno; } }}/* * get_relids_in_jointree: get set of base RT indexes present in a jointree */Relidsget_relids_in_jointree(Node *jtnode){ Relids result = NULL; if (jtnode == NULL) return result; if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; result = bms_make_singleton(varno); } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; foreach(l, f->fromlist) { result = bms_join(result, get_relids_in_jointree(lfirst(l))); } } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; /* join's own RT index is not wanted in result */ result = get_relids_in_jointree(j->larg); result = bms_join(result, get_relids_in_jointree(j->rarg)); } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); return result;}/* * get_relids_for_join: get set of base RT indexes making up a join */Relidsget_relids_for_join(PlannerInfo *root, int joinrelid){ Node *jtnode; jtnode = find_jointree_node_for_rel((Node *) root->parse->jointree, joinrelid); if (!jtnode) elog(ERROR, "could not find join node %d", joinrelid); return get_relids_in_jointree(jtnode);}/* * find_jointree_node_for_rel: locate jointree node for a base or join RT index * * Returns NULL if not found */static Node *find_jointree_node_for_rel(Node *jtnode, int relid){ if (jtnode == NULL) return NULL; if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; if (relid == varno) return jtnode; } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; foreach(l, f->fromlist) { jtnode = find_jointree_node_for_rel(lfirst(l), relid); if (jtnode) return jtnode; } } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; if (relid == j->rtindex) return jtnode; jtnode = find_jointree_node_for_rel(j->larg, relid); if (jtnode) return jtnode; jtnode = find_jointree_node_for_rel(j->rarg, relid); if (jtnode) return jtnode; } else elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); return NULL;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?