summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
authorTom Lane2023-12-19 16:12:16 +0000
committerTom Lane2023-12-19 16:12:16 +0000
commit7e1ce2b3de16dfbe1598cef060dfc8458522938a (patch)
treea0a5fe0eda7b6791d808f16ded3ae0b1af1175c8 /src/backend/optimizer/util
parent2a607fb822a2ad8f3a2cc714871283ad8cdf71c4 (diff)
Prevent integer overflow when forming tuple width estimates.
It's at least theoretically possible to overflow int32 when adding up column width estimates to make a row width estimate. (The bug example isn't terribly convincing as a real use-case, but perhaps wide joins would provide a more plausible route to trouble.) This'd lead to assertion failures or silly planner behavior. To forestall it, make the relevant functions compute their running sums in int64 arithmetic and then clamp to int32 range at the end. We can reasonably assume that MaxAllocSize is a hard limit on actual tuple width, so clamping to that is simply a correction for dubious input values, and there's no need to go as far as widening width variables to int64 everywhere. Per bug #18247 from RekGRpth. There've been no reports of this issue arising in practical cases, so I feel no need to back-patch. Richard Guo and Tom Lane Discussion: https://postgr.es/m/[email protected]
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/placeholder.c5
-rw-r--r--src/backend/optimizer/util/plancat.c4
-rw-r--r--src/backend/optimizer/util/relnode.c10
3 files changed, 13 insertions, 6 deletions
diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c
index b1723578e6f..66b5e2b1e76 100644
--- a/src/backend/optimizer/util/placeholder.c
+++ b/src/backend/optimizer/util/placeholder.c
@@ -375,6 +375,7 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
SpecialJoinInfo *sjinfo)
{
Relids relids = joinrel->relids;
+ int64 tuple_width = joinrel->reltarget->width;
ListCell *lc;
foreach(lc, root->placeholder_list)
@@ -419,7 +420,7 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
cost_qual_eval_node(&cost, (Node *) phv->phexpr, root);
joinrel->reltarget->cost.startup += cost.startup;
joinrel->reltarget->cost.per_tuple += cost.per_tuple;
- joinrel->reltarget->width += phinfo->ph_width;
+ tuple_width += phinfo->ph_width;
}
}
@@ -443,6 +444,8 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
phinfo->ph_lateral);
}
}
+
+ joinrel->reltarget->width = clamp_width_est(tuple_width);
}
/*
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 7159c775fbd..0e35b9d0ab9 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1137,7 +1137,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
int32
get_rel_data_width(Relation rel, int32 *attr_widths)
{
- int32 tuple_width = 0;
+ int64 tuple_width = 0;
int i;
for (i = 1; i <= RelationGetNumberOfAttributes(rel); i++)
@@ -1167,7 +1167,7 @@ get_rel_data_width(Relation rel, int32 *attr_widths)
tuple_width += item_width;
}
- return tuple_width;
+ return clamp_width_est(tuple_width);
}
/*
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 5d83f60eb9a..9dfeb4ffd4b 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -22,6 +22,7 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/inherit.h"
+#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/placeholder.h"
@@ -1092,6 +1093,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
bool can_null)
{
Relids relids = joinrel->relids;
+ int64 tuple_width = joinrel->reltarget->width;
ListCell *vars;
ListCell *lc;
@@ -1144,7 +1146,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
phv);
/* Bubbling up the precomputed result has cost zero */
- joinrel->reltarget->width += phinfo->ph_width;
+ tuple_width += phinfo->ph_width;
}
continue;
}
@@ -1165,7 +1167,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
list_nth(root->row_identity_vars, var->varattno - 1);
/* Update reltarget width estimate from RowIdentityVarInfo */
- joinrel->reltarget->width += ridinfo->rowidwidth;
+ tuple_width += ridinfo->rowidwidth;
}
else
{
@@ -1181,7 +1183,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
continue; /* nope, skip it */
/* Update reltarget width estimate from baserel's attr_widths */
- joinrel->reltarget->width += baserel->attr_widths[ndx];
+ tuple_width += baserel->attr_widths[ndx];
}
/*
@@ -1221,6 +1223,8 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
/* Vars have cost zero, so no need to adjust reltarget->cost */
}
+
+ joinrel->reltarget->width = clamp_width_est(tuple_width);
}
/*