Skip to content

Commit

Permalink
Return null for overflow when casting string to integer under safe op…
Browse files Browse the repository at this point in the history
…tion enabled (#5398)

* Return null for overflow when casting string to integer

* Use atoi_simd

* Use atoi

* Return to str.parse.

* Revert "Return to str.parse."

This reverts commit 53dd047.

* Check trailing string
  • Loading branch information
viirya authored Feb 15, 2024
1 parent a88d70d commit eb4be68
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 1 deletion.
1 change: 1 addition & 0 deletions arrow-cast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ chrono = { workspace = true }
half = { version = "2.1", default-features = false }
num = { version = "0.4", default-features = false, features = ["std"] }
lexical-core = { version = "^0.8", default-features = false, features = ["write-integers", "write-floats", "parse-integers", "parse-floats"] }
atoi = "2.0.0"
comfy-table = { version = "7.0", optional = true, default-features = false }
base64 = "0.21"

Expand Down
19 changes: 19 additions & 0 deletions arrow-cast/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4911,6 +4911,25 @@ mod tests {
assert!(c.is_null(2));
}

#[test]
fn test_cast_string_to_integral_overflow() {
let str = Arc::new(StringArray::from(vec![
Some("123"),
Some("-123"),
Some("86374"),
None,
])) as ArrayRef;

let options = CastOptions {
safe: true,
format_options: FormatOptions::default(),
};
let res = cast_with_options(&str, &DataType::Int16, &options).expect("should cast to i16");
let expected =
Arc::new(Int16Array::from(vec![Some(123), Some(-123), None, None])) as ArrayRef;
assert_eq!(&res, &expected);
}

#[test]
fn test_cast_string_to_timestamp() {
let a1 = Arc::new(StringArray::from(vec![
Expand Down
7 changes: 6 additions & 1 deletion arrow-cast/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,12 @@ macro_rules! parser_primitive {
($t:ty) => {
impl Parser for $t {
fn parse(string: &str) -> Option<Self::Native> {
lexical_core::parse::<Self::Native>(string.as_bytes()).ok()
match atoi::FromRadix10SignedChecked::from_radix_10_signed_checked(
string.as_bytes(),
) {
(Some(n), x) if x == string.len() => Some(n),
_ => None,
}
}
}
};
Expand Down

0 comments on commit eb4be68

Please sign in to comment.