diff --git a/.cspell.json b/.cspell.json index ab3d229cf..21d401563 100644 --- a/.cspell.json +++ b/.cspell.json @@ -83,6 +83,7 @@ "opargs", "pointee", "pyc", + "qmark", "reborrow", "reborrows", "reparenting", diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index c7ea5b59e..68f8969a0 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -875,7 +875,6 @@ class CursorTests(unittest.TestCase): with self.assertRaises(ZeroDivisionError): self.cu.execute("select name from test where name=?", L()) - @unittest.expectedFailure # TODO: RUSTPYTHON; mixed named and positional parameters not validated def test_execute_named_param_and_sequence(self): dataset = ( ("select :a", (1,)), diff --git a/crates/stdlib/src/_sqlite3.rs b/crates/stdlib/src/_sqlite3.rs index 5f15b0cbc..58d8ad7b3 100644 --- a/crates/stdlib/src/_sqlite3.rs +++ b/crates/stdlib/src/_sqlite3.rs @@ -3208,6 +3208,16 @@ mod _sqlite3 { } for i in 1..=num_needed { + let name = unsafe { sqlite3_bind_parameter_name(self.st, i) }; + if !name.is_null() && unsafe { *name } != b'?' as libc::c_char { + let name_str = ptr_to_str(name, vm)?; + return Err(new_programming_error( + vm, + format!( + "Binding {i} ('{name_str}') is a named parameter, but you supplied a sequence which requires nameless (qmark) placeholders." + ), + )); + } let val = seq.get_item(i as isize - 1, vm)?; self.bind_parameter(i, &val, vm)?; }