initsplan.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,362 行 · 第 1/4 页
C
1,362 行
/* * check_outerjoin_delay * Detect whether a qual referencing the given relids must be delayed * in application due to the presence of a lower outer join, and/or * may force extra delay of higher-level outer joins. * * If the qual must be delayed, add relids to *relids_p to reflect the lowest * safe level for evaluating the qual, and return TRUE. Any extra delay for * higher-level joins is reflected by setting delay_upper_joins to TRUE in * OuterJoinInfo structs. * * For an is_pushed_down qual, we can evaluate the qual as soon as (1) we have * all the rels it mentions, and (2) we are at or above any outer joins that * can null any of these rels and are below the syntactic location of the * given qual. We must enforce (2) because pushing down such a clause below * the OJ might cause the OJ to emit null-extended rows that should not have * been formed, or that should have been rejected by the clause. (This is * only an issue for non-strict quals, since if we can prove a qual mentioning * only nullable rels is strict, we'd have reduced the outer join to an inner * join in reduce_outer_joins().) * * To enforce (2), scan the oj_info_list and merge the required-relid sets of * any such OJs into the clause's own reference list. At the time we are * called, the oj_info_list contains only outer joins below this qual. We * have to repeat the scan until no new relids get added; this ensures that * the qual is suitably delayed regardless of the order in which OJs get * executed. As an example, if we have one OJ with LHS=A, RHS=B, and one with * LHS=B, RHS=C, it is implied that these can be done in either order; if the * B/C join is done first then the join to A can null C, so a qual actually * mentioning only C cannot be applied below the join to A. * * For a non-pushed-down qual, this isn't going to determine where we place the * qual, but we need to determine outerjoin_delayed anyway for possible use * in reconsider_outer_join_clauses(). * * Lastly, a pushed-down qual that references the nullable side of any current * oj_info_list member and has to be evaluated above that OJ (because its * required relids overlap the LHS too) causes that OJ's delay_upper_joins * flag to be set TRUE. This will prevent any higher-level OJs from * being interchanged with that OJ, which would result in not having any * correct place to evaluate the qual. (The case we care about here is a * sub-select WHERE clause within the RHS of some outer join. The WHERE * clause must effectively be treated as a degenerate clause of that outer * join's condition. Rather than trying to match such clauses with joins * directly, we set delay_upper_joins here, and when the upper outer join * is processed by make_outerjoininfo, it will refrain from allowing the * two OJs to commute.) */static boolcheck_outerjoin_delay(PlannerInfo *root, Relids *relids_p, bool is_pushed_down){ Relids relids = *relids_p; bool outerjoin_delayed; bool found_some; outerjoin_delayed = false; do { ListCell *l; found_some = false; foreach(l, root->oj_info_list) { OuterJoinInfo *ojinfo = (OuterJoinInfo *) lfirst(l); /* do we reference any nullable rels of this OJ? */ if (bms_overlap(relids, ojinfo->min_righthand) || (ojinfo->is_full_join && bms_overlap(relids, ojinfo->min_lefthand))) { /* yes, so set the result flag */ outerjoin_delayed = true; /* have we included all its rels in relids? */ if (!bms_is_subset(ojinfo->min_lefthand, relids) || !bms_is_subset(ojinfo->min_righthand, relids)) { /* no, so add them in */ relids = bms_add_members(relids, ojinfo->min_lefthand); relids = bms_add_members(relids, ojinfo->min_righthand); /* we'll need another iteration */ found_some = true; } /* set delay_upper_joins if needed */ if (is_pushed_down && !ojinfo->is_full_join && bms_overlap(relids, ojinfo->min_lefthand)) ojinfo->delay_upper_joins = true; } } } while (found_some); *relids_p = relids; return outerjoin_delayed;}/* * distribute_restrictinfo_to_rels * Push a completed RestrictInfo into the proper restriction or join * clause list(s). * * This is the last step of distribute_qual_to_rels() for ordinary qual * clauses. Clauses that are interesting for equivalence-class processing * are diverted to the EC machinery, but may ultimately get fed back here. */voiddistribute_restrictinfo_to_rels(PlannerInfo *root, RestrictInfo *restrictinfo){ Relids relids = restrictinfo->required_relids; RelOptInfo *rel; switch (bms_membership(relids)) { case BMS_SINGLETON: /* * There is only one relation participating in the clause, so it * is a restriction clause for that relation. */ rel = find_base_rel(root, bms_singleton_member(relids)); /* Add clause to rel's restriction list */ rel->baserestrictinfo = lappend(rel->baserestrictinfo, restrictinfo); break; case BMS_MULTIPLE: /* * The clause is a join clause, since there is more than one rel * in its relid set. */ /* * Check for hashjoinable operators. (We don't bother setting the * hashjoin info if we're not going to need it.) */ if (enable_hashjoin) check_hashjoinable(restrictinfo); /* * Add clause to the join lists of all the relevant relations. */ add_join_clause_to_rels(root, restrictinfo, relids); break; default: /* * clause references no rels, and therefore we have no place to * attach it. Shouldn't get here if callers are working properly. */ elog(ERROR, "cannot cope with variable-free clause"); break; }}/* * process_implied_equality * Create a restrictinfo item that says "item1 op item2", and push it * into the appropriate lists. (In practice opno is always a btree * equality operator.) * * "qualscope" is the nominal syntactic level to impute to the restrictinfo. * This must contain at least all the rels used in the expressions, but it * is used only to set the qual application level when both exprs are * variable-free. Otherwise the qual is applied at the lowest join level * that provides all its variables. * * "both_const" indicates whether both items are known pseudo-constant; * in this case it is worth applying eval_const_expressions() in case we * can produce constant TRUE or constant FALSE. (Otherwise it's not, * because the expressions went through eval_const_expressions already.) * * This is currently used only when an EquivalenceClass is found to * contain pseudoconstants. See path/pathkeys.c for more details. */voidprocess_implied_equality(PlannerInfo *root, Oid opno, Expr *item1, Expr *item2, Relids qualscope, bool below_outer_join, bool both_const){ Expr *clause; /* * Build the new clause. Copy to ensure it shares no substructure with * original (this is necessary in case there are subselects in there...) */ clause = make_opclause(opno, BOOLOID, /* opresulttype */ false, /* opretset */ (Expr *) copyObject(item1), (Expr *) copyObject(item2)); /* If both constant, try to reduce to a boolean constant. */ if (both_const) { clause = (Expr *) eval_const_expressions(root, (Node *) clause); /* If we produced const TRUE, just drop the clause */ if (clause && IsA(clause, Const)) { Const *cclause = (Const *) clause; Assert(cclause->consttype == BOOLOID); if (!cclause->constisnull && DatumGetBool(cclause->constvalue)) return; } } /* Make a copy of qualscope to avoid problems if source EC changes */ qualscope = bms_copy(qualscope); /* * Push the new clause into all the appropriate restrictinfo lists. */ distribute_qual_to_rels(root, (Node *) clause, true, below_outer_join, qualscope, NULL, NULL);}/* * build_implied_join_equality --- build a RestrictInfo for a derived equality * * This overlaps the functionality of process_implied_equality(), but we * must return the RestrictInfo, not push it into the joininfo tree. */RestrictInfo *build_implied_join_equality(Oid opno, Expr *item1, Expr *item2, Relids qualscope){ RestrictInfo *restrictinfo; Expr *clause; /* * Build the new clause. Copy to ensure it shares no substructure with * original (this is necessary in case there are subselects in there...) */ clause = make_opclause(opno, BOOLOID, /* opresulttype */ false, /* opretset */ (Expr *) copyObject(item1), (Expr *) copyObject(item2)); /* Make a copy of qualscope to avoid problems if source EC changes */ qualscope = bms_copy(qualscope); /* * Build the RestrictInfo node itself. */ restrictinfo = make_restrictinfo(clause, true, /* is_pushed_down */ false, /* outerjoin_delayed */ false, /* pseudoconstant */ qualscope); /* Set mergejoinability info always, and hashjoinability if enabled */ check_mergejoinable(restrictinfo); if (enable_hashjoin) check_hashjoinable(restrictinfo); return restrictinfo;}/***************************************************************************** * * CHECKS FOR MERGEJOINABLE AND HASHJOINABLE CLAUSES * *****************************************************************************//* * check_mergejoinable * If the restrictinfo's clause is mergejoinable, set the mergejoin * info fields in the restrictinfo. * * Currently, we support mergejoin for binary opclauses where * the operator is a mergejoinable operator. The arguments can be * anything --- as long as there are no volatile functions in them. */static voidcheck_mergejoinable(RestrictInfo *restrictinfo){ Expr *clause = restrictinfo->clause; Oid opno; if (restrictinfo->pseudoconstant) return; if (!is_opclause(clause)) return; if (list_length(((OpExpr *) clause)->args) != 2) return; opno = ((OpExpr *) clause)->opno; if (op_mergejoinable(opno) && !contain_volatile_functions((Node *) clause)) restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno); /* * Note: op_mergejoinable is just a hint; if we fail to find the operator * in any btree opfamilies, mergeopfamilies remains NIL and so the clause * is not treated as mergejoinable. */}/* * check_hashjoinable * If the restrictinfo's clause is hashjoinable, set the hashjoin * info fields in the restrictinfo. * * Currently, we support hashjoin for binary opclauses where * the operator is a hashjoinable operator. The arguments can be * anything --- as long as there are no volatile functions in them. */static voidcheck_hashjoinable(RestrictInfo *restrictinfo){ Expr *clause = restrictinfo->clause; Oid opno; if (restrictinfo->pseudoconstant) return; if (!is_opclause(clause)) return; if (list_length(((OpExpr *) clause)->args) != 2) return; opno = ((OpExpr *) clause)->opno; if (op_hashjoinable(opno) && !contain_volatile_functions((Node *) clause)) restrictinfo->hashjoinoperator = opno;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?