📄 createplan.c
字号:
} } /* Get the join qual clauses (in plain expression form) */ if (IS_OUTER_JOIN(best_path->jointype)) { get_actual_join_clauses(joinrestrictclauses, &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ joinclauses = get_actual_clauses(joinrestrictclauses); otherclauses = NIL; } /* Sort clauses into best execution order */ joinclauses = order_qual_clauses(root, joinclauses); otherclauses = order_qual_clauses(root, otherclauses); join_plan = make_nestloop(tlist, joinclauses, otherclauses, outer_plan, inner_plan, best_path->jointype); copy_path_costsize(&join_plan->join.plan, &best_path->path); return join_plan;}static MergeJoin *create_mergejoin_plan(Query *root, MergePath *best_path, Plan *outer_plan, Plan *inner_plan){ List *tlist = build_relation_tlist(best_path->jpath.path.parent); List *joinclauses; List *otherclauses; List *mergeclauses; MergeJoin *join_plan; /* Get the join qual clauses (in plain expression form) */ if (IS_OUTER_JOIN(best_path->jpath.jointype)) { get_actual_join_clauses(best_path->jpath.joinrestrictinfo, &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo); otherclauses = NIL; } /* * Remove the mergeclauses from the list of join qual clauses, leaving * the list of quals that must be checked as qpquals. */ mergeclauses = get_actual_clauses(best_path->path_mergeclauses); joinclauses = set_difference(joinclauses, mergeclauses); /* * Rearrange mergeclauses, if needed, so that the outer variable is * always on the left. */ mergeclauses = get_switched_clauses(best_path->path_mergeclauses, best_path->jpath.outerjoinpath->parent->relids); /* Sort clauses into best execution order */ /* NB: do NOT reorder the mergeclauses */ joinclauses = order_qual_clauses(root, joinclauses); otherclauses = order_qual_clauses(root, otherclauses); /* * Create explicit sort nodes for the outer and inner join paths if * necessary. The sort cost was already accounted for in the path. * Make sure there are no excess columns in the inputs if sorting. */ if (best_path->outersortkeys) { disuse_physical_tlist(outer_plan, best_path->jpath.outerjoinpath); outer_plan = (Plan *) make_sort_from_pathkeys(root, outer_plan, best_path->outersortkeys); } if (best_path->innersortkeys) { disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath); inner_plan = (Plan *) make_sort_from_pathkeys(root, inner_plan, best_path->innersortkeys); } /* * Now we can build the mergejoin node. */ join_plan = make_mergejoin(tlist, joinclauses, otherclauses, mergeclauses, outer_plan, inner_plan, best_path->jpath.jointype); copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path); return join_plan;}static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path, Plan *outer_plan, Plan *inner_plan){ List *tlist = build_relation_tlist(best_path->jpath.path.parent); List *joinclauses; List *otherclauses; List *hashclauses; HashJoin *join_plan; Hash *hash_plan; List *innerhashkeys; List *hcl; /* Get the join qual clauses (in plain expression form) */ if (IS_OUTER_JOIN(best_path->jpath.jointype)) { get_actual_join_clauses(best_path->jpath.joinrestrictinfo, &joinclauses, &otherclauses); } else { /* We can treat all clauses alike for an inner join */ joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo); otherclauses = NIL; } /* * Remove the hashclauses from the list of join qual clauses, leaving * the list of quals that must be checked as qpquals. */ hashclauses = get_actual_clauses(best_path->path_hashclauses); joinclauses = set_difference(joinclauses, hashclauses); /* * Rearrange hashclauses, if needed, so that the outer variable is * always on the left. */ hashclauses = get_switched_clauses(best_path->path_hashclauses, best_path->jpath.outerjoinpath->parent->relids); /* Sort clauses into best execution order */ joinclauses = order_qual_clauses(root, joinclauses); otherclauses = order_qual_clauses(root, otherclauses); hashclauses = order_qual_clauses(root, hashclauses); /* * Extract the inner hash keys (right-hand operands of the hashclauses) * to put in the Hash node. Must do a deep copy in case there are * subplans in the hash keys. */ innerhashkeys = NIL; foreach(hcl, hashclauses) innerhashkeys = lappend(innerhashkeys, copyObject(get_rightop(lfirst(hcl)))); /* We don't want any excess columns in the hashed tuples */ disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath); /* * Build the hash node and hash join node. */ hash_plan = make_hash(inner_plan->targetlist, innerhashkeys, inner_plan); join_plan = make_hashjoin(tlist, joinclauses, otherclauses, hashclauses, outer_plan, (Plan *) hash_plan, best_path->jpath.jointype); copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path); return join_plan;}/***************************************************************************** * * SUPPORTING ROUTINES * *****************************************************************************//* * fix_indxqual_references * Adjust indexqual clauses to the form the executor's indexqual * machinery needs, and check for recheckable (lossy) index conditions. * * We have three tasks here: * * Index keys must be represented by Var nodes with varattno set to the * index's attribute number, not the attribute number in the original rel. * * If the index key is on the right, commute the clause to put it on the * left. (Someday the executor might not need this, but for now it does.) * * If the indexable operator is marked 'amopreqcheck' in pg_amop, then * the index is "lossy" for this operator: it may return more tuples than * actually satisfy the operator condition. For each such operator, we * must add (the original form of) the indexqual clause to the "qpquals" * of the indexscan node, where the operator will be re-evaluated to * ensure it passes. * * This code used to be entirely bogus for multi-index scans. Now it keeps * track of which index applies to each subgroup of index qual clauses... * * Both the input list and the output lists have the form of lists of sublists * of qual clauses --- the top-level list has one entry for each indexscan * to be performed. The semantics are OR-of-ANDs. * * fixed_indexquals receives a modified copy of the indexqual list --- the * original is not changed. Note also that the copy shares no substructure * with the original; this is needed in case there is a subplan in it (we need * two separate copies of the subplan tree, or things will go awry). * * recheck_indexquals similarly receives a full copy of whichever clauses * need rechecking. */static voidfix_indxqual_references(List *indexquals, IndexPath *index_path, List **fixed_indexquals, List **recheck_indexquals){ FastList fixed_quals; FastList recheck_quals; Relids baserelids = index_path->path.parent->relids; int baserelid = index_path->path.parent->relid; List *ixinfo = index_path->indexinfo; List *i; FastListInit(&fixed_quals); FastListInit(&recheck_quals); foreach(i, indexquals) { List *indexqual = lfirst(i); IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo); List *fixed_qual; List *recheck_qual; fix_indxqual_sublist(indexqual, baserelids, baserelid, index, &fixed_qual, &recheck_qual); FastAppend(&fixed_quals, fixed_qual); if (recheck_qual != NIL) FastAppend(&recheck_quals, recheck_qual); ixinfo = lnext(ixinfo); } *fixed_indexquals = FastListValue(&fixed_quals); *recheck_indexquals = FastListValue(&recheck_quals);}/* * Fix the sublist of indexquals to be used in a particular scan. * * For each qual clause, commute if needed to put the indexkey operand on the * left, and then fix its varattno. (We do not need to change the other side * of the clause.) Also change the operator if necessary, and check for * lossy index behavior. * * Returns two lists: the list of fixed indexquals, and the list (usually * empty) of original clauses that must be rechecked as qpquals because * the index is lossy for this operator type. */static voidfix_indxqual_sublist(List *indexqual, Relids baserelids, int baserelid, IndexOptInfo *index, List **fixed_quals, List **recheck_quals){ FastList fixed_qual; FastList recheck_qual; List *i; FastListInit(&fixed_qual); FastListInit(&recheck_qual); foreach(i, indexqual) { OpExpr *clause = (OpExpr *) lfirst(i); OpExpr *newclause; Relids leftvarnos; Oid opclass; if (!IsA(clause, OpExpr) ||length(clause->args) != 2) elog(ERROR, "indexqual clause is not binary opclause"); /* * Make a copy that will become the fixed clause. * * We used to try to do a shallow copy here, but that fails if there * is a subplan in the arguments of the opclause. So just do a * full copy. */ newclause = (OpExpr *) copyObject((Node *) clause); /* * Check to see if the indexkey is on the right; if so, commute * the clause. The indexkey should be the side that refers to * (only) the base relation. */ leftvarnos = pull_varnos((Node *) lfirst(newclause->args)); if (!bms_equal(leftvarnos, baserelids)) CommuteClause(newclause); bms_free(leftvarnos); /* * Now, determine which index attribute this is, change the * indexkey operand as needed, and get the index opclass. */ lfirst(newclause->args) = fix_indxqual_operand(lfirst(newclause->args), baserelid, index, &opclass); FastAppend(&fixed_qual, newclause); /* * Finally, check to see if index is lossy for this operator. If * so, add (a copy of) original form of clause to recheck list. */ if (op_requires_recheck(newclause->opno, opclass)) FastAppend(&recheck_qual, copyObject((Node *) clause)); } *fixed_quals = FastListValue(&fixed_qual); *recheck_quals = FastListValue(&recheck_qual);}static Node *fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index, Oid *opclass){ /* * We represent index keys by Var nodes having the varno of the base * table but varattno equal to the index's attribute number (index * column position). This is a bit hokey ... would be cleaner to use * a special-purpose node type that could not be mistaken for a * regular Var. But it will do for now. */ Var *result; int pos; List *indexprs; /* * Remove any binary-compatible relabeling of the indexkey */ if (IsA(node, RelabelType)) node = (Node *) ((RelabelType *) node)->arg; if (IsA(node, Var) && ((Var *) node)->varno == baserelid) { /* Try to match against simple index columns */ int varatt = ((Var *) node)->varattno; if (varatt != 0) { for (pos = 0; pos < index->ncolumns; pos++) { if (index->indexkeys[pos] == varatt) { result = (Var *) copyObject(node); result->varattno = pos + 1; /* return the correct opclass, too */ *opclass = index->classlist[pos]; return (Node *) result; } } } } /* Try to match against index expressions */ indexprs = index->indexprs; for (pos = 0; pos < index->ncolumns; pos++) { if (index->indexkeys[pos] == 0) { Node *indexkey; if (indexprs == NIL) elog(ERROR, "too few entries in indexprs list"); indexkey = (Node *) lfirst(indexprs); if (indexkey && IsA(indexkey, RelabelType)) indexkey = (Node *) ((RelabelType *) indexkey)->arg; if (equal(node, indexkey)) { /* Found a match */ result = makeVar(baserelid, pos + 1, exprType(lfirst(indexprs)), -1, 0); /* return the correct opclass, too */ *opclass = index->classlist[pos]; return (Node *) result; } indexprs = lnext(indexprs); } } /* Ooops... */ elog(ERROR, "node is not an index attribute"); return NULL; /* keep compiler quiet */}/* * get_switched_clauses * Given a list of merge or hash joinclauses (as RestrictInfo nodes), * extract the bare clauses, and rearrange the elements within the * clauses, if needed, so the outer join variable is on the left and * the inner is on the right. The original data structure is not touched; * a modified list is returned. */static List *get_switched_clauses(List *clauses, Relids outerrelids){ List *t_list = NIL; List *i; foreach(i, clauses) { RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i); OpExpr *clause = (OpExpr *) restrictinfo->clause; Assert(is_opclause(clause)); if (bms_is_subset(restrictinfo->right_relids, outerrelids)) { /* * Duplicate just enough of the structure to allow commuting * the clause without changing the original list. Could use * copyObject, but a complete deep copy is overkill. */ OpExpr *temp = makeNode(OpExpr); temp->opno = clause->opno; temp->opfuncid = InvalidOid; temp->opresulttype = clause->opresulttype; temp->opretset = clause->opretset; temp->args = listCopy(clause->args); /* Commute it --- note this modifies the temp node in-place. */ CommuteClause(temp); t_list = lappend(t_list, temp); } else t_list = lappend(t_list, clause); } return t_list;}/* * order_qual_clauses * Given a list of qual clauses that will all be evaluated at the same * plan node, sort the list into the order we want to check the quals
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -