From 19e38ab8d34283e305696f94b203cdb80f332136 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Mon, 30 Dec 2019 02:01:09 -0800 Subject: [PATCH] [MySQL] [Postgres] Add support for BLOB and BYTEA types --- sqlx-core/src/mysql/types/bytes.rs | 41 +++++++++++++++++++++++++ sqlx-core/src/mysql/types/mod.rs | 1 + sqlx-core/src/postgres/types/bytes.rs | 43 +++++++++++++++++++++++++++ sqlx-core/src/postgres/types/mod.rs | 1 + tests/mysql-types.rs | 21 +++++++++++++ tests/postgres-types.rs | 20 +++++++++++++ 6 files changed, 127 insertions(+) create mode 100644 sqlx-core/src/mysql/types/bytes.rs create mode 100644 sqlx-core/src/postgres/types/bytes.rs diff --git a/sqlx-core/src/mysql/types/bytes.rs b/sqlx-core/src/mysql/types/bytes.rs new file mode 100644 index 00000000..c4b1e030 --- /dev/null +++ b/sqlx-core/src/mysql/types/bytes.rs @@ -0,0 +1,41 @@ +use byteorder::LittleEndian; + +use crate::decode::{Decode, DecodeError}; +use crate::encode::Encode; +use crate::mysql::protocol::Type; +use crate::mysql::types::MySqlTypeMetadata; +use crate::mysql::io::{BufMutExt, BufExt}; +use crate::mysql::MySql; +use crate::types::HasSqlType; + +// TODO: We only have support for BLOB below; we map [u8] to BLOB, as we do not have the size information yet + +impl HasSqlType<[u8]> for MySql { + fn metadata() -> MySqlTypeMetadata { + MySqlTypeMetadata::new(Type::BLOB) + } +} + +impl HasSqlType> for MySql { + fn metadata() -> MySqlTypeMetadata { + >::metadata() + } +} + +impl Encode for [u8] { + fn encode(&self, buf: &mut Vec) { + buf.put_bytes_lenenc::(self); + } +} + +impl Encode for Vec { + fn encode(&self, buf: &mut Vec) { + <[u8] as Encode>::encode(self, buf); + } +} + +impl Decode for Vec { + fn decode(mut buf: &[u8]) -> Result { + Ok(buf.get_bytes_lenenc::()?.unwrap_or_default().to_vec()) + } +} diff --git a/sqlx-core/src/mysql/types/mod.rs b/sqlx-core/src/mysql/types/mod.rs index c53f0866..885c3dfb 100644 --- a/sqlx-core/src/mysql/types/mod.rs +++ b/sqlx-core/src/mysql/types/mod.rs @@ -7,6 +7,7 @@ mod float; mod int; mod str; mod uint; +mod bytes; #[cfg(feature = "chrono")] mod chrono; diff --git a/sqlx-core/src/postgres/types/bytes.rs b/sqlx-core/src/postgres/types/bytes.rs new file mode 100644 index 00000000..9de4cf83 --- /dev/null +++ b/sqlx-core/src/postgres/types/bytes.rs @@ -0,0 +1,43 @@ +use crate::decode::{Decode, DecodeError}; +use crate::encode::Encode; +use crate::postgres::types::PgTypeMetadata; +use crate::postgres::Postgres; +use crate::types::HasSqlType; + +impl HasSqlType<[u8]> for Postgres { + fn metadata() -> PgTypeMetadata { + PgTypeMetadata::binary(17, 1001) + } +} + +impl HasSqlType> for Postgres { + fn metadata() -> Self::TypeMetadata { + >::metadata() + } +} + +impl Encode for [u8] { + fn encode(&self, buf: &mut Vec) { + buf.extend_from_slice(self); + } + + fn size_hint(&self) -> usize { + self.len() + } +} + +impl Encode for Vec { + fn encode(&self, buf: &mut Vec) { + <[u8] as Encode>::encode(self, buf); + } + + fn size_hint(&self) -> usize { + self.len() + } +} + +impl Decode for Vec { + fn decode(buf: &[u8]) -> Result { + Ok(buf.to_vec()) + } +} diff --git a/sqlx-core/src/postgres/types/mod.rs b/sqlx-core/src/postgres/types/mod.rs index 9b005d25..6063182e 100644 --- a/sqlx-core/src/postgres/types/mod.rs +++ b/sqlx-core/src/postgres/types/mod.rs @@ -1,4 +1,5 @@ mod bool; +mod bytes; mod float; mod int; mod str; diff --git a/tests/mysql-types.rs b/tests/mysql-types.rs index d612aab3..23f7f13a 100644 --- a/tests/mysql-types.rs +++ b/tests/mysql-types.rs @@ -44,3 +44,24 @@ test!(mysql_longlong_unsigned: u64: "2141512" == 2141512_u64); test!(mysql_longlong: i64: "2141512" == 2141512_i64); test!(mysql_string: String: "'helloworld'" == "helloworld"); + +#[async_std::test] +async fn mysql_bytes() -> anyhow::Result<()> { + let mut conn = connect().await?; + + let value = b"Hello, World"; + + let row = sqlx::query("SELECT X'48656c6c6f2c20576f726c64' = ?, ?") + .bind(&value[..]) + .bind(&value[..]) + .fetch_one(&mut conn) + .await?; + + assert!(row.get::(0)); + + let output: Vec = row.get(1); + + assert_eq!(&value[..], &*output); + + Ok(()) +} diff --git a/tests/postgres-types.rs b/tests/postgres-types.rs index 2f198a68..5db8b9ff 100644 --- a/tests/postgres-types.rs +++ b/tests/postgres-types.rs @@ -35,3 +35,23 @@ test!(postgres_real: f32: "9419.122::real" == 9419.122_f32); test!(postgres_double: f64: "939399419.1225182::double precision" == 939399419.1225182_f64); test!(postgres_text: String: "'this is foo'" == "this is foo", "''" == ""); + +#[async_std::test] +async fn postgres_bytes() -> anyhow::Result<()> { + let mut conn = connect().await?; + + let value = b"Hello, World"; + + let row = sqlx::query("SELECT E'\\\\x48656c6c6f2c20576f726c64' = $1, $1") + .bind(&value[..]) + .fetch_one(&mut conn) + .await?; + + assert!(row.get::(0)); + + let output: Vec = row.get(1); + + assert_eq!(&value[..], &*output); + + Ok(()) +}