initsplan.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,362 行 · 第 1/4 页
C
1,362 行
*/ foreach(l, (List *) f->quals) distribute_qual_to_rels(root, (Node *) lfirst(l), false, below_outer_join, *qualscope, NULL, NULL); } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; Relids leftids, rightids, left_inners, right_inners, nonnullable_rels, ojscope; List *leftjoinlist, *rightjoinlist; OuterJoinInfo *ojinfo; ListCell *qual; /* * Order of operations here is subtle and critical. First we recurse * to handle sub-JOINs. Their join quals will be placed without * regard for whether this level is an outer join, which is correct. * Then we place our own join quals, which are restricted by lower * outer joins in any case, and are forced to this level if this is an * outer join and they mention the outer side. Finally, if this is an * outer join, we create an oj_info_list entry for the join. This * will prevent quals above us in the join tree that use those rels * from being pushed down below this level. (It's okay for upper * quals to be pushed down to the outer side, however.) */ switch (j->jointype) { case JOIN_INNER: leftjoinlist = deconstruct_recurse(root, j->larg, below_outer_join, &leftids, &left_inners); rightjoinlist = deconstruct_recurse(root, j->rarg, below_outer_join, &rightids, &right_inners); *qualscope = bms_union(leftids, rightids); *inner_join_rels = *qualscope; /* Inner join adds no restrictions for quals */ nonnullable_rels = NULL; break; case JOIN_LEFT: leftjoinlist = deconstruct_recurse(root, j->larg, below_outer_join, &leftids, &left_inners); rightjoinlist = deconstruct_recurse(root, j->rarg, true, &rightids, &right_inners); *qualscope = bms_union(leftids, rightids); *inner_join_rels = bms_union(left_inners, right_inners); nonnullable_rels = leftids; break; case JOIN_FULL: leftjoinlist = deconstruct_recurse(root, j->larg, true, &leftids, &left_inners); rightjoinlist = deconstruct_recurse(root, j->rarg, true, &rightids, &right_inners); *qualscope = bms_union(leftids, rightids); *inner_join_rels = bms_union(left_inners, right_inners); /* each side is both outer and inner */ nonnullable_rels = *qualscope; break; case JOIN_RIGHT: /* notice we switch leftids and rightids */ leftjoinlist = deconstruct_recurse(root, j->larg, true, &rightids, &right_inners); rightjoinlist = deconstruct_recurse(root, j->rarg, below_outer_join, &leftids, &left_inners); *qualscope = bms_union(leftids, rightids); *inner_join_rels = bms_union(left_inners, right_inners); nonnullable_rels = leftids; break; default: elog(ERROR, "unrecognized join type: %d", (int) j->jointype); nonnullable_rels = NULL; /* keep compiler quiet */ leftjoinlist = rightjoinlist = NIL; break; } /* * For an OJ, form the OuterJoinInfo now, because we need the OJ's * semantic scope (ojscope) to pass to distribute_qual_to_rels. But * we mustn't add it to oj_info_list just yet, because we don't want * distribute_qual_to_rels to think it is an outer join below us. */ if (j->jointype != JOIN_INNER) { ojinfo = make_outerjoininfo(root, leftids, rightids, *inner_join_rels, (j->jointype == JOIN_FULL), j->quals); ojscope = bms_union(ojinfo->min_lefthand, ojinfo->min_righthand); } else { ojinfo = NULL; ojscope = NULL; } /* Process the qual clauses */ foreach(qual, (List *) j->quals) distribute_qual_to_rels(root, (Node *) lfirst(qual), false, below_outer_join, *qualscope, ojscope, nonnullable_rels); /* Now we can add the OuterJoinInfo to oj_info_list */ if (ojinfo) root->oj_info_list = lappend(root->oj_info_list, ojinfo); /* * Finally, compute the output joinlist. We fold subproblems together * except at a FULL JOIN or where join_collapse_limit would be * exceeded. */ if (j->jointype == JOIN_FULL) { /* force the join order exactly at this node */ joinlist = list_make1(list_make2(leftjoinlist, rightjoinlist)); } else if (list_length(leftjoinlist) + list_length(rightjoinlist) <= join_collapse_limit) { /* OK to combine subproblems */ joinlist = list_concat(leftjoinlist, rightjoinlist); } else { /* can't combine, but needn't force join order above here */ Node *leftpart, *rightpart; /* avoid creating useless 1-element sublists */ if (list_length(leftjoinlist) == 1) leftpart = (Node *) linitial(leftjoinlist); else leftpart = (Node *) leftjoinlist; if (list_length(rightjoinlist) == 1) rightpart = (Node *) linitial(rightjoinlist); else rightpart = (Node *) rightjoinlist; joinlist = list_make2(leftpart, rightpart); } } else { elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); joinlist = NIL; /* keep compiler quiet */ } return joinlist;}/* * make_outerjoininfo * Build an OuterJoinInfo for the current outer join * * Inputs: * left_rels: the base Relids syntactically on outer side of join * right_rels: the base Relids syntactically on inner side of join * inner_join_rels: base Relids participating in inner joins below this one * is_full_join: what it says * clause: the outer join's join condition * * If the join is a RIGHT JOIN, left_rels and right_rels are switched by * the caller, so that left_rels is always the nonnullable side. Hence * we need only distinguish the LEFT and FULL cases. * * The node should eventually be appended to root->oj_info_list, but we * do not do that here. * * Note: we assume that this function is invoked bottom-up, so that * root->oj_info_list already contains entries for all outer joins that are * syntactically below this one. */static OuterJoinInfo *make_outerjoininfo(PlannerInfo *root, Relids left_rels, Relids right_rels, Relids inner_join_rels, bool is_full_join, Node *clause){ OuterJoinInfo *ojinfo = makeNode(OuterJoinInfo); Relids clause_relids; Relids strict_relids; Relids min_lefthand; Relids min_righthand; ListCell *l; /* * Presently the executor cannot support FOR UPDATE/SHARE marking of rels * appearing on the nullable side of an outer join. (It's somewhat unclear * what that would mean, anyway: what should we mark when a result row is * generated from no element of the nullable relation?) So, complain if * any nullable rel is FOR UPDATE/SHARE. * * You might be wondering why this test isn't made far upstream in the * parser. It's because the parser hasn't got enough info --- consider * FOR UPDATE applied to a view. Only after rewriting and flattening do * we know whether the view contains an outer join. */ foreach(l, root->parse->rowMarks) { RowMarkClause *rc = (RowMarkClause *) lfirst(l); if (bms_is_member(rc->rti, right_rels) || (is_full_join && bms_is_member(rc->rti, left_rels))) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SELECT FOR UPDATE/SHARE cannot be applied to the nullable side of an outer join"))); } /* this always starts out false */ ojinfo->delay_upper_joins = false; /* If it's a full join, no need to be very smart */ ojinfo->syn_lefthand = left_rels; ojinfo->syn_righthand = right_rels; ojinfo->is_full_join = is_full_join; if (is_full_join) { ojinfo->min_lefthand = left_rels; ojinfo->min_righthand = right_rels; ojinfo->lhs_strict = false; /* don't care about this */ return ojinfo; } /* * Retrieve all relids mentioned within the join clause. */ clause_relids = pull_varnos(clause); /* * For which relids is the clause strict, ie, it cannot succeed if the * rel's columns are all NULL? */ strict_relids = find_nonnullable_rels(clause); /* Remember whether the clause is strict for any LHS relations */ ojinfo->lhs_strict = bms_overlap(strict_relids, left_rels); /* * Required LHS always includes the LHS rels mentioned in the clause. We * may have to add more rels based on lower outer joins; see below. */ min_lefthand = bms_intersect(clause_relids, left_rels); /* * Similarly for required RHS. But here, we must also include any lower * inner joins, to ensure we don't try to commute with any of them. */ min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels), right_rels); foreach(l, root->oj_info_list) { OuterJoinInfo *otherinfo = (OuterJoinInfo *) lfirst(l); /* ignore full joins --- other mechanisms preserve their ordering */ if (otherinfo->is_full_join) continue; /* * For a lower OJ in our LHS, if our join condition uses the lower * join's RHS and is not strict for that rel, we must preserve the * ordering of the two OJs, so add lower OJ's full syntactic relset to * min_lefthand. (We must use its full syntactic relset, not just its * min_lefthand + min_righthand. This is because there might be other * OJs below this one that this one can commute with, but we cannot * commute with them if we don't with this one.) * * Note: I believe we have to insist on being strict for at least one * rel in the lower OJ's min_righthand, not its whole syn_righthand. */ if (bms_overlap(left_rels, otherinfo->syn_righthand) && bms_overlap(clause_relids, otherinfo->syn_righthand) && !bms_overlap(strict_relids, otherinfo->min_righthand)) { min_lefthand = bms_add_members(min_lefthand, otherinfo->syn_lefthand); min_lefthand = bms_add_members(min_lefthand, otherinfo->syn_righthand); } /* * For a lower OJ in our RHS, if our join condition does not use the * lower join's RHS and the lower OJ's join condition is strict, we * can interchange the ordering of the two OJs; otherwise we must add * lower OJ's full syntactic relset to min_righthand. * * Here, we have to consider that "our join condition" includes any * clauses that syntactically appeared above the lower OJ and below * ours; those are equivalent to degenerate clauses in our OJ and must * be treated as such. Such clauses obviously can't reference our * LHS, and they must be non-strict for the lower OJ's RHS (else * reduce_outer_joins would have reduced the lower OJ to a plain * join). Hence the other ways in which we handle clauses within our * join condition are not affected by them. The net effect is * therefore sufficiently represented by the delay_upper_joins flag * saved for us by check_outerjoin_delay. */ if (bms_overlap(right_rels, otherinfo->syn_righthand)) { if (bms_overlap(clause_relids, otherinfo->syn_righthand) || !otherinfo->lhs_strict || otherinfo->delay_upper_joins) { min_righthand = bms_add_members(min_righthand, otherinfo->syn_lefthand); min_righthand = bms_add_members(min_righthand, otherinfo->syn_righthand); } } } /* * If we found nothing to put in min_lefthand, punt and make it the full * LHS, to avoid having an empty min_lefthand which will confuse later * processing. (We don't try to be smart about such cases, just correct.) * Likewise for min_righthand. */ if (bms_is_empty(min_lefthand)) min_lefthand = bms_copy(left_rels); if (bms_is_empty(min_righthand)) min_righthand = bms_copy(right_rels); /* Now they'd better be nonempty */ Assert(!bms_is_empty(min_lefthand)); Assert(!bms_is_empty(min_righthand)); /* Shouldn't overlap either */ Assert(!bms_overlap(min_lefthand, min_righthand)); ojinfo->min_lefthand = min_lefthand;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?