Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Lib/test/test_sqlite3/test_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ def test_delete_connection_text_factory(self):
with self.assertRaises(AttributeError):
del self.con.text_factory

def test_delete_cursor_row_factory(self):
# gh-149738: deleting row_factory should raise an exception
cur = self.con.cursor()
with self.assertRaises(AttributeError):
del cur.row_factory
# Executing a query here should succeed.
self.assertEqual(tuple(cur.execute("select 1").fetchone()), (1,))
Comment thread
serhiy-storchaka marked this conversation as resolved.
Resolved

def test_sqlite_row_index_unicode(self):
row = self.con.execute("select 1 as \xff").fetchone()
self.assertEqual(row["\xff"], 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
:mod:`sqlite3`: Disallow removing ``row_factory`` and ``text_factory`` attributes
of a connection to prevent a crash on a query.
of a connection or cursor to prevent a crash on a query.
22 changes: 21 additions & 1 deletion Modules/_sqlite/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1400,13 +1400,33 @@ static struct PyMemberDef cursor_members[] =
{"description", _Py_T_OBJECT, offsetof(pysqlite_Cursor, description), Py_READONLY},
{"lastrowid", _Py_T_OBJECT, offsetof(pysqlite_Cursor, lastrowid), Py_READONLY},
{"rowcount", Py_T_LONG, offsetof(pysqlite_Cursor, rowcount), Py_READONLY},
{"row_factory", _Py_T_OBJECT, offsetof(pysqlite_Cursor, row_factory), 0},
{"__weaklistoffset__", Py_T_PYSSIZET, offsetof(pysqlite_Cursor, in_weakreflist), Py_READONLY},
{NULL}
};

static PyObject *
cursor_get_row_factory(PyObject *op, void *closure)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nitpick: use Py_UNUSED(closure).

{
pysqlite_Cursor *self = (pysqlite_Cursor *)op;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use _pysqlite_Cursor_CAST().

return Py_NewRef(self->row_factory);
}

static int
cursor_set_row_factory(PyObject *op, PyObject *value, void *closure)
{
pysqlite_Cursor *self = (pysqlite_Cursor *)op;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same.

if (value == NULL) {
PyErr_SetString(PyExc_AttributeError,
"cannot delete row_factory attribute");
return -1;
}
Py_XSETREF(self->row_factory, Py_NewRef(value));
Comment thread
sobolevn marked this conversation as resolved.
Resolved
return 0;
}

static struct PyGetSetDef cursor_getsets[] = {
_SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF
{"row_factory", cursor_get_row_factory, cursor_set_row_factory},
{NULL},
};

Expand Down
Loading