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        ScalarValue::FixedSizeBinary(len, value) => match ty {
397            DataType::FixedSizeBinary(len2) => {
398                if len == len2 {
399                    Some(ScalarValue::FixedSizeBinary(*len, value.clone()))
400                } else {
401                    None
402                }
403            }
404            DataType::Binary => Some(ScalarValue::Binary(value.clone())),
405            _ => None,
406        },
407        ScalarValue::Binary(value) => match ty {
408            DataType::Binary => Some(ScalarValue::Binary(value.clone())),
409            DataType::LargeBinary => Some(ScalarValue::LargeBinary(value.clone())),
410            DataType::FixedSizeBinary(len) => {
411                if let Some(value) = value {
412                    if value.len() == *len as usize {
413                        Some(ScalarValue::FixedSizeBinary(*len, Some(value.clone())))
414                    } else {
415                        None
416                    }
417                } else {
418                    None
419                }
420            }
421            _ => None,
422        },
423        _ => None,
424    }
425}
426
427#[cfg(test)]
428mod tests {
429    use super::*;
430
431    #[test]
432    fn test_temporal_coerce() {
433        // Conversion from timestamps in one resolution to timestamps in another resolution is allowed
434        // s->s
435        assert_eq!(
436            safe_coerce_scalar(
437                &ScalarValue::TimestampSecond(Some(5), None),
438                &DataType::Timestamp(TimeUnit::Second, None),
439            ),
440            Some(ScalarValue::TimestampSecond(Some(5), None))
441        );
442        // s->ms
443        assert_eq!(
444            safe_coerce_scalar(
445                &ScalarValue::TimestampSecond(Some(5), None),
446                &DataType::Timestamp(TimeUnit::Millisecond, None),
447            ),
448            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
449        );
450        // s->us
451        assert_eq!(
452            safe_coerce_scalar(
453                &ScalarValue::TimestampSecond(Some(5), None),
454                &DataType::Timestamp(TimeUnit::Microsecond, None),
455            ),
456            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
457        );
458        // s->ns
459        assert_eq!(
460            safe_coerce_scalar(
461                &ScalarValue::TimestampSecond(Some(5), None),
462                &DataType::Timestamp(TimeUnit::Nanosecond, None),
463            ),
464            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
465        );
466        // ms->s
467        assert_eq!(
468            safe_coerce_scalar(
469                &ScalarValue::TimestampMillisecond(Some(5000), None),
470                &DataType::Timestamp(TimeUnit::Second, None),
471            ),
472            Some(ScalarValue::TimestampSecond(Some(5), None))
473        );
474        // ms->ms
475        assert_eq!(
476            safe_coerce_scalar(
477                &ScalarValue::TimestampMillisecond(Some(5000), None),
478                &DataType::Timestamp(TimeUnit::Millisecond, None),
479            ),
480            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
481        );
482        // ms->us
483        assert_eq!(
484            safe_coerce_scalar(
485                &ScalarValue::TimestampMillisecond(Some(5000), None),
486                &DataType::Timestamp(TimeUnit::Microsecond, None),
487            ),
488            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
489        );
490        // ms->ns
491        assert_eq!(
492            safe_coerce_scalar(
493                &ScalarValue::TimestampMillisecond(Some(5000), None),
494                &DataType::Timestamp(TimeUnit::Nanosecond, None),
495            ),
496            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
497        );
498        // us->s
499        assert_eq!(
500            safe_coerce_scalar(
501                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
502                &DataType::Timestamp(TimeUnit::Second, None),
503            ),
504            Some(ScalarValue::TimestampSecond(Some(5), None))
505        );
506        // us->ms
507        assert_eq!(
508            safe_coerce_scalar(
509                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
510                &DataType::Timestamp(TimeUnit::Millisecond, None),
511            ),
512            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
513        );
514        // us->us
515        assert_eq!(
516            safe_coerce_scalar(
517                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
518                &DataType::Timestamp(TimeUnit::Microsecond, None),
519            ),
520            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
521        );
522        // us->ns
523        assert_eq!(
524            safe_coerce_scalar(
525                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
526                &DataType::Timestamp(TimeUnit::Nanosecond, None),
527            ),
528            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
529        );
530        // ns->s
531        assert_eq!(
532            safe_coerce_scalar(
533                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
534                &DataType::Timestamp(TimeUnit::Second, None),
535            ),
536            Some(ScalarValue::TimestampSecond(Some(5), None))
537        );
538        // ns->ms
539        assert_eq!(
540            safe_coerce_scalar(
541                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
542                &DataType::Timestamp(TimeUnit::Millisecond, None),
543            ),
544            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
545        );
546        // ns->us
547        assert_eq!(
548            safe_coerce_scalar(
549                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
550                &DataType::Timestamp(TimeUnit::Microsecond, None),
551            ),
552            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
553        );
554        // ns->ns
555        assert_eq!(
556            safe_coerce_scalar(
557                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
558                &DataType::Timestamp(TimeUnit::Nanosecond, None),
559            ),
560            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
561        );
562        // Precision loss on coercion is allowed (truncation)
563        // ns->s
564        assert_eq!(
565            safe_coerce_scalar(
566                &ScalarValue::TimestampNanosecond(Some(5987654321), None),
567                &DataType::Timestamp(TimeUnit::Second, None),
568            ),
569            Some(ScalarValue::TimestampSecond(Some(5), None))
570        );
571        // Conversions from date-32 to date-64 is allowed
572        assert_eq!(
573            safe_coerce_scalar(&ScalarValue::Date32(Some(5)), &DataType::Date32,),
574            Some(ScalarValue::Date32(Some(5)))
575        );
576        assert_eq!(
577            safe_coerce_scalar(&ScalarValue::Date32(Some(5)), &DataType::Date64,),
578            Some(ScalarValue::Date64(Some(5 * MS_PER_DAY)))
579        );
580        assert_eq!(
581            safe_coerce_scalar(
582                &ScalarValue::Date64(Some(5 * MS_PER_DAY)),
583                &DataType::Date32,
584            ),
585            Some(ScalarValue::Date32(Some(5)))
586        );
587        assert_eq!(
588            safe_coerce_scalar(&ScalarValue::Date64(Some(5)), &DataType::Date64,),
589            Some(ScalarValue::Date64(Some(5)))
590        );
591        // Time-32 to time-64 (and within time-32 and time-64) is allowed
592        assert_eq!(
593            safe_coerce_scalar(
594                &ScalarValue::Time32Second(Some(5)),
595                &DataType::Time32(TimeUnit::Second),
596            ),
597            Some(ScalarValue::Time32Second(Some(5)))
598        );
599        assert_eq!(
600            safe_coerce_scalar(
601                &ScalarValue::Time32Second(Some(5)),
602                &DataType::Time32(TimeUnit::Millisecond),
603            ),
604            Some(ScalarValue::Time32Millisecond(Some(5000)))
605        );
606        assert_eq!(
607            safe_coerce_scalar(
608                &ScalarValue::Time32Second(Some(5)),
609                &DataType::Time64(TimeUnit::Microsecond),
610            ),
611            Some(ScalarValue::Time64Microsecond(Some(5000000)))
612        );
613        assert_eq!(
614            safe_coerce_scalar(
615                &ScalarValue::Time32Second(Some(5)),
616                &DataType::Time64(TimeUnit::Nanosecond),
617            ),
618            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
619        );
620        assert_eq!(
621            safe_coerce_scalar(
622                &ScalarValue::Time32Millisecond(Some(5000)),
623                &DataType::Time32(TimeUnit::Second),
624            ),
625            Some(ScalarValue::Time32Second(Some(5)))
626        );
627        assert_eq!(
628            safe_coerce_scalar(
629                &ScalarValue::Time32Millisecond(Some(5000)),
630                &DataType::Time32(TimeUnit::Millisecond),
631            ),
632            Some(ScalarValue::Time32Millisecond(Some(5000)))
633        );
634        assert_eq!(
635            safe_coerce_scalar(
636                &ScalarValue::Time32Millisecond(Some(5000)),
637                &DataType::Time64(TimeUnit::Microsecond),
638            ),
639            Some(ScalarValue::Time64Microsecond(Some(5000000)))
640        );
641        assert_eq!(
642            safe_coerce_scalar(
643                &ScalarValue::Time32Millisecond(Some(5000)),
644                &DataType::Time64(TimeUnit::Nanosecond),
645            ),
646            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
647        );
648        assert_eq!(
649            safe_coerce_scalar(
650                &ScalarValue::Time64Microsecond(Some(5000000)),
651                &DataType::Time32(TimeUnit::Second),
652            ),
653            Some(ScalarValue::Time32Second(Some(5)))
654        );
655        assert_eq!(
656            safe_coerce_scalar(
657                &ScalarValue::Time64Microsecond(Some(5000000)),
658                &DataType::Time32(TimeUnit::Millisecond),
659            ),
660            Some(ScalarValue::Time32Millisecond(Some(5000)))
661        );
662        assert_eq!(
663            safe_coerce_scalar(
664                &ScalarValue::Time64Microsecond(Some(5000000)),
665                &DataType::Time64(TimeUnit::Microsecond),
666            ),
667            Some(ScalarValue::Time64Microsecond(Some(5000000)))
668        );
669        assert_eq!(
670            safe_coerce_scalar(
671                &ScalarValue::Time64Microsecond(Some(5000000)),
672                &DataType::Time64(TimeUnit::Nanosecond),
673            ),
674            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
675        );
676        assert_eq!(
677            safe_coerce_scalar(
678                &ScalarValue::Time64Nanosecond(Some(5000000000)),
679                &DataType::Time32(TimeUnit::Second),
680            ),
681            Some(ScalarValue::Time32Second(Some(5)))
682        );
683        assert_eq!(
684            safe_coerce_scalar(
685                &ScalarValue::Time64Nanosecond(Some(5000000000)),
686                &DataType::Time32(TimeUnit::Millisecond),
687            ),
688            Some(ScalarValue::Time32Millisecond(Some(5000)))
689        );
690        assert_eq!(
691            safe_coerce_scalar(
692                &ScalarValue::Time64Nanosecond(Some(5000000000)),
693                &DataType::Time64(TimeUnit::Microsecond),
694            ),
695            Some(ScalarValue::Time64Microsecond(Some(5000000)))
696        );
697        assert_eq!(
698            safe_coerce_scalar(
699                &ScalarValue::Time64Nanosecond(Some(5000000000)),
700                &DataType::Time64(TimeUnit::Nanosecond),
701            ),
702            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
703        );
704    }
705}