Skip to content

fix: handle out of range errors in DATE_BIN instead of panicking - #20221

Merged
alamb merged 4 commits into
apache:mainfrom
mishop-15:fix-date-bin-panic
Feb 24, 2026
Merged

alamb merged 4 commits into
apache:mainfrom
mishop-15:fix-date-bin-panic

Conversation

@mishop-15

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Closes #20219

Rationale for this change

The DATE_BIN function was panicking when datetime operations went out of range instead of returning proper errors. The two specific cases were:

  1. Month subtraction going out of range causing DateTime - Months panic
  2. timestamp_nanos_opt() returning None and then unwrapping

What changes are included in this PR?

  • Changed date_bin_months_interval and to_utc_date_time to return Result instead of panicking
  • Replaced origin_date - Months and origin_date + Months with checked_sub_months and checked_add_months
  • Replaced .unwrap() calls with proper match statements and error handling
  • Updated all callers throughout the file to handle Result types

Are these changes tested?

Tested manually with the exact queries from the issue that were panicking:

select DATE_BIN('1637426858', TO_TIMESTAMP_MILLIS(1040292460), TIMESTAMP '1984-01-07 00:00:00');
select DATE_BIN('1637426858', TO_TIMESTAMP_MILLIS(-1040292460), TIMESTAMP '1984-01-07 00:00:00');

Both queries now return NULL instead of panicking. All existing unit tests pass.

Are there any user-facing changes?

Yes - queries with DATE_BIN that would previously panic now return NULL when datetime operations go out of range.

@github-actions github-actions Bot added the functions Changes to functions implementation label Feb 8, 2026

@neilconway neilconway left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking at this! Can we add some test cases?

@mishop-15

Copy link
Copy Markdown
Contributor Author

Thanks for looking at this! Can we add some test cases?

Added test cases for both out-of-range scenarios in the latest commit.

stride: i64,
stride_fn: fn(i64, i64, i64) -> i64,
) -> impl Fn(i64) -> i64 {
stride_fn: fn(i64, i64, i64) -> Result<i64>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Use BinFunction here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use BinFunction alias. Thanks for the review.

@mishop-15

Copy link
Copy Markdown
Contributor Author

@alamb @avantgardnerio When you get a chance, could you take a look at this PR? All feedback has been addressed, checks are passing, and it's ready for merge. Thanks!

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mishop-15

Can you please add some .slt tests that show the problem? I think that will be less verbose than using unit tests and will make sure everything is hooked up correctly

While adding .slt tests, can you also please include a few other tests such as

select date_bin(interval '1 month', to_timestamp_millis(-1040292460), timestamp '1984-01-07 00:00:00');

-- large strides to force overflows
  select date_bin(
    interval '1637426858 months',
    timestamp '1969-12-31 00:00:00',
    timestamp '1984-01-07 00:00:00'
  );

  select date_bin(
    interval '1637426858 months',
    to_timestamp_millis(-1040292000),
    timestamp '1984-01-07 00:00:00'
  ) as b;

  select date_bin(
    interval '1637426858 months',
    to_timestamp_millis(-2208988800000), -- 1900-01-01
    timestamp '1984-01-07 00:00:00'
  ) as b;

let array: PrimitiveArray<Time64MicrosecondType> =
array.unary(apply_stride_fn);
ColumnarValue::Array(Arc::new(array))
let result: PrimitiveArray<Time64MicrosecondType> = array

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using try_unary? https://docs.rs/arrow/latest/arrow/array/struct.PrimitiveArray.html#method.try_unary

I think that will result in a smaller diff and be faster as well

The same comment applies to the other methods in this function

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to try_unary, thanks for pointing that out!

const NANOS_PER_MILLI: i64 = 1_000_000;
const NANOS_PER_SEC: i64 = NANOSECONDS;

type BinFunction = fn(i64, i64, i64) -> Result<i64>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add comments here aout what BinFunction is and what it represents (e.g. what are the aguments and what does it return)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments explaining the arguments and return value.

@github-actions github-actions Bot added the sqllogictest SQL Logic Tests (.slt) label Feb 13, 2026

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. @mhilton would you perhaps have some time to review this PR?

@mhilton mhilton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@alamb
alamb added this pull request to the merge queue Feb 24, 2026
@alamb

alamb commented Feb 24, 2026

Copy link
Copy Markdown
Contributor

Thank you @mishop-15 and @mhilton and @neilconway

Merged via the queue into apache:main with commit 17d770d Feb 24, 2026
28 checks passed
de-bgunter pushed a commit to de-bgunter/datafusion that referenced this pull request Mar 24, 2026
…che#20221)

## Which issue does this PR close?

Closes apache#20219

## Rationale for this change

The DATE_BIN function was panicking when datetime operations went out of
range instead of returning proper errors. The two specific cases were:
1. Month subtraction going out of range causing `DateTime - Months`
panic
2. `timestamp_nanos_opt()` returning None and then unwrapping

## What changes are included in this PR?

- Changed `date_bin_months_interval` and `to_utc_date_time` to return
`Result` instead of panicking
- Replaced `origin_date - Months` and `origin_date + Months` with
`checked_sub_months` and `checked_add_months`
- Replaced `.unwrap()` calls with proper `match` statements and error
handling
- Updated all callers throughout the file to handle `Result` types

## Are these changes tested?

Tested manually with the exact queries from the issue that were
panicking:
```sql
select DATE_BIN('1637426858', TO_TIMESTAMP_MILLIS(1040292460), TIMESTAMP '1984-01-07 00:00:00');
select DATE_BIN('1637426858', TO_TIMESTAMP_MILLIS(-1040292460), TIMESTAMP '1984-01-07 00:00:00');
```

Both queries now return NULL instead of panicking. All existing unit
tests pass.

## Are there any user-facing changes?

Yes - queries with DATE_BIN that would previously panic now return NULL
when datetime operations go out of range.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

functions Changes to functions implementation sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

date_bin() panics on large inputs

4 participants