Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions crates/iceberg/src/spec/values/datum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub(crate) const INT_MAX: i32 = 2147483647;
pub(crate) const INT_MIN: i32 = -2147483648;
pub(crate) const LONG_MAX: i64 = 9223372036854775807;
pub(crate) const LONG_MIN: i64 = -9223372036854775808;
pub(crate) const FLOAT_MAX: f32 = 3.4028235e38;
pub(crate) const FLOAT_MIN: f32 = -3.4028235e38;
Comment on lines +51 to +52
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why not

Suggested change
pub(crate) const FLOAT_MAX: f32 = 3.4028235e38;
pub(crate) const FLOAT_MIN: f32 = -3.4028235e38;
pub(crate) const FLOAT_MAX: f64 = f32::MAX as f64;
pub(crate) const FLOAT_MIN: f64 = f32::MIN as f64;

?
Less chance of error + already casted to required type (may remove in-code casts in that case).


/// Literal associated with its type. The value and type pair is checked when construction, so the type and value is
/// guaranteed to be correct when used.
Expand Down Expand Up @@ -1109,6 +1111,16 @@ impl Datum {
})
}

fn double_to_float<T: Into<f64> + PartialOrd<f64>>(val: T) -> Datum {
if val > FLOAT_MAX as f64 {
Datum::new(PrimitiveType::Float, PrimitiveLiteral::AboveMax)
} else if val < FLOAT_MIN as f64 {
Datum::new(PrimitiveType::Float, PrimitiveLiteral::BelowMin)
} else {
Datum::float(val.into() as f32)
}
}

/// Convert the datum to `target_type`.
pub fn to(self, target_type: &Type) -> Result<Datum> {
match target_type {
Expand Down Expand Up @@ -1146,6 +1158,9 @@ impl Datum {
(PrimitiveLiteral::String(val), _, PrimitiveType::Timestamptz) => {
Datum::timestamptz_from_str(val)
}
(PrimitiveLiteral::Double(val), _, PrimitiveType::Float) => {
Ok(Datum::double_to_float(**val))
}

// TODO: implement more type conversions
(_, self_type, target_type) if self_type == target_type => Ok(self),
Expand Down
36 changes: 36 additions & 0 deletions crates/iceberg/src/spec/values/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1352,3 +1352,39 @@ fn test_date_from_json_as_number() {

// Both formats should produce the same Literal value
}

#[test]
fn test_iceberg_double_convert_to_float() {
let float_below_min = Datum::new(PrimitiveType::Float, PrimitiveLiteral::BelowMin);
let float_above_max = Datum::new(PrimitiveType::Float, PrimitiveLiteral::AboveMax);

let test_data = [
(Datum::double(-f64::NAN), Datum::float(-f32::NAN)),
(Datum::double(-f64::INFINITY), float_below_min.clone()),
(Datum::double(f64::MIN), float_below_min),
(Datum::double(f32::MIN as f64), Datum::float(f32::MIN)),
(Datum::double(-1.0), Datum::float(-1.0)),
(Datum::double(-f64::MIN_POSITIVE), Datum::float(-0.0)),
(
Datum::double(-f32::MIN_POSITIVE as f64),
Datum::float(-f32::MIN_POSITIVE),
),
(Datum::double(-0.0), Datum::float(-0.0)),
(Datum::double(0.0), Datum::float(0.0)),
(Datum::double(f64::MIN_POSITIVE), Datum::float(0.0)),
(
Datum::double(f32::MIN_POSITIVE as f64),
Datum::float(f32::MIN_POSITIVE),
),
(Datum::double(1.0), Datum::float(1.0)),
(Datum::double(f32::MAX as f64), Datum::float(f32::MAX)),
(Datum::double(f64::MAX), float_above_max.clone()),
(Datum::double(f64::INFINITY), float_above_max),
(Datum::double(f64::NAN), Datum::float(f32::NAN)),
];

for (datum, expected) in test_data {
let result = datum.to(&Primitive(PrimitiveType::Float)).unwrap();
assert_eq!(result, expected);
}
}
Loading