allpaths.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,290 行 · 第 1/3 页
C
1,290 行
/*------------------------------------------------------------------------- * * allpaths.c * Routines to find possible search paths for processing a query * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.168.2.2 2008/04/01 00:48:44 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#ifdef OPTIMIZER_DEBUG#include "nodes/print.h"#endif#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/geqo.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "optimizer/plancat.h"#include "optimizer/planner.h"#include "optimizer/prep.h"#include "optimizer/var.h"#include "parser/parse_clause.h"#include "parser/parse_expr.h"#include "parser/parsetree.h"#include "rewrite/rewriteManip.h"/* These parameters are set by GUC */bool enable_geqo = false; /* just in case GUC doesn't set it */int geqo_threshold;/* Hook for plugins to replace standard_join_search() */join_search_hook_type join_search_hook = NULL;static void set_base_rel_pathlists(PlannerInfo *root);static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte);static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte);static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte);static void set_dummy_rel_pathlist(RelOptInfo *rel);static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte);static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte);static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte);static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist);static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery, bool *differentTypes);static bool recurse_pushdown_safe(Node *setOp, Query *topquery, bool *differentTypes);static void compare_tlist_datatypes(List *tlist, List *colTypes, bool *differentTypes);static bool qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, bool *differentTypes);static void subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual);static void recurse_push_qual(Node *setOp, Query *topquery, RangeTblEntry *rte, Index rti, Node *qual);/* * make_one_rel * Finds all possible access paths for executing a query, returning a * single rel that represents the join of all base rels in the query. */RelOptInfo *make_one_rel(PlannerInfo *root, List *joinlist){ RelOptInfo *rel; /* * Generate access paths for the base rels. */ set_base_rel_pathlists(root); /* * Generate access paths for the entire join tree. */ rel = make_rel_from_joinlist(root, joinlist); /* * The result should join all and only the query's base rels. */#ifdef USE_ASSERT_CHECKING { 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; Assert(brel->relid == rti); /* sanity check on array */ /* ignore RTEs that are "other rels" */ if (brel->reloptkind != RELOPT_BASEREL) continue; Assert(bms_is_member(rti, rel->relids)); num_base_rels++; } Assert(bms_num_members(rel->relids) == num_base_rels); }#endif return rel;}/* * set_base_rel_pathlists * Finds all paths available for scanning each base-relation entry. * Sequential scan and any available indices are considered. * Each useful path is attached to its relation's 'pathlist' field. */static voidset_base_rel_pathlists(PlannerInfo *root){ Index rti; for (rti = 1; rti < root->simple_rel_array_size; rti++) { RelOptInfo *rel = root->simple_rel_array[rti]; /* there may be empty slots corresponding to non-baserel RTEs */ if (rel == NULL) continue; Assert(rel->relid == rti); /* sanity check on array */ /* ignore RTEs that are "other rels" */ if (rel->reloptkind != RELOPT_BASEREL) continue; set_rel_pathlist(root, rel, rti, root->simple_rte_array[rti]); }}/* * set_rel_pathlist * Build access paths for a base relation */static voidset_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte){ if (rte->inh) { /* It's an "append relation", process accordingly */ set_append_rel_pathlist(root, rel, rti, rte); } else if (rel->rtekind == RTE_SUBQUERY) { /* Subquery --- generate a separate plan for it */ set_subquery_pathlist(root, rel, rti, rte); } else if (rel->rtekind == RTE_FUNCTION) { /* RangeFunction --- generate a separate plan for it */ set_function_pathlist(root, rel, rte); } else if (rel->rtekind == RTE_VALUES) { /* Values list --- generate a separate plan for it */ set_values_pathlist(root, rel, rte); } else { /* Plain relation */ Assert(rel->rtekind == RTE_RELATION); set_plain_rel_pathlist(root, rel, rte); }#ifdef OPTIMIZER_DEBUG debug_print_rel(root, rel);#endif}/* * set_plain_rel_pathlist * Build access paths for a plain relation (no subquery, no inheritance) */static voidset_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){ /* * If we can prove we don't need to scan the rel via constraint exclusion, * set up a single dummy path for it. We only need to check for regular * baserels; if it's an otherrel, CE was already checked in * set_append_rel_pathlist(). */ if (rel->reloptkind == RELOPT_BASEREL && relation_excluded_by_constraints(root, rel, rte)) { set_dummy_rel_pathlist(rel); return; } /* Mark rel with estimated output rows, width, etc */ set_baserel_size_estimates(root, rel); /* Test any partial indexes of rel for applicability */ check_partial_indexes(root, rel); /* * Check to see if we can extract any restriction conditions from join * quals that are OR-of-AND structures. If so, add them to the rel's * restriction list, and recompute the size estimates. */ if (create_or_index_quals(root, rel)) set_baserel_size_estimates(root, rel); /* * Generate paths and add them to the rel's pathlist. * * Note: add_path() will discard any paths that are dominated by another * available path, keeping only those paths that are superior along at * least one dimension of cost or sortedness. */ /* Consider sequential scan */ add_path(rel, create_seqscan_path(root, rel)); /* Consider index scans */ create_index_paths(root, rel); /* Consider TID scans */ create_tidscan_paths(root, rel); /* Now find the cheapest of the paths for this rel */ set_cheapest(rel);}/* * set_append_rel_pathlist * Build access paths for an "append relation" * * The passed-in rel and RTE represent the entire append relation. The * relation's contents are computed by appending together the output of * the individual member relations. Note that in the inheritance case, * the first member relation is actually the same table as is mentioned in * the parent RTE ... but it has a different RTE and RelOptInfo. This is * a good thing because their outputs are not the same size. */static voidset_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte){ int parentRTindex = rti; List *subpaths = NIL; ListCell *l; /* * XXX for now, can't handle inherited expansion of FOR UPDATE/SHARE; can * we do better? (This will take some redesign because the executor * currently supposes that every rowMark relation is involved in every row * returned by the query.) */ if (get_rowmark(root->parse, parentRTindex)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries"))); /* * Initialize to compute size estimates for whole append relation */ rel->rows = 0; rel->width = 0; /* * Generate access paths for each member relation, and pick the cheapest * path for each one. */ foreach(l, root->append_rel_list) { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); int childRTindex; RangeTblEntry *childRTE; RelOptInfo *childrel; Path *childpath; ListCell *parentvars; ListCell *childvars; /* append_rel_list contains all append rels; ignore others */ if (appinfo->parent_relid != parentRTindex) continue; childRTindex = appinfo->child_relid; childRTE = root->simple_rte_array[childRTindex]; /* * The child rel's RelOptInfo was already created during * add_base_rels_to_query. */ childrel = find_base_rel(root, childRTindex); Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL); /* * We have to copy the parent's targetlist and quals to the child, * with appropriate substitution of variables. However, only the * baserestrictinfo quals are needed before we can check for * constraint exclusion; so do that first and then check to see if we * can disregard this child. */ childrel->baserestrictinfo = (List *) adjust_appendrel_attrs((Node *) rel->baserestrictinfo, appinfo); if (relation_excluded_by_constraints(root, childrel, childRTE)) { /* * This child need not be scanned, so we can omit it from the * appendrel. Mark it with a dummy cheapest-path though, in case * best_appendrel_indexscan() looks at it later. */ set_dummy_rel_pathlist(childrel); continue; } /* CE failed, so finish copying targetlist and join quals */ childrel->joininfo = (List *) adjust_appendrel_attrs((Node *) rel->joininfo, appinfo); childrel->reltargetlist = (List *) adjust_appendrel_attrs((Node *) rel->reltargetlist, appinfo); /* * We have to make child entries in the EquivalenceClass data * structures as well. */ if (rel->has_eclass_joins) { add_child_rel_equivalences(root, appinfo, rel, childrel); childrel->has_eclass_joins = true; } /* * Copy the parent's attr_needed data as well, with appropriate * adjustment of relids and attribute numbers. */ pfree(childrel->attr_needed); childrel->attr_needed = adjust_appendrel_attr_needed(rel, appinfo, childrel->min_attr, childrel->max_attr); /* * Compute the child's access paths, and add the cheapest one to the * Append path we are constructing for the parent. * * It's possible that the child is itself an appendrel, in which case * we can "cut out the middleman" and just add its child paths to our * own list. (We don't try to do this earlier because we need to * apply both levels of transformation to the quals.) */ set_rel_pathlist(root, childrel, childRTindex, childRTE); childpath = childrel->cheapest_total_path; if (IsA(childpath, AppendPath)) subpaths = list_concat(subpaths, ((AppendPath *) childpath)->subpaths); else subpaths = lappend(subpaths, childpath); /* * Propagate size information from the child back to the parent. For * simplicity, we use the largest widths from any child as the parent * estimates. (If you want to change this, beware of child * attr_widths[] entries that haven't been set and are still 0.) */ rel->rows += childrel->rows; if (childrel->width > rel->width) rel->width = childrel->width; forboth(parentvars, rel->reltargetlist, childvars, childrel->reltargetlist) { Var *parentvar = (Var *) lfirst(parentvars); Var *childvar = (Var *) lfirst(childvars); if (IsA(parentvar, Var) && IsA(childvar, Var)) { int pndx = parentvar->varattno - rel->min_attr; int cndx = childvar->varattno - childrel->min_attr; if (childrel->attr_widths[cndx] > rel->attr_widths[pndx]) rel->attr_widths[pndx] = childrel->attr_widths[cndx]; } } } /* * Set "raw tuples" count equal to "rows" for the appendrel; needed * because some places assume rel->tuples is valid for any baserel. */ rel->tuples = rel->rows; /* * Finally, build Append path and install it as the only access path for * the parent rel. (Note: this is correct even if we have zero or one * live subpath due to constraint exclusion.) */ add_path(rel, (Path *) create_append_path(rel, subpaths)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel);}/* * set_dummy_rel_pathlist * Build a dummy path for a relation that's been excluded by constraints * * Rather than inventing a special "dummy" path type, we represent this as an
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?