diff --git a/sqlx-sqlite/src/value.rs b/sqlx-sqlite/src/value.rs index c66a2501ae..bdf376c187 100644 --- a/sqlx-sqlite/src/value.rs +++ b/sqlx-sqlite/src/value.rs @@ -278,10 +278,14 @@ impl ValueHandle { unsafe { Self::try_dup_of(self.value.as_ptr(), self.column_type.clone()) } } - fn type_info(&self) -> SqliteTypeInfo { - let value_type = SqliteTypeInfo(DataType::from_code(unsafe { + fn value_type_info(&self) -> SqliteTypeInfo { + SqliteTypeInfo(DataType::from_code(unsafe { sqlite3_value_type(self.value.as_ptr()) - })); + })) + } + + fn type_info(&self) -> SqliteTypeInfo { + let value_type = self.value_type_info(); // Assume the actual value type is more accurate, if it's not NULL. match &self.column_type { @@ -305,7 +309,7 @@ impl ValueHandle { } fn is_null(&self) -> bool { - self.type_info().is_null() + self.value_type_info().is_null() } } diff --git a/tests/sqlite/sqlite.rs b/tests/sqlite/sqlite.rs index caa7776041..d8f8ee492c 100644 --- a/tests/sqlite/sqlite.rs +++ b/tests/sqlite/sqlite.rs @@ -1416,3 +1416,25 @@ enum SqliteTransactionState { Read, Write, } + +#[sqlx_macros::test] +async fn issue_3982() -> anyhow::Result<()> { + let mut conn = new::().await?; + + let r = sqlx::raw_sql("insert into products(product_no) values(1)") + .execute(&mut conn) + .await?; + assert_eq!(r.rows_affected(), 1); + + let (name,) = sqlx::query_as::<_, (Option,)>( + r#" + select name from products where name IS NULL + "#, + ) + .fetch_one(&mut conn) + .await?; + + assert_eq!(name, None,); + + Ok(()) +} diff --git a/tests/sqlite/types.rs b/tests/sqlite/types.rs index 4621dcafd1..52531b41c6 100644 --- a/tests/sqlite/types.rs +++ b/tests/sqlite/types.rs @@ -34,6 +34,10 @@ test_type!(str(Sqlite, "''" == "" )); +test_type!(null_str>(Sqlite, + "NULL" == None:: +)); + test_type!(bytes>(Sqlite, "X'DEADBEEF'" == vec![0xDE_u8, 0xAD, 0xBE, 0xEF],