extern crate time_ as time; use std::net::SocketAddr; #[cfg(feature = "rust_decimal")] use std::str::FromStr; use sqlx::mysql::MySql; use sqlx::{Executor, Row}; use sqlx::types::Text; use sqlx::mysql::types::MySqlTime; use sqlx_mysql::types::MySqlTimeSign; use sqlx_test::{new, test_type}; test_type!(bool(MySql, "false" == false, "true" == true)); test_type!(u8(MySql, "CAST(253 AS UNSIGNED)" == 253_u8)); test_type!(i8(MySql, "5" == 5_i8, "0" == 0_i8)); test_type!(u16(MySql, "CAST(21415 AS UNSIGNED)" == 21415_u16)); test_type!(i16(MySql, "21415" == 21415_i16)); test_type!(u32(MySql, "CAST(2141512 AS UNSIGNED)" == 2141512_u32)); test_type!(i32(MySql, "2141512" == 2141512_i32)); test_type!(u64(MySql, "CAST(2141512 AS UNSIGNED)" == 2141512_u64)); test_type!(i64(MySql, "2141512" == 2141512_i64)); test_type!(f64(MySql, "3.14159265e0" == 3.14159265_f64)); // NOTE: This behavior can be very surprising. MySQL implicitly widens FLOAT bind parameters // to DOUBLE. This results in the weirdness you see below. MySQL generally recommends to stay // away from FLOATs. test_type!(f32(MySql, "3.1410000324249268e0" == 3.141f32 as f64 as f32)); test_type!(string(MySql, "'helloworld'" == "helloworld", "''" == "" )); test_type!(bytes>(MySql, "X'DEADBEEF'" == vec![0xDE_u8, 0xAD, 0xBE, 0xEF], "X''" == Vec::::new(), "X'0000000052'" == vec![0_u8, 0, 0, 0, 0x52] )); #[cfg(feature = "uuid")] test_type!(uuid(MySql, "x'b731678f636f4135bc6f19440c13bd19'" == sqlx::types::Uuid::parse_str("b731678f-636f-4135-bc6f-19440c13bd19").unwrap(), "x'00000000000000000000000000000000'" == sqlx::types::Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap() )); #[cfg(feature = "uuid")] test_type!(uuid_hyphenated(MySql, "'b731678f-636f-4135-bc6f-19440c13bd19'" == sqlx::types::Uuid::parse_str("b731678f-636f-4135-bc6f-19440c13bd19").unwrap().hyphenated(), "'00000000-0000-0000-0000-000000000000'" == sqlx::types::Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap().hyphenated() )); #[cfg(feature = "uuid")] test_type!(uuid_simple(MySql, "'b731678f636f4135bc6f19440c13bd19'" == sqlx::types::Uuid::parse_str("b731678f636f4135bc6f19440c13bd19").unwrap().simple(), "'00000000000000000000000000000000'" == sqlx::types::Uuid::parse_str("00000000000000000000000000000000").unwrap().simple() )); test_type!(mysql_time(MySql, "TIME '00:00:00.000000'" == MySqlTime::ZERO, "TIME '-00:00:00.000000'" == MySqlTime::ZERO, "TIME '838:59:59.0'" == MySqlTime::MAX, "TIME '-838:59:59.0'" == MySqlTime::MIN, "TIME '123:45:56.890'" == MySqlTime::new(MySqlTimeSign::Positive, 123, 45, 56, 890_000).unwrap(), "TIME '-123:45:56.890'" == MySqlTime::new(MySqlTimeSign::Negative, 123, 45, 56, 890_000).unwrap(), "TIME '123:45:56.890011'" == MySqlTime::new(MySqlTimeSign::Positive, 123, 45, 56, 890_011).unwrap(), "TIME '-123:45:56.890011'" == MySqlTime::new(MySqlTimeSign::Negative, 123, 45, 56, 890_011).unwrap(), )); #[cfg(feature = "chrono")] mod chrono { use sqlx::types::chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc}; use super::*; test_type!(chrono_date(MySql, "DATE '2001-01-05'" == NaiveDate::from_ymd_opt(2001, 1, 5).unwrap(), "DATE '2050-11-23'" == NaiveDate::from_ymd_opt(2050, 11, 23).unwrap() )); test_type!(chrono_time_zero(MySql, "TIME '00:00:00.000000'" == NaiveTime::from_hms_micro_opt(0, 0, 0, 0).unwrap() )); test_type!(chrono_time(MySql, "TIME '05:10:20.115100'" == NaiveTime::from_hms_micro_opt(5, 10, 20, 115100).unwrap() )); test_type!(chrono_date_time(MySql, "TIMESTAMP '2019-01-02 05:10:20'" == NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_opt(5, 10, 20).unwrap() )); test_type!(chrono_timestamp>(MySql, "TIMESTAMP '2019-01-02 05:10:20.115100'" == Utc.from_utc_datetime( &NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_micro_opt(5, 10, 20, 115100).unwrap(), ) )); #[sqlx_macros::test] async fn test_type_chrono_zero_date() -> anyhow::Result<()> { let mut conn = sqlx_test::new::().await?; // ensure that zero dates are turned on // newer MySQL has these disabled by default conn.execute("SET @@sql_mode := REPLACE(@@sql_mode, 'NO_ZERO_IN_DATE', '');") .await?; conn.execute("SET @@sql_mode := REPLACE(@@sql_mode, 'NO_ZERO_DATE', '');") .await?; // date let row = sqlx::query("SELECT DATE '0000-00-00'") .fetch_one(&mut conn) .await?; let val: Option = row.get(0); assert_eq!(val, None); assert!(row.try_get::(0).is_err()); // datetime let row = sqlx::query("SELECT TIMESTAMP '0000-00-00 00:00:00'") .fetch_one(&mut conn) .await?; let val: Option = row.get(0); assert_eq!(val, None); assert!(row.try_get::(0).is_err()); Ok(()) } } #[cfg(feature = "time")] mod time_tests { use time::macros::{date, time}; use sqlx::types::time::{Date, OffsetDateTime, PrimitiveDateTime, Time}; use super::*; test_type!(time_date( MySql, "DATE '2001-01-05'" == date!(2001 - 1 - 5), "DATE '2050-11-23'" == date!(2050 - 11 - 23) )); test_type!(time_time_zero