Skip to content

Commit 5b14e44

Browse files
committed
Use strict cast in try_cast_to to error on overflow instead of silent NULL
1 parent 7b37778 commit 5b14e44

1 file changed

Lines changed: 81 additions & 4 deletions

File tree

datafusion-federation/src/schema_cast/record_convert.rs

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use datafusion::arrow::{
22
array::{Array, RecordBatch, RecordBatchOptions},
3-
compute::cast,
3+
compute::{cast_with_options, CastOptions},
44
datatypes::{DataType, IntervalUnit, SchemaRef},
55
};
66
use std::sync::Arc;
@@ -153,8 +153,18 @@ pub fn try_cast_to(record_batch: RecordBatch, expected_schema: SchemaRef) -> Res
153153
DataType::Interval(IntervalUnit::DayTime),
154154
) => cast_interval_monthdaynano_to_daytime(&Arc::clone(record_batch_col))
155155
.map_err(make_err),
156-
_ => cast(&Arc::clone(record_batch_col), expected_field.data_type())
157-
.map_err(make_err),
156+
_ => {
157+
let options = CastOptions {
158+
safe: false,
159+
..CastOptions::default()
160+
};
161+
cast_with_options(
162+
&Arc::clone(record_batch_col),
163+
expected_field.data_type(),
164+
&options,
165+
)
166+
.map_err(make_err)
167+
}
158168
}
159169
})
160170
.collect::<Result<Vec<Arc<dyn Array>>>>()
@@ -182,7 +192,7 @@ pub fn try_cast_to(record_batch: RecordBatch, expected_schema: SchemaRef) -> Res
182192
#[cfg(test)]
183193
mod test {
184194
use super::*;
185-
use datafusion::arrow::array::{LargeStringArray, RecordBatchOptions};
195+
use datafusion::arrow::array::{Decimal128Array, LargeStringArray, RecordBatchOptions};
186196
use datafusion::arrow::{
187197
array::{Int32Array, StringArray},
188198
datatypes::{DataType, Field, Schema, TimeUnit},
@@ -295,4 +305,71 @@ mod test {
295305
let expected = ["++", "++", "++"];
296306
assert_batches_eq!(expected, &[result]);
297307
}
308+
309+
/// Casting Decimal128(38,9) → Decimal128(38,27) must return an error when
310+
/// the upscale would overflow, instead of silently producing NULL.
311+
#[test]
312+
fn test_try_cast_to_decimal_overflow_returns_error() {
313+
// Value with 12 integer digits: 110_367_043_872.497010000
314+
// Internal i128 at scale 9 = 110367043872497010000
315+
let value_i128: i128 = 110_367_043_872_497_010_000;
316+
317+
let source_schema = Arc::new(Schema::new(vec![Field::new(
318+
"sum_charge",
319+
DataType::Decimal128(38, 9),
320+
true,
321+
)]));
322+
323+
let source_array = Decimal128Array::from(vec![Some(value_i128)])
324+
.with_precision_and_scale(38, 9)
325+
.expect("valid Decimal128(38,9)");
326+
327+
let batch =
328+
RecordBatch::try_new(source_schema, vec![Arc::new(source_array)]).expect("valid batch");
329+
330+
// Target schema with wider scale (38,27) — only allows 11 integer digits
331+
let target_schema = Arc::new(Schema::new(vec![Field::new(
332+
"sum_charge",
333+
DataType::Decimal128(38, 27),
334+
true,
335+
)]));
336+
337+
let result = try_cast_to(batch, target_schema);
338+
assert!(
339+
result.is_err(),
340+
"Decimal overflow should return an error, not silently produce NULL"
341+
);
342+
}
343+
344+
/// Casting Decimal128 with values that fit should succeed.
345+
#[test]
346+
fn test_try_cast_to_decimal_no_overflow_succeeds() {
347+
// Value with 11 integer digits: 99_999_999_999.000000000 (fits in 38-27=11 digits)
348+
let value_i128: i128 = 99_999_999_999_000_000_000;
349+
350+
let source_schema = Arc::new(Schema::new(vec![Field::new(
351+
"amount",
352+
DataType::Decimal128(38, 9),
353+
true,
354+
)]));
355+
356+
let source_array = Decimal128Array::from(vec![Some(value_i128)])
357+
.with_precision_and_scale(38, 9)
358+
.expect("valid Decimal128(38,9)");
359+
360+
let batch =
361+
RecordBatch::try_new(source_schema, vec![Arc::new(source_array)]).expect("valid batch");
362+
363+
let target_schema = Arc::new(Schema::new(vec![Field::new(
364+
"amount",
365+
DataType::Decimal128(38, 27),
366+
true,
367+
)]));
368+
369+
let result = try_cast_to(batch, target_schema);
370+
assert!(
371+
result.is_ok(),
372+
"Decimal cast should succeed when value fits: {result:?}"
373+
);
374+
}
298375
}

0 commit comments

Comments
 (0)