From 9b68eb19efa3b2310fcfc92093268bb75d0b7574 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Thu, 4 Jun 2020 22:39:10 +0200 Subject: [PATCH 1/5] fix(sqlx-macros): update trait definitions --- sqlx-core/src/error.rs | 2 +- sqlx-core/src/row.rs | 1 - sqlx-macros/src/derives/decode.rs | 10 +++---- sqlx-macros/src/derives/encode.rs | 47 +++++++++++++++++-------------- sqlx-macros/src/derives/row.rs | 10 +++---- sqlx-macros/src/derives/type.rs | 6 ++-- sqlx-macros/src/query/mod.rs | 2 +- src/lib.rs | 2 +- 8 files changed, 41 insertions(+), 39 deletions(-) diff --git a/sqlx-core/src/error.rs b/sqlx-core/src/error.rs index 11b791ff..3a898fb1 100644 --- a/sqlx-core/src/error.rs +++ b/sqlx-core/src/error.rs @@ -11,7 +11,7 @@ use crate::database::Database; pub type Result = StdResult; // Convenience type alias for usage within SQLx. -pub(crate) type BoxDynError = Box; +pub type BoxDynError = Box; /// An unexpected `NULL` was encountered during decoding. /// diff --git a/sqlx-core/src/row.rs b/sqlx-core/src/row.rs index f9a60b17..2b1e2c48 100644 --- a/sqlx-core/src/row.rs +++ b/sqlx-core/src/row.rs @@ -62,7 +62,6 @@ mod private_column_index { /// This trait is sealed and cannot be implemented for types outside of SQLx. /// /// [`FromRow`]: crate::row::FromRow -/// [`Cursor`]: crate::cursor::Cursor /// [`Query::fetch`]: crate::query::Query::fetch pub trait Row: private_row::Sealed + Unpin + Send + Sync + 'static { type Database: Database; diff --git a/sqlx-macros/src/derives/decode.rs b/sqlx-macros/src/derives/decode.rs index 9fe5cca6..15fbb5b0 100644 --- a/sqlx-macros/src/derives/decode.rs +++ b/sqlx-macros/src/derives/decode.rs @@ -71,7 +71,7 @@ fn expand_derive_decode_transparent( let tts = quote!( impl #impl_generics sqlx::decode::Decode<'de, DB> for #ident #ty_generics #where_clause { - fn decode(value: >::RawValue) -> sqlx::Result { + fn decode(value: >::ValueRef) -> std::result::Result { <#ty as sqlx::decode::Decode<'de, DB>>::decode(value).map(Self) } } @@ -100,13 +100,13 @@ fn expand_derive_decode_weak_enum( Ok(quote!( impl<'de, DB: sqlx::Database> sqlx::decode::Decode<'de, DB> for #ident where #repr: sqlx::decode::Decode<'de, DB> { - fn decode(value: >::RawValue) -> sqlx::Result { + fn decode(value: >::ValueRef) -> std::result::Result { let value = <#repr as sqlx::decode::Decode<'de, DB>>::decode(value)?; match value { #(#arms)* - _ => Err(sqlx::Error::Decode(format!("invalid value {:?} for enum {}", value, #ident_s).into())) + _ => Err(Box::new(sqlx::Error::Decode(format!("invalid value {:?} for enum {}", value, #ident_s).into()))) } } } @@ -140,12 +140,12 @@ fn expand_derive_decode_strong_enum( Ok(quote!( impl<'de, DB: sqlx::Database> sqlx::decode::Decode<'de, DB> for #ident where &'de str: sqlx::decode::Decode<'de, DB> { - fn decode(value: >::RawValue) -> sqlx::Result { + fn decode(value: >::ValueRef) -> std::result::Result { let value = <&'de str as sqlx::decode::Decode<'de, DB>>::decode(value)?; match value { #(#value_arms)* - _ => Err(sqlx::Error::Decode(format!("invalid value {:?} for enum {}", value, #ident_s).into())) + _ => Err(Box::new(sqlx::Error::Decode(format!("invalid value {:?} for enum {}", value, #ident_s).into()))) } } } diff --git a/sqlx-macros/src/derives/encode.rs b/sqlx-macros/src/derives/encode.rs index 12ebb396..fa732e56 100644 --- a/sqlx-macros/src/derives/encode.rs +++ b/sqlx-macros/src/derives/encode.rs @@ -3,12 +3,13 @@ use super::attributes::{ check_weak_enum_attributes, parse_child_attributes, parse_container_attributes, }; use super::rename_all; +use proc_macro2::Span; use quote::quote; use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{ parse_quote, Data, DataEnum, DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed, - FieldsUnnamed, Stmt, Variant, + FieldsUnnamed, Lifetime, Stmt, Variant, }; pub fn expand_derive_encode(input: &DeriveInput) -> syn::Result { @@ -61,22 +62,25 @@ fn expand_derive_encode_transparent( let (_, ty_generics, _) = generics.split_for_impl(); // add db type for impl generics & where clause + let lifetime = Lifetime::new("'q", Span::call_site()); let mut generics = generics.clone(); generics.params.insert(0, parse_quote!(DB: sqlx::Database)); generics .make_where_clause() .predicates - .push(parse_quote!(#ty: sqlx::encode::Encode)); + .push(parse_quote!(#ty: sqlx::encode::Encode<#lifetime, DB>)); let (impl_generics, _, where_clause) = generics.split_for_impl(); Ok(quote!( - impl #impl_generics sqlx::encode::Encode for #ident #ty_generics #where_clause { - fn encode(&self, buf: &mut DB::RawBuffer) { - sqlx::encode::Encode::encode(&self.0, buf) + impl<#lifetime> #impl_generics sqlx::encode::Encode<#lifetime, DB> for #ident #ty_generics #where_clause { + fn encode(self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { + sqlx::encode::Encode::encode(self.0, buf) } - fn encode_nullable(&self, buf: &mut DB::RawBuffer) -> sqlx::encode::IsNull { - sqlx::encode::Encode::encode_nullable(&self.0, buf) + + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { + sqlx::encode::Encode::encode_by_ref(&self.0, buf) } + fn size_hint(&self) -> usize { sqlx::encode::Encode::size_hint(&self.0) } @@ -94,13 +98,13 @@ fn expand_derive_encode_weak_enum( let ident = &input.ident; Ok(quote!( - impl sqlx::encode::Encode for #ident where #repr: sqlx::encode::Encode { - fn encode(&self, buf: &mut DB::RawBuffer) { - sqlx::encode::Encode::encode(&(*self as #repr), buf) + impl<'q, DB: sqlx::Database> sqlx::encode::Encode<'q, DB> for #ident where #repr: sqlx::encode::Encode<'q, DB> { + fn encode(self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { + sqlx::encode::Encode::encode((self as #repr), buf) } - fn encode_nullable(&self, buf: &mut DB::RawBuffer) -> sqlx::encode::IsNull { - sqlx::encode::Encode::encode_nullable(&(*self as #repr), buf) + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { + sqlx::encode::Encode::encode_by_ref(&(*self as #repr), buf) } fn size_hint(&self) -> usize { @@ -136,19 +140,20 @@ fn expand_derive_encode_strong_enum( } Ok(quote!( - impl sqlx::encode::Encode for #ident where str: sqlx::encode::Encode { - fn encode(&self, buf: &mut DB::RawBuffer) { + impl<'q, DB: sqlx::Database> sqlx::encode::Encode<'q, DB> for #ident where str: sqlx::encode::Encode<'q, DB> { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { let val = match self { #(#value_arms)* }; - >::encode(val, buf) + + >::encode_by_ref(val, buf) } fn size_hint(&self) -> usize { let val = match self { #(#value_arms)* }; - >::size_hint(val) + >::size_hint(val) } } )) @@ -177,8 +182,8 @@ fn expand_derive_encode_struct( for field in fields { let ty = &field.ty; - predicates.push(parse_quote!(#ty: sqlx::encode::Encode)); - predicates.push(parse_quote!(#ty: sqlx::types::Type)); + predicates.push(parse_quote!(#ty: sqlx::encode::Encode<'q, sqlx::Postgres>)); + predicates.push(parse_quote!(#ty: sqlx::types::Type<'q, sqlx::Postgres>)); } let (impl_generics, _, where_clause) = generics.split_for_impl(); @@ -202,13 +207,13 @@ fn expand_derive_encode_struct( }); tts.extend(quote!( - impl #impl_generics sqlx::encode::Encode for #ident #ty_generics #where_clause { - fn encode(&self, buf: &mut sqlx::postgres::PgRawBuffer) { + impl<'q> #impl_generics sqlx::encode::Encode<'q, sqlx::Postgres> for #ident #ty_generics #where_clause { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> sqlx::encode::IsNull { let mut encoder = sqlx::postgres::types::raw::PgRecordEncoder::new(buf); #(#writes)* - encoder.finish(); + encoder.finish() } fn size_hint(&self) -> usize { diff --git a/sqlx-macros/src/derives/row.rs b/sqlx-macros/src/derives/row.rs index 7466ebd5..b461cbc6 100644 --- a/sqlx-macros/src/derives/row.rs +++ b/sqlx-macros/src/derives/row.rs @@ -53,9 +53,7 @@ fn expand_derive_from_row_struct( let (_, ty_generics, _) = generics.split_for_impl(); let mut generics = generics.clone(); - generics - .params - .insert(0, parse_quote!(R: sqlx::Row<#lifetime>)); + generics.params.insert(0, parse_quote!(R: sqlx::Row)); if provided { generics.params.insert(0, parse_quote!(#lifetime)); @@ -63,7 +61,7 @@ fn expand_derive_from_row_struct( let predicates = &mut generics.make_where_clause().predicates; - predicates.push(parse_quote!(&#lifetime str: sqlx::row::ColumnIndex<#lifetime, R>)); + predicates.push(parse_quote!(&#lifetime str: sqlx::ColumnIndex)); for field in fields { let ty = &field.ty; @@ -91,8 +89,8 @@ fn expand_derive_from_row_struct( let names = fields.iter().map(|field| &field.ident); Ok(quote!( - impl #impl_generics sqlx::row::FromRow<#lifetime, R> for #ident #ty_generics #where_clause { - fn from_row(row: &R) -> sqlx::Result { + impl #impl_generics sqlx::FromRow<#lifetime, R> for #ident #ty_generics #where_clause { + fn from_row(row: &#lifetime R) -> sqlx::Result { #(#reads)* Ok(#ident { diff --git a/sqlx-macros/src/derives/type.rs b/sqlx-macros/src/derives/type.rs index d72a5511..cbbfe24a 100644 --- a/sqlx-macros/src/derives/type.rs +++ b/sqlx-macros/src/derives/type.rs @@ -64,12 +64,12 @@ fn expand_derive_has_sql_type_transparent( generics .make_where_clause() .predicates - .push(parse_quote!(#ty: sqlx::types::Type)); + .push(parse_quote!(#ty: sqlx::Type)); let (impl_generics, _, where_clause) = generics.split_for_impl(); Ok(quote!( - impl #impl_generics sqlx::types::Type< DB > for #ident #ty_generics #where_clause { + impl #impl_generics sqlx::Type< DB > for #ident #ty_generics #where_clause { fn type_info() -> DB::TypeInfo { <#ty as sqlx::Type>::type_info() } @@ -154,7 +154,7 @@ fn expand_derive_has_sql_type_struct( let ty_name = attributes.rename.unwrap_or_else(|| ident.to_string()); tts.extend(quote!( - impl sqlx::types::Type< sqlx::Postgres > for #ident { + impl sqlx::Type< sqlx::Postgres > for #ident { fn type_info() -> sqlx::postgres::PgTypeInfo { sqlx::postgres::PgTypeInfo::with_name(#ty_name) } diff --git a/sqlx-macros/src/query/mod.rs b/sqlx-macros/src/query/mod.rs index 08ccece7..1300b024 100644 --- a/sqlx-macros/src/query/mod.rs +++ b/sqlx-macros/src/query/mod.rs @@ -226,7 +226,7 @@ where let ret_tokens = quote! { macro_rules! macro_result { (#($#arg_names:expr),*) => {{ - use sqlx::arguments::Arguments as _; + use sqlx::Arguments as _; #args_tokens diff --git a/src/lib.rs b/src/lib.rs index 4a44ec0e..3b1ab4a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ pub use sqlx_core::describe; pub use sqlx_core::types::{self, Type}; #[doc(inline)] -pub use sqlx_core::error::{self, Error, Result}; +pub use sqlx_core::error::{self, BoxDynError, Error, Result}; #[cfg(feature = "mysql")] #[cfg_attr(docsrs, doc(cfg(feature = "mysql")))] From a0d1106f90daccf015ac6ea75d6b537a28186bee Mon Sep 17 00:00:00 2001 From: rage311 Date: Tue, 2 Jun 2020 21:30:23 -0600 Subject: [PATCH 2/5] Added quotes to listen/unlisten channel names to honor case sensitivity and be consistent with 'listen_all()' --- examples/postgres/listen/src/main.rs | 1 + sqlx-core/src/postgres/listener.rs | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/postgres/listen/src/main.rs b/examples/postgres/listen/src/main.rs index 16dd2dfa..dadf7ab9 100644 --- a/examples/postgres/listen/src/main.rs +++ b/examples/postgres/listen/src/main.rs @@ -51,6 +51,7 @@ async fn main() -> Result<(), Box> { async fn notify(mut pool: &PgPool) { static COUNTER: AtomicUsize = AtomicUsize::new(0); + // Note that channel names are lower-cased by Postgres unless they are quoted let res = pool .execute(&*format!( r#" diff --git a/sqlx-core/src/postgres/listener.rs b/sqlx-core/src/postgres/listener.rs index 61437fc8..62f98f66 100644 --- a/sqlx-core/src/postgres/listener.rs +++ b/sqlx-core/src/postgres/listener.rs @@ -64,9 +64,10 @@ impl PgListener { } /// Starts listening for notifications on a channel. + /// The channel name is quoted here to ensure case sensitivity. pub async fn listen(&mut self, channel: &str) -> Result<(), Error> { self.connection() - .execute(&*format!("LISTEN {}", ident(channel))) + .execute(&*format!(r#"LISTEN "{}""#, ident(channel))) .await?; self.channels.push(channel.to_owned()); @@ -92,9 +93,10 @@ impl PgListener { } /// Stops listening for notifications on a channel. + /// The channel name is quoted here to ensure case sensitivity. pub async fn unlisten(&mut self, channel: &str) -> Result<(), Error> { self.connection() - .execute(&*format!("UNLISTEN {}", ident(channel))) + .execute(&*format!(r#"UNLISTEN "{}""#, ident(channel))) .await?; if let Some(pos) = self.channels.iter().position(|s| s == channel) { From e3dbd58bf27555dc58627220e3d19c0252061118 Mon Sep 17 00:00:00 2001 From: Austin Bonander Date: Fri, 5 Jun 2020 19:58:01 -0700 Subject: [PATCH 3/5] PgConnection: use more obvious/safer query for `ping()` --- sqlx-core/src/postgres/connection/mod.rs | 3 ++- tests/postgres/postgres.rs | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sqlx-core/src/postgres/connection/mod.rs b/sqlx-core/src/postgres/connection/mod.rs index 343de9df..a54bd7ab 100644 --- a/sqlx-core/src/postgres/connection/mod.rs +++ b/sqlx-core/src/postgres/connection/mod.rs @@ -117,7 +117,8 @@ impl Connection for PgConnection { } fn ping(&mut self) -> BoxFuture<'_, Result<(), Error>> { - self.execute("SELECT 1").map_ok(|_| ()).boxed() + // By sending a comment we avoid an error if the connection was in the middle of a rowset + self.execute("/* SQLx ping */").map_ok(|_| ()).boxed() } #[doc(hidden)] diff --git a/tests/postgres/postgres.rs b/tests/postgres/postgres.rs index ec319697..4fe44686 100644 --- a/tests/postgres/postgres.rs +++ b/tests/postgres/postgres.rs @@ -1,6 +1,6 @@ use futures::TryStreamExt; use sqlx::postgres::PgRow; -use sqlx::{postgres::Postgres, Executor, Row}; +use sqlx::{postgres::Postgres, Connection, Executor, Row}; use sqlx_core::postgres::{PgDatabaseError, PgErrorPosition, PgSeverity}; use sqlx_test::new; @@ -18,6 +18,15 @@ async fn it_connects() -> anyhow::Result<()> { Ok(()) } +#[sqlx_macros::test] +async fn it_pings() -> anyhow::Result<()> { + let mut conn = new::().await?; + + conn.ping().await?; + + Ok(()) +} + #[sqlx_macros::test] async fn it_maths() -> anyhow::Result<()> { let mut conn = new::().await?; From 1b9ef2b7f299cbd5ebe584efd3f00d7e3a72752e Mon Sep 17 00:00:00 2001 From: Daniel Akhterov Date: Sat, 6 Jun 2020 10:59:44 -0700 Subject: [PATCH 4/5] fix: comment out mssql module --- sqlx-core/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlx-core/src/lib.rs b/sqlx-core/src/lib.rs index 2b868c6e..f01e9a3c 100644 --- a/sqlx-core/src/lib.rs +++ b/sqlx-core/src/lib.rs @@ -60,9 +60,9 @@ pub mod sqlite; #[cfg_attr(docsrs, doc(cfg(feature = "mysql")))] pub mod mysql; -#[cfg(feature = "mssql")] -#[cfg_attr(docsrs, doc(cfg(feature = "mssql")))] -pub mod mssql; +// #[cfg(feature = "mssql")] +// #[cfg_attr(docsrs, doc(cfg(feature = "mssql")))] +// pub mod mssql; #[cfg(feature = "db2")] #[cfg_attr(docsrs, doc(cfg(feature = "db2")))] From 286324766096de33ae8815b78f2dfc773f06bd1e Mon Sep 17 00:00:00 2001 From: Daniel Akhterov Date: Sat, 6 Jun 2020 11:01:40 -0700 Subject: [PATCH 5/5] fix: remove mssql and db2 modules --- sqlx-core/src/lib.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sqlx-core/src/lib.rs b/sqlx-core/src/lib.rs index f01e9a3c..315ab346 100644 --- a/sqlx-core/src/lib.rs +++ b/sqlx-core/src/lib.rs @@ -59,11 +59,3 @@ pub mod sqlite; #[cfg(feature = "mysql")] #[cfg_attr(docsrs, doc(cfg(feature = "mysql")))] pub mod mysql; - -// #[cfg(feature = "mssql")] -// #[cfg_attr(docsrs, doc(cfg(feature = "mssql")))] -// pub mod mssql; - -#[cfg(feature = "db2")] -#[cfg_attr(docsrs, doc(cfg(feature = "db2")))] -pub mod db2;