diff options
Diffstat (limited to 'src/backend/optimizer/path/allpaths.c')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 191 |
1 files changed, 158 insertions, 33 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 7e017a746f1..12fc576612f 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.66 2000/10/05 19:11:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.67 2000/11/12 00:36:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "optimizer/paths.h" #include "optimizer/plancat.h" #include "optimizer/planner.h" +#include "optimizer/prep.h" #include "parser/parsetree.h" @@ -28,7 +29,12 @@ bool enable_geqo = true; int geqo_rels = DEFAULT_GEQO_RELS; -static void set_base_rel_pathlist(Query *root); +static void set_base_rel_pathlists(Query *root); +static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel, + RangeTblEntry *rte); +static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, + RangeTblEntry *rte, + List *inheritlist); static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels); @@ -51,7 +57,7 @@ make_one_rel(Query *root) /* * Generate access paths for the base rels. */ - set_base_rel_pathlist(root); + set_base_rel_pathlists(root); /* * Generate access paths for the entire join tree. @@ -69,23 +75,26 @@ make_one_rel(Query *root) } /* - * set_base_rel_pathlist + * 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 void -set_base_rel_pathlist(Query *root) +set_base_rel_pathlists(Query *root) { List *rellist; foreach(rellist, root->base_rel_list) { RelOptInfo *rel = (RelOptInfo *) lfirst(rellist); + Index rti; RangeTblEntry *rte; + List *inheritlist; Assert(length(rel->relids) == 1); /* better be base rel */ - rte = rt_fetch(lfirsti(rel->relids), root->rtable); + rti = lfirsti(rel->relids); + rte = rt_fetch(rti, root->rtable); if (rel->issubquery) { @@ -109,47 +118,163 @@ set_base_rel_pathlist(Query *root) /* Generate appropriate path */ add_path(rel, create_subqueryscan_path(rel)); + + /* Select cheapest path (pretty easy in this case...) */ + set_cheapest(rel); + } + else if ((inheritlist = expand_inherted_rtentry(root, rti)) != NIL) + { + /* Relation is root of an inheritance tree, process specially */ + set_inherited_rel_pathlist(root, rel, rte, inheritlist); } else { /* Plain relation */ - List *indices = find_secondary_indexes(rte->relid); + set_plain_rel_pathlist(root, rel, rte); + } + } +} - /* Mark rel with estimated output rows, width, etc */ - set_baserel_size_estimates(root, rel); +/* + * set_plain_rel_pathlist + * Build access paths for a plain relation (no subquery, no inheritance) + */ +static void +set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + List *indices = find_secondary_indexes(rte->relid); - /* - * 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. - */ + /* Mark rel with estimated output rows, width, etc */ + set_baserel_size_estimates(root, rel); - /* Consider sequential scan */ - add_path(rel, create_seqscan_path(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 TID scans */ - create_tidscan_paths(root, rel); + /* Consider sequential scan */ + add_path(rel, create_seqscan_path(rel)); - /* Consider index paths for both simple and OR index clauses */ - create_index_paths(root, rel, indices, - rel->baserestrictinfo, - rel->joininfo); + /* Consider TID scans */ + create_tidscan_paths(root, rel); - /* - * Note: create_or_index_paths depends on create_index_paths to - * have marked OR restriction clauses with relevant indices; this - * is why it doesn't need to be given the list of indices. - */ - create_or_index_paths(root, rel, rel->baserestrictinfo); - } + /* Consider index paths for both simple and OR index clauses */ + create_index_paths(root, rel, indices, + rel->baserestrictinfo, + rel->joininfo); + + /* + * Note: create_or_index_paths depends on create_index_paths to + * have marked OR restriction clauses with relevant indices; this + * is why it doesn't need to be given the list of indices. + */ + create_or_index_paths(root, rel, rel->baserestrictinfo); + + /* Now find the cheapest of the paths for this rel */ + set_cheapest(rel); +} + +/* + * set_inherited_rel_pathlist + * Build access paths for a inheritance tree rooted at rel + * + * inheritlist is a list of RT indexes of all tables in the inheritance tree, + * including the parent itself. Note we will not come here unless there's + * at least one child in addition to the parent. + */ +static void +set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte, + List *inheritlist) +{ + int parentRTindex = lfirsti(rel->relids); + Oid parentOID = rte->relid; + List *subpaths = NIL; + List *il; + + /* + * XXX for now, can't handle inherited expansion of FOR UPDATE; + * can we do better? + */ + if (intMember(parentRTindex, root->rowMarks)) + elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries"); - /* Now find the cheapest of the paths for this rel */ - set_cheapest(rel); + /* + * Recompute size estimates for whole inheritance tree + */ + rel->rows = 0; + rel->width = 0; + + /* + * Generate access paths for each table in the tree (parent AND children), + * and pick the cheapest path for each table. + */ + foreach(il, inheritlist) + { + int childRTindex = lfirsti(il); + RangeTblEntry *childrte; + Oid childOID; + RelOptInfo *childrel; + + childrte = rt_fetch(childRTindex, root->rtable); + childOID = childrte->relid; + + /* + * Make a RelOptInfo for the child so we can do planning. Do NOT + * attach the RelOptInfo to the query's base_rel_list, however. + * + * NOTE: when childRTindex == parentRTindex, we create a second + * RelOptInfo for the same relation. This RelOptInfo will represent + * the parent table alone, whereas the original RelOptInfo represents + * the union of the inheritance tree members. + */ + childrel = make_base_rel(root, childRTindex); + + /* + * Copy the parent's targetlist and restriction quals to the child, + * with attribute-number adjustment if needed. We don't bother + * to copy the join quals, since we can't do any joining here. + */ + childrel->targetlist = (List *) + adjust_inherited_attrs((Node *) rel->targetlist, + parentRTindex, + parentOID, + childRTindex, + childOID); + childrel->baserestrictinfo = (List *) + adjust_inherited_attrs((Node *) rel->baserestrictinfo, + parentRTindex, + parentOID, + childRTindex, + childOID); + childrel->baserestrictcost = rel->baserestrictcost; + + /* + * Now compute child access paths, and save the cheapest. + */ + set_plain_rel_pathlist(root, childrel, childrte); + + subpaths = lappend(subpaths, childrel->cheapest_total_path); + + /* Also update total size estimates */ + rel->rows += childrel->rows; + if (childrel->width > rel->width) + rel->width = childrel->width; } + + /* + * Finally, build Append path and install it as the only access + * path for the parent rel. + */ + add_path(rel, (Path *) create_append_path(rel, subpaths)); + + /* Select cheapest path (pretty easy in this case...) */ + set_cheapest(rel); } + /* * make_fromexpr_rel * Build access paths for a FromExpr jointree node. |