aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/path/allpaths.c4
-rw-r--r--src/backend/optimizer/path/costsize.c8
-rw-r--r--src/backend/optimizer/path/joinpath.c8
-rw-r--r--src/backend/optimizer/path/joinrels.c97
-rw-r--r--src/include/nodes/relation.h7
5 files changed, 113 insertions, 11 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index ef0b25bf5e2..91725db98cb 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.168 2008/01/11 04:02:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.168.2.1 2008/03/24 21:53:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -428,7 +428,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
* 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
- * AppendPath with no members.
+ * AppendPath with no members (see also IS_DUMMY_PATH macro).
*/
static void
set_dummy_rel_pathlist(RelOptInfo *rel)
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index f2009fa66c3..8200add6ef1 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.191 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.191.2.1 2008/03/24 21:53:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1385,6 +1385,12 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
Selectivity joininfactor;
Path sort_path; /* dummy for result of cost_sort */
+ /* Protect some assumptions below that rowcounts aren't zero */
+ if (outer_path_rows <= 0)
+ outer_path_rows = 1;
+ if (inner_path_rows <= 0)
+ inner_path_rows = 1;
+
if (!enable_mergejoin)
startup_cost += disable_cost;
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index d5e2506d7a0..b26d2077e6f 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.115 2008/01/09 20:42:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.115.2.1 2008/03/24 21:53:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -837,11 +837,9 @@ best_appendrel_indexscan(PlannerInfo *root, RelOptInfo *rel,
/*
* 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).
+ * it will have a cheapest_total_path that's a "dummy" path.
*/
- if (IsA(childrel->cheapest_total_path, AppendPath) &&
- ((AppendPath *) childrel->cheapest_total_path)->subpaths == NIL)
+ if (IS_DUMMY_PATH(childrel->cheapest_total_path))
continue; /* OK, we can ignore it */
/*
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 8df5c21f1fd..7b8565db438 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.91 2008/01/11 04:02:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.91.2.1 2008/03/24 21:53:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,6 +27,8 @@ static List *make_rels_by_clauseless_joins(PlannerInfo *root,
ListCell *other_rels);
static bool has_join_restriction(PlannerInfo *root, RelOptInfo *rel);
static bool has_legal_joinclause(PlannerInfo *root, RelOptInfo *rel);
+static bool is_dummy_rel(RelOptInfo *rel);
+static void mark_dummy_join(RelOptInfo *rel);
/*
@@ -571,35 +573,75 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
&restrictlist);
/*
- * Consider paths using each rel as both outer and inner.
+ * If we've already proven this join is empty, we needn't consider
+ * any more paths for it.
+ */
+ if (is_dummy_rel(joinrel))
+ {
+ bms_free(joinrelids);
+ return joinrel;
+ }
+
+ /*
+ * Consider paths using each rel as both outer and inner. Depending
+ * on the join type, a provably empty outer or inner rel might mean
+ * the join is provably empty too; in which case throw away any
+ * previously computed paths and mark the join as dummy. (We do it
+ * this way since it's conceivable that dummy-ness of a multi-element
+ * join might only be noticeable for certain construction paths.)
*/
switch (jointype)
{
case JOIN_INNER:
+ if (is_dummy_rel(rel1) || is_dummy_rel(rel2))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_INNER,
restrictlist);
add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_INNER,
restrictlist);
break;
case JOIN_LEFT:
+ if (is_dummy_rel(rel1))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_LEFT,
restrictlist);
add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_RIGHT,
restrictlist);
break;
case JOIN_FULL:
+ if (is_dummy_rel(rel1) && is_dummy_rel(rel2))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_FULL,
restrictlist);
add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_FULL,
restrictlist);
break;
case JOIN_RIGHT:
+ if (is_dummy_rel(rel2))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_RIGHT,
restrictlist);
add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_LEFT,
restrictlist);
break;
case JOIN_IN:
+ if (is_dummy_rel(rel1) || is_dummy_rel(rel2))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_IN,
restrictlist);
/* REVERSE_IN isn't supported by joinpath.c */
@@ -609,6 +651,11 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
restrictlist);
break;
case JOIN_REVERSE_IN:
+ if (is_dummy_rel(rel1) || is_dummy_rel(rel2))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
/* REVERSE_IN isn't supported by joinpath.c */
add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_IN,
restrictlist);
@@ -618,12 +665,22 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
restrictlist);
break;
case JOIN_UNIQUE_OUTER:
+ if (is_dummy_rel(rel1) || is_dummy_rel(rel2))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_OUTER,
restrictlist);
add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_INNER,
restrictlist);
break;
case JOIN_UNIQUE_INNER:
+ if (is_dummy_rel(rel1) || is_dummy_rel(rel2))
+ {
+ mark_dummy_join(joinrel);
+ break;
+ }
add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_UNIQUE_INNER,
restrictlist);
add_paths_to_joinrel(root, joinrel, rel2, rel1, JOIN_UNIQUE_OUTER,
@@ -883,3 +940,39 @@ has_legal_joinclause(PlannerInfo *root, RelOptInfo *rel)
return false;
}
+
+
+/*
+ * is_dummy_rel --- has relation been proven empty?
+ *
+ * If so, it will have a single path that is dummy.
+ */
+static bool
+is_dummy_rel(RelOptInfo *rel)
+{
+ return (rel->cheapest_total_path != NULL &&
+ IS_DUMMY_PATH(rel->cheapest_total_path));
+}
+
+/*
+ * Mark a joinrel as proven empty.
+ */
+static void
+mark_dummy_join(RelOptInfo *rel)
+{
+ /* Set dummy size estimate */
+ rel->rows = 0;
+
+ /* Evict any previously chosen paths */
+ rel->pathlist = NIL;
+
+ /* Set up the dummy path */
+ add_path(rel, (Path *) create_append_path(rel, NIL));
+
+ /*
+ * Although set_cheapest will be done again later, we do it immediately
+ * in order to keep is_dummy_rel as cheap as possible (ie, not have
+ * to examine the pathlist).
+ */
+ set_cheapest(rel);
+}
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index b106c590e3e..a9081b72a8a 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.154 2008/01/11 04:02:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.154.2.1 2008/03/24 21:53:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -693,6 +693,8 @@ typedef struct TidPath
*
* Note: it is possible for "subpaths" to contain only one, or even no,
* elements. These cases are optimized during create_append_plan.
+ * In particular, an AppendPath with no subpaths is a "dummy" path that
+ * is created to represent the case that a relation is provably empty.
*/
typedef struct AppendPath
{
@@ -700,6 +702,9 @@ typedef struct AppendPath
List *subpaths; /* list of component Paths */
} AppendPath;
+#define IS_DUMMY_PATH(p) \
+ (IsA((p), AppendPath) && ((AppendPath *) (p))->subpaths == NIL)
+
/*
* ResultPath represents use of a Result plan node to compute a variable-free
* targetlist with no underlying tables (a "SELECT expressions" query).