Skip to content

Commit e4d9613

Browse files
authored
MSSQL: preserve bound type for NULL parameter declarations (#59)
* fix: satisfy clippy on latest stable * ci: pin clippy to Rust 1.98.1 * fix(clippy): remove redundant formatting borrow * test: remove useless format in postgres type fixture * ci: use pinned toolchain action without ignored input * fix(mssql): declare NULL parameters using their Rust type * test(mssql): cover null parameter declarations * test(mssql): replace null declaration test with ISNULL query covering #58 Replace test_null_argument_uses_bound_type_for_declaration with a test that builds SELECT ISNULL(@p1, N'hello') via QueryBuilder, referencing #58 * test(mssql): e2e test for ISNULL with null parameter (issue #58) Replace unit test with an end-to-end test asserting SELECT ISNULL(@p1, N'hello') with a null bind returns 'hello'. Closes #58 * fmt * Fix MSSQL null varbinary declarations
1 parent 5119742 commit e4d9613

4 files changed

Lines changed: 25 additions & 3 deletions

File tree

‎sqlx-core/src/mssql/arguments.rs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ impl MssqlArguments {
6565
T: Encode<'q, Mssql> + Type<Mssql>,
6666
{
6767
let ty = value.produces().unwrap_or_else(T::type_info);
68+
// `DataType::Null` is required in TDS for null values, but the
69+
// `sp_executesql` declaration needs the parameter's Rust type.
70+
let declaration_ty = if ty.0.is_null() {
71+
T::type_info()
72+
} else {
73+
ty.clone()
74+
};
6875

6976
// produce an ordinal parameter name
7077
// @p1, @p2, ... @pN
@@ -91,7 +98,7 @@ impl MssqlArguments {
9198

9299
declarations.push_str(name);
93100
declarations.push(' ');
94-
ty.0.fmt(declarations);
101+
declaration_ty.0.fmt(declarations);
95102

96103
// write out the parameter
97104

‎sqlx-core/src/mssql/types/bytes.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::borrow::Cow;
88

99
impl Type<Mssql> for [u8] {
1010
fn type_info() -> MssqlTypeInfo {
11-
MssqlTypeInfo(TypeInfo::new(DataType::BigVarBinary, 0))
11+
MssqlTypeInfo(TypeInfo::new(DataType::BigVarBinary, 0xFF_FF))
1212
}
1313

1414
fn compatible(ty: &MssqlTypeInfo) -> bool {

‎sqlx-core/src/mssql/types/json.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
99

1010
impl<T> Type<Mssql> for Json<T> {
1111
fn type_info() -> MssqlTypeInfo {
12-
MssqlTypeInfo(TypeInfo::new(DataType::BigVarBinary, 0))
12+
MssqlTypeInfo(TypeInfo::new(DataType::BigVarBinary, 0xFF_FF))
1313
}
1414

1515
fn compatible(ty: &MssqlTypeInfo) -> bool {

‎tests/mssql/mssql.rs‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,21 @@ async fn it_binds_empty_string_and_null() -> anyhow::Result<()> {
193193
Ok(())
194194
}
195195

196+
// Regression test for https://github.com/sqlpage/sqlx-oldapi/issues/58
197+
#[sqlx_macros::test]
198+
async fn it_binds_null_with_type_in_isnull_expression() -> anyhow::Result<()> {
199+
let mut conn = new::<Mssql>().await?;
200+
201+
let (val,): (String,) = sqlx_oldapi::query_as("SELECT ISNULL(@p1, N'hello')")
202+
.bind(None::<String>)
203+
.fetch_one(&mut conn)
204+
.await?;
205+
206+
assert_eq!(val, "hello");
207+
208+
Ok(())
209+
}
210+
196211
#[sqlx_macros::test]
197212
async fn it_binds_string_with_special_chars() -> anyhow::Result<()> {
198213
let mut conn = new::<Mssql>().await?;

0 commit comments

Comments
 (0)