diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 9f572d759b7..b86fc5ed67a 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -45,9 +45,10 @@ * (total_cost - startup_cost) * tuples_to_fetch / path->rows; * Note that a base relation's rows count (and, by extension, plan_rows for * plan nodes below the LIMIT node) are set without regard to any LIMIT, so - * that this equation works properly. (Also, these routines guarantee not to - * set the rows count to zero, so there will be no zero divide.) The LIMIT is - * applied as a top-level plan node. + * that this equation works properly. (Note: while path->rows is never zero + * for ordinary relations, it is zero for paths for provably-empty relations, + * so beware of division-by-zero.) The LIMIT is applied as a top-level + * plan node. * * For largely historical reasons, most of the routines in this module use * the passed result Path only to store their results (rows, startup_cost and @@ -1991,6 +1992,12 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path, QualCost restrict_qual_cost; double ntuples; + /* Protect some assumptions below that rowcounts aren't zero or NaN */ + if (outer_path_rows <= 0 || isnan(outer_path_rows)) + outer_path_rows = 1; + if (inner_path_rows <= 0 || isnan(inner_path_rows)) + inner_path_rows = 1; + /* Mark the path with the correct row estimate */ if (path->path.param_info) path->path.rows = path->path.param_info->ppi_rows; @@ -3025,8 +3032,8 @@ cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan) if (subplan->subLinkType == EXISTS_SUBLINK) { - /* we only need to fetch 1 tuple */ - sp_cost.per_tuple += plan_run_cost / plan->plan_rows; + /* we only need to fetch 1 tuple; clamp to avoid zero divide */ + sp_cost.per_tuple += plan_run_cost / clamp_row_est(plan->plan_rows); } else if (subplan->subLinkType == ALL_SUBLINK || subplan->subLinkType == ANY_SUBLINK) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index db347b85c35..86d80727ed9 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -3346,12 +3346,10 @@ create_grouping_paths(PlannerInfo *root, } /* - * Estimate number of groups. Note: if cheapest_path is a dummy, it will - * have zero rowcount estimate, which we don't want to use for fear of - * divide-by-zero. Hence clamp. + * Estimate number of groups. */ dNumGroups = get_number_of_groups(root, - clamp_row_est(cheapest_path->rows), + cheapest_path->rows, rollup_lists, rollup_groupclauses); @@ -3415,7 +3413,7 @@ create_grouping_paths(PlannerInfo *root, /* Estimate number of partial groups. */ dNumPartialGroups = get_number_of_groups(root, - clamp_row_est(cheapest_partial_path->rows), + cheapest_partial_path->rows, NIL, NIL); @@ -4840,8 +4838,8 @@ get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction) if (tuple_fraction <= 0.0) return best_path; - /* Convert absolute # of tuples to a fraction; no need to clamp */ - if (tuple_fraction >= 1.0) + /* Convert absolute # of tuples to a fraction; no need to clamp to 0..1 */ + if (tuple_fraction >= 1.0 && best_path->rows > 0) tuple_fraction /= best_path->rows; foreach(l, rel->pathlist)