feat(mysql): support reading and writing BIT via unsigned integers

e.g., BIT(64) is u64 and BIT(2) is u8
This commit is contained in:
Ryan Leckey 2020-07-26 19:38:48 -07:00
parent 7b132d1dbc
commit ec0e84d8ac
3 changed files with 53 additions and 4 deletions

View File

@ -1,7 +1,5 @@
use std::convert::TryInto;
use byteorder::{ByteOrder, LittleEndian};
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
@ -14,6 +12,7 @@ fn uint_type_info(ty: ColumnType) -> MySqlTypeInfo {
r#type: ty,
flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,
char_set: 63,
max_size: None,
}
}
@ -26,6 +25,7 @@ fn uint_compatible(ty: &MySqlTypeInfo) -> bool {
| ColumnType::Int24
| ColumnType::LongLong
| ColumnType::Year
| ColumnType::Bit
) && ty.flags.contains(ColumnFlags::UNSIGNED)
}
@ -102,8 +102,22 @@ impl Encode<'_, MySql> for u64 {
}
fn uint_decode(value: MySqlValueRef<'_>) -> Result<u64, BoxDynError> {
if value.type_info.r#type == ColumnType::Bit {
// NOTE: Regardless of the value format, there is raw binary data here
let buf = value.as_bytes()?;
let mut value: u64 = 0;
for b in buf {
value = (*b as u64) | (value << 8);
}
return Ok(value);
}
Ok(match value.format() {
MySqlValueFormat::Text => value.as_str()?.parse()?,
MySqlValueFormat::Binary => {
let buf = value.as_bytes()?;
LittleEndian::read_uint(buf, buf.len())

View File

@ -12,10 +12,10 @@ type Error = Box<dyn std::error::Error>;
type Result<T> = std::result::Result<T, Error>;
mod common;
mod database;
mod derives;
mod query;
mod common;
#[cfg(feature = "migrate")]
mod migrate;

View File

@ -5,7 +5,7 @@ use std::str::FromStr;
use sqlx::mysql::MySql;
use sqlx::{Executor, Row};
use sqlx_test::test_type;
use sqlx_test::{test_type, new};
test_type!(bool(MySql, "false" == false, "true" == true));
@ -251,3 +251,38 @@ mod json_tests {
"\'{\"json_column\":[1,2]}\'" == Json(Customer { json_column: Json(vec![1, 2]) })
));
}
#[sqlx_macros::test]
async fn test_bits() -> anyhow::Result<()> {
let mut conn = new::<MySql>().await?;
conn.execute(r#"
CREATE TEMPORARY TABLE with_bits (
id INT PRIMARY KEY AUTO_INCREMENT,
value_1 BIT(1) NOT NULL,
value_n BIT(64) NOT NULL
);
"#).await?;
sqlx::query("INSERT INTO with_bits (value_1, value_n) VALUES (?, ?)")
.bind(&1_u8)
.bind(&510202_u32)
.execute(&mut conn)
.await?;
// BINARY
let (v1, vn): (u8, u64) = sqlx::query_as("SELECT value_1, value_n FROM with_bits").fetch_one(&mut conn).await?;
assert_eq!(v1, 1);
assert_eq!(vn, 510202);
// TEXT
let row = conn.fetch_one("SELECT value_1, value_n FROM with_bits").await?;
let v1: u8 = row.try_get(0)?;
let vn: u64 = row.try_get(1)?;
assert_eq!(v1, 1);
assert_eq!(vn, 510202);
Ok(())
}