Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ef113cd

Browse files
Issue #27861: Fixed a crash in sqlite3.Connection.cursor() when a factory
creates not a cursor. Patch by Xiang Zhang.
1 parent 5de141f commit ef113cd

4 files changed

Lines changed: 35 additions & 9 deletions

File tree

Doc/library/sqlite3.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,11 @@ Connection Objects
285285

286286
.. versionadded:: 3.2
287287

288-
.. method:: cursor([cursorClass])
288+
.. method:: cursor(factory=Cursor)
289289

290-
The cursor method accepts a single optional parameter *cursorClass*. If
291-
supplied, this must be a custom cursor class that extends
292-
:class:`sqlite3.Cursor`.
290+
The cursor method accepts a single optional parameter *factory*. If
291+
supplied, this must be a callable returning an instance of :class:`Cursor`
292+
or its subclasses.
293293

294294
.. method:: commit()
295295

Lib/sqlite3/test/factory.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,21 @@ def tearDown(self):
5858
self.con.close()
5959

6060
def CheckIsInstance(self):
61-
cur = self.con.cursor(factory=MyCursor)
61+
cur = self.con.cursor()
62+
self.assertIsInstance(cur, sqlite.Cursor)
63+
cur = self.con.cursor(MyCursor)
64+
self.assertIsInstance(cur, MyCursor)
65+
cur = self.con.cursor(factory=lambda con: MyCursor(con))
6266
self.assertIsInstance(cur, MyCursor)
6367

68+
def CheckInvalidFactory(self):
69+
# not a callable at all
70+
self.assertRaises(TypeError, self.con.cursor, None)
71+
# invalid callable with not exact one argument
72+
self.assertRaises(TypeError, self.con.cursor, lambda: None)
73+
# invalid callable returning non-cursor
74+
self.assertRaises(TypeError, self.con.cursor, lambda con: None)
75+
6476
class RowFactoryTestsBackwardsCompat(unittest.TestCase):
6577
def setUp(self):
6678
self.con = sqlite.connect(":memory:")
@@ -183,10 +195,12 @@ def CheckSqliteRowAsSequence(self):
183195
def CheckFakeCursorClass(self):
184196
# Issue #24257: Incorrect use of PyObject_IsInstance() caused
185197
# segmentation fault.
198+
# Issue #27861: Also applies for cursor factory.
186199
class FakeCursor(str):
187200
__class__ = sqlite.Cursor
188-
cur = self.con.cursor(factory=FakeCursor)
189-
self.assertRaises(TypeError, sqlite.Row, cur, ())
201+
self.con.row_factory = sqlite.Row
202+
self.assertRaises(TypeError, self.con.cursor, FakeCursor)
203+
self.assertRaises(TypeError, sqlite.Row, FakeCursor(), ())
190204

191205
def tearDown(self):
192206
self.con.close()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ Core and Builtins
5050
Library
5151
-------
5252

53+
- Issue #27861: Fixed a crash in sqlite3.Connection.cursor() when a factory
54+
creates not a cursor. Patch by Xiang Zhang.
55+
5356
- Issue #19884: Avoid spurious output on OS X with Gnu Readline.
5457

5558
- Issue #10513: Fix a regression in Connection.commit(). Statements should

Modules/_sqlite/connection.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ int pysqlite_connection_register_cursor(pysqlite_Connection* connection, PyObjec
300300

301301
PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args, PyObject* kwargs)
302302
{
303-
static char *kwlist[] = {"factory", NULL, NULL};
303+
static char *kwlist[] = {"factory", NULL};
304304
PyObject* factory = NULL;
305305
PyObject* cursor;
306306

@@ -317,7 +317,16 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args,
317317
factory = (PyObject*)&pysqlite_CursorType;
318318
}
319319

320-
cursor = PyObject_CallFunction(factory, "O", self);
320+
cursor = PyObject_CallFunctionObjArgs(factory, (PyObject *)self, NULL);
321+
if (cursor == NULL)
322+
return NULL;
323+
if (!PyObject_TypeCheck(cursor, &pysqlite_CursorType)) {
324+
PyErr_Format(PyExc_TypeError,
325+
"factory must return a cursor, not %.100s",
326+
Py_TYPE(cursor)->tp_name);
327+
Py_DECREF(cursor);
328+
return NULL;
329+
}
321330

322331
_pysqlite_drop_unused_cursor_references(self);
323332

0 commit comments

Comments
 (0)