Skip to content

Commit 9afd01b

Browse files
committed
fix(date_bin): use checked_rem to handle i64::MIN % -1 overflow
1 parent 7e5c137 commit 9afd01b

1 file changed

Lines changed: 18 additions & 1 deletion

File tree

‎datafusion/functions/src/datetime/date_bin.rs‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,11 @@ fn date_bin_nanos_interval(stride_nanos: i64, source: i64, origin: i64) -> Resul
340340

341341
// distance from origin to bin
342342
fn compute_distance(time_diff: i64, stride: i64) -> Result<i64> {
343-
let remainder = time_diff % stride;
343+
let remainder = time_diff.checked_rem(stride).ok_or_else(|| {
344+
arrow::error::ArrowError::InvalidArgumentError(format!(
345+
"date_bin compute_distance time_diff {time_diff} % stride {stride} overflows i64"
346+
))
347+
})?;
344348
let time_delta = time_diff.checked_sub(remainder).ok_or_else(|| {
345349
arrow::error::ArrowError::InvalidArgumentError(format!(
346350
"date_bin compute_distance time_diff {time_diff} - remainder {remainder} overflows i64"
@@ -1391,4 +1395,17 @@ mod tests {
13911395
panic!("Expected TimestampNanosecond scalar");
13921396
}
13931397
}
1398+
1399+
#[test]
1400+
fn test_date_bin_compute_distance_rem_overflow() {
1401+
// Regression for #22215: `time_diff % stride` panics with "attempt to
1402+
// calculate the remainder with overflow" when `time_diff == i64::MIN`
1403+
// and `stride == -1`. Now it must return a normal Err that the scalar
1404+
// pipeline maps to NULL.
1405+
let result = date_bin_nanos_interval(-1, i64::MIN, 0);
1406+
assert!(
1407+
result.is_err(),
1408+
"expected Err for time_diff=i64::MIN, stride=-1, got {result:?}"
1409+
);
1410+
}
13941411
}

0 commit comments

Comments
 (0)