aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/path/allpaths.c104
-rw-r--r--src/test/regress/expected/join.out20
-rw-r--r--src/test/regress/sql/join.sql12
3 files changed, 94 insertions, 42 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 1590be11675..8fc1cfd15f5 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -360,6 +360,11 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
break;
}
}
+
+ /*
+ * We insist that all non-dummy rels have a nonzero rowcount estimate.
+ */
+ Assert(rel->rows > 0 || IS_DUMMY_REL(rel));
}
/*
@@ -579,6 +584,9 @@ set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Let FDW adjust the size estimates, if it can */
rel->fdwroutine->GetForeignRelSize(root, rel, rte->relid);
+
+ /* ... but do not let it set the rows estimate to zero */
+ rel->rows = clamp_row_est(rel->rows);
}
/*
@@ -608,6 +616,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte)
{
int parentRTindex = rti;
+ bool has_live_children;
double parent_rows;
double parent_size;
double *parent_attrsizes;
@@ -628,6 +637,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
* Note: if you consider changing this logic, beware that child rels could
* have zero rows and/or width, if they were excluded by constraints.
*/
+ has_live_children = false;
parent_rows = 0;
parent_size = 0;
nattrs = rel->max_attr - rel->min_attr + 1;
@@ -755,70 +765,80 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
if (IS_DUMMY_REL(childrel))
continue;
+ /* We have at least one live child. */
+ has_live_children = true;
+
/*
* Accumulate size information from each live child.
*/
- if (childrel->rows > 0)
+ Assert(childrel->rows > 0);
+
+ parent_rows += childrel->rows;
+ parent_size += childrel->width * childrel->rows;
+
+ /*
+ * Accumulate per-column estimates too. We need not do anything for
+ * PlaceHolderVars in the parent list. If child expression isn't a
+ * Var, or we didn't record a width estimate for it, we have to fall
+ * back on a datatype-based estimate.
+ *
+ * By construction, child's reltargetlist is 1-to-1 with parent's.
+ */
+ forboth(parentvars, rel->reltargetlist,
+ childvars, childrel->reltargetlist)
{
- parent_rows += childrel->rows;
- parent_size += childrel->width * childrel->rows;
+ Var *parentvar = (Var *) lfirst(parentvars);
+ Node *childvar = (Node *) lfirst(childvars);
- /*
- * Accumulate per-column estimates too. We need not do anything
- * for PlaceHolderVars in the parent list. If child expression
- * isn't a Var, or we didn't record a width estimate for it, we
- * have to fall back on a datatype-based estimate.
- *
- * By construction, child's reltargetlist is 1-to-1 with parent's.
- */
- forboth(parentvars, rel->reltargetlist,
- childvars, childrel->reltargetlist)
+ if (IsA(parentvar, Var))
{
- Var *parentvar = (Var *) lfirst(parentvars);
- Node *childvar = (Node *) lfirst(childvars);
+ int pndx = parentvar->varattno - rel->min_attr;
+ int32 child_width = 0;
- if (IsA(parentvar, Var))
+ if (IsA(childvar, Var) &&
+ ((Var *) childvar)->varno == childrel->relid)
{
- int pndx = parentvar->varattno - rel->min_attr;
- int32 child_width = 0;
+ int cndx = ((Var *) childvar)->varattno - childrel->min_attr;
- if (IsA(childvar, Var) &&
- ((Var *) childvar)->varno == childrel->relid)
- {
- int cndx = ((Var *) childvar)->varattno - childrel->min_attr;
-
- child_width = childrel->attr_widths[cndx];
- }
- if (child_width <= 0)
- child_width = get_typavgwidth(exprType(childvar),
- exprTypmod(childvar));
- Assert(child_width > 0);
- parent_attrsizes[pndx] += child_width * childrel->rows;
+ child_width = childrel->attr_widths[cndx];
}
+ if (child_width <= 0)
+ child_width = get_typavgwidth(exprType(childvar),
+ exprTypmod(childvar));
+ Assert(child_width > 0);
+ parent_attrsizes[pndx] += child_width * childrel->rows;
}
}
}
- /*
- * Save the finished size estimates.
- */
- rel->rows = parent_rows;
- if (parent_rows > 0)
+ if (has_live_children)
{
+ /*
+ * Save the finished size estimates.
+ */
int i;
+ Assert(parent_rows > 0);
+ rel->rows = parent_rows;
rel->width = rint(parent_size / parent_rows);
for (i = 0; i < nattrs; i++)
rel->attr_widths[i] = rint(parent_attrsizes[i] / parent_rows);
+
+ /*
+ * Set "raw tuples" count equal to "rows" for the appendrel; needed
+ * because some places assume rel->tuples is valid for any baserel.
+ */
+ rel->tuples = parent_rows;
}
else
- rel->width = 0; /* attr_widths should be zero already */
-
- /*
- * Set "raw tuples" count equal to "rows" for the appendrel; needed
- * because some places assume rel->tuples is valid for any baserel.
- */
- rel->tuples = parent_rows;
+ {
+ /*
+ * All children were excluded by constraints, so mark the whole
+ * appendrel dummy. We must do this in this phase so that the rel's
+ * dummy-ness is visible when we generate paths for other rels.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
pfree(parent_attrsizes);
}
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 139f7e04987..96ec997ed16 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -2165,6 +2165,26 @@ select count(*) from tenk1 x where
rollback;
--
+-- regression test: be sure we cope with proven-dummy append rels
+--
+explain (costs off)
+select aa, bb, unique1, unique1
+ from tenk1 right join b on aa = unique1
+ where bb < bb and bb is null;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
+select aa, bb, unique1, unique1
+ from tenk1 right join b on aa = unique1
+ where bb < bb and bb is null;
+ aa | bb | unique1 | unique1
+----+----+---------+---------
+(0 rows)
+
+--
-- Clean up
--
DROP TABLE t1;
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 5b65ea8c922..ada78db2644 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -353,6 +353,17 @@ select count(*) from tenk1 x where
x.unique1 in (select aa.f1 from int4_tbl aa,float8_tbl bb where aa.f1=bb.f1);
rollback;
+--
+-- regression test: be sure we cope with proven-dummy append rels
+--
+explain (costs off)
+select aa, bb, unique1, unique1
+ from tenk1 right join b on aa = unique1
+ where bb < bb and bb is null;
+
+select aa, bb, unique1, unique1
+ from tenk1 right join b on aa = unique1
+ where bb < bb and bb is null;
--
-- Clean up
@@ -1120,6 +1131,7 @@ select atts.relid::regclass, s.* from pg_stats s join
a.attrelid::regclass::text join (select unnest(indkey) attnum,
indexrelid from pg_index i) atts on atts.attnum = a.attnum where
schemaname != 'pg_catalog';
+
--
-- Test LATERAL
--