This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new ed5f8e7f01 Precision::<usize>::{add, sub, multiply}: avoid overflows
(#17929)
ed5f8e7f01 is described below
commit ed5f8e7f016a250c2fe5f008a87a5fb66c5ca96d
Author: Thomas Tanon <[email protected]>
AuthorDate: Tue Oct 7 21:26:51 2025 +0200
Precision::<usize>::{add, sub, multiply}: avoid overflows (#17929)
Use saturating operations
Note this is not consistent with Precision::<ScalarValue> that wraps, happy
to change behavior to wrapping here too
---
datafusion/common/src/stats.rs | 49 ++++++++++++++++++++++++++++++++++++------
1 file changed, 43 insertions(+), 6 deletions(-)
diff --git a/datafusion/common/src/stats.rs b/datafusion/common/src/stats.rs
index f54fa55aec..2481a88676 100644
--- a/datafusion/common/src/stats.rs
+++ b/datafusion/common/src/stats.rs
@@ -120,10 +120,15 @@ impl Precision<usize> {
/// values is [`Precision::Absent`], the result is `Absent` too.
pub fn add(&self, other: &Precision<usize>) -> Precision<usize> {
match (self, other) {
- (Precision::Exact(a), Precision::Exact(b)) => Precision::Exact(a +
b),
+ (Precision::Exact(a), Precision::Exact(b)) =>
a.checked_add(*b).map_or_else(
+ || Precision::Inexact(a.saturating_add(*b)),
+ Precision::Exact,
+ ),
(Precision::Inexact(a), Precision::Exact(b))
| (Precision::Exact(a), Precision::Inexact(b))
- | (Precision::Inexact(a), Precision::Inexact(b)) =>
Precision::Inexact(a + b),
+ | (Precision::Inexact(a), Precision::Inexact(b)) => {
+ Precision::Inexact(a.saturating_add(*b))
+ }
(_, _) => Precision::Absent,
}
}
@@ -133,10 +138,15 @@ impl Precision<usize> {
/// values is [`Precision::Absent`], the result is `Absent` too.
pub fn sub(&self, other: &Precision<usize>) -> Precision<usize> {
match (self, other) {
- (Precision::Exact(a), Precision::Exact(b)) => Precision::Exact(a -
b),
+ (Precision::Exact(a), Precision::Exact(b)) =>
a.checked_sub(*b).map_or_else(
+ || Precision::Inexact(a.saturating_sub(*b)),
+ Precision::Exact,
+ ),
(Precision::Inexact(a), Precision::Exact(b))
| (Precision::Exact(a), Precision::Inexact(b))
- | (Precision::Inexact(a), Precision::Inexact(b)) =>
Precision::Inexact(a - b),
+ | (Precision::Inexact(a), Precision::Inexact(b)) => {
+ Precision::Inexact(a.saturating_sub(*b))
+ }
(_, _) => Precision::Absent,
}
}
@@ -146,10 +156,15 @@ impl Precision<usize> {
/// values is [`Precision::Absent`], the result is `Absent` too.
pub fn multiply(&self, other: &Precision<usize>) -> Precision<usize> {
match (self, other) {
- (Precision::Exact(a), Precision::Exact(b)) => Precision::Exact(a *
b),
+ (Precision::Exact(a), Precision::Exact(b)) =>
a.checked_mul(*b).map_or_else(
+ || Precision::Inexact(a.saturating_mul(*b)),
+ Precision::Exact,
+ ),
(Precision::Inexact(a), Precision::Exact(b))
| (Precision::Exact(a), Precision::Inexact(b))
- | (Precision::Inexact(a), Precision::Inexact(b)) =>
Precision::Inexact(a * b),
+ | (Precision::Inexact(a), Precision::Inexact(b)) => {
+ Precision::Inexact(a.saturating_mul(*b))
+ }
(_, _) => Precision::Absent,
}
}
@@ -807,11 +822,21 @@ mod tests {
let precision2 = Precision::Inexact(23);
let precision3 = Precision::Exact(30);
let absent_precision = Precision::Absent;
+ let precision_max_exact = Precision::Exact(usize::MAX);
+ let precision_max_inexact = Precision::Exact(usize::MAX);
assert_eq!(precision1.add(&precision2), Precision::Inexact(65));
assert_eq!(precision1.add(&precision3), Precision::Exact(72));
assert_eq!(precision2.add(&precision3), Precision::Inexact(53));
assert_eq!(precision1.add(&absent_precision), Precision::Absent);
+ assert_eq!(
+ precision_max_exact.add(&precision1),
+ Precision::Inexact(usize::MAX)
+ );
+ assert_eq!(
+ precision_max_inexact.add(&precision1),
+ Precision::Inexact(usize::MAX)
+ );
}
#[test]
@@ -843,6 +868,8 @@ mod tests {
assert_eq!(precision1.sub(&precision2), Precision::Inexact(19));
assert_eq!(precision1.sub(&precision3), Precision::Exact(12));
+ assert_eq!(precision2.sub(&precision1), Precision::Inexact(0));
+ assert_eq!(precision3.sub(&precision1), Precision::Inexact(0));
assert_eq!(precision1.sub(&absent_precision), Precision::Absent);
}
@@ -871,12 +898,22 @@ mod tests {
let precision1 = Precision::Exact(6);
let precision2 = Precision::Inexact(3);
let precision3 = Precision::Exact(5);
+ let precision_max_exact = Precision::Exact(usize::MAX);
+ let precision_max_inexact = Precision::Exact(usize::MAX);
let absent_precision = Precision::Absent;
assert_eq!(precision1.multiply(&precision2), Precision::Inexact(18));
assert_eq!(precision1.multiply(&precision3), Precision::Exact(30));
assert_eq!(precision2.multiply(&precision3), Precision::Inexact(15));
assert_eq!(precision1.multiply(&absent_precision), Precision::Absent);
+ assert_eq!(
+ precision_max_exact.multiply(&precision1),
+ Precision::Inexact(usize::MAX)
+ );
+ assert_eq!(
+ precision_max_inexact.multiply(&precision1),
+ Precision::Inexact(usize::MAX)
+ );
}
#[test]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]