initsplan.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,362 行 · 第 1/4 页
C
1,362 行
ojinfo->min_righthand = min_righthand; return ojinfo;}/***************************************************************************** * * QUALIFICATIONS * *****************************************************************************//* * distribute_qual_to_rels * Add clause information to either the baserestrictinfo or joininfo list * (depending on whether the clause is a join) of each base relation * mentioned in the clause. A RestrictInfo node is created and added to * the appropriate list for each rel. Alternatively, if the clause uses a * mergejoinable operator and is not delayed by outer-join rules, enter * the left- and right-side expressions into the query's list of * EquivalenceClasses. * * 'clause': the qual clause to be distributed * 'is_deduced': TRUE if the qual came from implied-equality deduction * 'below_outer_join': TRUE if the qual is from a JOIN/ON that is below the * nullable side of a higher-level outer join * 'qualscope': set of baserels the qual's syntactic scope covers * 'ojscope': NULL if not an outer-join qual, else the minimum set of baserels * needed to form this join * 'outerjoin_nonnullable': NULL if not an outer-join qual, else the set of * baserels appearing on the outer (nonnullable) side of the join * (for FULL JOIN this includes both sides of the join, and must in fact * equal qualscope) * * 'qualscope' identifies what level of JOIN the qual came from syntactically. * 'ojscope' is needed if we decide to force the qual up to the outer-join * level, which will be ojscope not necessarily qualscope. */static voiddistribute_qual_to_rels(PlannerInfo *root, Node *clause, bool is_deduced, bool below_outer_join, Relids qualscope, Relids ojscope, Relids outerjoin_nonnullable){ Relids relids; bool is_pushed_down; bool outerjoin_delayed; bool pseudoconstant = false; bool maybe_equivalence; bool maybe_outer_join; RestrictInfo *restrictinfo; /* * Retrieve all relids mentioned within the clause. */ relids = pull_varnos(clause); /* * Cross-check: clause should contain no relids not within its scope. * Otherwise the parser messed up. */ if (!bms_is_subset(relids, qualscope)) elog(ERROR, "JOIN qualification cannot refer to other relations"); if (ojscope && !bms_is_subset(relids, ojscope)) elog(ERROR, "JOIN qualification cannot refer to other relations"); /* * If the clause is variable-free, our normal heuristic for pushing it * down to just the mentioned rels doesn't work, because there are none. * * If the clause is an outer-join clause, we must force it to the OJ's * semantic level to preserve semantics. * * Otherwise, when the clause contains volatile functions, we force it to * be evaluated at its original syntactic level. This preserves the * expected semantics. * * When the clause contains no volatile functions either, it is actually a * pseudoconstant clause that will not change value during any one * execution of the plan, and hence can be used as a one-time qual in a * gating Result plan node. We put such a clause into the regular * RestrictInfo lists for the moment, but eventually createplan.c will * pull it out and make a gating Result node immediately above whatever * plan node the pseudoconstant clause is assigned to. It's usually best * to put a gating node as high in the plan tree as possible. If we are * not below an outer join, we can actually push the pseudoconstant qual * all the way to the top of the tree. If we are below an outer join, we * leave the qual at its original syntactic level (we could push it up to * just below the outer join, but that seems more complex than it's * worth). */ if (bms_is_empty(relids)) { if (ojscope) { /* clause is attached to outer join, eval it there */ relids = bms_copy(ojscope); /* mustn't use as gating qual, so don't mark pseudoconstant */ } else { /* eval at original syntactic level */ relids = bms_copy(qualscope); if (!contain_volatile_functions(clause)) { /* mark as gating qual */ pseudoconstant = true; /* tell createplan.c to check for gating quals */ root->hasPseudoConstantQuals = true; /* if not below outer join, push it to top of tree */ if (!below_outer_join) relids = get_relids_in_jointree((Node *) root->parse->jointree); } } } /*---------- * Check to see if clause application must be delayed by outer-join * considerations. * * A word about is_pushed_down: we mark the qual as "pushed down" if * it is (potentially) applicable at a level different from its original * syntactic level. This flag is used to distinguish OUTER JOIN ON quals * from other quals pushed down to the same joinrel. The rules are: * WHERE quals and INNER JOIN quals: is_pushed_down = true. * Non-degenerate OUTER JOIN quals: is_pushed_down = false. * Degenerate OUTER JOIN quals: is_pushed_down = true. * A "degenerate" OUTER JOIN qual is one that doesn't mention the * non-nullable side, and hence can be pushed down into the nullable side * without changing the join result. It is correct to treat it as a * regular filter condition at the level where it is evaluated. * * Note: it is not immediately obvious that a simple boolean is enough * for this: if for some reason we were to attach a degenerate qual to * its original join level, it would need to be treated as an outer join * qual there. However, this cannot happen, because all the rels the * clause mentions must be in the outer join's min_righthand, therefore * the join it needs must be formed before the outer join; and we always * attach quals to the lowest level where they can be evaluated. But * if we were ever to re-introduce a mechanism for delaying evaluation * of "expensive" quals, this area would need work. *---------- */ if (is_deduced) { /* * If the qual came from implied-equality deduction, it should not be * outerjoin-delayed, else deducer blew it. But we can't check this * because the ojinfo list may now contain OJs above where the qual * belongs. */ Assert(!ojscope); is_pushed_down = true; outerjoin_delayed = false; /* Don't feed it back for more deductions */ maybe_equivalence = false; maybe_outer_join = false; } else if (bms_overlap(relids, outerjoin_nonnullable)) { /* * The qual is attached to an outer join and mentions (some of the) * rels on the nonnullable side, so it's not degenerate. * * We can't use such a clause to deduce equivalence (the left and * right sides might be unequal above the join because one of them has * gone to NULL) ... but we might be able to use it for more limited * deductions, if it is mergejoinable. So consider adding it to the * lists of set-aside outer-join clauses. */ is_pushed_down = false; maybe_equivalence = false; maybe_outer_join = true; /* Check to see if must be delayed by lower outer join */ outerjoin_delayed = check_outerjoin_delay(root, &relids, false); /* * Now force the qual to be evaluated exactly at the level of joining * corresponding to the outer join. We cannot let it get pushed down * into the nonnullable side, since then we'd produce no output rows, * rather than the intended single null-extended row, for any * nonnullable-side rows failing the qual. * * (Do this step after calling check_outerjoin_delay, because that * trashes relids.) */ Assert(ojscope); relids = ojscope; Assert(!pseudoconstant); } else { /* * Normal qual clause or degenerate outer-join clause. Either way, we * can mark it as pushed-down. */ is_pushed_down = true; /* Check to see if must be delayed by lower outer join */ outerjoin_delayed = check_outerjoin_delay(root, &relids, true); if (outerjoin_delayed) { /* Should still be a subset of current scope ... */ Assert(bms_is_subset(relids, qualscope)); /* * Because application of the qual will be delayed by outer join, * we mustn't assume its vars are equal everywhere. */ maybe_equivalence = false; } else { /* * Qual is not delayed by any lower outer-join restriction, so we * can consider feeding it to the equivalence machinery. However, * if it's itself within an outer-join clause, treat it as though * it appeared below that outer join (note that we can only get * here when the clause references only nullable-side rels). */ maybe_equivalence = true; if (outerjoin_nonnullable != NULL) below_outer_join = true; } /* * Since it doesn't mention the LHS, it's certainly not useful as a * set-aside OJ clause, even if it's in an OJ. */ maybe_outer_join = false; } /* * Build the RestrictInfo node itself. */ restrictinfo = make_restrictinfo((Expr *) clause, is_pushed_down, outerjoin_delayed, pseudoconstant, relids); /* * If it's a join clause (either naturally, or because delayed by * outer-join rules), add vars used in the clause to targetlists of their * relations, so that they will be emitted by the plan nodes that scan * those relations (else they won't be available at the join node!). * * Note: if the clause gets absorbed into an EquivalenceClass then this * may be unnecessary, but for now we have to do it to cover the case * where the EC becomes ec_broken and we end up reinserting the original * clauses into the plan. */ if (bms_membership(relids) == BMS_MULTIPLE) { List *vars = pull_var_clause(clause, false); add_vars_to_targetlist(root, vars, relids); list_free(vars); } /* * We check "mergejoinability" of every clause, not only join clauses, * because we want to know about equivalences between vars of the same * relation, or between vars and consts. */ check_mergejoinable(restrictinfo); /* * If it is a true equivalence clause, send it to the EquivalenceClass * machinery. We do *not* attach it directly to any restriction or join * lists. The EC code will propagate it to the appropriate places later. * * If the clause has a mergejoinable operator and is not * outerjoin-delayed, yet isn't an equivalence because it is an outer-join * clause, the EC code may yet be able to do something with it. We add it * to appropriate lists for further consideration later. Specifically: * * If it is a left or right outer-join qualification that relates the two * sides of the outer join (no funny business like leftvar1 = leftvar2 + * rightvar), we add it to root->left_join_clauses or * root->right_join_clauses according to which side the nonnullable * variable appears on. * * If it is a full outer-join qualification, we add it to * root->full_join_clauses. (Ideally we'd discard cases that aren't * leftvar = rightvar, as we do for left/right joins, but this routine * doesn't have the info needed to do that; and the current usage of the * full_join_clauses list doesn't require that, so it's not currently * worth complicating this routine's API to make it possible.) * * If none of the above hold, pass it off to * distribute_restrictinfo_to_rels(). */ if (restrictinfo->mergeopfamilies) { if (maybe_equivalence) { if (process_equivalence(root, restrictinfo, below_outer_join)) return; /* EC rejected it, so pass to distribute_restrictinfo_to_rels */ } else if (maybe_outer_join && restrictinfo->can_join) { if (bms_is_subset(restrictinfo->left_relids, outerjoin_nonnullable) && !bms_overlap(restrictinfo->right_relids, outerjoin_nonnullable)) { /* we have outervar = innervar */ root->left_join_clauses = lappend(root->left_join_clauses, restrictinfo); return; } if (bms_is_subset(restrictinfo->right_relids, outerjoin_nonnullable) && !bms_overlap(restrictinfo->left_relids, outerjoin_nonnullable)) { /* we have innervar = outervar */ root->right_join_clauses = lappend(root->right_join_clauses, restrictinfo); return; } if (bms_equal(outerjoin_nonnullable, qualscope)) { /* FULL JOIN (above tests cannot match in this case) */ root->full_join_clauses = lappend(root->full_join_clauses, restrictinfo); return; } } } /* No EC special case applies, so push it into the clause lists */ distribute_restrictinfo_to_rels(root, restrictinfo);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?