lance_datafusion/
expr.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4//! Utilities for working with datafusion expressions
5
6use std::sync::Arc;
7
8use arrow::compute::cast;
9use arrow_array::{cast::AsArray, ArrayRef};
10use arrow_schema::{DataType, TimeUnit};
11use datafusion_common::ScalarValue;
12
13const MS_PER_DAY: i64 = 86400000;
14
15// This is slightly tedious but when we convert expressions from SQL strings to logical
16// datafusion expressions there is no type coercion that happens.  In other words "x = 7"
17// will always yield "x = 7_u64" regardless of the type of the column "x".  As a result, we
18// need to do that literal coercion ourselves.
19pub fn safe_coerce_scalar(value: &ScalarValue, ty: &DataType) -> Option<ScalarValue> {
20    match value {
21        ScalarValue::Int8(val) => match ty {
22            DataType::Int8 => Some(value.clone()),
23            DataType::Int16 => val.map(|v| ScalarValue::Int16(Some(i16::from(v)))),
24            DataType::Int32 => val.map(|v| ScalarValue::Int32(Some(i32::from(v)))),
25            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(i64::from(v)))),
26            DataType::UInt8 => {
27                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
28            }
29            DataType::UInt16 => {
30                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
31            }
32            DataType::UInt32 => {
33                val.and_then(|v| u32::try_from(v).map(|v| ScalarValue::UInt32(Some(v))).ok())
34            }
35            DataType::UInt64 => {
36                val.and_then(|v| u64::try_from(v).map(|v| ScalarValue::UInt64(Some(v))).ok())
37            }
38            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(f32::from(v)))),
39            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
40            _ => None,
41        },
42        ScalarValue::Int16(val) => match ty {
43            DataType::Int8 => {
44                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
45            }
46            DataType::Int16 => Some(value.clone()),
47            DataType::Int32 => val.map(|v| ScalarValue::Int32(Some(i32::from(v)))),
48            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(i64::from(v)))),
49            DataType::UInt8 => {
50                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
51            }
52            DataType::UInt16 => {
53                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
54            }
55            DataType::UInt32 => {
56                val.and_then(|v| u32::try_from(v).map(|v| ScalarValue::UInt32(Some(v))).ok())
57            }
58            DataType::UInt64 => {
59                val.and_then(|v| u64::try_from(v).map(|v| ScalarValue::UInt64(Some(v))).ok())
60            }
61            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(f32::from(v)))),
62            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
63            _ => None,
64        },
65        ScalarValue::Int32(val) => match ty {
66            DataType::Int8 => {
67                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
68            }
69            DataType::Int16 => {
70                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
71            }
72            DataType::Int32 => Some(value.clone()),
73            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(i64::from(v)))),
74            DataType::UInt8 => {
75                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
76            }
77            DataType::UInt16 => {
78                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
79            }
80            DataType::UInt32 => {
81                val.and_then(|v| u32::try_from(v).map(|v| ScalarValue::UInt32(Some(v))).ok())
82            }
83            DataType::UInt64 => {
84                val.and_then(|v| u64::try_from(v).map(|v| ScalarValue::UInt64(Some(v))).ok())
85            }
86            // These conversions are inherently lossy as the full range of i32 cannot
87            // be represented in f32.  However, there is no f32::TryFrom(i32) and its not
88            // clear users would want that anyways
89            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
90            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(v as f64))),
91            _ => None,
92        },
93        ScalarValue::Int64(val) => match ty {
94            DataType::Int8 => {
95                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
96            }
97            DataType::Int16 => {
98                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
99            }
100            DataType::Int32 => {
101                val.and_then(|v| i32::try_from(v).map(|v| ScalarValue::Int32(Some(v))).ok())
102            }
103            DataType::Int64 => Some(value.clone()),
104            DataType::UInt8 => {
105                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
106            }
107            DataType::UInt16 => {
108                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
109            }
110            DataType::UInt32 => {
111                val.and_then(|v| u32::try_from(v).map(|v| ScalarValue::UInt32(Some(v))).ok())
112            }
113            DataType::UInt64 => {
114                val.and_then(|v| u64::try_from(v).map(|v| ScalarValue::UInt64(Some(v))).ok())
115            }
116            // See above warning about lossy float conversion
117            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
118            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(v as f64))),
119            _ => None,
120        },
121        ScalarValue::UInt8(val) => match ty {
122            DataType::Int8 => {
123                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
124            }
125            DataType::Int16 => val.map(|v| ScalarValue::Int16(Some(v.into()))),
126            DataType::Int32 => val.map(|v| ScalarValue::Int32(Some(v.into()))),
127            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(v.into()))),
128            DataType::UInt8 => Some(value.clone()),
129            DataType::UInt16 => val.map(|v| ScalarValue::UInt16(Some(u16::from(v)))),
130            DataType::UInt32 => val.map(|v| ScalarValue::UInt32(Some(u32::from(v)))),
131            DataType::UInt64 => val.map(|v| ScalarValue::UInt64(Some(u64::from(v)))),
132            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(f32::from(v)))),
133            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
134            _ => None,
135        },
136        ScalarValue::UInt16(val) => match ty {
137            DataType::Int8 => {
138                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
139            }
140            DataType::Int16 => {
141                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
142            }
143            DataType::Int32 => val.map(|v| ScalarValue::Int32(Some(v.into()))),
144            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(v.into()))),
145            DataType::UInt8 => {
146                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
147            }
148            DataType::UInt16 => Some(value.clone()),
149            DataType::UInt32 => val.map(|v| ScalarValue::UInt32(Some(u32::from(v)))),
150            DataType::UInt64 => val.map(|v| ScalarValue::UInt64(Some(u64::from(v)))),
151            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(f32::from(v)))),
152            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
153            _ => None,
154        },
155        ScalarValue::UInt32(val) => match ty {
156            DataType::Int8 => {
157                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
158            }
159            DataType::Int16 => {
160                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
161            }
162            DataType::Int32 => {
163                val.and_then(|v| i32::try_from(v).map(|v| ScalarValue::Int32(Some(v))).ok())
164            }
165            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(v.into()))),
166            DataType::UInt8 => {
167                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
168            }
169            DataType::UInt16 => {
170                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
171            }
172            DataType::UInt32 => Some(value.clone()),
173            DataType::UInt64 => val.map(|v| ScalarValue::UInt64(Some(u64::from(v)))),
174            // See above warning about lossy float conversion
175            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
176            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(v as f64))),
177            _ => None,
178        },
179        ScalarValue::UInt64(val) => match ty {
180            DataType::Int8 => {
181                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
182            }
183            DataType::Int16 => {
184                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
185            }
186            DataType::Int32 => {
187                val.and_then(|v| i32::try_from(v).map(|v| ScalarValue::Int32(Some(v))).ok())
188            }
189            DataType::Int64 => {
190                val.and_then(|v| i64::try_from(v).map(|v| ScalarValue::Int64(Some(v))).ok())
191            }
192            DataType::UInt8 => {
193                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
194            }
195            DataType::UInt16 => {
196                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
197            }
198            DataType::UInt32 => {
199                val.and_then(|v| u32::try_from(v).map(|v| ScalarValue::UInt32(Some(v))).ok())
200            }
201            DataType::UInt64 => Some(value.clone()),
202            // See above warning about lossy float conversion
203            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
204            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(v as f64))),
205            _ => None,
206        },
207        ScalarValue::Float32(val) => match ty {
208            DataType::Float32 => Some(value.clone()),
209            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
210            _ => None,
211        },
212        ScalarValue::Float64(val) => match ty {
213            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
214            DataType::Float64 => Some(value.clone()),
215            _ => None,
216        },
217        ScalarValue::Utf8(val) => match ty {
218            DataType::Utf8 => Some(value.clone()),
219            DataType::LargeUtf8 => Some(ScalarValue::LargeUtf8(val.clone())),
220            _ => None,
221        },
222        ScalarValue::LargeUtf8(val) => match ty {
223            DataType::Utf8 => Some(ScalarValue::Utf8(val.clone())),
224            DataType::LargeUtf8 => Some(value.clone()),
225            _ => None,
226        },
227        ScalarValue::Boolean(_) => match ty {
228            DataType::Boolean => Some(value.clone()),
229            _ => None,
230        },
231        ScalarValue::Null => Some(value.clone()),
232        ScalarValue::List(values) => {
233            let values = values.clone() as ArrayRef;
234            let new_values = cast(&values, ty).ok()?;
235            match ty {
236                DataType::List(_) => {
237                    Some(ScalarValue::List(Arc::new(new_values.as_list().clone())))
238                }
239                DataType::LargeList(_) => Some(ScalarValue::LargeList(Arc::new(
240                    new_values.as_list().clone(),
241                ))),
242                DataType::FixedSizeList(_, _) => Some(ScalarValue::FixedSizeList(Arc::new(
243                    new_values.as_fixed_size_list().clone(),
244                ))),
245                _ => None,
246            }
247        }
248        ScalarValue::TimestampSecond(seconds, _) => match ty {
249            DataType::Timestamp(TimeUnit::Second, _) => Some(value.clone()),
250            DataType::Timestamp(TimeUnit::Millisecond, tz) => seconds
251                .and_then(|v| v.checked_mul(1000))
252                .map(|val| ScalarValue::TimestampMillisecond(Some(val), tz.clone())),
253            DataType::Timestamp(TimeUnit::Microsecond, tz) => seconds
254                .and_then(|v| v.checked_mul(1000000))
255                .map(|val| ScalarValue::TimestampMicrosecond(Some(val), tz.clone())),
256            DataType::Timestamp(TimeUnit::Nanosecond, tz) => seconds
257                .and_then(|v| v.checked_mul(1000000000))
258                .map(|val| ScalarValue::TimestampNanosecond(Some(val), tz.clone())),
259            _ => None,
260        },
261        ScalarValue::TimestampMillisecond(millis, _) => match ty {
262            DataType::Timestamp(TimeUnit::Second, tz) => {
263                millis.map(|val| ScalarValue::TimestampSecond(Some(val / 1000), tz.clone()))
264            }
265            DataType::Timestamp(TimeUnit::Millisecond, _) => Some(value.clone()),
266            DataType::Timestamp(TimeUnit::Microsecond, tz) => millis
267                .and_then(|v| v.checked_mul(1000))
268                .map(|val| ScalarValue::TimestampMicrosecond(Some(val), tz.clone())),
269            DataType::Timestamp(TimeUnit::Nanosecond, tz) => millis
270                .and_then(|v| v.checked_mul(1000000))
271                .map(|val| ScalarValue::TimestampNanosecond(Some(val), tz.clone())),
272            _ => None,
273        },
274        ScalarValue::TimestampMicrosecond(micros, _) => match ty {
275            DataType::Timestamp(TimeUnit::Second, tz) => {
276                micros.map(|val| ScalarValue::TimestampSecond(Some(val / 1000000), tz.clone()))
277            }
278            DataType::Timestamp(TimeUnit::Millisecond, tz) => {
279                micros.map(|val| ScalarValue::TimestampMillisecond(Some(val / 1000), tz.clone()))
280            }
281            DataType::Timestamp(TimeUnit::Microsecond, _) => Some(value.clone()),
282            DataType::Timestamp(TimeUnit::Nanosecond, tz) => micros
283                .and_then(|v| v.checked_mul(1000))
284                .map(|val| ScalarValue::TimestampNanosecond(Some(val), tz.clone())),
285            _ => None,
286        },
287        ScalarValue::TimestampNanosecond(nanos, _) => {
288            match ty {
289                DataType::Timestamp(TimeUnit::Second, tz) => nanos
290                    .map(|val| ScalarValue::TimestampSecond(Some(val / 1000000000), tz.clone())),
291                DataType::Timestamp(TimeUnit::Millisecond, tz) => nanos
292                    .map(|val| ScalarValue::TimestampMillisecond(Some(val / 1000000), tz.clone())),
293                DataType::Timestamp(TimeUnit::Microsecond, tz) => {
294                    nanos.map(|val| ScalarValue::TimestampMicrosecond(Some(val / 1000), tz.clone()))
295                }
296                DataType::Timestamp(TimeUnit::Nanosecond, _) => Some(value.clone()),
297                _ => None,
298            }
299        }
300        ScalarValue::Date32(ticks) => match ty {
301            DataType::Date32 => Some(value.clone()),
302            DataType::Date64 => Some(ScalarValue::Date64(
303                ticks.map(|v| i64::from(v) * MS_PER_DAY),
304            )),
305            _ => None,
306        },
307        ScalarValue::Date64(ticks) => match ty {
308            DataType::Date32 => Some(ScalarValue::Date32(ticks.map(|v| (v / MS_PER_DAY) as i32))),
309            DataType::Date64 => Some(value.clone()),
310            _ => None,
311        },
312        ScalarValue::Time32Second(seconds) => {
313            match ty {
314                DataType::Time32(TimeUnit::Second) => Some(value.clone()),
315                DataType::Time32(TimeUnit::Millisecond) => {
316                    seconds.map(|val| ScalarValue::Time32Millisecond(Some(val * 1000)))
317                }
318                DataType::Time64(TimeUnit::Microsecond) => seconds
319                    .map(|val| ScalarValue::Time64Microsecond(Some(i64::from(val) * 1000000))),
320                DataType::Time64(TimeUnit::Nanosecond) => seconds
321                    .map(|val| ScalarValue::Time64Nanosecond(Some(i64::from(val) * 1000000000))),
322                _ => None,
323            }
324        }
325        ScalarValue::Time32Millisecond(millis) => match ty {
326            DataType::Time32(TimeUnit::Second) => {
327                millis.map(|val| ScalarValue::Time32Second(Some(val / 1000)))
328            }
329            DataType::Time32(TimeUnit::Millisecond) => Some(value.clone()),
330            DataType::Time64(TimeUnit::Microsecond) => {
331                millis.map(|val| ScalarValue::Time64Microsecond(Some(i64::from(val) * 1000)))
332            }
333            DataType::Time64(TimeUnit::Nanosecond) => {
334                millis.map(|val| ScalarValue::Time64Nanosecond(Some(i64::from(val) * 1000000)))
335            }
336            _ => None,
337        },
338        ScalarValue::Time64Microsecond(micros) => match ty {
339            DataType::Time32(TimeUnit::Second) => {
340                micros.map(|val| ScalarValue::Time32Second(Some((val / 1000000) as i32)))
341            }
342            DataType::Time32(TimeUnit::Millisecond) => {
343                micros.map(|val| ScalarValue::Time32Millisecond(Some((val / 1000) as i32)))
344            }
345            DataType::Time64(TimeUnit::Microsecond) => Some(value.clone()),
346            DataType::Time64(TimeUnit::Nanosecond) => {
347                micros.map(|val| ScalarValue::Time64Nanosecond(Some(val * 1000)))
348            }
349            _ => None,
350        },
351        ScalarValue::Time64Nanosecond(nanos) => match ty {
352            DataType::Time32(TimeUnit::Second) => {
353                nanos.map(|val| ScalarValue::Time32Second(Some((val / 1000000000) as i32)))
354            }
355            DataType::Time32(TimeUnit::Millisecond) => {
356                nanos.map(|val| ScalarValue::Time32Millisecond(Some((val / 1000000) as i32)))
357            }
358            DataType::Time64(TimeUnit::Microsecond) => {
359                nanos.map(|val| ScalarValue::Time64Microsecond(Some(val / 1000)))
360            }
361            DataType::Time64(TimeUnit::Nanosecond) => Some(value.clone()),
362            _ => None,
363        },
364        ScalarValue::LargeList(values) => {
365            let values = values.clone() as ArrayRef;
366            let new_values = cast(&values, ty).ok()?;
367            match ty {
368                DataType::List(_) => {
369                    Some(ScalarValue::List(Arc::new(new_values.as_list().clone())))
370                }
371                DataType::LargeList(_) => Some(ScalarValue::LargeList(Arc::new(
372                    new_values.as_list().clone(),
373                ))),
374                DataType::FixedSizeList(_, _) => Some(ScalarValue::FixedSizeList(Arc::new(
375                    new_values.as_fixed_size_list().clone(),
376                ))),
377                _ => None,
378            }
379        }
380        ScalarValue::FixedSizeList(values) => {
381            let values = values.clone() as ArrayRef;
382            let new_values = cast(&values, ty).ok()?;
383            match ty {
384                DataType::List(_) => {
385                    Some(ScalarValue::List(Arc::new(new_values.as_list().clone())))
386                }
387                DataType::LargeList(_) => Some(ScalarValue::LargeList(Arc::new(
388                    new_values.as_list().clone(),
389                ))),
390                DataType::FixedSizeList(_, _) => Some(ScalarValue::FixedSizeList(Arc::new(
391                    new_values.as_fixed_size_list().clone(),
392                ))),
393                _ => None,
394            }
395        }
396        _ => None,
397    }
398}
399
400#[cfg(test)]
401mod tests {
402    use super::*;
403
404    #[test]
405    fn test_temporal_coerce() {
406        // Conversion from timestamps in one resolution to timestamps in another resolution is allowed
407        // s->s
408        assert_eq!(
409            safe_coerce_scalar(
410                &ScalarValue::TimestampSecond(Some(5), None),
411                &DataType::Timestamp(TimeUnit::Second, None),
412            ),
413            Some(ScalarValue::TimestampSecond(Some(5), None))
414        );
415        // s->ms
416        assert_eq!(
417            safe_coerce_scalar(
418                &ScalarValue::TimestampSecond(Some(5), None),
419                &DataType::Timestamp(TimeUnit::Millisecond, None),
420            ),
421            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
422        );
423        // s->us
424        assert_eq!(
425            safe_coerce_scalar(
426                &ScalarValue::TimestampSecond(Some(5), None),
427                &DataType::Timestamp(TimeUnit::Microsecond, None),
428            ),
429            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
430        );
431        // s->ns
432        assert_eq!(
433            safe_coerce_scalar(
434                &ScalarValue::TimestampSecond(Some(5), None),
435                &DataType::Timestamp(TimeUnit::Nanosecond, None),
436            ),
437            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
438        );
439        // ms->s
440        assert_eq!(
441            safe_coerce_scalar(
442                &ScalarValue::TimestampMillisecond(Some(5000), None),
443                &DataType::Timestamp(TimeUnit::Second, None),
444            ),
445            Some(ScalarValue::TimestampSecond(Some(5), None))
446        );
447        // ms->ms
448        assert_eq!(
449            safe_coerce_scalar(
450                &ScalarValue::TimestampMillisecond(Some(5000), None),
451                &DataType::Timestamp(TimeUnit::Millisecond, None),
452            ),
453            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
454        );
455        // ms->us
456        assert_eq!(
457            safe_coerce_scalar(
458                &ScalarValue::TimestampMillisecond(Some(5000), None),
459                &DataType::Timestamp(TimeUnit::Microsecond, None),
460            ),
461            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
462        );
463        // ms->ns
464        assert_eq!(
465            safe_coerce_scalar(
466                &ScalarValue::TimestampMillisecond(Some(5000), None),
467                &DataType::Timestamp(TimeUnit::Nanosecond, None),
468            ),
469            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
470        );
471        // us->s
472        assert_eq!(
473            safe_coerce_scalar(
474                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
475                &DataType::Timestamp(TimeUnit::Second, None),
476            ),
477            Some(ScalarValue::TimestampSecond(Some(5), None))
478        );
479        // us->ms
480        assert_eq!(
481            safe_coerce_scalar(
482                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
483                &DataType::Timestamp(TimeUnit::Millisecond, None),
484            ),
485            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
486        );
487        // us->us
488        assert_eq!(
489            safe_coerce_scalar(
490                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
491                &DataType::Timestamp(TimeUnit::Microsecond, None),
492            ),
493            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
494        );
495        // us->ns
496        assert_eq!(
497            safe_coerce_scalar(
498                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
499                &DataType::Timestamp(TimeUnit::Nanosecond, None),
500            ),
501            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
502        );
503        // ns->s
504        assert_eq!(
505            safe_coerce_scalar(
506                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
507                &DataType::Timestamp(TimeUnit::Second, None),
508            ),
509            Some(ScalarValue::TimestampSecond(Some(5), None))
510        );
511        // ns->ms
512        assert_eq!(
513            safe_coerce_scalar(
514                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
515                &DataType::Timestamp(TimeUnit::Millisecond, None),
516            ),
517            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
518        );
519        // ns->us
520        assert_eq!(
521            safe_coerce_scalar(
522                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
523                &DataType::Timestamp(TimeUnit::Microsecond, None),
524            ),
525            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
526        );
527        // ns->ns
528        assert_eq!(
529            safe_coerce_scalar(
530                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
531                &DataType::Timestamp(TimeUnit::Nanosecond, None),
532            ),
533            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
534        );
535        // Precision loss on coercion is allowed (truncation)
536        // ns->s
537        assert_eq!(
538            safe_coerce_scalar(
539                &ScalarValue::TimestampNanosecond(Some(5987654321), None),
540                &DataType::Timestamp(TimeUnit::Second, None),
541            ),
542            Some(ScalarValue::TimestampSecond(Some(5), None))
543        );
544        // Conversions from date-32 to date-64 is allowed
545        assert_eq!(
546            safe_coerce_scalar(&ScalarValue::Date32(Some(5)), &DataType::Date32,),
547            Some(ScalarValue::Date32(Some(5)))
548        );
549        assert_eq!(
550            safe_coerce_scalar(&ScalarValue::Date32(Some(5)), &DataType::Date64,),
551            Some(ScalarValue::Date64(Some(5 * MS_PER_DAY)))
552        );
553        assert_eq!(
554            safe_coerce_scalar(
555                &ScalarValue::Date64(Some(5 * MS_PER_DAY)),
556                &DataType::Date32,
557            ),
558            Some(ScalarValue::Date32(Some(5)))
559        );
560        assert_eq!(
561            safe_coerce_scalar(&ScalarValue::Date64(Some(5)), &DataType::Date64,),
562            Some(ScalarValue::Date64(Some(5)))
563        );
564        // Time-32 to time-64 (and within time-32 and time-64) is allowed
565        assert_eq!(
566            safe_coerce_scalar(
567                &ScalarValue::Time32Second(Some(5)),
568                &DataType::Time32(TimeUnit::Second),
569            ),
570            Some(ScalarValue::Time32Second(Some(5)))
571        );
572        assert_eq!(
573            safe_coerce_scalar(
574                &ScalarValue::Time32Second(Some(5)),
575                &DataType::Time32(TimeUnit::Millisecond),
576            ),
577            Some(ScalarValue::Time32Millisecond(Some(5000)))
578        );
579        assert_eq!(
580            safe_coerce_scalar(
581                &ScalarValue::Time32Second(Some(5)),
582                &DataType::Time64(TimeUnit::Microsecond),
583            ),
584            Some(ScalarValue::Time64Microsecond(Some(5000000)))
585        );
586        assert_eq!(
587            safe_coerce_scalar(
588                &ScalarValue::Time32Second(Some(5)),
589                &DataType::Time64(TimeUnit::Nanosecond),
590            ),
591            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
592        );
593        assert_eq!(
594            safe_coerce_scalar(
595                &ScalarValue::Time32Millisecond(Some(5000)),
596                &DataType::Time32(TimeUnit::Second),
597            ),
598            Some(ScalarValue::Time32Second(Some(5)))
599        );
600        assert_eq!(
601            safe_coerce_scalar(
602                &ScalarValue::Time32Millisecond(Some(5000)),
603                &DataType::Time32(TimeUnit::Millisecond),
604            ),
605            Some(ScalarValue::Time32Millisecond(Some(5000)))
606        );
607        assert_eq!(
608            safe_coerce_scalar(
609                &ScalarValue::Time32Millisecond(Some(5000)),
610                &DataType::Time64(TimeUnit::Microsecond),
611            ),
612            Some(ScalarValue::Time64Microsecond(Some(5000000)))
613        );
614        assert_eq!(
615            safe_coerce_scalar(
616                &ScalarValue::Time32Millisecond(Some(5000)),
617                &DataType::Time64(TimeUnit::Nanosecond),
618            ),
619            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
620        );
621        assert_eq!(
622            safe_coerce_scalar(
623                &ScalarValue::Time64Microsecond(Some(5000000)),
624                &DataType::Time32(TimeUnit::Second),
625            ),
626            Some(ScalarValue::Time32Second(Some(5)))
627        );
628        assert_eq!(
629            safe_coerce_scalar(
630                &ScalarValue::Time64Microsecond(Some(5000000)),
631                &DataType::Time32(TimeUnit::Millisecond),
632            ),
633            Some(ScalarValue::Time32Millisecond(Some(5000)))
634        );
635        assert_eq!(
636            safe_coerce_scalar(
637                &ScalarValue::Time64Microsecond(Some(5000000)),
638                &DataType::Time64(TimeUnit::Microsecond),
639            ),
640            Some(ScalarValue::Time64Microsecond(Some(5000000)))
641        );
642        assert_eq!(
643            safe_coerce_scalar(
644                &ScalarValue::Time64Microsecond(Some(5000000)),
645                &DataType::Time64(TimeUnit::Nanosecond),
646            ),
647            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
648        );
649        assert_eq!(
650            safe_coerce_scalar(
651                &ScalarValue::Time64Nanosecond(Some(5000000000)),
652                &DataType::Time32(TimeUnit::Second),
653            ),
654            Some(ScalarValue::Time32Second(Some(5)))
655        );
656        assert_eq!(
657            safe_coerce_scalar(
658                &ScalarValue::Time64Nanosecond(Some(5000000000)),
659                &DataType::Time32(TimeUnit::Millisecond),
660            ),
661            Some(ScalarValue::Time32Millisecond(Some(5000)))
662        );
663        assert_eq!(
664            safe_coerce_scalar(
665                &ScalarValue::Time64Nanosecond(Some(5000000000)),
666                &DataType::Time64(TimeUnit::Microsecond),
667            ),
668            Some(ScalarValue::Time64Microsecond(Some(5000000)))
669        );
670        assert_eq!(
671            safe_coerce_scalar(
672                &ScalarValue::Time64Nanosecond(Some(5000000000)),
673                &DataType::Time64(TimeUnit::Nanosecond),
674            ),
675            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
676        );
677    }
678}