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__()``.
(cherry picked from commit 0b419b7910)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Miss Islington (bot) 2020-09-17 00:57:07 -07:00 committed by GitHub
parent a9ba8ba9a7
commit f76a3889d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 3 deletions

View File

@ -276,7 +276,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):
@ -288,6 +288,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"})

View File

@ -133,6 +133,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.

View File

@ -0,0 +1 @@
Fixed crash when mutate list of parameters during iteration in :mod:`sqlite3`.

View File

@ -0,0 +1,2 @@
No longer override exceptions raised in ``__len__()`` of a sequence of
parameters in :mod:`sqlite3` with :exc:`~sqlite3.ProgrammingError`.

View File

@ -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);