Skip to content

Commit b5c7224

Browse files
committed
Add __delattr__ guard to sqlite3 cursor.row_factory attr to
prevent segfault and bring behaviour in line with docs
1 parent fb68617 commit b5c7224

2 files changed

Lines changed: 23 additions & 2 deletions

File tree

Lib/test/test_sqlite3/test_factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ def test_delete_connection_text_factory(self):
159159
def test_delete_cursor_row_factory(self):
160160
# gh-149738: deleting row_factory should raise an exception
161161
cur = self.con.cursor()
162-
del cur.row_factory
162+
with self.assertRaises(AttributeError):
163+
del cur.row_factory
163164
# Executing a query here should succeed.
164165
self.assertEqual(tuple(cur.execute("select 1").fetchone()), (1,))
165166

Modules/_sqlite/cursor.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,13 +1400,33 @@ static struct PyMemberDef cursor_members[] =
14001400
{"description", _Py_T_OBJECT, offsetof(pysqlite_Cursor, description), Py_READONLY},
14011401
{"lastrowid", _Py_T_OBJECT, offsetof(pysqlite_Cursor, lastrowid), Py_READONLY},
14021402
{"rowcount", Py_T_LONG, offsetof(pysqlite_Cursor, rowcount), Py_READONLY},
1403-
{"row_factory", _Py_T_OBJECT, offsetof(pysqlite_Cursor, row_factory), 0},
14041403
{"__weaklistoffset__", Py_T_PYSSIZET, offsetof(pysqlite_Cursor, in_weakreflist), Py_READONLY},
14051404
{NULL}
14061405
};
14071406

1407+
static PyObject *
1408+
cursor_get_row_factory(PyObject *op, void *closure)
1409+
{
1410+
pysqlite_Cursor *self = (pysqlite_Cursor *)op;
1411+
return Py_NewRef(self->row_factory);
1412+
}
1413+
1414+
static int
1415+
cursor_set_row_factory(PyObject *op, PyObject *value, void *closure)
1416+
{
1417+
pysqlite_Cursor *self = (pysqlite_Cursor *)op;
1418+
if (value == NULL) {
1419+
PyErr_SetString(PyExc_AttributeError,
1420+
"cannot delete row_factory attribute");
1421+
return -1;
1422+
}
1423+
Py_XSETREF(self->row_factory, Py_NewRef(value));
1424+
return 0;
1425+
}
1426+
14081427
static struct PyGetSetDef cursor_getsets[] = {
14091428
_SQLITE3_CURSOR_ARRAYSIZE_GETSETDEF
1429+
{"row_factory", cursor_get_row_factory, cursor_set_row_factory},
14101430
{NULL},
14111431
};
14121432

0 commit comments

Comments
 (0)