bpo-41662: Fix bugs in binding parameters in sqlite3 (GH-21998)
* When the parameters argument is a list, correctly handle the case of changing it during iteration. * When the parameters argument is a custom sequence, no longer override an exception raised in ``__len__()``.
This commit is contained in:
parent
dcfaa520c4
commit
0b419b7910
|
@ -270,7 +270,7 @@ class CursorTests(unittest.TestCase):
|
|||
self.assertEqual(row[0], "foo")
|
||||
|
||||
def CheckExecuteParamSequence(self):
|
||||
class L(object):
|
||||
class L:
|
||||
def __len__(self):
|
||||
return 1
|
||||
def __getitem__(self, x):
|
||||
|
@ -282,6 +282,18 @@ class CursorTests(unittest.TestCase):
|
|||
row = self.cu.fetchone()
|
||||
self.assertEqual(row[0], "foo")
|
||||
|
||||
def CheckExecuteParamSequenceBadLen(self):
|
||||
# Issue41662: Error in __len__() was overridden with ProgrammingError.
|
||||
class L:
|
||||
def __len__(self):
|
||||
1/0
|
||||
def __getitem__(slf, x):
|
||||
raise AssertionError
|
||||
|
||||
self.cu.execute("insert into test(name) values ('foo')")
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
self.cu.execute("select name from test where name=?", L())
|
||||
|
||||
def CheckExecuteDictMapping(self):
|
||||
self.cu.execute("insert into test(name) values ('foo')")
|
||||
self.cu.execute("select name from test where name=:name", {"name": "foo"})
|
||||
|
|
|
@ -132,6 +132,19 @@ class RegressionTests(unittest.TestCase):
|
|||
con.execute("insert into foo(bar) values (5)")
|
||||
con.execute(SELECT)
|
||||
|
||||
def CheckBindMutatingList(self):
|
||||
# Issue41662: Crash when mutate a list of parameters during iteration.
|
||||
class X:
|
||||
def __conform__(self, protocol):
|
||||
parameters.clear()
|
||||
return "..."
|
||||
parameters = [X(), 0]
|
||||
con = sqlite.connect(":memory:",detect_types=sqlite.PARSE_DECLTYPES)
|
||||
con.execute("create table foo(bar X, baz integer)")
|
||||
# Should not crash
|
||||
with self.assertRaises(IndexError):
|
||||
con.execute("insert into foo(bar, baz) values (?, ?)", parameters)
|
||||
|
||||
def CheckErrorMsgDecodeError(self):
|
||||
# When porting the module to Python 3.0, the error message about
|
||||
# decoding errors disappeared. This verifies they're back again.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fixed crash when mutate list of parameters during iteration in :mod:`sqlite3`.
|
|
@ -0,0 +1,2 @@
|
|||
No longer override exceptions raised in ``__len__()`` of a sequence of
|
||||
parameters in :mod:`sqlite3` with :exc:`~sqlite3.ProgrammingError`.
|
|
@ -227,6 +227,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
|
|||
num_params = PyList_GET_SIZE(parameters);
|
||||
} else {
|
||||
num_params = PySequence_Size(parameters);
|
||||
if (num_params == -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (num_params != num_params_needed) {
|
||||
PyErr_Format(pysqlite_ProgrammingError,
|
||||
|
@ -238,9 +241,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
|
|||
for (i = 0; i < num_params; i++) {
|
||||
if (PyTuple_CheckExact(parameters)) {
|
||||
current_param = PyTuple_GET_ITEM(parameters, i);
|
||||
Py_XINCREF(current_param);
|
||||
Py_INCREF(current_param);
|
||||
} else if (PyList_CheckExact(parameters)) {
|
||||
current_param = PyList_GET_ITEM(parameters, i);
|
||||
current_param = PyList_GetItem(parameters, i);
|
||||
Py_XINCREF(current_param);
|
||||
} else {
|
||||
current_param = PySequence_GetItem(parameters, i);
|
||||
|
|
Loading…
Reference in New Issue