Skip to content

Commit 3d4db81

Browse files
committed
fix: cast literal to timestamp
1 parent 17b2f11 commit 3d4db81

1 file changed

Lines changed: 68 additions & 4 deletions

File tree

datafusion/optimizer/src/unwrap_cast_in_comparison.rs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,16 +400,40 @@ fn try_cast_literal_to_type(
400400
DataType::UInt32 => ScalarValue::UInt32(Some(value as u32)),
401401
DataType::UInt64 => ScalarValue::UInt64(Some(value as u64)),
402402
DataType::Timestamp(TimeUnit::Second, tz) => {
403-
ScalarValue::TimestampSecond(Some(value as i64), tz.clone())
403+
let value = cast_between_timestamp(
404+
lit_data_type,
405+
DataType::Timestamp(TimeUnit::Second, tz.clone()),
406+
value,
407+
)
408+
.unwrap();
409+
ScalarValue::TimestampSecond(Some(value), tz.clone())
404410
}
405411
DataType::Timestamp(TimeUnit::Millisecond, tz) => {
406-
ScalarValue::TimestampMillisecond(Some(value as i64), tz.clone())
412+
let value = cast_between_timestamp(
413+
lit_data_type,
414+
DataType::Timestamp(TimeUnit::Millisecond, tz.clone()),
415+
value,
416+
)
417+
.unwrap();
418+
ScalarValue::TimestampMillisecond(Some(value), tz.clone())
407419
}
408420
DataType::Timestamp(TimeUnit::Microsecond, tz) => {
409-
ScalarValue::TimestampMicrosecond(Some(value as i64), tz.clone())
421+
let value = cast_between_timestamp(
422+
lit_data_type,
423+
DataType::Timestamp(TimeUnit::Microsecond, tz.clone()),
424+
value,
425+
)
426+
.unwrap();
427+
ScalarValue::TimestampMicrosecond(Some(value), tz.clone())
410428
}
411429
DataType::Timestamp(TimeUnit::Nanosecond, tz) => {
412-
ScalarValue::TimestampNanosecond(Some(value as i64), tz.clone())
430+
let value = cast_between_timestamp(
431+
lit_data_type,
432+
DataType::Timestamp(TimeUnit::Nanosecond, tz.clone()),
433+
value,
434+
)
435+
.unwrap();
436+
ScalarValue::TimestampNanosecond(Some(value), tz.clone())
413437
}
414438
DataType::Decimal128(p, s) => {
415439
ScalarValue::Decimal128(Some(value), *p, *s)
@@ -428,6 +452,31 @@ fn try_cast_literal_to_type(
428452
}
429453
}
430454

455+
/// Cast a timestamp value from one unit to another
456+
fn cast_between_timestamp(from: DataType, to: DataType, value: i128) -> Option<i64> {
457+
let seconds = match from {
458+
DataType::Timestamp(TimeUnit::Second, _) => Some(value * 1000 * 1000 * 1000),
459+
DataType::Timestamp(TimeUnit::Millisecond, _) => Some(value * 1000 * 1000),
460+
DataType::Timestamp(TimeUnit::Microsecond, _) => Some(value * 1000),
461+
DataType::Timestamp(TimeUnit::Nanosecond, _) => Some(value),
462+
_ => return Some(value as i64),
463+
};
464+
465+
match to {
466+
DataType::Timestamp(TimeUnit::Second, _) => {
467+
seconds.map(|s| (s / 1000 / 1000 / 1000) as i64)
468+
}
469+
DataType::Timestamp(TimeUnit::Millisecond, _) => {
470+
seconds.map(|s| (s / 1000 / 1000) as i64)
471+
}
472+
DataType::Timestamp(TimeUnit::Microsecond, _) => {
473+
seconds.map(|s| (s / 1000) as i64)
474+
}
475+
DataType::Timestamp(TimeUnit::Nanosecond, _) => seconds.map(|s| s as i64),
476+
_ => None,
477+
}
478+
}
479+
431480
#[cfg(test)]
432481
mod tests {
433482
use super::*;
@@ -1070,4 +1119,19 @@ mod tests {
10701119
}
10711120
}
10721121
}
1122+
1123+
#[test]
1124+
fn test_try_cast_literal_to_timestamp() {
1125+
let new_scalar = try_cast_literal_to_type(
1126+
&ScalarValue::TimestampNanosecond(Some(123456), None),
1127+
&DataType::Timestamp(TimeUnit::Microsecond, None),
1128+
)
1129+
.unwrap()
1130+
.unwrap();
1131+
1132+
assert_eq!(
1133+
new_scalar,
1134+
ScalarValue::TimestampMicrosecond(Some(123), None)
1135+
);
1136+
}
10731137
}

0 commit comments

Comments
 (0)