Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
23 changes: 17 additions & 6 deletions Modules/_sqlite/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,18 @@ int pysqlite_cache_init(pysqlite_Cache* self, PyObject* args, PyObject* kwargs)
Py_INCREF(factory);
self->factory = factory;

self->decref_factory = 1;
return 0;
}

static int cache_traverse(pysqlite_Cache *self, visitproc visit, void *arg)
{
Py_VISIT(self->factory);
return 0;
}

static int cache_clear(pysqlite_Cache *self)
{
Py_CLEAR(self->factory);
return 0;
}

Expand All @@ -95,6 +105,8 @@ void pysqlite_cache_dealloc(pysqlite_Cache* self)
pysqlite_Node* node;
pysqlite_Node* delete_node;

PyObject_GC_UnTrack(self);

if (!self->factory) {
/* constructor failed, just get out of here */
return;
Expand All @@ -108,11 +120,9 @@ void pysqlite_cache_dealloc(pysqlite_Cache* self)
Py_DECREF(delete_node);
}

if (self->decref_factory) {
Py_DECREF(self->factory);
}
Py_DECREF(self->mapping);

tp->tp_clear((PyObject *)self);
tp->tp_free(self);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -283,15 +293,16 @@ static PyMethodDef cache_methods[] = {
static PyType_Slot cache_slots[] = {
{Py_tp_dealloc, pysqlite_cache_dealloc},
{Py_tp_methods, cache_methods},
{Py_tp_new, PyType_GenericNew},
{Py_tp_init, pysqlite_cache_init},
{Py_tp_traverse, cache_traverse},
{Py_tp_clear, cache_clear},
{0, NULL},
};

static PyType_Spec cache_spec = {
.name = MODULE_NAME ".Cache",
.basicsize = sizeof(pysqlite_Cache),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = cache_slots,
};
PyTypeObject *pysqlite_CacheType = NULL;
Expand Down
4 changes: 0 additions & 4 deletions Modules/_sqlite/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ typedef struct

pysqlite_Node* first;
pysqlite_Node* last;

/* if set, decrement the factory function when the Cache is deallocated.
* this is almost always desirable, but not in the pysqlite context */
int decref_factory;
} pysqlite_Cache;

extern PyTypeObject *pysqlite_NodeType;
Expand Down
28 changes: 17 additions & 11 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,6 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
return -1;
}

/* By default, the Cache class INCREFs the factory in its initializer, and
* decrefs it in its deallocator method. Since this would create a circular
* reference here, we're breaking it by decrementing self, and telling the
* cache class to not decref the factory (self) in its deallocator.
*/
self->statement_cache->decref_factory = 0;
Py_DECREF(self);

self->detect_types = detect_types;
self->timeout = timeout;
(void)sqlite3_busy_timeout(self->db, (int)(timeout*1000));
Expand Down Expand Up @@ -225,11 +217,23 @@ void pysqlite_do_all_statements(pysqlite_Connection* self, int action, int reset
}
}

static int connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg)
{
Py_VISIT(self->statement_cache);
return 0;
}

static int connection_clear(pysqlite_Connection *self)
{
Py_CLEAR(self->statement_cache);
return 0;
}

void pysqlite_connection_dealloc(pysqlite_Connection* self)
{
PyTypeObject *tp = Py_TYPE(self);

Py_XDECREF(self->statement_cache);
PyObject_GC_UnTrack(self);

/* Clean up if user has not called .close() explicitly. */
if (self->db) {
Expand All @@ -246,6 +250,7 @@ void pysqlite_connection_dealloc(pysqlite_Connection* self)
Py_XDECREF(self->statements);
Py_XDECREF(self->cursors);

tp->tp_clear((PyObject *)self);
tp->tp_free(self);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -1920,16 +1925,17 @@ static PyType_Slot connection_slots[] = {
{Py_tp_methods, connection_methods},
{Py_tp_members, connection_members},
{Py_tp_getset, connection_getset},
{Py_tp_new, PyType_GenericNew},
{Py_tp_init, pysqlite_connection_init},
{Py_tp_call, pysqlite_connection_call},
{Py_tp_traverse, connection_traverse},
{Py_tp_clear, connection_clear},
{0, NULL},
};

static PyType_Spec connection_spec = {
.name = MODULE_NAME ".Connection",
.basicsize = sizeof(pysqlite_Connection),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = connection_slots,
};

Expand Down