diff --git a/src/servers/src/mysql/helper.rs b/src/servers/src/mysql/helper.rs index e18053a9b793..c933fcc8626c 100644 --- a/src/servers/src/mysql/helper.rs +++ b/src/servers/src/mysql/helper.rs @@ -17,7 +17,9 @@ use std::time::Duration; use chrono::NaiveDate; use common_query::prelude::ScalarValue; +use common_time::Timestamp; use datatypes::prelude::ConcreteDataType; +use datatypes::types::TimestampType; use datatypes::value::{self, Value}; use itertools::Itertools; use opensrv_mysql::{to_naive_datetime, ParamValue, ValueInner}; @@ -161,7 +163,7 @@ pub fn convert_value(param: &ParamValue, t: &ConcreteDataType) -> Result Ok(ScalarValue::Binary(Some(b.to_vec()))), - + ConcreteDataType::Timestamp(ts_type) => covert_bytes_to_timestamp(b, ts_type), _ => error::PreparedStmtTypeMismatchSnafu { expected: t, actual: param.coltype, @@ -235,8 +237,41 @@ pub fn convert_expr_to_scalar_value(param: &Expr, t: &ConcreteDataType) -> Resul } } +fn covert_bytes_to_timestamp(bytes: &[u8], ts_type: &TimestampType) -> Result { + let ts = Timestamp::from_str_utc(&String::from_utf8_lossy(bytes)) + .map_err(|e| { + error::MysqlValueConversionSnafu { + err_msg: e.to_string(), + } + .build() + })? + .convert_to(ts_type.unit()) + .ok_or_else(|| { + error::MysqlValueConversionSnafu { + err_msg: "Overflow when converting timestamp to target unit".to_string(), + } + .build() + })?; + match ts_type { + TimestampType::Nanosecond(_) => { + Ok(ScalarValue::TimestampNanosecond(Some(ts.value()), None)) + } + TimestampType::Microsecond(_) => { + Ok(ScalarValue::TimestampMicrosecond(Some(ts.value()), None)) + } + TimestampType::Millisecond(_) => { + Ok(ScalarValue::TimestampMillisecond(Some(ts.value()), None)) + } + TimestampType::Second(_) => Ok(ScalarValue::TimestampSecond(Some(ts.value()), None)), + } +} + #[cfg(test)] mod tests { + use datatypes::types::{ + TimestampMicrosecondType, TimestampMillisecondType, TimestampNanosecondType, + TimestampSecondType, + }; use sql::dialect::MySqlDialect; use sql::parser::{ParseOptions, ParserContext}; @@ -340,4 +375,87 @@ mod tests { let v = convert_expr_to_scalar_value(&expr, &t).unwrap(); assert_eq!(ScalarValue::Time64Microsecond(None), v); } + + #[test] + fn test_convert_bytes_to_timestamp() { + let test_cases = vec![ + // input unix timestamp in seconds -> nanosecond. + ( + "2024-12-26 12:00:00", + TimestampType::Nanosecond(TimestampNanosecondType), + ScalarValue::TimestampNanosecond(Some(1735214400000000000), None), + ), + // input unix timestamp in seconds -> microsecond. + ( + "2024-12-26 12:00:00", + TimestampType::Microsecond(TimestampMicrosecondType), + ScalarValue::TimestampMicrosecond(Some(1735214400000000), None), + ), + // input unix timestamp in seconds -> millisecond. + ( + "2024-12-26 12:00:00", + TimestampType::Millisecond(TimestampMillisecondType), + ScalarValue::TimestampMillisecond(Some(1735214400000), None), + ), + // input unix timestamp in seconds -> second. + ( + "2024-12-26 12:00:00", + TimestampType::Second(TimestampSecondType), + ScalarValue::TimestampSecond(Some(1735214400), None), + ), + // input unix timestamp in milliseconds -> nanosecond. + ( + "2024-12-26 12:00:00.123", + TimestampType::Nanosecond(TimestampNanosecondType), + ScalarValue::TimestampNanosecond(Some(1735214400123000000), None), + ), + // input unix timestamp in milliseconds -> microsecond. + ( + "2024-12-26 12:00:00.123", + TimestampType::Microsecond(TimestampMicrosecondType), + ScalarValue::TimestampMicrosecond(Some(1735214400123000), None), + ), + // input unix timestamp in milliseconds -> millisecond. + ( + "2024-12-26 12:00:00.123", + TimestampType::Millisecond(TimestampMillisecondType), + ScalarValue::TimestampMillisecond(Some(1735214400123), None), + ), + // input unix timestamp in milliseconds -> second. + ( + "2024-12-26 12:00:00.123", + TimestampType::Second(TimestampSecondType), + ScalarValue::TimestampSecond(Some(1735214400), None), + ), + // input unix timestamp in microseconds -> nanosecond. + ( + "2024-12-26 12:00:00.123456", + TimestampType::Nanosecond(TimestampNanosecondType), + ScalarValue::TimestampNanosecond(Some(1735214400123456000), None), + ), + // input unix timestamp in microseconds -> microsecond. + ( + "2024-12-26 12:00:00.123456", + TimestampType::Microsecond(TimestampMicrosecondType), + ScalarValue::TimestampMicrosecond(Some(1735214400123456), None), + ), + // input unix timestamp in microseconds -> millisecond. + ( + "2024-12-26 12:00:00.123456", + TimestampType::Millisecond(TimestampMillisecondType), + ScalarValue::TimestampMillisecond(Some(1735214400123), None), + ), + // input unix timestamp in milliseconds -> second. + ( + "2024-12-26 12:00:00.123456", + TimestampType::Second(TimestampSecondType), + ScalarValue::TimestampSecond(Some(1735214400), None), + ), + ]; + + for (input, ts_type, expected) in test_cases { + let result = covert_bytes_to_timestamp(input.as_bytes(), &ts_type).unwrap(); + assert_eq!(result, expected); + } + } }