Skip to main content

datafusion_expr_common/
casts.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Utilities for casting scalar literals to different data types
19//!
20//! This module contains functions for casting ScalarValue literals
21//! to different data types, originally extracted from the optimizer's
22//! unwrap_cast module to be shared between logical and physical layers.
23
24use std::cmp::Ordering;
25
26use arrow::datatypes::{
27    DataType, MAX_DECIMAL32_FOR_EACH_PRECISION, MAX_DECIMAL64_FOR_EACH_PRECISION,
28    MAX_DECIMAL128_FOR_EACH_PRECISION, MIN_DECIMAL32_FOR_EACH_PRECISION,
29    MIN_DECIMAL64_FOR_EACH_PRECISION, MIN_DECIMAL128_FOR_EACH_PRECISION, TimeUnit,
30};
31use arrow::temporal_conversions::{
32    MICROSECONDS, MILLISECONDS, MILLISECONDS_IN_DAY, NANOSECONDS,
33};
34use datafusion_common::ScalarValue;
35
36/// Convert a literal [`ScalarValue`] to `target_type`, preserving the exact value.
37///
38/// Returns `None` if the value cannot be represented in `target_type`
39/// *exactly*.
40///
41/// This is a restricted, value-preserving cast used to rewrite comparison
42/// predicates of the form `CAST(col AS target_type) <op> literal` into
43/// `col <op> try_cast_literal_to_type(literal, col_type)`. That rewrite is
44/// only valid when the cast cannot change the comparison result.
45///
46/// # Supported Casts
47/// * numeric → numeric, including integers, decimals, `Date32`/`Date64` and
48///   `Timestamp`s, rejecting values outside the target's range or that would
49///   lose decimal digits
50/// * string → string between `Utf8`, `LargeUtf8` and `Utf8View`
51/// * wrapping a value into, or unwrapping it out of, a `Dictionary` whose value
52///   type matches the literal's type
53/// * `Binary` → `FixedSizeBinary` of the matching length
54/// * `Timestamp` → `Timestamp` cast between different time units is allowed even
55///   though it can truncate (for example nanoseconds → seconds), and a unit
56///   conversion that overflows yields a `NULL` literal rather than `None`.
57///
58/// # See Also
59/// - [`ScalarValue::cast_to`]: a general-purpose cast that can lose information
60///   or change a value's meaning.
61pub fn try_cast_literal_to_type(
62    lit_value: &ScalarValue,
63    target_type: &DataType,
64) -> Option<ScalarValue> {
65    let lit_data_type = lit_value.data_type();
66    if !is_supported_type(&lit_data_type) || !is_supported_type(target_type) {
67        return None;
68    }
69    if lit_value.is_null() {
70        // null value can be cast to any type of null value
71        return ScalarValue::try_from(target_type).ok();
72    }
73    try_cast_numeric_literal(lit_value, target_type)
74        .or_else(|| try_cast_string_literal(lit_value, target_type))
75        .or_else(|| try_cast_dictionary(lit_value, target_type))
76        .or_else(|| try_cast_binary(lit_value, target_type))
77}
78
79/// Returns true if unwrap_cast_in_comparison supports this data type
80pub fn is_supported_type(data_type: &DataType) -> bool {
81    is_supported_numeric_type(data_type)
82        || is_supported_string_type(data_type)
83        || is_supported_dictionary_type(data_type)
84        || is_supported_binary_type(data_type)
85}
86
87fn is_date_type(data_type: &DataType) -> bool {
88    matches!(data_type, DataType::Date32 | DataType::Date64)
89}
90
91/// Returns true when unwrapping a date/timestamp cast could change comparison
92/// semantics.
93///
94/// A `Date` stores only a calendar day, while a `Timestamp` stores a specific
95/// instant or wall-clock time. `Timestamp -> Date` is lossy because it drops the
96/// time-of-day. `Date -> Timestamp` is also lossy in this optimizer context
97/// because there is no unique inverse: converting a date to a timestamp has to
98/// invent a time component such as midnight.
99///
100/// For example, `CAST(ts AS DATE) = DATE '2024-01-01'` means "any timestamp
101/// during that day", but unwrapping it to `ts = TIMESTAMP '2024-01-01
102/// 00:00:00'` matches only midnight.
103///
104/// An identity cast (`from_type == to_type`, e.g. `Date32 -> Date32`) never
105/// changes comparison semantics and is therefore not lossy.
106///
107/// A cast between the two date types (`Date32` <-> `Date64`) is not pre-filtered
108/// as lossy here, because whether it loses information is a per-value question
109/// rather than a per-type one. `Date32` -> `Date64` is always exact (a day scaled
110/// to midnight in milliseconds). `Date64` -> `Date32` is exact only when the value
111/// lands on a day boundary: Arrow nominally defines `Date64` as whole days encoded
112/// in milliseconds, but arrow-rs does not enforce that (see arrow-rs#5288), so a
113/// `Date64` carrying sub-day milliseconds would lose them. This is not a licence to
114/// drop them - [`try_cast_numeric_literal`] returns `None` for a `Date64` value not
115/// divisible by 86_400_000, so an inexact `Date64` -> `Date32` fold never happens.
116fn is_lossy_temporal_cast(from_type: &DataType, to_type: &DataType) -> bool {
117    if from_type == to_type {
118        return false;
119    }
120    if is_date_type(from_type) && is_date_type(to_type) {
121        return false;
122    }
123    (is_date_type(from_type) && to_type.is_temporal())
124        || (is_date_type(to_type) && from_type.is_temporal())
125}
126
127/// Returns true when casting a timestamp from `from_type` to `to_type` loses
128/// timestamp precision.
129///
130/// This is used by comparison cast unwrapping to avoid rewrites such as
131/// `CAST(ts_ns AS timestamp(ms)) = lit_ms` -> `ts_ns = lit_ns`. The original
132/// predicate can match any nanosecond value in the same millisecond, while the
133/// rewritten predicate only matches the exact millisecond boundary.
134pub fn is_timestamp_precision_narrowing_cast(
135    from_type: &DataType,
136    to_type: &DataType,
137) -> bool {
138    let (DataType::Timestamp(from_unit, _), DataType::Timestamp(to_unit, _)) =
139        (from_type, to_type)
140    else {
141        return false;
142    };
143
144    timestamp_unit_scale(from_unit) > timestamp_unit_scale(to_unit)
145}
146
147/// Returns true when casting a date column from `from_type` to `to_type` narrows
148/// `Date64` (milliseconds) to `Date32` (days).
149///
150/// Like [`is_timestamp_precision_narrowing_cast`], this guards comparison cast
151/// unwrapping against a many-to-one column cast. `CAST(date64 AS Date32) = lit_day`
152/// matches any millisecond within that day, but the rewritten `date64 = lit_ms`
153/// matches only midnight. Arrow does not require `Date64` values to be whole days
154/// (see arrow-rs#5288), so the column may carry sub-day values the planner cannot
155/// see; the widening direction (`Date32 -> Date64`) is injective and stays allowed.
156pub fn is_date_narrowing_cast(from_type: &DataType, to_type: &DataType) -> bool {
157    matches!((from_type, to_type), (DataType::Date64, DataType::Date32))
158}
159
160fn timestamp_unit_scale(unit: &TimeUnit) -> i128 {
161    match unit {
162        TimeUnit::Second => 1,
163        TimeUnit::Millisecond => MILLISECONDS as i128,
164        TimeUnit::Microsecond => MICROSECONDS as i128,
165        TimeUnit::Nanosecond => NANOSECONDS as i128,
166    }
167}
168
169/// Returns true if unwrap_cast_in_comparison supports this numeric type
170fn is_supported_numeric_type(data_type: &DataType) -> bool {
171    matches!(
172        data_type,
173        DataType::UInt8
174            | DataType::UInt16
175            | DataType::UInt32
176            | DataType::UInt64
177            | DataType::Int8
178            | DataType::Int16
179            | DataType::Int32
180            | DataType::Int64
181            | DataType::Date32
182            | DataType::Date64
183            | DataType::Decimal32(_, _)
184            | DataType::Decimal64(_, _)
185            | DataType::Decimal128(_, _)
186            | DataType::Timestamp(_, _)
187    )
188}
189
190/// Returns true if unwrap_cast_in_comparison supports casting this value as a string
191fn is_supported_string_type(data_type: &DataType) -> bool {
192    matches!(
193        data_type,
194        DataType::Utf8 | DataType::LargeUtf8 | DataType::Utf8View
195    )
196}
197
198/// Returns true if unwrap_cast_in_comparison supports casting this value as a dictionary
199fn is_supported_dictionary_type(data_type: &DataType) -> bool {
200    matches!(data_type,
201                    DataType::Dictionary(_, inner) if is_supported_type(inner))
202}
203
204fn is_supported_binary_type(data_type: &DataType) -> bool {
205    matches!(data_type, DataType::Binary | DataType::FixedSizeBinary(_))
206}
207
208/// Scale a `Date32`/`Date64` literal value into the units of `target_type`,
209/// returning `None` when the conversion is not exact.
210///
211/// `Date32` counts **days** since the Unix epoch while `Date64` counts
212/// **milliseconds** since the Unix epoch, so a cross conversion scales by
213/// [`MILLISECONDS_IN_DAY`]:
214/// * `Date32` -> `Date64` is always exact: `days * MILLISECONDS_IN_DAY`
215///   (guarded against `i64`/`i128` overflow).
216/// * `Date64` -> `Date32` is exact only when the millisecond value lands on a
217///   whole-day boundary; otherwise it returns `None` so the cast unwrap is
218///   skipped (correct for every operator, including `=`).
219///
220/// For a same-type date cast or a date/integer cast the generic `mul`
221/// multiplier already applies, so this returns `value * mul`.
222fn scale_date_literal(
223    value: i128,
224    from_type: &DataType,
225    target_type: &DataType,
226    mul: i128,
227) -> Option<i128> {
228    const MILLIS_PER_DAY: i128 = MILLISECONDS_IN_DAY as i128;
229    match (from_type, target_type) {
230        (DataType::Date32, DataType::Date64) => value.checked_mul(MILLIS_PER_DAY),
231        (DataType::Date64, DataType::Date32) => {
232            (value % MILLIS_PER_DAY == 0).then_some(value / MILLIS_PER_DAY)
233        }
234        _ => value.checked_mul(mul),
235    }
236}
237
238/// Convert a numeric value from one numeric data type to another
239fn try_cast_numeric_literal(
240    lit_value: &ScalarValue,
241    target_type: &DataType,
242) -> Option<ScalarValue> {
243    let lit_data_type = lit_value.data_type();
244    if !is_supported_numeric_type(&lit_data_type)
245        || !is_supported_numeric_type(target_type)
246    {
247        return None;
248    }
249
250    if is_lossy_temporal_cast(&lit_data_type, target_type) {
251        return None;
252    }
253
254    let mul = match target_type {
255        DataType::UInt8
256        | DataType::UInt16
257        | DataType::UInt32
258        | DataType::UInt64
259        | DataType::Int8
260        | DataType::Int16
261        | DataType::Int32
262        | DataType::Int64
263        | DataType::Date32
264        | DataType::Date64 => 1_i128,
265        DataType::Timestamp(_, _) => 1_i128,
266        DataType::Decimal32(_, scale) => 10_i128.pow(*scale as u32),
267        DataType::Decimal64(_, scale) => 10_i128.pow(*scale as u32),
268        DataType::Decimal128(_, scale) => 10_i128.pow(*scale as u32),
269        _ => return None,
270    };
271    let (target_min, target_max) = match target_type {
272        DataType::UInt8 => (u8::MIN as i128, u8::MAX as i128),
273        DataType::UInt16 => (u16::MIN as i128, u16::MAX as i128),
274        DataType::UInt32 => (u32::MIN as i128, u32::MAX as i128),
275        DataType::UInt64 => (u64::MIN as i128, u64::MAX as i128),
276        DataType::Int8 => (i8::MIN as i128, i8::MAX as i128),
277        DataType::Int16 => (i16::MIN as i128, i16::MAX as i128),
278        DataType::Int32 | DataType::Date32 => (i32::MIN as i128, i32::MAX as i128),
279        DataType::Int64 | DataType::Date64 => (i64::MIN as i128, i64::MAX as i128),
280        DataType::Timestamp(_, _) => (i64::MIN as i128, i64::MAX as i128),
281        DataType::Decimal32(precision, _) => (
282            // Different precision for decimal32 can store different range of value.
283            // For example, the precision is 3, the max of value is `999` and the min
284            // value is `-999`
285            MIN_DECIMAL32_FOR_EACH_PRECISION[*precision as usize] as i128,
286            MAX_DECIMAL32_FOR_EACH_PRECISION[*precision as usize] as i128,
287        ),
288        DataType::Decimal64(precision, _) => (
289            // Different precision for decimal64 can store different range of value.
290            // For example, the precision is 3, the max of value is `999` and the min
291            // value is `-999`
292            MIN_DECIMAL64_FOR_EACH_PRECISION[*precision as usize] as i128,
293            MAX_DECIMAL64_FOR_EACH_PRECISION[*precision as usize] as i128,
294        ),
295        DataType::Decimal128(precision, _) => (
296            // Different precision for decimal128 can store different range of value.
297            // For example, the precision is 3, the max of value is `999` and the min
298            // value is `-999`
299            MIN_DECIMAL128_FOR_EACH_PRECISION[*precision as usize],
300            MAX_DECIMAL128_FOR_EACH_PRECISION[*precision as usize],
301        ),
302        _ => return None,
303    };
304    let lit_value_target_type = match lit_value {
305        ScalarValue::Int8(Some(v)) => (*v as i128).checked_mul(mul),
306        ScalarValue::Int16(Some(v)) => (*v as i128).checked_mul(mul),
307        ScalarValue::Int32(Some(v)) => (*v as i128).checked_mul(mul),
308        ScalarValue::Int64(Some(v)) => (*v as i128).checked_mul(mul),
309        ScalarValue::UInt8(Some(v)) => (*v as i128).checked_mul(mul),
310        ScalarValue::UInt16(Some(v)) => (*v as i128).checked_mul(mul),
311        ScalarValue::UInt32(Some(v)) => (*v as i128).checked_mul(mul),
312        ScalarValue::UInt64(Some(v)) => (*v as i128).checked_mul(mul),
313        ScalarValue::Date32(Some(v)) => {
314            scale_date_literal(*v as i128, &lit_data_type, target_type, mul)
315        }
316        ScalarValue::Date64(Some(v)) => {
317            scale_date_literal(*v as i128, &lit_data_type, target_type, mul)
318        }
319        ScalarValue::TimestampSecond(Some(v), _) => (*v as i128).checked_mul(mul),
320        ScalarValue::TimestampMillisecond(Some(v), _) => (*v as i128).checked_mul(mul),
321        ScalarValue::TimestampMicrosecond(Some(v), _) => (*v as i128).checked_mul(mul),
322        ScalarValue::TimestampNanosecond(Some(v), _) => (*v as i128).checked_mul(mul),
323        ScalarValue::Decimal32(Some(v), _, scale) => {
324            let v = *v as i128;
325            let lit_scale_mul = 10_i128.pow(*scale as u32);
326            if mul >= lit_scale_mul {
327                // Example:
328                // lit is decimal(123,3,2)
329                // target type is decimal(5,3)
330                // the lit can be converted to the decimal(1230,5,3)
331                v.checked_mul(mul / lit_scale_mul)
332            } else if v % (lit_scale_mul / mul) == 0 {
333                // Example:
334                // lit is decimal(123000,10,3)
335                // target type is int32: the lit can be converted to INT32(123)
336                // target type is decimal(10,2): the lit can be converted to decimal(12300,10,2)
337                Some(v / (lit_scale_mul / mul))
338            } else {
339                // can't convert the lit decimal to the target data type
340                None
341            }
342        }
343        ScalarValue::Decimal64(Some(v), _, scale) => {
344            let v = *v as i128;
345            let lit_scale_mul = 10_i128.pow(*scale as u32);
346            if mul >= lit_scale_mul {
347                // Example:
348                // lit is decimal(123,3,2)
349                // target type is decimal(5,3)
350                // the lit can be converted to the decimal(1230,5,3)
351                v.checked_mul(mul / lit_scale_mul)
352            } else if v % (lit_scale_mul / mul) == 0 {
353                // Example:
354                // lit is decimal(123000,10,3)
355                // target type is int32: the lit can be converted to INT32(123)
356                // target type is decimal(10,2): the lit can be converted to decimal(12300,10,2)
357                Some(v / (lit_scale_mul / mul))
358            } else {
359                // can't convert the lit decimal to the target data type
360                None
361            }
362        }
363        ScalarValue::Decimal128(Some(v), _, scale) => {
364            let lit_scale_mul = 10_i128.pow(*scale as u32);
365            if mul >= lit_scale_mul {
366                // Example:
367                // lit is decimal(123,3,2)
368                // target type is decimal(5,3)
369                // the lit can be converted to the decimal(1230,5,3)
370                (*v).checked_mul(mul / lit_scale_mul)
371            } else if (*v) % (lit_scale_mul / mul) == 0 {
372                // Example:
373                // lit is decimal(123000,10,3)
374                // target type is int32: the lit can be converted to INT32(123)
375                // target type is decimal(10,2): the lit can be converted to decimal(12300,10,2)
376                Some(*v / (lit_scale_mul / mul))
377            } else {
378                // can't convert the lit decimal to the target data type
379                None
380            }
381        }
382        _ => None,
383    };
384
385    match lit_value_target_type {
386        None => None,
387        Some(value) => {
388            if value >= target_min && value <= target_max {
389                // the value casted from lit to the target type is in the range of target type.
390                // return the target type of scalar value
391                let result_scalar = match target_type {
392                    DataType::Int8 => ScalarValue::Int8(Some(value as i8)),
393                    DataType::Int16 => ScalarValue::Int16(Some(value as i16)),
394                    DataType::Int32 => ScalarValue::Int32(Some(value as i32)),
395                    DataType::Int64 => ScalarValue::Int64(Some(value as i64)),
396                    DataType::Date32 => ScalarValue::Date32(Some(value as i32)),
397                    DataType::Date64 => ScalarValue::Date64(Some(value as i64)),
398                    DataType::UInt8 => ScalarValue::UInt8(Some(value as u8)),
399                    DataType::UInt16 => ScalarValue::UInt16(Some(value as u16)),
400                    DataType::UInt32 => ScalarValue::UInt32(Some(value as u32)),
401                    DataType::UInt64 => ScalarValue::UInt64(Some(value as u64)),
402                    DataType::Timestamp(TimeUnit::Second, tz) => {
403                        let value = cast_between_timestamp(
404                            &lit_data_type,
405                            &DataType::Timestamp(TimeUnit::Second, tz.clone()),
406                            value,
407                        );
408                        ScalarValue::TimestampSecond(value, tz.clone())
409                    }
410                    DataType::Timestamp(TimeUnit::Millisecond, tz) => {
411                        let value = cast_between_timestamp(
412                            &lit_data_type,
413                            &DataType::Timestamp(TimeUnit::Millisecond, tz.clone()),
414                            value,
415                        );
416                        ScalarValue::TimestampMillisecond(value, tz.clone())
417                    }
418                    DataType::Timestamp(TimeUnit::Microsecond, tz) => {
419                        let value = cast_between_timestamp(
420                            &lit_data_type,
421                            &DataType::Timestamp(TimeUnit::Microsecond, tz.clone()),
422                            value,
423                        );
424                        ScalarValue::TimestampMicrosecond(value, tz.clone())
425                    }
426                    DataType::Timestamp(TimeUnit::Nanosecond, tz) => {
427                        let value = cast_between_timestamp(
428                            &lit_data_type,
429                            &DataType::Timestamp(TimeUnit::Nanosecond, tz.clone()),
430                            value,
431                        );
432                        ScalarValue::TimestampNanosecond(value, tz.clone())
433                    }
434                    DataType::Decimal32(p, s) => {
435                        ScalarValue::Decimal32(Some(value as i32), *p, *s)
436                    }
437                    DataType::Decimal64(p, s) => {
438                        ScalarValue::Decimal64(Some(value as i64), *p, *s)
439                    }
440                    DataType::Decimal128(p, s) => {
441                        ScalarValue::Decimal128(Some(value), *p, *s)
442                    }
443                    _ => {
444                        return None;
445                    }
446                };
447                Some(result_scalar)
448            } else {
449                None
450            }
451        }
452    }
453}
454
455fn try_cast_string_literal(
456    lit_value: &ScalarValue,
457    target_type: &DataType,
458) -> Option<ScalarValue> {
459    let string_value = lit_value.try_as_str()?.map(|s| s.to_string());
460    let scalar_value = match target_type {
461        DataType::Utf8 => ScalarValue::Utf8(string_value),
462        DataType::LargeUtf8 => ScalarValue::LargeUtf8(string_value),
463        DataType::Utf8View => ScalarValue::Utf8View(string_value),
464        _ => return None,
465    };
466    Some(scalar_value)
467}
468
469/// Attempt to cast to/from a dictionary type by wrapping/unwrapping the dictionary
470fn try_cast_dictionary(
471    lit_value: &ScalarValue,
472    target_type: &DataType,
473) -> Option<ScalarValue> {
474    let lit_value_type = lit_value.data_type();
475    let result_scalar = match (lit_value, target_type) {
476        // Unwrap dictionary when inner type matches target type
477        (ScalarValue::Dictionary(_, inner_value), _)
478            if inner_value.data_type() == *target_type =>
479        {
480            (**inner_value).clone()
481        }
482        // Wrap type when target type is dictionary
483        (_, DataType::Dictionary(index_type, inner_type))
484            if **inner_type == lit_value_type =>
485        {
486            ScalarValue::Dictionary(index_type.clone(), Box::new(lit_value.clone()))
487        }
488        _ => {
489            return None;
490        }
491    };
492    Some(result_scalar)
493}
494
495/// Cast a timestamp value from one unit to another
496fn cast_between_timestamp(from: &DataType, to: &DataType, value: i128) -> Option<i64> {
497    let value = value as i64;
498    let from_scale = match from {
499        DataType::Timestamp(TimeUnit::Second, _) => 1,
500        DataType::Timestamp(TimeUnit::Millisecond, _) => MILLISECONDS,
501        DataType::Timestamp(TimeUnit::Microsecond, _) => MICROSECONDS,
502        DataType::Timestamp(TimeUnit::Nanosecond, _) => NANOSECONDS,
503        _ => return Some(value),
504    };
505
506    let to_scale = match to {
507        DataType::Timestamp(TimeUnit::Second, _) => 1,
508        DataType::Timestamp(TimeUnit::Millisecond, _) => MILLISECONDS,
509        DataType::Timestamp(TimeUnit::Microsecond, _) => MICROSECONDS,
510        DataType::Timestamp(TimeUnit::Nanosecond, _) => NANOSECONDS,
511        _ => return Some(value),
512    };
513
514    match from_scale.cmp(&to_scale) {
515        Ordering::Less => value.checked_mul(to_scale / from_scale),
516        Ordering::Greater => Some(value / (from_scale / to_scale)),
517        Ordering::Equal => Some(value),
518    }
519}
520
521fn try_cast_binary(
522    lit_value: &ScalarValue,
523    target_type: &DataType,
524) -> Option<ScalarValue> {
525    match (lit_value, target_type) {
526        (ScalarValue::Binary(Some(v)), DataType::FixedSizeBinary(n))
527            if v.len() == *n as usize =>
528        {
529            Some(ScalarValue::FixedSizeBinary(*n, Some(v.clone())))
530        }
531        _ => None,
532    }
533}
534
535#[cfg(test)]
536mod tests {
537    use super::*;
538    use arrow::compute::{CastOptions, cast_with_options};
539    use arrow::datatypes::{Field, Fields};
540    use std::sync::Arc;
541
542    #[derive(Debug, Clone)]
543    enum ExpectedCast {
544        /// test successfully cast value and it is as specified
545        Value(ScalarValue),
546        /// test returned OK, but could not cast the value
547        NoValue,
548    }
549
550    /// Runs try_cast_literal_to_type with the specified inputs and
551    /// ensure it computes the expected output, and ensures the
552    /// casting is consistent with the Arrow kernels
553    fn expect_cast(
554        literal: ScalarValue,
555        target_type: DataType,
556        expected_result: ExpectedCast,
557    ) {
558        let actual_value = try_cast_literal_to_type(&literal, &target_type);
559
560        println!("expect_cast: ");
561        println!("  {literal:?} --> {target_type}");
562        println!("  expected_result: {expected_result:?}");
563        println!("  actual_result:   {actual_value:?}");
564
565        match expected_result {
566            ExpectedCast::Value(expected_value) => {
567                let actual_value =
568                    actual_value.expect("Expected cast value but got None");
569
570                assert_eq!(actual_value, expected_value);
571
572                // Verify that calling the arrow
573                // cast kernel yields the same results
574                // input array
575                let literal_array = literal
576                    .to_array_of_size(1)
577                    .expect("Failed to convert to array of size");
578                let expected_array = expected_value
579                    .to_array_of_size(1)
580                    .expect("Failed to convert to array of size");
581                let cast_array = cast_with_options(
582                    &literal_array,
583                    &target_type,
584                    &CastOptions::default(),
585                )
586                .expect("Expected to be cast array with arrow cast kernel");
587
588                assert_eq!(
589                    &expected_array, &cast_array,
590                    "Result of casting {literal:?} with arrow was\n {cast_array:#?}\nbut expected\n{expected_array:#?}"
591                );
592
593                // Verify that for timestamp types the timezones are the same
594                // (ScalarValue::cmp doesn't account for timezones);
595                if let (
596                    DataType::Timestamp(left_unit, left_tz),
597                    DataType::Timestamp(right_unit, right_tz),
598                ) = (actual_value.data_type(), expected_value.data_type())
599                {
600                    assert_eq!(left_unit, right_unit);
601                    assert_eq!(left_tz, right_tz);
602                }
603            }
604            ExpectedCast::NoValue => {
605                assert!(
606                    actual_value.is_none(),
607                    "Expected no cast value, but got {actual_value:?}"
608                );
609            }
610        }
611    }
612
613    #[test]
614    fn test_try_cast_to_type_nulls() {
615        // test that nulls can be cast to/from all integer types
616        let scalars = vec![
617            ScalarValue::Int8(None),
618            ScalarValue::Int16(None),
619            ScalarValue::Int32(None),
620            ScalarValue::Int64(None),
621            ScalarValue::UInt8(None),
622            ScalarValue::UInt16(None),
623            ScalarValue::UInt32(None),
624            ScalarValue::UInt64(None),
625            ScalarValue::Decimal128(None, 3, 0),
626            ScalarValue::Decimal128(None, 8, 2),
627            ScalarValue::Utf8(None),
628            ScalarValue::LargeUtf8(None),
629        ];
630
631        for s1 in &scalars {
632            for s2 in &scalars {
633                let expected_value = ExpectedCast::Value(s2.clone());
634
635                expect_cast(s1.clone(), s2.data_type(), expected_value);
636            }
637        }
638    }
639
640    #[test]
641    fn test_try_cast_to_type_int_in_range() {
642        // test values that can be cast to/from all integer types
643        let scalars = vec![
644            ScalarValue::Int8(Some(123)),
645            ScalarValue::Int16(Some(123)),
646            ScalarValue::Int32(Some(123)),
647            ScalarValue::Int64(Some(123)),
648            ScalarValue::UInt8(Some(123)),
649            ScalarValue::UInt16(Some(123)),
650            ScalarValue::UInt32(Some(123)),
651            ScalarValue::UInt64(Some(123)),
652            ScalarValue::Decimal128(Some(123), 3, 0),
653            ScalarValue::Decimal128(Some(12300), 8, 2),
654        ];
655
656        for s1 in &scalars {
657            for s2 in &scalars {
658                let expected_value = ExpectedCast::Value(s2.clone());
659
660                expect_cast(s1.clone(), s2.data_type(), expected_value);
661            }
662        }
663
664        let max_i32 = ScalarValue::Int32(Some(i32::MAX));
665        expect_cast(
666            max_i32,
667            DataType::UInt64,
668            ExpectedCast::Value(ScalarValue::UInt64(Some(i32::MAX as u64))),
669        );
670
671        let min_i32 = ScalarValue::Int32(Some(i32::MIN));
672        expect_cast(
673            min_i32,
674            DataType::Int64,
675            ExpectedCast::Value(ScalarValue::Int64(Some(i32::MIN as i64))),
676        );
677
678        let max_i64 = ScalarValue::Int64(Some(i64::MAX));
679        expect_cast(
680            max_i64,
681            DataType::UInt64,
682            ExpectedCast::Value(ScalarValue::UInt64(Some(i64::MAX as u64))),
683        );
684    }
685
686    #[test]
687    fn test_try_cast_to_type_int_out_of_range() {
688        let min_i32 = ScalarValue::Int32(Some(i32::MIN));
689        let min_i64 = ScalarValue::Int64(Some(i64::MIN));
690        let max_i64 = ScalarValue::Int64(Some(i64::MAX));
691        let max_u64 = ScalarValue::UInt64(Some(u64::MAX));
692
693        expect_cast(max_i64.clone(), DataType::Int8, ExpectedCast::NoValue);
694
695        expect_cast(max_i64.clone(), DataType::Int16, ExpectedCast::NoValue);
696
697        expect_cast(max_i64, DataType::Int32, ExpectedCast::NoValue);
698
699        expect_cast(max_u64, DataType::Int64, ExpectedCast::NoValue);
700
701        expect_cast(min_i64, DataType::UInt64, ExpectedCast::NoValue);
702
703        expect_cast(min_i32, DataType::UInt64, ExpectedCast::NoValue);
704
705        // decimal out of range
706        expect_cast(
707            ScalarValue::Decimal128(Some(99999999999999999999999999999999999900), 38, 0),
708            DataType::Int64,
709            ExpectedCast::NoValue,
710        );
711
712        expect_cast(
713            ScalarValue::Decimal128(Some(-9999999999999999999999999999999999), 37, 1),
714            DataType::Int64,
715            ExpectedCast::NoValue,
716        );
717    }
718
719    #[test]
720    fn test_try_decimal_cast_in_range() {
721        expect_cast(
722            ScalarValue::Decimal128(Some(12300), 5, 2),
723            DataType::Decimal128(3, 0),
724            ExpectedCast::Value(ScalarValue::Decimal128(Some(123), 3, 0)),
725        );
726
727        expect_cast(
728            ScalarValue::Decimal128(Some(12300), 5, 2),
729            DataType::Decimal128(8, 0),
730            ExpectedCast::Value(ScalarValue::Decimal128(Some(123), 8, 0)),
731        );
732
733        expect_cast(
734            ScalarValue::Decimal128(Some(12300), 5, 2),
735            DataType::Decimal128(8, 5),
736            ExpectedCast::Value(ScalarValue::Decimal128(Some(12300000), 8, 5)),
737        );
738    }
739
740    #[test]
741    fn test_try_decimal_cast_out_of_range() {
742        // decimal would lose precision
743        expect_cast(
744            ScalarValue::Decimal128(Some(12345), 5, 2),
745            DataType::Decimal128(3, 0),
746            ExpectedCast::NoValue,
747        );
748
749        // decimal would lose precision
750        expect_cast(
751            ScalarValue::Decimal128(Some(12300), 5, 2),
752            DataType::Decimal128(2, 0),
753            ExpectedCast::NoValue,
754        );
755    }
756
757    #[test]
758    fn test_try_cast_to_type_timestamps() {
759        for time_unit in [
760            TimeUnit::Second,
761            TimeUnit::Millisecond,
762            TimeUnit::Microsecond,
763            TimeUnit::Nanosecond,
764        ] {
765            let utc = Some("+00:00".into());
766            // No timezone, utc timezone
767            let (lit_tz_none, lit_tz_utc) = match time_unit {
768                TimeUnit::Second => (
769                    ScalarValue::TimestampSecond(Some(12345), None),
770                    ScalarValue::TimestampSecond(Some(12345), utc),
771                ),
772
773                TimeUnit::Millisecond => (
774                    ScalarValue::TimestampMillisecond(Some(12345), None),
775                    ScalarValue::TimestampMillisecond(Some(12345), utc),
776                ),
777
778                TimeUnit::Microsecond => (
779                    ScalarValue::TimestampMicrosecond(Some(12345), None),
780                    ScalarValue::TimestampMicrosecond(Some(12345), utc),
781                ),
782
783                TimeUnit::Nanosecond => (
784                    ScalarValue::TimestampNanosecond(Some(12345), None),
785                    ScalarValue::TimestampNanosecond(Some(12345), utc),
786                ),
787            };
788
789            // DataFusion ignores timezones for comparisons of ScalarValue
790            // so double check it here
791            assert_eq!(lit_tz_none, lit_tz_utc);
792
793            // e.g. DataType::Timestamp(_, None)
794            let dt_tz_none = lit_tz_none.data_type();
795
796            // e.g. DataType::Timestamp(_, Some(utc))
797            let dt_tz_utc = lit_tz_utc.data_type();
798
799            // None <--> None
800            expect_cast(
801                lit_tz_none.clone(),
802                dt_tz_none.clone(),
803                ExpectedCast::Value(lit_tz_none.clone()),
804            );
805
806            // None <--> Utc
807            expect_cast(
808                lit_tz_none.clone(),
809                dt_tz_utc.clone(),
810                ExpectedCast::Value(lit_tz_utc.clone()),
811            );
812
813            // Utc <--> None
814            expect_cast(
815                lit_tz_utc.clone(),
816                dt_tz_none.clone(),
817                ExpectedCast::Value(lit_tz_none.clone()),
818            );
819
820            // Utc <--> Utc
821            expect_cast(
822                lit_tz_utc.clone(),
823                dt_tz_utc.clone(),
824                ExpectedCast::Value(lit_tz_utc.clone()),
825            );
826
827            // timestamp to int64
828            expect_cast(
829                lit_tz_utc.clone(),
830                DataType::Int64,
831                ExpectedCast::Value(ScalarValue::Int64(Some(12345))),
832            );
833
834            // int64 to timestamp
835            expect_cast(
836                ScalarValue::Int64(Some(12345)),
837                dt_tz_none.clone(),
838                ExpectedCast::Value(lit_tz_none.clone()),
839            );
840
841            // int64 to timestamp
842            expect_cast(
843                ScalarValue::Int64(Some(12345)),
844                dt_tz_utc.clone(),
845                ExpectedCast::Value(lit_tz_utc.clone()),
846            );
847
848            // timestamp to string (not supported yet)
849            expect_cast(
850                lit_tz_utc.clone(),
851                DataType::LargeUtf8,
852                ExpectedCast::NoValue,
853            );
854        }
855    }
856
857    #[test]
858    fn test_try_cast_to_type_date_timestamp_lossy_not_allowed() {
859        expect_cast(
860            ScalarValue::Date32(Some(1)),
861            DataType::Timestamp(TimeUnit::Second, None),
862            ExpectedCast::NoValue,
863        );
864
865        expect_cast(
866            ScalarValue::Date64(Some(86_400_000)),
867            DataType::Timestamp(TimeUnit::Millisecond, None),
868            ExpectedCast::NoValue,
869        );
870
871        expect_cast(
872            ScalarValue::TimestampSecond(Some(86_400), None),
873            DataType::Date32,
874            ExpectedCast::NoValue,
875        );
876
877        expect_cast(
878            ScalarValue::TimestampMillisecond(Some(86_400_000), None),
879            DataType::Date64,
880            ExpectedCast::NoValue,
881        );
882    }
883
884    #[test]
885    fn test_try_cast_identity_date_allowed() {
886        // An identity Date cast (e.g. `CAST(date_col AS DATE)` where the column
887        // is already Date32) must fold: it never changes comparison semantics,
888        // so `try_cast_literal_to_type` should return the same value rather than
889        // treating it as a lossy temporal cast.
890        expect_cast(
891            ScalarValue::Date32(Some(19_723)),
892            DataType::Date32,
893            ExpectedCast::Value(ScalarValue::Date32(Some(19_723))),
894        );
895
896        expect_cast(
897            ScalarValue::Date64(Some(1_704_067_200_000)),
898            DataType::Date64,
899            ExpectedCast::Value(ScalarValue::Date64(Some(1_704_067_200_000))),
900        );
901
902        // is_lossy_temporal_cast must classify an identity cast as non-lossy.
903        assert!(!is_lossy_temporal_cast(
904            &DataType::Date32,
905            &DataType::Date32
906        ));
907        assert!(!is_lossy_temporal_cast(
908            &DataType::Date64,
909            &DataType::Date64
910        ));
911    }
912
913    #[test]
914    fn test_try_cast_between_date32_and_date64() {
915        // 2025-01-01 is day 20089 since the Unix epoch, which is
916        // 20089 * 86_400_000 = 1_735_689_600_000 milliseconds.
917        const DAY_2025_01_01: i32 = 20089;
918        const MS_2025_01_01: i64 = 1_735_689_600_000;
919        assert_eq!(DAY_2025_01_01 as i64 * MILLISECONDS_IN_DAY, MS_2025_01_01);
920
921        // Date32 -> Date64 is always exact (days scaled up to milliseconds).
922        expect_cast(
923            ScalarValue::Date32(Some(DAY_2025_01_01)),
924            DataType::Date64,
925            ExpectedCast::Value(ScalarValue::Date64(Some(MS_2025_01_01))),
926        );
927
928        // Date64 -> Date32 is exact only on a whole-day boundary.
929        expect_cast(
930            ScalarValue::Date64(Some(MS_2025_01_01)),
931            DataType::Date32,
932            ExpectedCast::Value(ScalarValue::Date32(Some(DAY_2025_01_01))),
933        );
934
935        // A Date64 value that is not on a day boundary cannot be represented as
936        // a Date32 exactly, so no rewrite is produced.
937        expect_cast(
938            ScalarValue::Date64(Some(MS_2025_01_01 + 1)),
939            DataType::Date32,
940            ExpectedCast::NoValue,
941        );
942        expect_cast(
943            ScalarValue::Date64(Some(MS_2025_01_01 - 1)),
944            DataType::Date32,
945            ExpectedCast::NoValue,
946        );
947
948        // The epoch and negative (pre-epoch) days round-trip exactly.
949        expect_cast(
950            ScalarValue::Date32(Some(0)),
951            DataType::Date64,
952            ExpectedCast::Value(ScalarValue::Date64(Some(0))),
953        );
954        expect_cast(
955            ScalarValue::Date32(Some(-1)),
956            DataType::Date64,
957            ExpectedCast::Value(ScalarValue::Date64(Some(-MILLISECONDS_IN_DAY))),
958        );
959        expect_cast(
960            ScalarValue::Date64(Some(-MILLISECONDS_IN_DAY)),
961            DataType::Date32,
962            ExpectedCast::Value(ScalarValue::Date32(Some(-1))),
963        );
964
965        // Same-type date casts remain identity conversions.
966        expect_cast(
967            ScalarValue::Date32(Some(DAY_2025_01_01)),
968            DataType::Date32,
969            ExpectedCast::Value(ScalarValue::Date32(Some(DAY_2025_01_01))),
970        );
971        expect_cast(
972            ScalarValue::Date64(Some(MS_2025_01_01)),
973            DataType::Date64,
974            ExpectedCast::Value(ScalarValue::Date64(Some(MS_2025_01_01))),
975        );
976    }
977
978    #[test]
979    fn test_is_lossy_temporal_cast_date_pairs() {
980        // Date <-> Date is let through the pre-filter (per-value exactness is
981        // enforced downstream in try_cast_numeric_literal, not here).
982        assert!(!is_lossy_temporal_cast(
983            &DataType::Date32,
984            &DataType::Date64
985        ));
986        assert!(!is_lossy_temporal_cast(
987            &DataType::Date64,
988            &DataType::Date32
989        ));
990        // Identity is not lossy.
991        assert!(!is_lossy_temporal_cast(
992            &DataType::Date32,
993            &DataType::Date32
994        ));
995        // Date <-> Timestamp remains lossy.
996        let ts = DataType::Timestamp(TimeUnit::Millisecond, None);
997        assert!(is_lossy_temporal_cast(&DataType::Date32, &ts));
998        assert!(is_lossy_temporal_cast(&ts, &DataType::Date32));
999    }
1000
1001    #[test]
1002    fn test_timestamp_precision_narrowing_cast() {
1003        let ts_ns = DataType::Timestamp(TimeUnit::Nanosecond, None);
1004        let ts_us = DataType::Timestamp(TimeUnit::Microsecond, None);
1005        let ts_ms = DataType::Timestamp(TimeUnit::Millisecond, None);
1006        let ts_s = DataType::Timestamp(TimeUnit::Second, None);
1007
1008        assert!(is_timestamp_precision_narrowing_cast(&ts_ns, &ts_ms));
1009        assert!(is_timestamp_precision_narrowing_cast(&ts_us, &ts_s));
1010        assert!(!is_timestamp_precision_narrowing_cast(&ts_ms, &ts_ns));
1011        assert!(!is_timestamp_precision_narrowing_cast(&ts_ms, &ts_ms));
1012        assert!(!is_timestamp_precision_narrowing_cast(
1013            &DataType::Int64,
1014            &ts_ms
1015        ));
1016    }
1017
1018    #[test]
1019    fn test_is_date_narrowing_cast() {
1020        // Only Date64 -> Date32 narrows (ms -> days, many-to-one).
1021        assert!(is_date_narrowing_cast(&DataType::Date64, &DataType::Date32));
1022        // The widening direction is injective and must not be flagged.
1023        assert!(!is_date_narrowing_cast(
1024            &DataType::Date32,
1025            &DataType::Date64
1026        ));
1027        // Identity and non-date pairs are not date-narrowing casts.
1028        assert!(!is_date_narrowing_cast(
1029            &DataType::Date32,
1030            &DataType::Date32
1031        ));
1032        assert!(!is_date_narrowing_cast(
1033            &DataType::Date64,
1034            &DataType::Date64
1035        ));
1036        assert!(!is_date_narrowing_cast(&DataType::Int64, &DataType::Date32));
1037    }
1038
1039    #[test]
1040    fn test_scale_date_literal_exactness_and_overflow() {
1041        const MS_PER_DAY: i128 = MILLISECONDS_IN_DAY as i128;
1042
1043        // Date32 -> Date64 is always exact: days scaled to midnight milliseconds.
1044        // 2025-01-01 is day 20089 = 1_735_689_600_000 ms.
1045        assert_eq!(
1046            scale_date_literal(20089, &DataType::Date32, &DataType::Date64, 1),
1047            Some(1_735_689_600_000)
1048        );
1049        assert_eq!(
1050            scale_date_literal(0, &DataType::Date32, &DataType::Date64, 1),
1051            Some(0)
1052        );
1053        // Negative (pre-epoch) whole day: 1969-12-31 is day -1 = -86_400_000 ms.
1054        assert_eq!(
1055            scale_date_literal(-1, &DataType::Date32, &DataType::Date64, 1),
1056            Some(-86_400_000)
1057        );
1058
1059        // Date64 -> Date32 is exact only on a whole-day boundary.
1060        assert_eq!(
1061            scale_date_literal(
1062                1_735_689_600_000,
1063                &DataType::Date64,
1064                &DataType::Date32,
1065                1
1066            ),
1067            Some(20089)
1068        );
1069        assert_eq!(
1070            scale_date_literal(-86_400_000, &DataType::Date64, &DataType::Date32, 1),
1071            Some(-1)
1072        );
1073        // Sub-day values are not exactly representable as a Date32, in both the
1074        // positive and the pre-epoch negative direction -> None (no fold).
1075        assert_eq!(
1076            scale_date_literal(
1077                1_735_732_800_000,
1078                &DataType::Date64,
1079                &DataType::Date32,
1080                1
1081            ),
1082            None
1083        );
1084        assert_eq!(
1085            scale_date_literal(-43_200_000, &DataType::Date64, &DataType::Date32, 1),
1086            None
1087        );
1088
1089        // Extremes: a Date32 at i32::MIN / i32::MAX widens with checked i128
1090        // arithmetic, producing the exact millisecond value without overflow or
1091        // panic.
1092        assert_eq!(
1093            scale_date_literal(i32::MAX as i128, &DataType::Date32, &DataType::Date64, 1),
1094            Some(i32::MAX as i128 * MS_PER_DAY)
1095        );
1096        assert_eq!(
1097            scale_date_literal(i32::MIN as i128, &DataType::Date32, &DataType::Date64, 1),
1098            Some(i32::MIN as i128 * MS_PER_DAY)
1099        );
1100    }
1101
1102    #[test]
1103    fn test_try_cast_to_type_unsupported() {
1104        // int64 to list
1105        expect_cast(
1106            ScalarValue::Int64(Some(12345)),
1107            DataType::List(Arc::new(Field::new("f", DataType::Int32, true))),
1108            ExpectedCast::NoValue,
1109        );
1110    }
1111
1112    #[test]
1113    fn test_try_cast_literal_to_timestamp() {
1114        // same timestamp
1115        let new_scalar = try_cast_literal_to_type(
1116            &ScalarValue::TimestampNanosecond(Some(123456), None),
1117            &DataType::Timestamp(TimeUnit::Nanosecond, None),
1118        )
1119        .unwrap();
1120
1121        assert_eq!(
1122            new_scalar,
1123            ScalarValue::TimestampNanosecond(Some(123456), None)
1124        );
1125
1126        // TimestampNanosecond to TimestampMicrosecond
1127        let new_scalar = try_cast_literal_to_type(
1128            &ScalarValue::TimestampNanosecond(Some(123456), None),
1129            &DataType::Timestamp(TimeUnit::Microsecond, None),
1130        )
1131        .unwrap();
1132
1133        assert_eq!(
1134            new_scalar,
1135            ScalarValue::TimestampMicrosecond(Some(123), None)
1136        );
1137
1138        // TimestampNanosecond to TimestampMillisecond
1139        let new_scalar = try_cast_literal_to_type(
1140            &ScalarValue::TimestampNanosecond(Some(123456), None),
1141            &DataType::Timestamp(TimeUnit::Millisecond, None),
1142        )
1143        .unwrap();
1144
1145        assert_eq!(new_scalar, ScalarValue::TimestampMillisecond(Some(0), None));
1146
1147        // TimestampNanosecond to TimestampSecond
1148        let new_scalar = try_cast_literal_to_type(
1149            &ScalarValue::TimestampNanosecond(Some(123456), None),
1150            &DataType::Timestamp(TimeUnit::Second, None),
1151        )
1152        .unwrap();
1153
1154        assert_eq!(new_scalar, ScalarValue::TimestampSecond(Some(0), None));
1155
1156        // TimestampMicrosecond to TimestampNanosecond
1157        let new_scalar = try_cast_literal_to_type(
1158            &ScalarValue::TimestampMicrosecond(Some(123), None),
1159            &DataType::Timestamp(TimeUnit::Nanosecond, None),
1160        )
1161        .unwrap();
1162
1163        assert_eq!(
1164            new_scalar,
1165            ScalarValue::TimestampNanosecond(Some(123000), None)
1166        );
1167
1168        // TimestampMicrosecond to TimestampMillisecond
1169        let new_scalar = try_cast_literal_to_type(
1170            &ScalarValue::TimestampMicrosecond(Some(123), None),
1171            &DataType::Timestamp(TimeUnit::Millisecond, None),
1172        )
1173        .unwrap();
1174
1175        assert_eq!(new_scalar, ScalarValue::TimestampMillisecond(Some(0), None));
1176
1177        // TimestampMicrosecond to TimestampSecond
1178        let new_scalar = try_cast_literal_to_type(
1179            &ScalarValue::TimestampMicrosecond(Some(123456789), None),
1180            &DataType::Timestamp(TimeUnit::Second, None),
1181        )
1182        .unwrap();
1183        assert_eq!(new_scalar, ScalarValue::TimestampSecond(Some(123), None));
1184
1185        // TimestampMillisecond to TimestampNanosecond
1186        let new_scalar = try_cast_literal_to_type(
1187            &ScalarValue::TimestampMillisecond(Some(123), None),
1188            &DataType::Timestamp(TimeUnit::Nanosecond, None),
1189        )
1190        .unwrap();
1191        assert_eq!(
1192            new_scalar,
1193            ScalarValue::TimestampNanosecond(Some(123000000), None)
1194        );
1195
1196        // TimestampMillisecond to TimestampMicrosecond
1197        let new_scalar = try_cast_literal_to_type(
1198            &ScalarValue::TimestampMillisecond(Some(123), None),
1199            &DataType::Timestamp(TimeUnit::Microsecond, None),
1200        )
1201        .unwrap();
1202        assert_eq!(
1203            new_scalar,
1204            ScalarValue::TimestampMicrosecond(Some(123000), None)
1205        );
1206        // TimestampMillisecond to TimestampSecond
1207        let new_scalar = try_cast_literal_to_type(
1208            &ScalarValue::TimestampMillisecond(Some(123456789), None),
1209            &DataType::Timestamp(TimeUnit::Second, None),
1210        )
1211        .unwrap();
1212        assert_eq!(new_scalar, ScalarValue::TimestampSecond(Some(123456), None));
1213
1214        // TimestampSecond to TimestampNanosecond
1215        let new_scalar = try_cast_literal_to_type(
1216            &ScalarValue::TimestampSecond(Some(123), None),
1217            &DataType::Timestamp(TimeUnit::Nanosecond, None),
1218        )
1219        .unwrap();
1220        assert_eq!(
1221            new_scalar,
1222            ScalarValue::TimestampNanosecond(Some(123000000000), None)
1223        );
1224
1225        // TimestampSecond to TimestampMicrosecond
1226        let new_scalar = try_cast_literal_to_type(
1227            &ScalarValue::TimestampSecond(Some(123), None),
1228            &DataType::Timestamp(TimeUnit::Microsecond, None),
1229        )
1230        .unwrap();
1231        assert_eq!(
1232            new_scalar,
1233            ScalarValue::TimestampMicrosecond(Some(123000000), None)
1234        );
1235
1236        // TimestampSecond to TimestampMillisecond
1237        let new_scalar = try_cast_literal_to_type(
1238            &ScalarValue::TimestampSecond(Some(123), None),
1239            &DataType::Timestamp(TimeUnit::Millisecond, None),
1240        )
1241        .unwrap();
1242        assert_eq!(
1243            new_scalar,
1244            ScalarValue::TimestampMillisecond(Some(123000), None)
1245        );
1246
1247        // overflow
1248        let new_scalar = try_cast_literal_to_type(
1249            &ScalarValue::TimestampSecond(Some(i64::MAX), None),
1250            &DataType::Timestamp(TimeUnit::Millisecond, None),
1251        )
1252        .unwrap();
1253        assert_eq!(new_scalar, ScalarValue::TimestampMillisecond(None, None));
1254    }
1255
1256    #[test]
1257    fn test_try_cast_to_string_type() {
1258        let scalars = vec![
1259            ScalarValue::from("string"),
1260            ScalarValue::LargeUtf8(Some("string".to_owned())),
1261        ];
1262
1263        for s1 in &scalars {
1264            for s2 in &scalars {
1265                let expected_value = ExpectedCast::Value(s2.clone());
1266
1267                expect_cast(s1.clone(), s2.data_type(), expected_value);
1268            }
1269        }
1270    }
1271
1272    #[test]
1273    fn test_try_cast_to_dictionary_type() {
1274        fn dictionary_type(t: DataType) -> DataType {
1275            DataType::Dictionary(Box::new(DataType::Int32), Box::new(t))
1276        }
1277        fn dictionary_value(value: ScalarValue) -> ScalarValue {
1278            ScalarValue::Dictionary(Box::new(DataType::Int32), Box::new(value))
1279        }
1280        let scalars = vec![
1281            ScalarValue::from("string"),
1282            ScalarValue::LargeUtf8(Some("string".to_owned())),
1283        ];
1284        for s in &scalars {
1285            expect_cast(
1286                s.clone(),
1287                dictionary_type(s.data_type()),
1288                ExpectedCast::Value(dictionary_value(s.clone())),
1289            );
1290            expect_cast(
1291                dictionary_value(s.clone()),
1292                s.data_type(),
1293                ExpectedCast::Value(s.clone()),
1294            )
1295        }
1296    }
1297
1298    #[test]
1299    fn test_try_cast_to_fixed_size_binary() {
1300        expect_cast(
1301            ScalarValue::Binary(Some(vec![1, 2, 3])),
1302            DataType::FixedSizeBinary(3),
1303            ExpectedCast::Value(ScalarValue::FixedSizeBinary(3, Some(vec![1, 2, 3]))),
1304        )
1305    }
1306
1307    #[test]
1308    fn test_numeric_boundary_values() {
1309        // Test exact boundary values for signed integers
1310        expect_cast(
1311            ScalarValue::Int8(Some(i8::MAX)),
1312            DataType::UInt8,
1313            ExpectedCast::Value(ScalarValue::UInt8(Some(i8::MAX as u8))),
1314        );
1315
1316        expect_cast(
1317            ScalarValue::Int8(Some(i8::MIN)),
1318            DataType::UInt8,
1319            ExpectedCast::NoValue,
1320        );
1321
1322        expect_cast(
1323            ScalarValue::UInt8(Some(u8::MAX)),
1324            DataType::Int8,
1325            ExpectedCast::NoValue,
1326        );
1327
1328        // Test cross-type boundary scenarios
1329        expect_cast(
1330            ScalarValue::Int32(Some(i32::MAX)),
1331            DataType::Int64,
1332            ExpectedCast::Value(ScalarValue::Int64(Some(i32::MAX as i64))),
1333        );
1334
1335        expect_cast(
1336            ScalarValue::Int64(Some(i64::MIN)),
1337            DataType::UInt64,
1338            ExpectedCast::NoValue,
1339        );
1340
1341        // Test unsigned to signed edge cases
1342        expect_cast(
1343            ScalarValue::UInt32(Some(u32::MAX)),
1344            DataType::Int32,
1345            ExpectedCast::NoValue,
1346        );
1347
1348        expect_cast(
1349            ScalarValue::UInt64(Some(u64::MAX)),
1350            DataType::Int64,
1351            ExpectedCast::NoValue,
1352        );
1353    }
1354
1355    #[test]
1356    fn test_decimal_precision_limits() {
1357        use arrow::datatypes::{
1358            MAX_DECIMAL128_FOR_EACH_PRECISION, MIN_DECIMAL128_FOR_EACH_PRECISION,
1359        };
1360
1361        // Test maximum precision values
1362        expect_cast(
1363            ScalarValue::Decimal128(Some(MAX_DECIMAL128_FOR_EACH_PRECISION[3]), 3, 0),
1364            DataType::Decimal128(5, 0),
1365            ExpectedCast::Value(ScalarValue::Decimal128(
1366                Some(MAX_DECIMAL128_FOR_EACH_PRECISION[3]),
1367                5,
1368                0,
1369            )),
1370        );
1371
1372        // Test minimum precision values
1373        expect_cast(
1374            ScalarValue::Decimal128(Some(MIN_DECIMAL128_FOR_EACH_PRECISION[3]), 3, 0),
1375            DataType::Decimal128(5, 0),
1376            ExpectedCast::Value(ScalarValue::Decimal128(
1377                Some(MIN_DECIMAL128_FOR_EACH_PRECISION[3]),
1378                5,
1379                0,
1380            )),
1381        );
1382
1383        // Test scale increase
1384        expect_cast(
1385            ScalarValue::Decimal128(Some(123), 3, 0),
1386            DataType::Decimal128(5, 2),
1387            ExpectedCast::Value(ScalarValue::Decimal128(Some(12300), 5, 2)),
1388        );
1389
1390        // Test precision overflow (value too large for target precision)
1391        expect_cast(
1392            ScalarValue::Decimal128(Some(MAX_DECIMAL128_FOR_EACH_PRECISION[10]), 10, 0),
1393            DataType::Decimal128(3, 0),
1394            ExpectedCast::NoValue,
1395        );
1396
1397        // Test non-divisible decimal conversion (should fail)
1398        expect_cast(
1399            ScalarValue::Decimal128(Some(12345), 5, 3), // 12.345
1400            DataType::Int32,
1401            ExpectedCast::NoValue, // Can't convert 12.345 to integer without loss
1402        );
1403
1404        // Test edge case: scale reduction with precision loss
1405        expect_cast(
1406            ScalarValue::Decimal128(Some(12345), 5, 2), // 123.45
1407            DataType::Decimal128(3, 0),                 // Can only hold up to 999
1408            ExpectedCast::NoValue,
1409        );
1410    }
1411
1412    #[test]
1413    fn test_timestamp_overflow_scenarios() {
1414        // Test overflow in timestamp conversions
1415        let max_seconds = i64::MAX / 1_000_000_000; // Avoid overflow when converting to nanos
1416
1417        // This should work - within safe range
1418        expect_cast(
1419            ScalarValue::TimestampSecond(Some(max_seconds), None),
1420            DataType::Timestamp(TimeUnit::Nanosecond, None),
1421            ExpectedCast::Value(ScalarValue::TimestampNanosecond(
1422                Some(max_seconds * 1_000_000_000),
1423                None,
1424            )),
1425        );
1426
1427        // Test very large nanosecond value conversion to smaller units
1428        expect_cast(
1429            ScalarValue::TimestampNanosecond(Some(i64::MAX), None),
1430            DataType::Timestamp(TimeUnit::Second, None),
1431            ExpectedCast::Value(ScalarValue::TimestampSecond(
1432                Some(i64::MAX / 1_000_000_000),
1433                None,
1434            )),
1435        );
1436
1437        // Test precision loss in downscaling
1438        expect_cast(
1439            ScalarValue::TimestampNanosecond(Some(1), None),
1440            DataType::Timestamp(TimeUnit::Second, None),
1441            ExpectedCast::Value(ScalarValue::TimestampSecond(Some(0), None)),
1442        );
1443
1444        expect_cast(
1445            ScalarValue::TimestampMicrosecond(Some(999), None),
1446            DataType::Timestamp(TimeUnit::Millisecond, None),
1447            ExpectedCast::Value(ScalarValue::TimestampMillisecond(Some(0), None)),
1448        );
1449    }
1450
1451    #[test]
1452    fn test_string_view() {
1453        // Test Utf8View to other string types
1454        expect_cast(
1455            ScalarValue::Utf8View(Some("test".to_string())),
1456            DataType::Utf8,
1457            ExpectedCast::Value(ScalarValue::Utf8(Some("test".to_string()))),
1458        );
1459
1460        expect_cast(
1461            ScalarValue::Utf8View(Some("test".to_string())),
1462            DataType::LargeUtf8,
1463            ExpectedCast::Value(ScalarValue::LargeUtf8(Some("test".to_string()))),
1464        );
1465
1466        // Test other string types to Utf8View
1467        expect_cast(
1468            ScalarValue::Utf8(Some("hello".to_string())),
1469            DataType::Utf8View,
1470            ExpectedCast::Value(ScalarValue::Utf8View(Some("hello".to_string()))),
1471        );
1472
1473        expect_cast(
1474            ScalarValue::LargeUtf8(Some("world".to_string())),
1475            DataType::Utf8View,
1476            ExpectedCast::Value(ScalarValue::Utf8View(Some("world".to_string()))),
1477        );
1478
1479        // Test empty string
1480        expect_cast(
1481            ScalarValue::Utf8(Some("".to_string())),
1482            DataType::Utf8View,
1483            ExpectedCast::Value(ScalarValue::Utf8View(Some("".to_string()))),
1484        );
1485
1486        // Test large string
1487        let large_string = "x".repeat(1000);
1488        expect_cast(
1489            ScalarValue::LargeUtf8(Some(large_string.clone())),
1490            DataType::Utf8View,
1491            ExpectedCast::Value(ScalarValue::Utf8View(Some(large_string))),
1492        );
1493    }
1494
1495    #[test]
1496    fn test_binary_size_edge_cases() {
1497        // Test size mismatch - too small
1498        expect_cast(
1499            ScalarValue::Binary(Some(vec![1, 2])),
1500            DataType::FixedSizeBinary(3),
1501            ExpectedCast::NoValue,
1502        );
1503
1504        // Test size mismatch - too large
1505        expect_cast(
1506            ScalarValue::Binary(Some(vec![1, 2, 3, 4])),
1507            DataType::FixedSizeBinary(3),
1508            ExpectedCast::NoValue,
1509        );
1510
1511        // Test empty binary
1512        expect_cast(
1513            ScalarValue::Binary(Some(vec![])),
1514            DataType::FixedSizeBinary(0),
1515            ExpectedCast::Value(ScalarValue::FixedSizeBinary(0, Some(vec![]))),
1516        );
1517
1518        // Test exact size match
1519        expect_cast(
1520            ScalarValue::Binary(Some(vec![1, 2, 3])),
1521            DataType::FixedSizeBinary(3),
1522            ExpectedCast::Value(ScalarValue::FixedSizeBinary(3, Some(vec![1, 2, 3]))),
1523        );
1524
1525        // Test single byte
1526        expect_cast(
1527            ScalarValue::Binary(Some(vec![42])),
1528            DataType::FixedSizeBinary(1),
1529            ExpectedCast::Value(ScalarValue::FixedSizeBinary(1, Some(vec![42]))),
1530        );
1531    }
1532
1533    #[test]
1534    fn test_dictionary_index_types() {
1535        // Test different dictionary index types
1536        let string_value = ScalarValue::Utf8(Some("test".to_string()));
1537
1538        // Int8 index dictionary
1539        let dict_int8 =
1540            DataType::Dictionary(Box::new(DataType::Int8), Box::new(DataType::Utf8));
1541        expect_cast(
1542            string_value.clone(),
1543            dict_int8,
1544            ExpectedCast::Value(ScalarValue::Dictionary(
1545                Box::new(DataType::Int8),
1546                Box::new(string_value.clone()),
1547            )),
1548        );
1549
1550        // Int16 index dictionary
1551        let dict_int16 =
1552            DataType::Dictionary(Box::new(DataType::Int16), Box::new(DataType::Utf8));
1553        expect_cast(
1554            string_value.clone(),
1555            dict_int16,
1556            ExpectedCast::Value(ScalarValue::Dictionary(
1557                Box::new(DataType::Int16),
1558                Box::new(string_value.clone()),
1559            )),
1560        );
1561
1562        // Int64 index dictionary
1563        let dict_int64 =
1564            DataType::Dictionary(Box::new(DataType::Int64), Box::new(DataType::Utf8));
1565        expect_cast(
1566            string_value.clone(),
1567            dict_int64,
1568            ExpectedCast::Value(ScalarValue::Dictionary(
1569                Box::new(DataType::Int64),
1570                Box::new(string_value.clone()),
1571            )),
1572        );
1573
1574        // Test dictionary unwrapping
1575        let dict_value = ScalarValue::Dictionary(
1576            Box::new(DataType::Int32),
1577            Box::new(ScalarValue::LargeUtf8(Some("unwrap_test".to_string()))),
1578        );
1579        expect_cast(
1580            dict_value,
1581            DataType::LargeUtf8,
1582            ExpectedCast::Value(ScalarValue::LargeUtf8(Some("unwrap_test".to_string()))),
1583        );
1584    }
1585
1586    #[test]
1587    fn test_type_support_functions() {
1588        // Test numeric type support
1589        assert!(is_supported_numeric_type(&DataType::Int8));
1590        assert!(is_supported_numeric_type(&DataType::UInt64));
1591        assert!(is_supported_numeric_type(&DataType::Decimal128(10, 2)));
1592        assert!(is_supported_numeric_type(&DataType::Timestamp(
1593            TimeUnit::Nanosecond,
1594            None
1595        )));
1596        assert!(!is_supported_numeric_type(&DataType::Float32));
1597        assert!(!is_supported_numeric_type(&DataType::Float64));
1598
1599        // Test string type support
1600        assert!(is_supported_string_type(&DataType::Utf8));
1601        assert!(is_supported_string_type(&DataType::LargeUtf8));
1602        assert!(is_supported_string_type(&DataType::Utf8View));
1603        assert!(!is_supported_string_type(&DataType::Binary));
1604
1605        // Test binary type support
1606        assert!(is_supported_binary_type(&DataType::Binary));
1607        assert!(is_supported_binary_type(&DataType::FixedSizeBinary(10)));
1608        assert!(!is_supported_binary_type(&DataType::Utf8));
1609
1610        // Test dictionary type support with nested types
1611        assert!(is_supported_dictionary_type(&DataType::Dictionary(
1612            Box::new(DataType::Int32),
1613            Box::new(DataType::Utf8)
1614        )));
1615        assert!(is_supported_dictionary_type(&DataType::Dictionary(
1616            Box::new(DataType::Int32),
1617            Box::new(DataType::Int64)
1618        )));
1619        assert!(!is_supported_dictionary_type(&DataType::Dictionary(
1620            Box::new(DataType::Int32),
1621            Box::new(DataType::List(Arc::new(Field::new(
1622                "item",
1623                DataType::Int32,
1624                true
1625            ))))
1626        )));
1627
1628        // Test overall type support
1629        assert!(is_supported_type(&DataType::Int32));
1630        assert!(is_supported_type(&DataType::Utf8));
1631        assert!(is_supported_type(&DataType::Binary));
1632        assert!(is_supported_type(&DataType::Dictionary(
1633            Box::new(DataType::Int32),
1634            Box::new(DataType::Utf8)
1635        )));
1636        assert!(!is_supported_type(&DataType::List(Arc::new(Field::new(
1637            "item",
1638            DataType::Int32,
1639            true
1640        )))));
1641        assert!(!is_supported_type(&DataType::Struct(Fields::empty())));
1642    }
1643
1644    #[test]
1645    fn test_error_conditions() {
1646        // Test unsupported source type
1647        expect_cast(
1648            ScalarValue::Float32(Some(1.5)),
1649            DataType::Int32,
1650            ExpectedCast::NoValue,
1651        );
1652
1653        // Test unsupported target type
1654        expect_cast(
1655            ScalarValue::Int32(Some(123)),
1656            DataType::Float64,
1657            ExpectedCast::NoValue,
1658        );
1659
1660        // Test both types unsupported
1661        expect_cast(
1662            ScalarValue::Float64(Some(1.5)),
1663            DataType::Float32,
1664            ExpectedCast::NoValue,
1665        );
1666
1667        // Test complex unsupported types
1668        let list_type =
1669            DataType::List(Arc::new(Field::new("item", DataType::Int32, true)));
1670        expect_cast(
1671            ScalarValue::Int32(Some(123)),
1672            list_type,
1673            ExpectedCast::NoValue,
1674        );
1675
1676        // Test dictionary with unsupported inner type
1677        let bad_dict = DataType::Dictionary(
1678            Box::new(DataType::Int32),
1679            Box::new(DataType::List(Arc::new(Field::new(
1680                "item",
1681                DataType::Int32,
1682                true,
1683            )))),
1684        );
1685        expect_cast(
1686            ScalarValue::Int32(Some(123)),
1687            bad_dict,
1688            ExpectedCast::NoValue,
1689        );
1690    }
1691}