Skip to main content

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            DataType::Decimal128(_, _) | DataType::Decimal256(_, _) => value.cast_to(ty).ok(),
120            _ => None,
121        },
122        ScalarValue::UInt8(val) => match ty {
123            DataType::Int8 => {
124                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
125            }
126            DataType::Int16 => val.map(|v| ScalarValue::Int16(Some(v.into()))),
127            DataType::Int32 => val.map(|v| ScalarValue::Int32(Some(v.into()))),
128            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(v.into()))),
129            DataType::UInt8 => Some(value.clone()),
130            DataType::UInt16 => val.map(|v| ScalarValue::UInt16(Some(u16::from(v)))),
131            DataType::UInt32 => val.map(|v| ScalarValue::UInt32(Some(u32::from(v)))),
132            DataType::UInt64 => val.map(|v| ScalarValue::UInt64(Some(u64::from(v)))),
133            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(f32::from(v)))),
134            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
135            _ => None,
136        },
137        ScalarValue::UInt16(val) => match ty {
138            DataType::Int8 => {
139                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
140            }
141            DataType::Int16 => {
142                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
143            }
144            DataType::Int32 => val.map(|v| ScalarValue::Int32(Some(v.into()))),
145            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(v.into()))),
146            DataType::UInt8 => {
147                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
148            }
149            DataType::UInt16 => Some(value.clone()),
150            DataType::UInt32 => val.map(|v| ScalarValue::UInt32(Some(u32::from(v)))),
151            DataType::UInt64 => val.map(|v| ScalarValue::UInt64(Some(u64::from(v)))),
152            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(f32::from(v)))),
153            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
154            _ => None,
155        },
156        ScalarValue::UInt32(val) => match ty {
157            DataType::Int8 => {
158                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
159            }
160            DataType::Int16 => {
161                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
162            }
163            DataType::Int32 => {
164                val.and_then(|v| i32::try_from(v).map(|v| ScalarValue::Int32(Some(v))).ok())
165            }
166            DataType::Int64 => val.map(|v| ScalarValue::Int64(Some(v.into()))),
167            DataType::UInt8 => {
168                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
169            }
170            DataType::UInt16 => {
171                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
172            }
173            DataType::UInt32 => Some(value.clone()),
174            DataType::UInt64 => val.map(|v| ScalarValue::UInt64(Some(u64::from(v)))),
175            // See above warning about lossy float conversion
176            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
177            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(v as f64))),
178            _ => None,
179        },
180        ScalarValue::UInt64(val) => match ty {
181            DataType::Int8 => {
182                val.and_then(|v| i8::try_from(v).map(|v| ScalarValue::Int8(Some(v))).ok())
183            }
184            DataType::Int16 => {
185                val.and_then(|v| i16::try_from(v).map(|v| ScalarValue::Int16(Some(v))).ok())
186            }
187            DataType::Int32 => {
188                val.and_then(|v| i32::try_from(v).map(|v| ScalarValue::Int32(Some(v))).ok())
189            }
190            DataType::Int64 => {
191                val.and_then(|v| i64::try_from(v).map(|v| ScalarValue::Int64(Some(v))).ok())
192            }
193            DataType::UInt8 => {
194                val.and_then(|v| u8::try_from(v).map(|v| ScalarValue::UInt8(Some(v))).ok())
195            }
196            DataType::UInt16 => {
197                val.and_then(|v| u16::try_from(v).map(|v| ScalarValue::UInt16(Some(v))).ok())
198            }
199            DataType::UInt32 => {
200                val.and_then(|v| u32::try_from(v).map(|v| ScalarValue::UInt32(Some(v))).ok())
201            }
202            DataType::UInt64 => Some(value.clone()),
203            // See above warning about lossy float conversion
204            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
205            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(v as f64))),
206            _ => None,
207        },
208        ScalarValue::Float32(val) => match ty {
209            DataType::Float32 => Some(value.clone()),
210            DataType::Float64 => val.map(|v| ScalarValue::Float64(Some(f64::from(v)))),
211            _ => None,
212        },
213        ScalarValue::Float64(val) => match ty {
214            DataType::Float32 => val.map(|v| ScalarValue::Float32(Some(v as f32))),
215            DataType::Float64 => Some(value.clone()),
216            _ => None,
217        },
218        ScalarValue::Utf8(val) => match ty {
219            DataType::Utf8 => Some(value.clone()),
220            DataType::LargeUtf8 => Some(ScalarValue::LargeUtf8(val.clone())),
221            _ => None,
222        },
223        ScalarValue::LargeUtf8(val) => match ty {
224            DataType::Utf8 => Some(ScalarValue::Utf8(val.clone())),
225            DataType::LargeUtf8 => Some(value.clone()),
226            _ => None,
227        },
228        ScalarValue::Boolean(_) => match ty {
229            DataType::Boolean => Some(value.clone()),
230            _ => None,
231        },
232        ScalarValue::Null => Some(value.clone()),
233        ScalarValue::List(values) => {
234            let values = values.clone() as ArrayRef;
235            let new_values = cast(&values, ty).ok()?;
236            match ty {
237                DataType::List(_) => {
238                    Some(ScalarValue::List(Arc::new(new_values.as_list().clone())))
239                }
240                DataType::LargeList(_) => Some(ScalarValue::LargeList(Arc::new(
241                    new_values.as_list().clone(),
242                ))),
243                DataType::FixedSizeList(_, _) => Some(ScalarValue::FixedSizeList(Arc::new(
244                    new_values.as_fixed_size_list().clone(),
245                ))),
246                _ => None,
247            }
248        }
249        ScalarValue::TimestampSecond(seconds, _) => match ty {
250            DataType::Timestamp(TimeUnit::Second, _) => Some(value.clone()),
251            DataType::Timestamp(TimeUnit::Millisecond, tz) => seconds
252                .and_then(|v| v.checked_mul(1000))
253                .map(|val| ScalarValue::TimestampMillisecond(Some(val), tz.clone())),
254            DataType::Timestamp(TimeUnit::Microsecond, tz) => seconds
255                .and_then(|v| v.checked_mul(1000000))
256                .map(|val| ScalarValue::TimestampMicrosecond(Some(val), tz.clone())),
257            DataType::Timestamp(TimeUnit::Nanosecond, tz) => seconds
258                .and_then(|v| v.checked_mul(1000000000))
259                .map(|val| ScalarValue::TimestampNanosecond(Some(val), tz.clone())),
260            _ => None,
261        },
262        ScalarValue::TimestampMillisecond(millis, _) => match ty {
263            DataType::Timestamp(TimeUnit::Second, tz) => {
264                millis.map(|val| ScalarValue::TimestampSecond(Some(val / 1000), tz.clone()))
265            }
266            DataType::Timestamp(TimeUnit::Millisecond, _) => Some(value.clone()),
267            DataType::Timestamp(TimeUnit::Microsecond, tz) => millis
268                .and_then(|v| v.checked_mul(1000))
269                .map(|val| ScalarValue::TimestampMicrosecond(Some(val), tz.clone())),
270            DataType::Timestamp(TimeUnit::Nanosecond, tz) => millis
271                .and_then(|v| v.checked_mul(1000000))
272                .map(|val| ScalarValue::TimestampNanosecond(Some(val), tz.clone())),
273            _ => None,
274        },
275        ScalarValue::TimestampMicrosecond(micros, _) => match ty {
276            DataType::Timestamp(TimeUnit::Second, tz) => {
277                micros.map(|val| ScalarValue::TimestampSecond(Some(val / 1000000), tz.clone()))
278            }
279            DataType::Timestamp(TimeUnit::Millisecond, tz) => {
280                micros.map(|val| ScalarValue::TimestampMillisecond(Some(val / 1000), tz.clone()))
281            }
282            DataType::Timestamp(TimeUnit::Microsecond, _) => Some(value.clone()),
283            DataType::Timestamp(TimeUnit::Nanosecond, tz) => micros
284                .and_then(|v| v.checked_mul(1000))
285                .map(|val| ScalarValue::TimestampNanosecond(Some(val), tz.clone())),
286            _ => None,
287        },
288        ScalarValue::TimestampNanosecond(nanos, _) => {
289            match ty {
290                DataType::Timestamp(TimeUnit::Second, tz) => nanos
291                    .map(|val| ScalarValue::TimestampSecond(Some(val / 1000000000), tz.clone())),
292                DataType::Timestamp(TimeUnit::Millisecond, tz) => nanos
293                    .map(|val| ScalarValue::TimestampMillisecond(Some(val / 1000000), tz.clone())),
294                DataType::Timestamp(TimeUnit::Microsecond, tz) => {
295                    nanos.map(|val| ScalarValue::TimestampMicrosecond(Some(val / 1000), tz.clone()))
296                }
297                DataType::Timestamp(TimeUnit::Nanosecond, _) => Some(value.clone()),
298                _ => None,
299            }
300        }
301        ScalarValue::Date32(ticks) => match ty {
302            DataType::Date32 => Some(value.clone()),
303            DataType::Date64 => Some(ScalarValue::Date64(
304                ticks.map(|v| i64::from(v) * MS_PER_DAY),
305            )),
306            _ => None,
307        },
308        ScalarValue::Date64(ticks) => match ty {
309            DataType::Date32 => Some(ScalarValue::Date32(ticks.map(|v| (v / MS_PER_DAY) as i32))),
310            DataType::Date64 => Some(value.clone()),
311            _ => None,
312        },
313        ScalarValue::Time32Second(seconds) => {
314            match ty {
315                DataType::Time32(TimeUnit::Second) => Some(value.clone()),
316                DataType::Time32(TimeUnit::Millisecond) => {
317                    seconds.map(|val| ScalarValue::Time32Millisecond(Some(val * 1000)))
318                }
319                DataType::Time64(TimeUnit::Microsecond) => seconds
320                    .map(|val| ScalarValue::Time64Microsecond(Some(i64::from(val) * 1000000))),
321                DataType::Time64(TimeUnit::Nanosecond) => seconds
322                    .map(|val| ScalarValue::Time64Nanosecond(Some(i64::from(val) * 1000000000))),
323                _ => None,
324            }
325        }
326        ScalarValue::Time32Millisecond(millis) => match ty {
327            DataType::Time32(TimeUnit::Second) => {
328                millis.map(|val| ScalarValue::Time32Second(Some(val / 1000)))
329            }
330            DataType::Time32(TimeUnit::Millisecond) => Some(value.clone()),
331            DataType::Time64(TimeUnit::Microsecond) => {
332                millis.map(|val| ScalarValue::Time64Microsecond(Some(i64::from(val) * 1000)))
333            }
334            DataType::Time64(TimeUnit::Nanosecond) => {
335                millis.map(|val| ScalarValue::Time64Nanosecond(Some(i64::from(val) * 1000000)))
336            }
337            _ => None,
338        },
339        ScalarValue::Time64Microsecond(micros) => match ty {
340            DataType::Time32(TimeUnit::Second) => {
341                micros.map(|val| ScalarValue::Time32Second(Some((val / 1000000) as i32)))
342            }
343            DataType::Time32(TimeUnit::Millisecond) => {
344                micros.map(|val| ScalarValue::Time32Millisecond(Some((val / 1000) as i32)))
345            }
346            DataType::Time64(TimeUnit::Microsecond) => Some(value.clone()),
347            DataType::Time64(TimeUnit::Nanosecond) => {
348                micros.map(|val| ScalarValue::Time64Nanosecond(Some(val * 1000)))
349            }
350            _ => None,
351        },
352        ScalarValue::Time64Nanosecond(nanos) => match ty {
353            DataType::Time32(TimeUnit::Second) => {
354                nanos.map(|val| ScalarValue::Time32Second(Some((val / 1000000000) as i32)))
355            }
356            DataType::Time32(TimeUnit::Millisecond) => {
357                nanos.map(|val| ScalarValue::Time32Millisecond(Some((val / 1000000) as i32)))
358            }
359            DataType::Time64(TimeUnit::Microsecond) => {
360                nanos.map(|val| ScalarValue::Time64Microsecond(Some(val / 1000)))
361            }
362            DataType::Time64(TimeUnit::Nanosecond) => Some(value.clone()),
363            _ => None,
364        },
365        ScalarValue::LargeList(values) => {
366            let values = values.clone() as ArrayRef;
367            let new_values = cast(&values, ty).ok()?;
368            match ty {
369                DataType::List(_) => {
370                    Some(ScalarValue::List(Arc::new(new_values.as_list().clone())))
371                }
372                DataType::LargeList(_) => Some(ScalarValue::LargeList(Arc::new(
373                    new_values.as_list().clone(),
374                ))),
375                DataType::FixedSizeList(_, _) => Some(ScalarValue::FixedSizeList(Arc::new(
376                    new_values.as_fixed_size_list().clone(),
377                ))),
378                _ => None,
379            }
380        }
381        ScalarValue::FixedSizeList(values) => {
382            let values = values.clone() as ArrayRef;
383            let new_values = cast(&values, ty).ok()?;
384            match ty {
385                DataType::List(_) => {
386                    Some(ScalarValue::List(Arc::new(new_values.as_list().clone())))
387                }
388                DataType::LargeList(_) => Some(ScalarValue::LargeList(Arc::new(
389                    new_values.as_list().clone(),
390                ))),
391                DataType::FixedSizeList(_, _) => Some(ScalarValue::FixedSizeList(Arc::new(
392                    new_values.as_fixed_size_list().clone(),
393                ))),
394                _ => None,
395            }
396        }
397        ScalarValue::FixedSizeBinary(len, value) => match ty {
398            DataType::FixedSizeBinary(len2) => {
399                if len == len2 {
400                    Some(ScalarValue::FixedSizeBinary(*len, value.clone()))
401                } else {
402                    None
403                }
404            }
405            DataType::Binary => Some(ScalarValue::Binary(value.clone())),
406            _ => None,
407        },
408        ScalarValue::Binary(value) => match ty {
409            DataType::Binary => Some(ScalarValue::Binary(value.clone())),
410            DataType::LargeBinary => Some(ScalarValue::LargeBinary(value.clone())),
411            DataType::FixedSizeBinary(len) => {
412                if let Some(value) = value {
413                    if value.len() == *len as usize {
414                        Some(ScalarValue::FixedSizeBinary(*len, Some(value.clone())))
415                    } else {
416                        None
417                    }
418                } else {
419                    None
420                }
421            }
422            _ => None,
423        },
424        _ => None,
425    }
426}
427
428#[cfg(test)]
429mod tests {
430    use super::*;
431
432    #[test]
433    fn test_temporal_coerce() {
434        // Conversion from timestamps in one resolution to timestamps in another resolution is allowed
435        // s->s
436        assert_eq!(
437            safe_coerce_scalar(
438                &ScalarValue::TimestampSecond(Some(5), None),
439                &DataType::Timestamp(TimeUnit::Second, None),
440            ),
441            Some(ScalarValue::TimestampSecond(Some(5), None))
442        );
443        // s->ms
444        assert_eq!(
445            safe_coerce_scalar(
446                &ScalarValue::TimestampSecond(Some(5), None),
447                &DataType::Timestamp(TimeUnit::Millisecond, None),
448            ),
449            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
450        );
451        // s->us
452        assert_eq!(
453            safe_coerce_scalar(
454                &ScalarValue::TimestampSecond(Some(5), None),
455                &DataType::Timestamp(TimeUnit::Microsecond, None),
456            ),
457            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
458        );
459        // s->ns
460        assert_eq!(
461            safe_coerce_scalar(
462                &ScalarValue::TimestampSecond(Some(5), None),
463                &DataType::Timestamp(TimeUnit::Nanosecond, None),
464            ),
465            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
466        );
467        // ms->s
468        assert_eq!(
469            safe_coerce_scalar(
470                &ScalarValue::TimestampMillisecond(Some(5000), None),
471                &DataType::Timestamp(TimeUnit::Second, None),
472            ),
473            Some(ScalarValue::TimestampSecond(Some(5), None))
474        );
475        // ms->ms
476        assert_eq!(
477            safe_coerce_scalar(
478                &ScalarValue::TimestampMillisecond(Some(5000), None),
479                &DataType::Timestamp(TimeUnit::Millisecond, None),
480            ),
481            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
482        );
483        // ms->us
484        assert_eq!(
485            safe_coerce_scalar(
486                &ScalarValue::TimestampMillisecond(Some(5000), None),
487                &DataType::Timestamp(TimeUnit::Microsecond, None),
488            ),
489            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
490        );
491        // ms->ns
492        assert_eq!(
493            safe_coerce_scalar(
494                &ScalarValue::TimestampMillisecond(Some(5000), None),
495                &DataType::Timestamp(TimeUnit::Nanosecond, None),
496            ),
497            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
498        );
499        // us->s
500        assert_eq!(
501            safe_coerce_scalar(
502                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
503                &DataType::Timestamp(TimeUnit::Second, None),
504            ),
505            Some(ScalarValue::TimestampSecond(Some(5), None))
506        );
507        // us->ms
508        assert_eq!(
509            safe_coerce_scalar(
510                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
511                &DataType::Timestamp(TimeUnit::Millisecond, None),
512            ),
513            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
514        );
515        // us->us
516        assert_eq!(
517            safe_coerce_scalar(
518                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
519                &DataType::Timestamp(TimeUnit::Microsecond, None),
520            ),
521            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
522        );
523        // us->ns
524        assert_eq!(
525            safe_coerce_scalar(
526                &ScalarValue::TimestampMicrosecond(Some(5000000), None),
527                &DataType::Timestamp(TimeUnit::Nanosecond, None),
528            ),
529            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
530        );
531        // ns->s
532        assert_eq!(
533            safe_coerce_scalar(
534                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
535                &DataType::Timestamp(TimeUnit::Second, None),
536            ),
537            Some(ScalarValue::TimestampSecond(Some(5), None))
538        );
539        // ns->ms
540        assert_eq!(
541            safe_coerce_scalar(
542                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
543                &DataType::Timestamp(TimeUnit::Millisecond, None),
544            ),
545            Some(ScalarValue::TimestampMillisecond(Some(5000), None))
546        );
547        // ns->us
548        assert_eq!(
549            safe_coerce_scalar(
550                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
551                &DataType::Timestamp(TimeUnit::Microsecond, None),
552            ),
553            Some(ScalarValue::TimestampMicrosecond(Some(5000000), None))
554        );
555        // ns->ns
556        assert_eq!(
557            safe_coerce_scalar(
558                &ScalarValue::TimestampNanosecond(Some(5000000000), None),
559                &DataType::Timestamp(TimeUnit::Nanosecond, None),
560            ),
561            Some(ScalarValue::TimestampNanosecond(Some(5000000000), None))
562        );
563        // Precision loss on coercion is allowed (truncation)
564        // ns->s
565        assert_eq!(
566            safe_coerce_scalar(
567                &ScalarValue::TimestampNanosecond(Some(5987654321), None),
568                &DataType::Timestamp(TimeUnit::Second, None),
569            ),
570            Some(ScalarValue::TimestampSecond(Some(5), None))
571        );
572        // Conversions from date-32 to date-64 is allowed
573        assert_eq!(
574            safe_coerce_scalar(&ScalarValue::Date32(Some(5)), &DataType::Date32,),
575            Some(ScalarValue::Date32(Some(5)))
576        );
577        assert_eq!(
578            safe_coerce_scalar(&ScalarValue::Date32(Some(5)), &DataType::Date64,),
579            Some(ScalarValue::Date64(Some(5 * MS_PER_DAY)))
580        );
581        assert_eq!(
582            safe_coerce_scalar(
583                &ScalarValue::Date64(Some(5 * MS_PER_DAY)),
584                &DataType::Date32,
585            ),
586            Some(ScalarValue::Date32(Some(5)))
587        );
588        assert_eq!(
589            safe_coerce_scalar(&ScalarValue::Date64(Some(5)), &DataType::Date64,),
590            Some(ScalarValue::Date64(Some(5)))
591        );
592        // Time-32 to time-64 (and within time-32 and time-64) is allowed
593        assert_eq!(
594            safe_coerce_scalar(
595                &ScalarValue::Time32Second(Some(5)),
596                &DataType::Time32(TimeUnit::Second),
597            ),
598            Some(ScalarValue::Time32Second(Some(5)))
599        );
600        assert_eq!(
601            safe_coerce_scalar(
602                &ScalarValue::Time32Second(Some(5)),
603                &DataType::Time32(TimeUnit::Millisecond),
604            ),
605            Some(ScalarValue::Time32Millisecond(Some(5000)))
606        );
607        assert_eq!(
608            safe_coerce_scalar(
609                &ScalarValue::Time32Second(Some(5)),
610                &DataType::Time64(TimeUnit::Microsecond),
611            ),
612            Some(ScalarValue::Time64Microsecond(Some(5000000)))
613        );
614        assert_eq!(
615            safe_coerce_scalar(
616                &ScalarValue::Time32Second(Some(5)),
617                &DataType::Time64(TimeUnit::Nanosecond),
618            ),
619            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
620        );
621        assert_eq!(
622            safe_coerce_scalar(
623                &ScalarValue::Time32Millisecond(Some(5000)),
624                &DataType::Time32(TimeUnit::Second),
625            ),
626            Some(ScalarValue::Time32Second(Some(5)))
627        );
628        assert_eq!(
629            safe_coerce_scalar(
630                &ScalarValue::Time32Millisecond(Some(5000)),
631                &DataType::Time32(TimeUnit::Millisecond),
632            ),
633            Some(ScalarValue::Time32Millisecond(Some(5000)))
634        );
635        assert_eq!(
636            safe_coerce_scalar(
637                &ScalarValue::Time32Millisecond(Some(5000)),
638                &DataType::Time64(TimeUnit::Microsecond),
639            ),
640            Some(ScalarValue::Time64Microsecond(Some(5000000)))
641        );
642        assert_eq!(
643            safe_coerce_scalar(
644                &ScalarValue::Time32Millisecond(Some(5000)),
645                &DataType::Time64(TimeUnit::Nanosecond),
646            ),
647            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
648        );
649        assert_eq!(
650            safe_coerce_scalar(
651                &ScalarValue::Time64Microsecond(Some(5000000)),
652                &DataType::Time32(TimeUnit::Second),
653            ),
654            Some(ScalarValue::Time32Second(Some(5)))
655        );
656        assert_eq!(
657            safe_coerce_scalar(
658                &ScalarValue::Time64Microsecond(Some(5000000)),
659                &DataType::Time32(TimeUnit::Millisecond),
660            ),
661            Some(ScalarValue::Time32Millisecond(Some(5000)))
662        );
663        assert_eq!(
664            safe_coerce_scalar(
665                &ScalarValue::Time64Microsecond(Some(5000000)),
666                &DataType::Time64(TimeUnit::Microsecond),
667            ),
668            Some(ScalarValue::Time64Microsecond(Some(5000000)))
669        );
670        assert_eq!(
671            safe_coerce_scalar(
672                &ScalarValue::Time64Microsecond(Some(5000000)),
673                &DataType::Time64(TimeUnit::Nanosecond),
674            ),
675            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
676        );
677        assert_eq!(
678            safe_coerce_scalar(
679                &ScalarValue::Time64Nanosecond(Some(5000000000)),
680                &DataType::Time32(TimeUnit::Second),
681            ),
682            Some(ScalarValue::Time32Second(Some(5)))
683        );
684        assert_eq!(
685            safe_coerce_scalar(
686                &ScalarValue::Time64Nanosecond(Some(5000000000)),
687                &DataType::Time32(TimeUnit::Millisecond),
688            ),
689            Some(ScalarValue::Time32Millisecond(Some(5000)))
690        );
691        assert_eq!(
692            safe_coerce_scalar(
693                &ScalarValue::Time64Nanosecond(Some(5000000000)),
694                &DataType::Time64(TimeUnit::Microsecond),
695            ),
696            Some(ScalarValue::Time64Microsecond(Some(5000000)))
697        );
698        assert_eq!(
699            safe_coerce_scalar(
700                &ScalarValue::Time64Nanosecond(Some(5000000000)),
701                &DataType::Time64(TimeUnit::Nanosecond),
702            ),
703            Some(ScalarValue::Time64Nanosecond(Some(5000000000)))
704        );
705    }
706}