Skip to content

Commit e8d9df0

Browse files
miss-islingtonErlend Egeberg Aasland
and
Erlend Egeberg Aasland
authored
bpo-42972: Fully implement GC protocol for sqlite3 heap types (GH-26104)
(cherry picked from commit d3c277a) Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
1 parent 05f8ad0 commit e8d9df0

File tree

6 files changed

+190
-72
lines changed

6 files changed

+190
-72
lines changed

Modules/_sqlite/cache.c

+60-23
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,29 @@ pysqlite_new_node(PyObject *key, PyObject *data)
4444
return node;
4545
}
4646

47+
static int
48+
node_traverse(pysqlite_Node *self, visitproc visit, void *arg)
49+
{
50+
Py_VISIT(self->key);
51+
Py_VISIT(self->data);
52+
Py_VISIT(Py_TYPE(self));
53+
return 0;
54+
}
55+
56+
static int
57+
node_clear(pysqlite_Node *self)
58+
{
59+
Py_CLEAR(self->key);
60+
Py_CLEAR(self->data);
61+
return 0;
62+
}
63+
4764
static void
4865
pysqlite_node_dealloc(pysqlite_Node *self)
4966
{
5067
PyTypeObject *tp = Py_TYPE(self);
51-
52-
Py_DECREF(self->key);
53-
Py_DECREF(self->data);
54-
68+
PyObject_GC_UnTrack(self);
69+
tp->tp_clear((PyObject *)self);
5570
tp->tp_free(self);
5671
Py_DECREF(tp);
5772
}
@@ -88,31 +103,51 @@ pysqlite_cache_init(pysqlite_Cache *self, PyObject *args, PyObject *kwargs)
88103
return 0;
89104
}
90105

91-
static void
92-
pysqlite_cache_dealloc(pysqlite_Cache *self)
106+
static int
107+
cache_traverse(pysqlite_Cache *self, visitproc visit, void *arg)
93108
{
94-
PyTypeObject *tp = Py_TYPE(self);
95-
pysqlite_Node* node;
96-
pysqlite_Node* delete_node;
97-
98-
if (!self->factory) {
99-
/* constructor failed, just get out of here */
100-
return;
109+
pysqlite_Node *node = self->first;
110+
while (node) {
111+
Py_VISIT(node);
112+
node = node->next;
113+
}
114+
Py_VISIT(self->mapping);
115+
if (self->decref_factory) {
116+
Py_VISIT(self->factory);
101117
}
118+
Py_VISIT(Py_TYPE(self));
119+
return 0;
120+
}
102121

122+
static int
123+
cache_clear(pysqlite_Cache *self)
124+
{
103125
/* iterate over all nodes and deallocate them */
104-
node = self->first;
126+
pysqlite_Node *node = self->first;
127+
self->first = NULL;
105128
while (node) {
106-
delete_node = node;
129+
pysqlite_Node *delete_node = node;
107130
node = node->next;
108-
Py_DECREF(delete_node);
131+
Py_CLEAR(delete_node);
109132
}
110-
111133
if (self->decref_factory) {
112-
Py_DECREF(self->factory);
134+
Py_CLEAR(self->factory);
135+
}
136+
Py_CLEAR(self->mapping);
137+
return 0;
138+
}
139+
140+
static void
141+
pysqlite_cache_dealloc(pysqlite_Cache *self)
142+
{
143+
if (!self->factory) {
144+
/* constructor failed, just get out of here */
145+
return;
113146
}
114-
Py_DECREF(self->mapping);
115147

148+
PyObject_GC_UnTrack(self);
149+
PyTypeObject *tp = Py_TYPE(self);
150+
tp->tp_clear((PyObject *)self);
116151
tp->tp_free(self);
117152
Py_DECREF(tp);
118153
}
@@ -260,14 +295,15 @@ pysqlite_cache_display(pysqlite_Cache *self, PyObject *args)
260295

261296
static PyType_Slot node_slots[] = {
262297
{Py_tp_dealloc, pysqlite_node_dealloc},
263-
{Py_tp_new, PyType_GenericNew},
298+
{Py_tp_traverse, node_traverse},
299+
{Py_tp_clear, node_clear},
264300
{0, NULL},
265301
};
266302

267303
static PyType_Spec node_spec = {
268304
.name = MODULE_NAME ".Node",
269305
.basicsize = sizeof(pysqlite_Node),
270-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
306+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
271307
.slots = node_slots,
272308
};
273309
PyTypeObject *pysqlite_NodeType = NULL;
@@ -283,15 +319,16 @@ static PyMethodDef cache_methods[] = {
283319
static PyType_Slot cache_slots[] = {
284320
{Py_tp_dealloc, pysqlite_cache_dealloc},
285321
{Py_tp_methods, cache_methods},
286-
{Py_tp_new, PyType_GenericNew},
287322
{Py_tp_init, pysqlite_cache_init},
323+
{Py_tp_traverse, cache_traverse},
324+
{Py_tp_clear, cache_clear},
288325
{0, NULL},
289326
};
290327

291328
static PyType_Spec cache_spec = {
292329
.name = MODULE_NAME ".Cache",
293330
.basicsize = sizeof(pysqlite_Cache),
294-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
331+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
295332
.slots = cache_slots,
296333
};
297334
PyTypeObject *pysqlite_CacheType = NULL;

Modules/_sqlite/connection.c

+41-17
Original file line numberDiff line numberDiff line change
@@ -225,28 +225,51 @@ pysqlite_do_all_statements(pysqlite_Connection *self, int action,
225225
}
226226
}
227227

228+
static int
229+
connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg)
230+
{
231+
Py_VISIT(self->statement_cache);
232+
Py_VISIT(self->isolation_level);
233+
Py_VISIT(self->function_pinboard_trace_callback);
234+
Py_VISIT(self->function_pinboard_progress_handler);
235+
Py_VISIT(self->function_pinboard_authorizer_cb);
236+
Py_VISIT(self->row_factory);
237+
Py_VISIT(self->text_factory);
238+
Py_VISIT(self->collations);
239+
Py_VISIT(self->statements);
240+
Py_VISIT(self->cursors);
241+
Py_VISIT(Py_TYPE(self));
242+
return 0;
243+
}
244+
245+
static int
246+
connection_clear(pysqlite_Connection *self)
247+
{
248+
Py_CLEAR(self->statement_cache);
249+
Py_CLEAR(self->isolation_level);
250+
Py_CLEAR(self->function_pinboard_trace_callback);
251+
Py_CLEAR(self->function_pinboard_progress_handler);
252+
Py_CLEAR(self->function_pinboard_authorizer_cb);
253+
Py_CLEAR(self->row_factory);
254+
Py_CLEAR(self->text_factory);
255+
Py_CLEAR(self->collations);
256+
Py_CLEAR(self->statements);
257+
Py_CLEAR(self->cursors);
258+
return 0;
259+
}
260+
228261
static void
229-
pysqlite_connection_dealloc(pysqlite_Connection *self)
262+
connection_dealloc(pysqlite_Connection *self)
230263
{
231264
PyTypeObject *tp = Py_TYPE(self);
232-
233-
Py_XDECREF(self->statement_cache);
265+
PyObject_GC_UnTrack(self);
266+
tp->tp_clear((PyObject *)self);
234267

235268
/* Clean up if user has not called .close() explicitly. */
236269
if (self->db) {
237270
sqlite3_close_v2(self->db);
238271
}
239272

240-
Py_XDECREF(self->isolation_level);
241-
Py_XDECREF(self->function_pinboard_trace_callback);
242-
Py_XDECREF(self->function_pinboard_progress_handler);
243-
Py_XDECREF(self->function_pinboard_authorizer_cb);
244-
Py_XDECREF(self->row_factory);
245-
Py_XDECREF(self->text_factory);
246-
Py_XDECREF(self->collations);
247-
Py_XDECREF(self->statements);
248-
Py_XDECREF(self->cursors);
249-
250273
tp->tp_free(self);
251274
Py_DECREF(tp);
252275
}
@@ -1328,7 +1351,7 @@ pysqlite_connection_call(pysqlite_Connection *self, PyObject *args,
13281351

13291352
_pysqlite_drop_unused_statement_references(self);
13301353

1331-
statement = PyObject_New(pysqlite_Statement, pysqlite_StatementType);
1354+
statement = PyObject_GC_New(pysqlite_Statement, pysqlite_StatementType);
13321355
if (!statement) {
13331356
return NULL;
13341357
}
@@ -1909,21 +1932,22 @@ static struct PyMemberDef connection_members[] =
19091932
};
19101933

19111934
static PyType_Slot connection_slots[] = {
1912-
{Py_tp_dealloc, pysqlite_connection_dealloc},
1935+
{Py_tp_dealloc, connection_dealloc},
19131936
{Py_tp_doc, (void *)connection_doc},
19141937
{Py_tp_methods, connection_methods},
19151938
{Py_tp_members, connection_members},
19161939
{Py_tp_getset, connection_getset},
1917-
{Py_tp_new, PyType_GenericNew},
19181940
{Py_tp_init, pysqlite_connection_init},
19191941
{Py_tp_call, pysqlite_connection_call},
1942+
{Py_tp_traverse, connection_traverse},
1943+
{Py_tp_clear, connection_clear},
19201944
{0, NULL},
19211945
};
19221946

19231947
static PyType_Spec connection_spec = {
19241948
.name = MODULE_NAME ".Connection",
19251949
.basicsize = sizeof(pysqlite_Connection),
1926-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1950+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
19271951
.slots = connection_slots,
19281952
};
19291953

Modules/_sqlite/cursor.c

+33-13
Original file line numberDiff line numberDiff line change
@@ -81,27 +81,46 @@ pysqlite_cursor_init_impl(pysqlite_Cursor *self,
8181
return 0;
8282
}
8383

84-
static void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
84+
static int
85+
cursor_traverse(pysqlite_Cursor *self, visitproc visit, void *arg)
8586
{
86-
PyTypeObject *tp = Py_TYPE(self);
87+
Py_VISIT(self->connection);
88+
Py_VISIT(self->row_cast_map);
89+
Py_VISIT(self->row_factory);
90+
Py_VISIT(self->next_row);
91+
Py_VISIT(Py_TYPE(self));
92+
return 0;
93+
}
8794

95+
static int
96+
cursor_clear(pysqlite_Cursor *self)
97+
{
8898
/* Reset the statement if the user has not closed the cursor */
8999
if (self->statement) {
90100
pysqlite_statement_reset(self->statement);
91-
Py_DECREF(self->statement);
101+
Py_CLEAR(self->statement);
92102
}
93103

94-
Py_XDECREF(self->connection);
95-
Py_XDECREF(self->row_cast_map);
96-
Py_XDECREF(self->description);
97-
Py_XDECREF(self->lastrowid);
98-
Py_XDECREF(self->row_factory);
99-
Py_XDECREF(self->next_row);
104+
Py_CLEAR(self->connection);
105+
Py_CLEAR(self->row_cast_map);
106+
Py_CLEAR(self->description);
107+
Py_CLEAR(self->lastrowid);
108+
Py_CLEAR(self->row_factory);
109+
Py_CLEAR(self->next_row);
100110

101111
if (self->in_weakreflist != NULL) {
102112
PyObject_ClearWeakRefs((PyObject*)self);
103113
}
104114

115+
return 0;
116+
}
117+
118+
static void
119+
cursor_dealloc(PyObject *self)
120+
{
121+
PyTypeObject *tp = Py_TYPE(self);
122+
PyObject_GC_UnTrack(self);
123+
tp->tp_clear(self);
105124
tp->tp_free(self);
106125
Py_DECREF(tp);
107126
}
@@ -487,7 +506,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
487506

488507
if (self->statement->in_use) {
489508
Py_SETREF(self->statement,
490-
PyObject_New(pysqlite_Statement, pysqlite_StatementType));
509+
PyObject_GC_New(pysqlite_Statement, pysqlite_StatementType));
491510
if (!self->statement) {
492511
goto error;
493512
}
@@ -1006,21 +1025,22 @@ static const char cursor_doc[] =
10061025
PyDoc_STR("SQLite database cursor class.");
10071026

10081027
static PyType_Slot cursor_slots[] = {
1009-
{Py_tp_dealloc, pysqlite_cursor_dealloc},
1028+
{Py_tp_dealloc, cursor_dealloc},
10101029
{Py_tp_doc, (void *)cursor_doc},
10111030
{Py_tp_iter, PyObject_SelfIter},
10121031
{Py_tp_iternext, pysqlite_cursor_iternext},
10131032
{Py_tp_methods, cursor_methods},
10141033
{Py_tp_members, cursor_members},
1015-
{Py_tp_new, PyType_GenericNew},
10161034
{Py_tp_init, pysqlite_cursor_init},
1035+
{Py_tp_traverse, cursor_traverse},
1036+
{Py_tp_clear, cursor_clear},
10171037
{0, NULL},
10181038
};
10191039

10201040
static PyType_Spec cursor_spec = {
10211041
.name = MODULE_NAME ".Cursor",
10221042
.basicsize = sizeof(pysqlite_Cursor),
1023-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1043+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
10241044
.slots = cursor_slots,
10251045
};
10261046

Modules/_sqlite/prepare_protocol.c

+10-3
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,33 @@ pysqlite_prepare_protocol_init(pysqlite_PrepareProtocol *self, PyObject *args,
3030
return 0;
3131
}
3232

33+
static int
34+
pysqlite_prepare_protocol_traverse(PyObject *self, visitproc visit, void *arg)
35+
{
36+
Py_VISIT(Py_TYPE(self));
37+
return 0;
38+
}
39+
3340
static void
3441
pysqlite_prepare_protocol_dealloc(pysqlite_PrepareProtocol *self)
3542
{
3643
PyTypeObject *tp = Py_TYPE(self);
37-
44+
PyObject_GC_UnTrack(self);
3845
tp->tp_free(self);
3946
Py_DECREF(tp);
4047
}
4148

4249
static PyType_Slot type_slots[] = {
4350
{Py_tp_dealloc, pysqlite_prepare_protocol_dealloc},
44-
{Py_tp_new, PyType_GenericNew},
4551
{Py_tp_init, pysqlite_prepare_protocol_init},
52+
{Py_tp_traverse, pysqlite_prepare_protocol_traverse},
4653
{0, NULL},
4754
};
4855

4956
static PyType_Spec type_spec = {
5057
.name = MODULE_NAME ".PrepareProtocol",
5158
.basicsize = sizeof(pysqlite_PrepareProtocol),
52-
.flags = Py_TPFLAGS_DEFAULT,
59+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
5360
.slots = type_slots,
5461
};
5562

0 commit comments

Comments
 (0)