allpaths.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,290 行 · 第 1/3 页
C
1,290 行
* AppendPath with no members (see also IS_DUMMY_PATH macro). */static voidset_dummy_rel_pathlist(RelOptInfo *rel){ /* Set dummy size estimates --- we leave attr_widths[] as zeroes */ rel->rows = 0; rel->width = 0; add_path(rel, (Path *) create_append_path(rel, NIL)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* quick-and-dirty test to see if any joining is needed */static boolhas_multiple_baserels(PlannerInfo *root){ int num_base_rels = 0; Index rti; for (rti = 1; rti < root->simple_rel_array_size; rti++) { RelOptInfo *brel = root->simple_rel_array[rti]; if (brel == NULL) continue; /* ignore RTEs that are "other rels" */ if (brel->reloptkind == RELOPT_BASEREL) if (++num_base_rels > 1) return true; } return false;}/* * set_subquery_pathlist * Build the (single) access path for a subquery RTE */static voidset_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte){ Query *parse = root->parse; Query *subquery = rte->subquery; bool *differentTypes; double tuple_fraction; PlannerInfo *subroot; List *pathkeys; /* We need a workspace for keeping track of set-op type coercions */ differentTypes = (bool *) palloc0((list_length(subquery->targetList) + 1) * sizeof(bool)); /* * If there are any restriction clauses that have been attached to the * subquery relation, consider pushing them down to become WHERE or HAVING * quals of the subquery itself. This transformation is useful because it * may allow us to generate a better plan for the subquery than evaluating * all the subquery output rows and then filtering them. * * There are several cases where we cannot push down clauses. Restrictions * involving the subquery are checked by subquery_is_pushdown_safe(). * Restrictions on individual clauses are checked by * qual_is_pushdown_safe(). Also, we don't want to push down * pseudoconstant clauses; better to have the gating node above the * subquery. * * Non-pushed-down clauses will get evaluated as qpquals of the * SubqueryScan node. * * XXX Are there any cases where we want to make a policy decision not to * push down a pushable qual, because it'd result in a worse plan? */ if (rel->baserestrictinfo != NIL && subquery_is_pushdown_safe(subquery, subquery, differentTypes)) { /* OK to consider pushing down individual quals */ List *upperrestrictlist = NIL; ListCell *l; foreach(l, rel->baserestrictinfo) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); Node *clause = (Node *) rinfo->clause; if (!rinfo->pseudoconstant && qual_is_pushdown_safe(subquery, rti, clause, differentTypes)) { /* Push it down */ subquery_push_qual(subquery, rte, rti, clause); } else { /* Keep it in the upper query */ upperrestrictlist = lappend(upperrestrictlist, rinfo); } } rel->baserestrictinfo = upperrestrictlist; } pfree(differentTypes); /* * We can safely pass the outer tuple_fraction down to the subquery if the * outer level has no joining, aggregation, or sorting to do. Otherwise * we'd better tell the subquery to plan for full retrieval. (XXX This * could probably be made more intelligent ...) */ if (parse->hasAggs || parse->groupClause || parse->havingQual || parse->distinctClause || parse->sortClause || has_multiple_baserels(root)) tuple_fraction = 0.0; /* default case */ else tuple_fraction = root->tuple_fraction; /* Generate the plan for the subquery */ rel->subplan = subquery_planner(root->glob, subquery, root->query_level + 1, tuple_fraction, &subroot); rel->subrtable = subroot->parse->rtable; /* Copy number of output rows from subplan */ rel->tuples = rel->subplan->plan_rows; /* Mark rel with estimated output rows, width, etc */ set_baserel_size_estimates(root, rel); /* Convert subquery pathkeys to outer representation */ pathkeys = convert_subquery_pathkeys(root, rel, subroot->query_pathkeys); /* Generate appropriate path */ add_path(rel, create_subqueryscan_path(rel, pathkeys)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* * set_function_pathlist * Build the (single) access path for a function RTE */static voidset_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){ /* Mark rel with estimated output rows, width, etc */ set_function_size_estimates(root, rel); /* Generate appropriate path */ add_path(rel, create_functionscan_path(root, rel)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* * set_values_pathlist * Build the (single) access path for a VALUES RTE */static voidset_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){ /* Mark rel with estimated output rows, width, etc */ set_values_size_estimates(root, rel); /* Generate appropriate path */ add_path(rel, create_valuesscan_path(root, rel)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* * make_rel_from_joinlist * Build access paths using a "joinlist" to guide the join path search. * * See comments for deconstruct_jointree() for definition of the joinlist * data structure. */static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist){ int levels_needed; List *initial_rels; ListCell *jl; /* * Count the number of child joinlist nodes. This is the depth of the * dynamic-programming algorithm we must employ to consider all ways of * joining the child nodes. */ levels_needed = list_length(joinlist); if (levels_needed <= 0) return NULL; /* nothing to do? */ /* * Construct a list of rels corresponding to the child joinlist nodes. * This may contain both base rels and rels constructed according to * sub-joinlists. */ initial_rels = NIL; foreach(jl, joinlist) { Node *jlnode = (Node *) lfirst(jl); RelOptInfo *thisrel; if (IsA(jlnode, RangeTblRef)) { int varno = ((RangeTblRef *) jlnode)->rtindex; thisrel = find_base_rel(root, varno); } else if (IsA(jlnode, List)) { /* Recurse to handle subproblem */ thisrel = make_rel_from_joinlist(root, (List *) jlnode); } else { elog(ERROR, "unrecognized joinlist node type: %d", (int) nodeTag(jlnode)); thisrel = NULL; /* keep compiler quiet */ } initial_rels = lappend(initial_rels, thisrel); } if (levels_needed == 1) { /* * Single joinlist node, so we're done. */ return (RelOptInfo *) linitial(initial_rels); } else { /* * Consider the different orders in which we could join the rels, * using a plugin, GEQO, or the regular join search code. * * We put the initial_rels list into a PlannerInfo field because * has_legal_joinclause() needs to look at it (ugly :-(). */ root->initial_rels = initial_rels; if (join_search_hook) return (*join_search_hook) (root, levels_needed, initial_rels); else if (enable_geqo && levels_needed >= geqo_threshold) return geqo(root, levels_needed, initial_rels); else return standard_join_search(root, levels_needed, initial_rels); }}/* * standard_join_search * Find possible joinpaths for a query by successively finding ways * to join component relations into join relations. * * 'levels_needed' is the number of iterations needed, ie, the number of * independent jointree items in the query. This is > 1. * * 'initial_rels' is a list of RelOptInfo nodes for each independent * jointree item. These are the components to be joined together. * Note that levels_needed == list_length(initial_rels). * * Returns the final level of join relations, i.e., the relation that is * the result of joining all the original relations together. * At least one implementation path must be provided for this relation and * all required sub-relations. * * To support loadable plugins that modify planner behavior by changing the * join searching algorithm, we provide a hook variable that lets a plugin * replace or supplement this function. Any such hook must return the same * final join relation as the standard code would, but it might have a * different set of implementation paths attached, and only the sub-joinrels * needed for these paths need have been instantiated. * * Note to plugin authors: the functions invoked during standard_join_search() * modify root->join_rel_list and root->join_rel_hash. If you want to do more * than one join-order search, you'll probably need to save and restore the * original states of those data structures. See geqo_eval() for an example. */RelOptInfo *standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels){ List **joinitems; int lev; RelOptInfo *rel; /* * We employ a simple "dynamic programming" algorithm: we first find all * ways to build joins of two jointree items, then all ways to build joins * of three items (from two-item joins and single items), then four-item * joins, and so on until we have considered all ways to join all the * items into one rel. * * joinitems[j] is a list of all the j-item rels. Initially we set * joinitems[1] to represent all the single-jointree-item relations. */ joinitems = (List **) palloc0((levels_needed + 1) * sizeof(List *)); joinitems[1] = initial_rels; for (lev = 2; lev <= levels_needed; lev++) { ListCell *x; /* * Determine all possible pairs of relations to be joined at this * level, and build paths for making each one from every available * pair of lower-level relations. */ joinitems[lev] = join_search_one_level(root, lev, joinitems); /* * Do cleanup work on each just-processed rel. */ foreach(x, joinitems[lev]) { rel = (RelOptInfo *) lfirst(x); /* Find and save the cheapest paths for this rel */ set_cheapest(rel);#ifdef OPTIMIZER_DEBUG debug_print_rel(root, rel);#endif } } /* * We should have a single rel at the final level. */ if (joinitems[levels_needed] == NIL) elog(ERROR, "failed to build any %d-way joins", levels_needed); Assert(list_length(joinitems[levels_needed]) == 1); rel = (RelOptInfo *) linitial(joinitems[levels_needed]); return rel;}/***************************************************************************** * PUSHING QUALS DOWN INTO SUBQUERIES *****************************************************************************//* * subquery_is_pushdown_safe - is a subquery safe for pushing down quals? * * subquery is the particular component query being checked. topquery * is the top component of a set-operations tree (the same Query if no * set-op is involved). * * Conditions checked here: * * 1. If the subquery has a LIMIT clause, we must not push down any quals, * since that could change the set of rows returned. * * 2. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push * quals into it, because that would change the results. * * 3. For subqueries using UNION/UNION ALL/INTERSECT/INTERSECT ALL, we can * push quals into each component query, but the quals can only reference * subquery columns that suffer no type coercions in the set operation. * Otherwise there are possible semantic gotchas. So, we check the * component queries to see if any of them have different output types; * differentTypes[k] is set true if column k has different type in any * component. */static boolsubquery_is_pushdown_safe(Query *subquery, Query *topquery, bool *differentTypes){ SetOperationStmt *topop; /* Check point 1 */ if (subquery->limitOffset != NULL || subquery->limitCount != NULL) return false; /* Are we at top level, or looking at a setop component? */ if (subquery == topquery) { /* Top level, so check any component queries */ if (subquery->setOperations != NULL) if (!recurse_pushdown_safe(subquery->setOperations, topquery, differentTypes)) return false; } else { /* Setop component must not have more components (too weird) */ if (subquery->setOperations != NULL) return false; /* Check whether setop component output types match top level */ topop = (SetOperationStmt *) topquery->setOperations; Assert(topop && IsA(topop, SetOperationStmt)); compare_tlist_datatypes(subquery->targetList, topop->colTypes, differentTypes); } return true;}/* * Helper routine to recurse through setOperations tree */static boolrecurse_pushdown_safe(Node *setOp, Query *topquery, bool *differentTypes){ if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; RangeTblEntry *rte = rt_fetch(rtr->rtindex, topquery->rtable); Query *subquery = rte->subquery; Assert(subquery != NULL); return subquery_is_pushdown_safe(subquery, topquery, differentTypes); } else if (IsA(setOp, SetOperationStmt)) { SetOperationStmt *op = (SetOperationStmt *) setOp;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?