mirror of
https://github.com/python/cpython.git
synced 2025-09-27 18:59:43 +00:00
bpo-42213: Check connection in sqlite3.Connection.__enter__ (GH-26512)
Try to harden connection close: - add tests that exercise stuff against a closed database - add wrapper for sqlite3_close_v2() - check connection on __enter__ - explicitly free pending statements before close() - sqlite3_close_v2() always returns SQLITE_OK
This commit is contained in:
parent
937cebc93b
commit
82ad22a97d
2 changed files with 35 additions and 16 deletions
|
@ -135,6 +135,26 @@ class ConnectionTests(unittest.TestCase):
|
||||||
def test_close(self):
|
def test_close(self):
|
||||||
self.cx.close()
|
self.cx.close()
|
||||||
|
|
||||||
|
def test_use_after_close(self):
|
||||||
|
sql = "select 1"
|
||||||
|
cu = self.cx.cursor()
|
||||||
|
res = cu.execute(sql)
|
||||||
|
self.cx.close()
|
||||||
|
self.assertRaises(sqlite.ProgrammingError, res.fetchall)
|
||||||
|
self.assertRaises(sqlite.ProgrammingError, cu.execute, sql)
|
||||||
|
self.assertRaises(sqlite.ProgrammingError, cu.executemany, sql, [])
|
||||||
|
self.assertRaises(sqlite.ProgrammingError, cu.executescript, sql)
|
||||||
|
self.assertRaises(sqlite.ProgrammingError, self.cx.execute, sql)
|
||||||
|
self.assertRaises(sqlite.ProgrammingError,
|
||||||
|
self.cx.executemany, sql, [])
|
||||||
|
self.assertRaises(sqlite.ProgrammingError, self.cx.executescript, sql)
|
||||||
|
self.assertRaises(sqlite.ProgrammingError,
|
||||||
|
self.cx.create_function, "t", 1, lambda x: x)
|
||||||
|
self.assertRaises(sqlite.ProgrammingError, self.cx.cursor)
|
||||||
|
with self.assertRaises(sqlite.ProgrammingError):
|
||||||
|
with self.cx:
|
||||||
|
pass
|
||||||
|
|
||||||
def test_exceptions(self):
|
def test_exceptions(self):
|
||||||
# Optional DB-API extension.
|
# Optional DB-API extension.
|
||||||
self.assertEqual(self.cx.Warning, sqlite.Warning)
|
self.assertEqual(self.cx.Warning, sqlite.Warning)
|
||||||
|
|
|
@ -258,6 +258,16 @@ connection_clear(pysqlite_Connection *self)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
connection_close(pysqlite_Connection *self)
|
||||||
|
{
|
||||||
|
if (self->db) {
|
||||||
|
int rc = sqlite3_close_v2(self->db);
|
||||||
|
assert(rc == SQLITE_OK);
|
||||||
|
self->db = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
connection_dealloc(pysqlite_Connection *self)
|
connection_dealloc(pysqlite_Connection *self)
|
||||||
{
|
{
|
||||||
|
@ -266,9 +276,7 @@ connection_dealloc(pysqlite_Connection *self)
|
||||||
tp->tp_clear((PyObject *)self);
|
tp->tp_clear((PyObject *)self);
|
||||||
|
|
||||||
/* Clean up if user has not called .close() explicitly. */
|
/* Clean up if user has not called .close() explicitly. */
|
||||||
if (self->db) {
|
connection_close(self);
|
||||||
sqlite3_close_v2(self->db);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp->tp_free(self);
|
tp->tp_free(self);
|
||||||
Py_DECREF(tp);
|
Py_DECREF(tp);
|
||||||
|
@ -353,24 +361,12 @@ static PyObject *
|
||||||
pysqlite_connection_close_impl(pysqlite_Connection *self)
|
pysqlite_connection_close_impl(pysqlite_Connection *self)
|
||||||
/*[clinic end generated code: output=a546a0da212c9b97 input=3d58064bbffaa3d3]*/
|
/*[clinic end generated code: output=a546a0da212c9b97 input=3d58064bbffaa3d3]*/
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!pysqlite_check_thread(self)) {
|
if (!pysqlite_check_thread(self)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pysqlite_do_all_statements(self, ACTION_FINALIZE, 1);
|
pysqlite_do_all_statements(self, ACTION_FINALIZE, 1);
|
||||||
|
connection_close(self);
|
||||||
if (self->db) {
|
|
||||||
rc = sqlite3_close_v2(self->db);
|
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
|
||||||
_pysqlite_seterror(self->db);
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
self->db = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1820,6 +1816,9 @@ static PyObject *
|
||||||
pysqlite_connection_enter_impl(pysqlite_Connection *self)
|
pysqlite_connection_enter_impl(pysqlite_Connection *self)
|
||||||
/*[clinic end generated code: output=457b09726d3e9dcd input=127d7a4f17e86d8f]*/
|
/*[clinic end generated code: output=457b09726d3e9dcd input=127d7a4f17e86d8f]*/
|
||||||
{
|
{
|
||||||
|
if (!pysqlite_check_connection(self)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return Py_NewRef((PyObject *)self);
|
return Py_NewRef((PyObject *)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue