diff options
Diffstat (limited to 'src/backend/optimizer/path/costsize.c')
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 5227346aeb1..22635d29270 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -219,6 +219,35 @@ clamp_row_est(double nrows) } /* + * clamp_width_est + * Force a tuple-width estimate to a sane value. + * + * The planner represents datatype width and tuple width estimates as int32. + * When summing column width estimates to create a tuple width estimate, + * it's possible to reach integer overflow in edge cases. To ensure sane + * behavior, we form such sums in int64 arithmetic and then apply this routine + * to clamp to int32 range. + */ +int32 +clamp_width_est(int64 tuple_width) +{ + /* + * Anything more than MaxAllocSize is clearly bogus, since we could not + * create a tuple that large. + */ + if (tuple_width > MaxAllocSize) + return (int32) MaxAllocSize; + + /* + * Unlike clamp_row_est, we just Assert that the value isn't negative, + * rather than masking such errors. + */ + Assert(tuple_width >= 0); + + return (int32) tuple_width; +} + +/* * clamp_cardinality_to_long * Cast a Cardinality value to a sane long value. */ @@ -6101,7 +6130,7 @@ static void set_rel_width(PlannerInfo *root, RelOptInfo *rel) { Oid reloid = planner_rt_fetch(rel->relid, root)->relid; - int32 tuple_width = 0; + int64 tuple_width = 0; bool have_wholerow_var = false; ListCell *lc; @@ -6213,7 +6242,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) */ if (have_wholerow_var) { - int32 wholerow_width = MAXALIGN(SizeofHeapTupleHeader); + int64 wholerow_width = MAXALIGN(SizeofHeapTupleHeader); if (reloid != InvalidOid) { @@ -6230,7 +6259,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) wholerow_width += rel->attr_widths[i - rel->min_attr]; } - rel->attr_widths[0 - rel->min_attr] = wholerow_width; + rel->attr_widths[0 - rel->min_attr] = clamp_width_est(wholerow_width); /* * Include the whole-row Var as part of the output tuple. Yes, that @@ -6239,8 +6268,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) tuple_width += wholerow_width; } - Assert(tuple_width >= 0); - rel->reltarget->width = tuple_width; + rel->reltarget->width = clamp_width_est(tuple_width); } /* @@ -6258,7 +6286,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target) { - int32 tuple_width = 0; + int64 tuple_width = 0; ListCell *lc; /* Vars are assumed to have cost zero, but other exprs do not */ @@ -6282,8 +6310,7 @@ set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target) } } - Assert(tuple_width >= 0); - target->width = tuple_width; + target->width = clamp_width_est(tuple_width); return target; } |