From 1c6126cacbe5dec05e997cb7694e0bcf5f01757b Mon Sep 17 00:00:00 2001 From: serejkaaa512 Date: Tue, 16 Nov 2021 12:48:55 +0300 Subject: [PATCH 1/2] added unsigned big integers support for mysql --- src/ast/values.rs | 28 +++++++++++++++++-- src/connector/mssql/conversion.rs | 1 + src/connector/mysql/conversion.rs | 42 +++++++++++++++++----------- src/connector/postgres/conversion.rs | 7 +++++ src/connector/sqlite/conversion.rs | 5 ++++ src/connector/type_identifier.rs | 1 + src/tests/query.rs | 24 +++++++++++++--- src/visitor/mssql.rs | 1 + src/visitor/mysql.rs | 1 + src/visitor/postgres.rs | 1 + src/visitor/sqlite.rs | 1 + 11 files changed, 90 insertions(+), 22 deletions(-) diff --git a/src/ast/values.rs b/src/ast/values.rs index 945664b2e..ad3b2f27a 100644 --- a/src/ast/values.rs +++ b/src/ast/values.rs @@ -40,6 +40,8 @@ where /// compatibility. #[derive(Debug, Clone, PartialEq)] pub enum Value<'a> { + /// 64-bit unsigned integer. + UnsignedInteger(Option), /// 64-bit signed integer. Integer(Option), /// 32-bit floating point. @@ -107,6 +109,7 @@ impl<'a> fmt::Display for Params<'a> { impl<'a> fmt::Display for Value<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let res = match self { + Value::UnsignedInteger(val) => val.map(|v| write!(f, "{}", v)), Value::Integer(val) => val.map(|v| write!(f, "{}", v)), Value::Float(val) => val.map(|v| write!(f, "{}", v)), Value::Double(val) => val.map(|v| write!(f, "{}", v)), @@ -155,6 +158,7 @@ impl<'a> fmt::Display for Value<'a> { impl<'a> From> for serde_json::Value { fn from(pv: Value<'a>) -> Self { let res = match pv { + Value::UnsignedInteger(i) => i.map(|i| serde_json::Value::Number(Number::from(i))), Value::Integer(i) => i.map(|i| serde_json::Value::Number(Number::from(i))), Value::Float(f) => f.map(|f| match Number::from_f64(f as f64) { Some(number) => serde_json::Value::Number(number), @@ -209,6 +213,14 @@ impl<'a> Value<'a> { Value::Integer(Some(value.into())) } + /// Creates a new unsigned integer value. + pub fn unsigned_integer(value: I) -> Self + where + I: Into, + { + Value::UnsignedInteger(Some(value.into())) + } + /// Creates a new decimal value. #[cfg(feature = "bigdecimal")] #[cfg_attr(feature = "docs", doc(cfg(feature = "bigdecimal")))] @@ -321,6 +333,7 @@ impl<'a> Value<'a> { /// `true` if the `Value` is null. pub const fn is_null(&self) -> bool { match self { + Value::UnsignedInteger(i) => i.is_none(), Value::Integer(i) => i.is_none(), Value::Float(i) => i.is_none(), Value::Double(i) => i.is_none(), @@ -412,7 +425,15 @@ impl<'a> Value<'a> { /// `true` if the `Value` is an integer. pub const fn is_integer(&self) -> bool { - matches!(self, Value::Integer(_)) + matches!(self, Value::Integer(_) | Value::UnsignedInteger(_)) + } + + /// Returns an `u64` if the value is an integer, otherwise `None`. + pub const fn as_u64(&self) -> Option { + match self { + Value::UnsignedInteger(i) => *i, + _ => None, + } } /// Returns an `i64` if the value is an integer, otherwise `None`. @@ -476,6 +497,7 @@ impl<'a> Value<'a> { Value::Boolean(_) => true, // For schemas which don't tag booleans Value::Integer(Some(i)) if *i == 0 || *i == 1 => true, + Value::UnsignedInteger(Some(i)) if *i == 0 || *i == 1 => true, _ => false, } } @@ -486,6 +508,7 @@ impl<'a> Value<'a> { Value::Boolean(b) => *b, // For schemas which don't tag booleans Value::Integer(Some(i)) if *i == 0 || *i == 1 => Some(*i == 1), + Value::UnsignedInteger(Some(i)) if *i == 0 || *i == 1 => Some(*i == 1), _ => None, } } @@ -610,10 +633,11 @@ impl<'a> Value<'a> { } value!(val: i64, Integer, val); +value!(val: u64, UnsignedInteger, val); value!(val: bool, Boolean, val); value!(val: &'a str, Text, val.into()); value!(val: String, Text, val.into()); -value!(val: usize, Integer, i64::try_from(val).unwrap()); +value!(val: usize, UnsignedInteger, u64::try_from(val).unwrap()); value!(val: i32, Integer, i64::try_from(val).unwrap()); value!(val: &'a [u8], Bytes, val.into()); value!(val: f64, Double, val); diff --git a/src/connector/mssql/conversion.rs b/src/connector/mssql/conversion.rs index 1e5d2e5bb..1cd0899e0 100644 --- a/src/connector/mssql/conversion.rs +++ b/src/connector/mssql/conversion.rs @@ -20,6 +20,7 @@ pub fn conv_params<'a>(params: &'a [Value<'a>]) -> crate::Result ToSql for Value<'a> { fn to_sql(&self) -> ColumnData<'_> { match self { + Value::UnsignedInteger(_) => panic!("Unsigned integers are not supported on SQL Server."), Value::Integer(val) => val.to_sql(), Value::Float(val) => val.to_sql(), Value::Double(val) => val.to_sql(), diff --git a/src/connector/mysql/conversion.rs b/src/connector/mysql/conversion.rs index 4b769419e..25c3f9b6e 100644 --- a/src/connector/mysql/conversion.rs +++ b/src/connector/mysql/conversion.rs @@ -9,7 +9,6 @@ use mysql_async::{ self as my, consts::{ColumnFlags, ColumnType}, }; -use std::convert::TryFrom; #[tracing::instrument(skip(params))] pub fn conv_params<'a>(params: &[Value<'a>]) -> crate::Result { @@ -22,6 +21,7 @@ pub fn conv_params<'a>(params: &[Value<'a>]) -> crate::Result { for pv in params { let res = match pv { + Value::UnsignedInteger(i) => i.map(my::Value::UInt), Value::Integer(i) => i.map(my::Value::Int), Value::Float(f) => f.map(my::Value::Float), Value::Double(f) => f.map(my::Value::Double), @@ -108,15 +108,29 @@ impl TypeIdentifier for my::Column { fn is_integer(&self) -> bool { use ColumnType::*; - matches!( - self.column_type(), - MYSQL_TYPE_TINY - | MYSQL_TYPE_SHORT - | MYSQL_TYPE_LONG - | MYSQL_TYPE_LONGLONG - | MYSQL_TYPE_YEAR - | MYSQL_TYPE_INT24 - ) + if !self.flags().intersects(ColumnFlags::UNSIGNED_FLAG) { + matches!( + self.column_type(), + MYSQL_TYPE_TINY + | MYSQL_TYPE_SHORT + | MYSQL_TYPE_LONG + | MYSQL_TYPE_LONGLONG + | MYSQL_TYPE_YEAR + | MYSQL_TYPE_INT24 + ) + } else { + false + } + } + + fn is_unsigned_integer(&self) -> bool { + use ColumnType::*; + + if self.flags().intersects(ColumnFlags::UNSIGNED_FLAG) { + matches!(self.column_type(), MYSQL_TYPE_LONG | MYSQL_TYPE_LONGLONG) + } else { + false + } } fn is_datetime(&self) -> bool { @@ -245,12 +259,7 @@ impl TakeRow for my::Row { my::Value::Bytes(b) if column.character_set() == 63 => Value::bytes(b), my::Value::Bytes(s) => Value::text(String::from_utf8(s)?), my::Value::Int(i) => Value::integer(i), - my::Value::UInt(i) => Value::integer(i64::try_from(i).map_err(|_| { - let msg = "Unsigned integers larger than 9_223_372_036_854_775_807 are currently not handled."; - let kind = ErrorKind::value_out_of_range(msg); - - Error::builder(kind).build() - })?), + my::Value::UInt(i) => Value::unsigned_integer(i), my::Value::Float(f) => Value::from(f), my::Value::Double(f) => Value::from(f), #[cfg(feature = "chrono")] @@ -291,6 +300,7 @@ impl TakeRow for my::Row { t if t.is_enum() => Value::Enum(None), t if t.is_null() => Value::Integer(None), t if t.is_integer() => Value::Integer(None), + t if t.is_unsigned_integer() => Value::UnsignedInteger(None), t if t.is_float() => Value::Float(None), t if t.is_double() => Value::Double(None), t if t.is_text() => Value::Text(None), diff --git a/src/connector/postgres/conversion.rs b/src/connector/postgres/conversion.rs index d0109aae0..ce1ea3930 100644 --- a/src/connector/postgres/conversion.rs +++ b/src/connector/postgres/conversion.rs @@ -506,8 +506,15 @@ impl<'a> ToSql for Value<'a> { (Value::Integer(integer), &PostgresType::TEXT) => { integer.map(|integer| format!("{}", integer).to_sql(ty, out)) } + (Value::UnsignedInteger(integer), &PostgresType::TEXT) => { + integer.map(|integer| format!("{}", integer).to_sql(ty, out)) + } (Value::Integer(integer), &PostgresType::OID) => integer.map(|integer| (integer as u32).to_sql(ty, out)), + (Value::UnsignedInteger(integer), &PostgresType::OID) => { + integer.map(|integer| (integer as u32).to_sql(ty, out)) + } (Value::Integer(integer), _) => integer.map(|integer| (integer as i64).to_sql(ty, out)), + (Value::UnsignedInteger(integer), _) => integer.map(|integer| (integer as i64).to_sql(ty, out)), (Value::Float(float), &PostgresType::FLOAT8) => float.map(|float| (float as f64).to_sql(ty, out)), #[cfg(feature = "bigdecimal")] (Value::Float(float), &PostgresType::NUMERIC) => float diff --git a/src/connector/sqlite/conversion.rs b/src/connector/sqlite/conversion.rs index 5d47c3a8c..c23f447b0 100644 --- a/src/connector/sqlite/conversion.rs +++ b/src/connector/sqlite/conversion.rs @@ -63,6 +63,10 @@ impl TypeIdentifier for Column<'_> { ) } + fn is_unsigned_integer(&self) -> bool { + false + } + fn is_datetime(&self) -> bool { matches!( self.decl_type(), @@ -222,6 +226,7 @@ impl<'a> ToColumnNames for SqliteRows<'a> { impl<'a> ToSql for Value<'a> { fn to_sql(&self) -> Result { let value = match self { + Value::UnsignedInteger(_) => panic!("Unsigned integers are not supported in SQLite."), Value::Integer(integer) => integer.map(ToSqlOutput::from), Value::Float(float) => float.map(|f| f as f64).map(ToSqlOutput::from), Value::Double(double) => double.map(ToSqlOutput::from), diff --git a/src/connector/type_identifier.rs b/src/connector/type_identifier.rs index e7c7918a8..a376598ea 100644 --- a/src/connector/type_identifier.rs +++ b/src/connector/type_identifier.rs @@ -3,6 +3,7 @@ pub(crate) trait TypeIdentifier { fn is_float(&self) -> bool; fn is_double(&self) -> bool; fn is_integer(&self) -> bool; + fn is_unsigned_integer(&self) -> bool; fn is_datetime(&self) -> bool; fn is_time(&self) -> bool; fn is_date(&self) -> bool; diff --git a/src/tests/query.rs b/src/tests/query.rs index 6fa2444bf..9c766a0ad 100644 --- a/src/tests/query.rs +++ b/src/tests/query.rs @@ -1295,16 +1295,16 @@ async fn unsigned_integers_are_handled(api: &mut dyn TestApi) -> crate::Result<( let insert = Insert::multi_into(&table, &["big"]) .values((2,)) - .values((std::i64::MAX,)); + .values((std::u64::MAX - 1,)); api.conn().insert(insert.into()).await?; let select = Select::from_table(&table).column("big").order_by("id"); let roundtripped = api.conn().select(select).await?; - let expected = &[2, std::i64::MAX]; - let actual: Vec = roundtripped + let expected = &[2, std::u64::MAX - 1]; + let actual: Vec = roundtripped .into_iter() - .map(|row| row.at(0).unwrap().as_i64().unwrap()) + .map(|row| row.at(0).unwrap().as_u64().unwrap()) .collect(); assert_eq!(actual, expected); @@ -2871,3 +2871,19 @@ async fn delete_comment(api: &mut dyn TestApi) -> crate::Result<()> { Ok(()) } + +#[test_each_connector(tags("mysql"))] +async fn unsigned_integer(api: &mut dyn TestApi) -> crate::Result<()> { + let table = api.create_table("id BIGINT UNSIGNED primary key").await?; + + let insert = Insert::multi_into(&table, &["id"]).values((std::u64::MAX - 1,)); + + api.conn().query(insert.into()).await?; + + let select = Select::from_table(&table).so_that("id".equals(std::u64::MAX - 1)); + let result = api.conn().query(select.into()).await?; + + assert!(!result.is_empty()); + + Ok(()) +} diff --git a/src/visitor/mssql.rs b/src/visitor/mssql.rs index 116ce4d00..4588890ae 100644 --- a/src/visitor/mssql.rs +++ b/src/visitor/mssql.rs @@ -281,6 +281,7 @@ impl<'a> Visitor<'a> for Mssql<'a> { fn visit_raw_value(&mut self, value: Value<'a>) -> visitor::Result { let res = match value { + Value::UnsignedInteger(i) => i.map(|i| self.write(i)), Value::Integer(i) => i.map(|i| self.write(i)), Value::Float(d) => d.map(|f| match f { f if f.is_nan() => self.write("'NaN'"), diff --git a/src/visitor/mysql.rs b/src/visitor/mysql.rs index 7128bbc75..f5769119d 100644 --- a/src/visitor/mysql.rs +++ b/src/visitor/mysql.rs @@ -112,6 +112,7 @@ impl<'a> Visitor<'a> for Mysql<'a> { fn visit_raw_value(&mut self, value: Value<'a>) -> visitor::Result { let res = match value { + Value::UnsignedInteger(i) => i.map(|i| self.write(i)), Value::Integer(i) => i.map(|i| self.write(i)), Value::Float(d) => d.map(|f| match f { f if f.is_nan() => self.write("'NaN'"), diff --git a/src/visitor/postgres.rs b/src/visitor/postgres.rs index 791525c84..76c3b2e14 100644 --- a/src/visitor/postgres.rs +++ b/src/visitor/postgres.rs @@ -71,6 +71,7 @@ impl<'a> Visitor<'a> for Postgres<'a> { fn visit_raw_value(&mut self, value: Value<'a>) -> visitor::Result { let res = match value { + Value::UnsignedInteger(i) => i.map(|i| self.write(i)), Value::Integer(i) => i.map(|i| self.write(i)), Value::Text(t) => t.map(|t| self.write(format!("'{}'", t))), Value::Enum(e) => e.map(|e| self.write(e)), diff --git a/src/visitor/sqlite.rs b/src/visitor/sqlite.rs index 4e3d922f4..b6722bbbf 100644 --- a/src/visitor/sqlite.rs +++ b/src/visitor/sqlite.rs @@ -43,6 +43,7 @@ impl<'a> Visitor<'a> for Sqlite<'a> { fn visit_raw_value(&mut self, value: Value<'a>) -> visitor::Result { let res = match value { + Value::UnsignedInteger(i) => i.map(|i| self.write(i)), Value::Integer(i) => i.map(|i| self.write(i)), Value::Text(t) => t.map(|t| self.write(format!("'{}'", t))), Value::Enum(e) => e.map(|e| self.write(e)), From b838af33a24d1ff5312b71e04e64c71e7ac52a1d Mon Sep 17 00:00:00 2001 From: serejkaaa512 Date: Thu, 18 Nov 2021 13:14:57 +0300 Subject: [PATCH 2/2] improved tests to use unsigned integers --- db/test.db | Bin 12288 -> 12288 bytes src/ast/select.rs | 4 ++-- src/connector/mssql/conversion.rs | 2 +- src/connector/mysql/conversion.rs | 12 ++++-------- src/connector/sqlite/conversion.rs | 2 +- src/serde.rs | 9 +++++++-- src/tests/query/error.rs | 17 ----------------- src/tests/types/mysql.rs | 8 ++++++++ src/tests/types/postgres.rs | 2 +- src/tests/types/sqlite.rs | 2 +- src/visitor/mssql.rs | 16 +++++++++++----- src/visitor/mysql.rs | 11 ++++------- src/visitor/postgres.rs | 11 +++++++---- src/visitor/sqlite.rs | 2 +- 14 files changed, 48 insertions(+), 50 deletions(-) diff --git a/db/test.db b/db/test.db index 8a9f2bd9300245f1b7d196af722e5a261c3fe66b..0de7eeda9d103767447ec88aff2eaf7aaba28c6f 100644 GIT binary patch delta 220 zcmZojXh@hKEoi{Nz`zW}Oh8&;qK+|8P|v@H7sz7}U|`@s%71jTpuiTs$twJ!_542= zstgSo8>LHttP))yQK+rW*eF_(n3R*6oS&DRT9lWXlAB+Wky?}tl#Q2{XKdtz$QC6g zB~_;6rzgW0OwK{Bjv=lJA&yQyt_pBr1&z!Uh0MGXg@U5Y+{B_vh3wQy9fiEa+*F0h c^Y{grtzG3OZ{(K{foq62gflmP=jT)a0Aln)Qvd(} delta 212 zcmZojXh@hKEy&5hz`zW}OhB4#qK+|8P|v@H7sz7}U|`^1&A)oHpuiTs$twJ!UU@0y z8JQ)iiRneDsky0nB}qAn$=QkMqD;;~u8twD3L%b8KCTMb)l8ntuk9HcZ^_7znU|7U dQCye Select<'a> { /// let (sql, params) = Sqlite::build(query)?; /// /// assert_eq!("SELECT `users`.* FROM `users` LIMIT ?", sql); - /// assert_eq!(vec![Value::from(10)], params); + /// assert_eq!(vec![Value::from(10u64)], params); /// # Ok(()) /// # } pub fn limit(mut self, limit: usize) -> Self { @@ -550,7 +550,7 @@ impl<'a> Select<'a> { /// let (sql, params) = Sqlite::build(query)?; /// /// assert_eq!("SELECT `users`.* FROM `users` LIMIT ? OFFSET ?", sql); - /// assert_eq!(vec![Value::from(-1), Value::from(10)], params); + /// assert_eq!(vec![Value::from(-1), Value::from(10u64)], params); /// # Ok(()) /// # } pub fn offset(mut self, offset: usize) -> Self { diff --git a/src/connector/mssql/conversion.rs b/src/connector/mssql/conversion.rs index 1cd0899e0..6f38356ca 100644 --- a/src/connector/mssql/conversion.rs +++ b/src/connector/mssql/conversion.rs @@ -20,7 +20,7 @@ pub fn conv_params<'a>(params: &'a [Value<'a>]) -> crate::Result ToSql for Value<'a> { fn to_sql(&self) -> ColumnData<'_> { match self { - Value::UnsignedInteger(_) => panic!("Unsigned integers are not supported on SQL Server."), + Value::UnsignedInteger(val) => ColumnData::I64((*val).map(|v| v as i64)), Value::Integer(val) => val.to_sql(), Value::Float(val) => val.to_sql(), Value::Double(val) => val.to_sql(), diff --git a/src/connector/mysql/conversion.rs b/src/connector/mysql/conversion.rs index 25c3f9b6e..57a85a386 100644 --- a/src/connector/mysql/conversion.rs +++ b/src/connector/mysql/conversion.rs @@ -108,7 +108,9 @@ impl TypeIdentifier for my::Column { fn is_integer(&self) -> bool { use ColumnType::*; - if !self.flags().intersects(ColumnFlags::UNSIGNED_FLAG) { + if self.flags().intersects(ColumnFlags::UNSIGNED_FLAG) && self.column_type() == MYSQL_TYPE_LONGLONG { + false + } else { matches!( self.column_type(), MYSQL_TYPE_TINY @@ -118,19 +120,13 @@ impl TypeIdentifier for my::Column { | MYSQL_TYPE_YEAR | MYSQL_TYPE_INT24 ) - } else { - false } } fn is_unsigned_integer(&self) -> bool { use ColumnType::*; - if self.flags().intersects(ColumnFlags::UNSIGNED_FLAG) { - matches!(self.column_type(), MYSQL_TYPE_LONG | MYSQL_TYPE_LONGLONG) - } else { - false - } + self.flags().intersects(ColumnFlags::UNSIGNED_FLAG) && self.column_type() == MYSQL_TYPE_LONGLONG } fn is_datetime(&self) -> bool { diff --git a/src/connector/sqlite/conversion.rs b/src/connector/sqlite/conversion.rs index c23f447b0..1486d8e91 100644 --- a/src/connector/sqlite/conversion.rs +++ b/src/connector/sqlite/conversion.rs @@ -226,7 +226,7 @@ impl<'a> ToColumnNames for SqliteRows<'a> { impl<'a> ToSql for Value<'a> { fn to_sql(&self) -> Result { let value = match self { - Value::UnsignedInteger(_) => panic!("Unsigned integers are not supported in SQLite."), + Value::UnsignedInteger(integer) => integer.map(|integer| integer as i64).map(ToSqlOutput::from), Value::Integer(integer) => integer.map(ToSqlOutput::from), Value::Float(float) => float.map(|f| f as f64).map(ToSqlOutput::from), Value::Double(double) => double.map(ToSqlOutput::from), diff --git a/src/serde.rs b/src/serde.rs index 63a9af47f..39ada6669 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -116,6 +116,8 @@ impl<'de> Deserializer<'de> for ValueDeserializer<'de> { Value::Enum(None) => visitor.visit_none(), Value::Integer(Some(i)) => visitor.visit_i64(i), Value::Integer(None) => visitor.visit_none(), + Value::UnsignedInteger(Some(i)) => visitor.visit_u64(i), + Value::UnsignedInteger(None) => visitor.visit_none(), Value::Boolean(Some(b)) => visitor.visit_bool(b), Value::Boolean(None) => visitor.visit_none(), Value::Char(Some(c)) => visitor.visit_char(c), @@ -244,7 +246,10 @@ mod tests { #[test] fn deserialize_user() { - let row = make_row(vec![("id", Value::integer(12)), ("name", "Georgina".into())]); + let row = make_row(vec![ + ("id", Value::unsigned_integer(12u64)), + ("name", "Georgina".into()), + ]); let user: User = from_row(row).unwrap(); assert_eq!( @@ -260,7 +265,7 @@ mod tests { #[test] fn from_rows_works() { let first_row = make_row(vec![ - ("id", Value::integer(12)), + ("id", Value::unsigned_integer(12u64)), ("name", "Georgina".into()), ("bio", Value::Text(None)), ]); diff --git a/src/tests/query/error.rs b/src/tests/query/error.rs index f0bbe1917..e27b99f03 100644 --- a/src/tests/query/error.rs +++ b/src/tests/query/error.rs @@ -171,23 +171,6 @@ async fn int_unsigned_negative_value_out_of_range(api: &mut dyn TestApi) -> crat Ok(()) } -#[test_each_connector(tags("mysql"))] -async fn bigint_unsigned_positive_value_out_of_range(api: &mut dyn TestApi) -> crate::Result<()> { - let table = api - .create_table("id int4 auto_increment primary key, big bigint unsigned") - .await?; - - let insert = format!(r#"INSERT INTO `{}` (`big`) VALUES (18446744073709551615)"#, table); - api.conn().execute_raw(&insert, &[]).await.unwrap(); - let result = api.conn().select(Select::from_table(&table)).await; - - assert!( - matches!(result.unwrap_err().kind(), ErrorKind::ValueOutOfRange { message } if message == "Unsigned integers larger than 9_223_372_036_854_775_807 are currently not handled.") - ); - - Ok(()) -} - #[test_each_connector(tags("mysql", "mssql", "postgresql"))] async fn length_mismatch(api: &mut dyn TestApi) -> crate::Result<()> { let table = api.create_table("value varchar(3)").await?; diff --git a/src/tests/types/mysql.rs b/src/tests/types/mysql.rs index 7c6b84046..c75dc77bb 100644 --- a/src/tests/types/mysql.rs +++ b/src/tests/types/mysql.rs @@ -90,6 +90,14 @@ test_type!(bigint( Value::integer(i64::MAX) )); +test_type!(bigint_unsigned( + mysql, + "bigint unsigned", + Value::UnsignedInteger(None), + Value::unsigned_integer(u64::MIN), + Value::unsigned_integer(u64::MAX) +)); + #[cfg(feature = "bigdecimal")] test_type!(decimal( mysql, diff --git a/src/tests/types/postgres.rs b/src/tests/types/postgres.rs index 77d821f5b..d27368bae 100644 --- a/src/tests/types/postgres.rs +++ b/src/tests/types/postgres.rs @@ -2,7 +2,7 @@ mod bigdecimal; use crate::tests::test_api::*; -#[cfg(feature = "bigdecimal")] +#[allow(unused)] use std::str::FromStr; test_type!(boolean( diff --git a/src/tests/types/sqlite.rs b/src/tests/types/sqlite.rs index b26ae1753..03b94d7bd 100644 --- a/src/tests/types/sqlite.rs +++ b/src/tests/types/sqlite.rs @@ -3,7 +3,7 @@ use crate::tests::test_api::sqlite_test_api; use crate::tests::test_api::TestApi; #[cfg(feature = "chrono")] use crate::{ast::*, connector::Queryable}; -#[cfg(feature = "bigdecimal")] +#[allow(unused)] use std::str::FromStr; test_type!(integer( diff --git a/src/visitor/mssql.rs b/src/visitor/mssql.rs index 4588890ae..ff02d6cbb 100644 --- a/src/visitor/mssql.rs +++ b/src/visitor/mssql.rs @@ -281,7 +281,7 @@ impl<'a> Visitor<'a> for Mssql<'a> { fn visit_raw_value(&mut self, value: Value<'a>) -> visitor::Result { let res = match value { - Value::UnsignedInteger(i) => i.map(|i| self.write(i)), + Value::UnsignedInteger(i) => i.map(|i| self.write(i as i64)), Value::Integer(i) => i.map(|i| self.write(i)), Value::Float(d) => d.map(|f| match f { f if f.is_nan() => self.write("'NaN'"), @@ -1101,7 +1101,7 @@ mod tests { let (sql, params) = Mssql::build(query).unwrap(); assert_eq!(expected_sql, sql); - assert_eq!(vec![Value::integer(0), Value::integer(10)], params); + assert_eq!(vec![Value::integer(0), Value::unsigned_integer(10u64)], params); } #[test] @@ -1111,7 +1111,7 @@ mod tests { let (sql, params) = Mssql::build(query).unwrap(); assert_eq!(expected_sql, sql); - assert_eq!(vec![Value::integer(10)], params); + assert_eq!(vec![Value::unsigned_integer(10u64)], params); } #[test] @@ -1125,7 +1125,10 @@ mod tests { let (sql, params) = Mssql::build(query).unwrap(); assert_eq!(expected_sql, sql); - assert_eq!(vec![Value::integer(10), Value::integer(9)], params); + assert_eq!( + vec![Value::unsigned_integer(10u64), Value::unsigned_integer(9u64)], + params + ); } #[test] @@ -1135,7 +1138,10 @@ mod tests { let (sql, params) = Mssql::build(query).unwrap(); assert_eq!(expected_sql, sql); - assert_eq!(vec![Value::integer(10), Value::integer(9)], params); + assert_eq!( + vec![Value::unsigned_integer(10u64), Value::unsigned_integer(9u64)], + params + ); } #[test] diff --git a/src/visitor/mysql.rs b/src/visitor/mysql.rs index f5769119d..3738df338 100644 --- a/src/visitor/mysql.rs +++ b/src/visitor/mysql.rs @@ -260,7 +260,7 @@ impl<'a> Visitor<'a> for Mysql<'a> { (None, Some(Value::Integer(Some(offset)))) if offset < 1 => Ok(()), (None, Some(offset)) => { self.write(" LIMIT ")?; - self.visit_parameterized(Value::from(9_223_372_036_854_775_807i64))?; + self.visit_parameterized(Value::from(18446744073709551615u64))?; self.write(" OFFSET ")?; self.visit_parameterized(offset) @@ -536,7 +536,7 @@ mod tests { #[test] fn test_limit_and_offset_when_both_are_set() { - let expected = expected_values("SELECT `users`.* FROM `users` LIMIT ? OFFSET ?", vec![10, 2]); + let expected = expected_values("SELECT `users`.* FROM `users` LIMIT ? OFFSET ?", vec![10u64, 2u64]); let query = Select::from_table("users").limit(10).offset(2); let (sql, params) = Mysql::build(query).unwrap(); @@ -546,10 +546,7 @@ mod tests { #[test] fn test_limit_and_offset_when_only_offset_is_set() { - let expected = expected_values( - "SELECT `users`.* FROM `users` LIMIT ? OFFSET ?", - vec![9_223_372_036_854_775_807i64, 10], - ); + let expected = expected_values("SELECT `users`.* FROM `users` LIMIT ? OFFSET ?", vec![u64::MAX, 10u64]); let query = Select::from_table("users").offset(10); let (sql, params) = Mysql::build(query).unwrap(); @@ -560,7 +557,7 @@ mod tests { #[test] fn test_limit_and_offset_when_only_limit_is_set() { - let expected = expected_values("SELECT `users`.* FROM `users` LIMIT ?", vec![10]); + let expected = expected_values("SELECT `users`.* FROM `users` LIMIT ?", vec![10u64]); let query = Select::from_table("users").limit(10); let (sql, params) = Mysql::build(query).unwrap(); diff --git a/src/visitor/postgres.rs b/src/visitor/postgres.rs index 76c3b2e14..a5604bcd6 100644 --- a/src/visitor/postgres.rs +++ b/src/visitor/postgres.rs @@ -71,7 +71,7 @@ impl<'a> Visitor<'a> for Postgres<'a> { fn visit_raw_value(&mut self, value: Value<'a>) -> visitor::Result { let res = match value { - Value::UnsignedInteger(i) => i.map(|i| self.write(i)), + Value::UnsignedInteger(i) => i.map(|i| self.write(i as i64)), Value::Integer(i) => i.map(|i| self.write(i)), Value::Text(t) => t.map(|t| self.write(format!("'{}'", t))), Value::Enum(e) => e.map(|e| self.write(e)), @@ -465,7 +465,10 @@ mod tests { #[test] fn test_limit_and_offset_when_both_are_set() { - let expected = expected_values("SELECT \"users\".* FROM \"users\" LIMIT $1 OFFSET $2", vec![10, 2]); + let expected = expected_values( + "SELECT \"users\".* FROM \"users\" LIMIT $1 OFFSET $2", + vec![10u64, 2u64], + ); let query = Select::from_table("users").limit(10).offset(2); let (sql, params) = Postgres::build(query).unwrap(); @@ -475,7 +478,7 @@ mod tests { #[test] fn test_limit_and_offset_when_only_offset_is_set() { - let expected = expected_values("SELECT \"users\".* FROM \"users\" OFFSET $1", vec![10]); + let expected = expected_values("SELECT \"users\".* FROM \"users\" OFFSET $1", vec![10u64]); let query = Select::from_table("users").offset(10); let (sql, params) = Postgres::build(query).unwrap(); @@ -485,7 +488,7 @@ mod tests { #[test] fn test_limit_and_offset_when_only_limit_is_set() { - let expected = expected_values("SELECT \"users\".* FROM \"users\" LIMIT $1", vec![10]); + let expected = expected_values("SELECT \"users\".* FROM \"users\" LIMIT $1", vec![10u64]); let query = Select::from_table("users").limit(10); let (sql, params) = Postgres::build(query).unwrap(); diff --git a/src/visitor/sqlite.rs b/src/visitor/sqlite.rs index b6722bbbf..dfb8c961c 100644 --- a/src/visitor/sqlite.rs +++ b/src/visitor/sqlite.rs @@ -43,7 +43,7 @@ impl<'a> Visitor<'a> for Sqlite<'a> { fn visit_raw_value(&mut self, value: Value<'a>) -> visitor::Result { let res = match value { - Value::UnsignedInteger(i) => i.map(|i| self.write(i)), + Value::UnsignedInteger(i) => i.map(|i| self.write(i as i64)), Value::Integer(i) => i.map(|i| self.write(i)), Value::Text(t) => t.map(|t| self.write(format!("'{}'", t))), Value::Enum(e) => e.map(|e| self.write(e)),