diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 81 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 15 | ||||
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 52 | ||||
-rw-r--r-- | src/include/optimizer/plancat.h | 5 |
4 files changed, 90 insertions, 63 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 890bb59a12f..d2100905406 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.141 2006/02/03 21:08:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.142 2006/02/04 23:03:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,7 +26,6 @@ #include "optimizer/paths.h" #include "optimizer/plancat.h" #include "optimizer/planner.h" -#include "optimizer/predtest.h" #include "optimizer/prep.h" #include "optimizer/var.h" #include "parser/parsetree.h" @@ -36,14 +35,12 @@ /* These parameters are set by GUC */ -bool constraint_exclusion = false; bool enable_geqo = false; /* just in case GUC doesn't set it */ int geqo_threshold; static void set_base_rel_pathlists(PlannerInfo *root); -static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte); +static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti); static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, @@ -146,8 +143,7 @@ set_base_rel_pathlists(PlannerInfo *root) if (rel->reloptkind != RELOPT_BASEREL) continue; - set_rel_pathlist(root, rel, rti, - rt_fetch(rti, root->parse->rtable)); + set_rel_pathlist(root, rel, rti); } } @@ -156,9 +152,10 @@ set_base_rel_pathlists(PlannerInfo *root) * Build access paths for a base relation */ static void -set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte) +set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti) { + RangeTblEntry *rte = rt_fetch(rti, root->parse->rtable); + if (rte->inh) { /* It's an "append relation", process accordingly */ @@ -208,6 +205,24 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) set_baserel_size_estimates(root, rel); /* + * If we can prove we don't need to scan the rel via constraint exclusion, + * set up a single dummy path for it. (Rather than inventing a special + * "dummy" path type, we represent this as an AppendPath with no members.) + */ + if (relation_excluded_by_constraints(rel, rte)) + { + /* Reset output-rows estimate to 0 */ + rel->rows = 0; + + add_path(rel, (Path *) create_append_path(rel, NIL)); + + /* Select cheapest path (pretty easy in this case...) */ + set_cheapest(rel); + + return; + } + + /* * Generate paths and add them to the rel's pathlist. * * Note: add_path() will discard any paths that are dominated by another @@ -273,7 +288,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); int childRTindex; RelOptInfo *childrel; - RangeTblEntry *childrte; Path *childpath; ListCell *parentvars; ListCell *childvars; @@ -316,53 +330,18 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, childrel->max_attr); /* - * If we can prove we don't need to scan this child via constraint - * exclusion, just ignore it. (We have to have converted the - * baserestrictinfo Vars before we can make the test.) - * - * XXX it'd probably be better to give the child some kind of dummy - * cheapest path, or otherwise explicitly mark it as ignorable. - * Currently there is an ugly check in join_before_append() to handle - * excluded children. - */ - childrte = rt_fetch(childRTindex, root->parse->rtable); - if (constraint_exclusion && - childrte->rtekind == RTE_RELATION) - { - List *constraint_pred; - - constraint_pred = get_relation_constraints(childrte->relid, - childrel); - - /* - * We do not currently enforce that CHECK constraints contain only - * immutable functions, so it's necessary to check here. We - * daren't draw conclusions from plan-time evaluation of - * non-immutable functions. - */ - if (!contain_mutable_functions((Node *) constraint_pred)) - { - /* - * The constraints are effectively ANDed together, so we can - * just try to refute the entire collection at once. This may - * allow us to make proofs that would fail if we took them - * individually. - */ - if (predicate_refuted_by(constraint_pred, - childrel->baserestrictinfo)) - continue; - } - } - - /* - * Compute the child's access paths, and save the cheapest. + * 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.) + * This test also handles the case where the child rel need not + * be scanned because of constraint exclusion: it'll have an + * Append path with no subpaths, and will vanish from our list. */ - set_rel_pathlist(root, childrel, childRTindex, childrte); + set_rel_pathlist(root, childrel, childRTindex); childpath = childrel->cheapest_total_path; if (IsA(childpath, AppendPath)) diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index df3bd128747..450bc26bed9 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.100 2006/02/03 21:08:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.101 2006/02/04 23:03:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -867,14 +867,13 @@ join_before_append(PlannerInfo *root, Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL); /* - * If the child has no cheapest_total_path, assume it was deemed - * excludable by constraint exclusion (see set_append_rel_pathlist). + * Check to see if child was rejected by constraint exclusion. + * If so, it will have a cheapest_total_path that's an Append path + * with no members (see set_plain_rel_pathlist). */ - if (childrel->cheapest_total_path == NULL) - { - Assert(constraint_exclusion); - continue; - } + if (IsA(childrel->cheapest_total_path, AppendPath) && + ((AppendPath *) childrel->cheapest_total_path)->subpaths == NIL) + continue; /* OK, we can ignore it */ /* * Get the best innerjoin indexpath (if any) for this outer rel. diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index c926ae5d488..b6dcfa144f2 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.117 2006/01/31 21:39:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.118 2006/02/04 23:03:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -25,6 +25,7 @@ #include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "optimizer/plancat.h" +#include "optimizer/predtest.h" #include "optimizer/prep.h" #include "optimizer/tlist.h" #include "parser/parsetree.h" @@ -40,8 +41,13 @@ #include "miscadmin.h" +/* GUC parameter */ +bool constraint_exclusion = false; + + static void estimate_rel_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples); +static List *get_relation_constraints(Oid relationObjectId, RelOptInfo *rel); /* @@ -360,7 +366,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths, * run, and in many cases it won't be invoked at all, so there seems no * point in caching the data in RelOptInfo. */ -List * +static List * get_relation_constraints(Oid relationObjectId, RelOptInfo *rel) { List *result = NIL; @@ -425,6 +431,48 @@ get_relation_constraints(Oid relationObjectId, RelOptInfo *rel) /* + * relation_excluded_by_constraints + * + * Detect whether the relation need not be scanned because it has CHECK + * constraints that conflict with the query's WHERE clause. + */ +bool +relation_excluded_by_constraints(RelOptInfo *rel, RangeTblEntry *rte) +{ + List *constraint_pred; + + /* Skip the test if constraint exclusion is disabled */ + if (!constraint_exclusion) + return false; + + /* Only plain relations have constraints */ + if (rte->rtekind != RTE_RELATION || rte->inh) + return false; + + /* OK to fetch the constraint expressions */ + constraint_pred = get_relation_constraints(rte->relid, rel); + + /* + * We do not currently enforce that CHECK constraints contain only + * immutable functions, so it's necessary to check here. We daren't draw + * conclusions from plan-time evaluation of non-immutable functions. + */ + if (contain_mutable_functions((Node *) constraint_pred)) + return false; + + /* + * The constraints are effectively ANDed together, so we can just try to + * refute the entire collection at once. This may allow us to make proofs + * that would fail if we took them individually. + */ + if (predicate_refuted_by(constraint_pred, rel->baserestrictinfo)) + return true; + + return false; +} + + +/* * build_physical_tlist * * Build a targetlist consisting of exactly the relation's user attributes, diff --git a/src/include/optimizer/plancat.h b/src/include/optimizer/plancat.h index 8a4c1e4941e..888105605b2 100644 --- a/src/include/optimizer/plancat.h +++ b/src/include/optimizer/plancat.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.37 2005/07/23 21:05:48 tgl Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/plancat.h,v 1.38 2006/02/04 23:03:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,8 @@ extern void get_relation_info(Oid relationObjectId, RelOptInfo *rel); -extern List *get_relation_constraints(Oid relationObjectId, RelOptInfo *rel); +extern bool relation_excluded_by_constraints(RelOptInfo *rel, + RangeTblEntry *rte); extern List *build_physical_tlist(PlannerInfo *root, RelOptInfo *rel); |