|
38 | 38 | #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() |
39 | 39 | #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() |
40 | 40 | #include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8NoNUL |
| 41 | +#include "pycore_weakref.h" |
41 | 42 |
|
42 | 43 | #include <stdbool.h> |
43 | 44 |
|
@@ -148,6 +149,7 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp |
148 | 149 | [clinic start generated code]*/ |
149 | 150 | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=67369db2faf80891]*/ |
150 | 151 |
|
| 152 | +static int _pysqlite_drop_unused_blob_references(pysqlite_Connection* self); |
151 | 153 | static void incref_callback_context(callback_context *ctx); |
152 | 154 | static void decref_callback_context(callback_context *ctx); |
153 | 155 | static void set_callback_context(callback_context **ctx_pp, |
@@ -305,6 +307,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, |
305 | 307 | self->thread_ident = PyThread_get_thread_ident(); |
306 | 308 | self->statement_cache = statement_cache; |
307 | 309 | self->blobs = blobs; |
| 310 | + self->created_blobs = 0; |
308 | 311 | self->row_factory = Py_NewRef(Py_None); |
309 | 312 | self->text_factory = Py_NewRef(&PyUnicode_Type); |
310 | 313 | self->trace_ctx = NULL; |
@@ -670,6 +673,10 @@ blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, |
670 | 673 | goto error; |
671 | 674 | } |
672 | 675 |
|
| 676 | + if (_pysqlite_drop_unused_blob_references(self) < 0) { |
| 677 | + goto error; |
| 678 | + } |
| 679 | + |
673 | 680 | return (PyObject *)obj; |
674 | 681 |
|
675 | 682 | error: |
@@ -1095,6 +1102,38 @@ final_callback(sqlite3_context *context) |
1095 | 1102 | PyGILState_Release(threadstate); |
1096 | 1103 | } |
1097 | 1104 |
|
| 1105 | +static int |
| 1106 | +_pysqlite_drop_unused_blob_references(pysqlite_Connection* self) |
| 1107 | +{ |
| 1108 | + /* we only need to do this once in a while */ |
| 1109 | + if (self->created_blobs++ < 200) { |
| 1110 | + return 0; |
| 1111 | + } |
| 1112 | + |
| 1113 | + self->created_blobs = 0; |
| 1114 | + |
| 1115 | + PyObject* new_list = PyList_New(0); |
| 1116 | + if (!new_list) { |
| 1117 | + return -1; |
| 1118 | + } |
| 1119 | + |
| 1120 | + assert(PyList_CheckExact(self->blobs)); |
| 1121 | + Py_ssize_t imax = PyList_GET_SIZE(self->blobs); |
| 1122 | + for (Py_ssize_t i = 0; i < imax; i++) { |
| 1123 | + PyObject* weakref = PyList_GET_ITEM(self->blobs, i); |
| 1124 | + if (_PyWeakref_IsDead(weakref)) { |
| 1125 | + continue; |
| 1126 | + } |
| 1127 | + if (PyList_Append(new_list, weakref) != 0) { |
| 1128 | + Py_DECREF(new_list); |
| 1129 | + return -1; |
| 1130 | + } |
| 1131 | + } |
| 1132 | + |
| 1133 | + Py_SETREF(self->blobs, new_list); |
| 1134 | + return 0; |
| 1135 | +} |
| 1136 | + |
1098 | 1137 | /* Allocate a UDF/callback context structure. In order to ensure that the state |
1099 | 1138 | * pointer always outlives the callback context, we make sure it owns a |
1100 | 1139 | * reference to the module itself. create_callback_context() is always called |
|
0 commit comments