Skip to content

Commit cc6c638

Browse files
authored
sqlite3: raise ProgrammingError when named param receives sequence (#8363)
CPython raises ProgrammingError with "Binding N is a named parameter" when a query uses named placeholders (, , ) but the caller passes a sequence instead of a mapping. RustPython's bind_parameters_sequence() did not check whether each binding slot is a named parameter, so no error was raised. Fix: call sqlite3_bind_parameter_name() for each slot in bind_parameters_sequence(). If the first byte of the returned name is not '?' (i.e. it is a named placeholder), raise ProgrammingError before attempting to bind. Assisted-by: GitHub Copilot:claude-sonnet-4-6
1 parent 003ebec commit cc6c638

3 files changed

Lines changed: 11 additions & 1 deletion

File tree

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"opargs",
8484
"pointee",
8585
"pyc",
86+
"qmark",
8687
"reborrow",
8788
"reborrows",
8889
"reparenting",

Lib/test/test_sqlite3/test_dbapi.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,6 @@ def __getitem__(slf, x):
875875
with self.assertRaises(ZeroDivisionError):
876876
self.cu.execute("select name from test where name=?", L())
877877

878-
@unittest.expectedFailure # TODO: RUSTPYTHON; mixed named and positional parameters not validated
879878
def test_execute_named_param_and_sequence(self):
880879
dataset = (
881880
("select :a", (1,)),

crates/stdlib/src/_sqlite3.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,6 +3208,16 @@ mod _sqlite3 {
32083208
}
32093209

32103210
for i in 1..=num_needed {
3211+
let name = unsafe { sqlite3_bind_parameter_name(self.st, i) };
3212+
if !name.is_null() && unsafe { *name } != b'?' as libc::c_char {
3213+
let name_str = ptr_to_str(name, vm)?;
3214+
return Err(new_programming_error(
3215+
vm,
3216+
format!(
3217+
"Binding {i} ('{name_str}') is a named parameter, but you supplied a sequence which requires nameless (qmark) placeholders."
3218+
),
3219+
));
3220+
}
32113221
let val = seq.get_item(i as isize - 1, vm)?;
32123222
self.bind_parameter(i, &val, vm)?;
32133223
}

0 commit comments

Comments
 (0)