Skip to content

Commit 243b6c3

Browse files
author
Erlend Egeberg Aasland
authored
bpo-44079: Strip superfluous statement cache from sqlite3.Connection (GH-25998)
1 parent b2f68b1 commit 243b6c3

File tree

4 files changed

+18
-116
lines changed

4 files changed

+18
-116
lines changed

Modules/_sqlite/connection.c

Lines changed: 17 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@
2929
#include "prepare_protocol.h"
3030
#include "util.h"
3131

32-
#define ACTION_FINALIZE 1
33-
#define ACTION_RESET 2
34-
3532
#if SQLITE_VERSION_NUMBER >= 3014000
3633
#define HAVE_TRACE_V2
3734
#endif
@@ -114,7 +111,6 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
114111
self->begin_statement = NULL;
115112

116113
Py_CLEAR(self->statement_cache);
117-
Py_CLEAR(self->statements);
118114
Py_CLEAR(self->cursors);
119115

120116
Py_INCREF(Py_None);
@@ -159,13 +155,11 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
159155
return -1;
160156
}
161157

162-
self->created_statements = 0;
163158
self->created_cursors = 0;
164159

165-
/* Create lists of weak references to statements/cursors */
166-
self->statements = PyList_New(0);
160+
/* Create list of weak references to cursors */
167161
self->cursors = PyList_New(0);
168-
if (!self->statements || !self->cursors) {
162+
if (self->cursors == NULL) {
169163
return -1;
170164
}
171165

@@ -198,37 +192,24 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
198192
return 0;
199193
}
200194

201-
/* action in (ACTION_RESET, ACTION_FINALIZE) */
202195
static void
203-
pysqlite_do_all_statements(pysqlite_Connection *self, int action,
204-
int reset_cursors)
196+
pysqlite_do_all_statements(pysqlite_Connection *self)
205197
{
206-
int i;
207-
PyObject* weakref;
208-
PyObject* statement;
209-
pysqlite_Cursor* cursor;
210-
211-
for (i = 0; i < PyList_Size(self->statements); i++) {
212-
weakref = PyList_GetItem(self->statements, i);
213-
statement = PyWeakref_GetObject(weakref);
214-
if (statement != Py_None) {
215-
Py_INCREF(statement);
216-
if (action == ACTION_RESET) {
217-
(void)pysqlite_statement_reset((pysqlite_Statement*)statement);
218-
} else {
219-
(void)pysqlite_statement_finalize((pysqlite_Statement*)statement);
220-
}
221-
Py_DECREF(statement);
198+
// Reset all statements
199+
sqlite3_stmt *stmt = NULL;
200+
while ((stmt = sqlite3_next_stmt(self->db, stmt))) {
201+
if (sqlite3_stmt_busy(stmt)) {
202+
(void)sqlite3_reset(stmt);
222203
}
223204
}
224205

225-
if (reset_cursors) {
226-
for (i = 0; i < PyList_Size(self->cursors); i++) {
227-
weakref = PyList_GetItem(self->cursors, i);
228-
cursor = (pysqlite_Cursor*)PyWeakref_GetObject(weakref);
229-
if ((PyObject*)cursor != Py_None) {
230-
cursor->reset = 1;
231-
}
206+
// Reset all cursors
207+
for (int i = 0; i < PyList_Size(self->cursors); i++) {
208+
PyObject *weakref = PyList_GetItem(self->cursors, i);
209+
PyObject *object = PyWeakref_GetObject(weakref);
210+
if (object != Py_None) {
211+
pysqlite_Cursor *cursor = (pysqlite_Cursor *)object;
212+
cursor->reset = 1;
232213
}
233214
}
234215
}
@@ -239,7 +220,6 @@ connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg)
239220
Py_VISIT(Py_TYPE(self));
240221
Py_VISIT(self->isolation_level);
241222
Py_VISIT(self->statement_cache);
242-
Py_VISIT(self->statements);
243223
Py_VISIT(self->cursors);
244224
Py_VISIT(self->row_factory);
245225
Py_VISIT(self->text_factory);
@@ -254,7 +234,6 @@ connection_clear(pysqlite_Connection *self)
254234
{
255235
Py_CLEAR(self->isolation_level);
256236
Py_CLEAR(self->statement_cache);
257-
Py_CLEAR(self->statements);
258237
Py_CLEAR(self->cursors);
259238
Py_CLEAR(self->row_factory);
260239
Py_CLEAR(self->text_factory);
@@ -378,7 +357,7 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
378357
return NULL;
379358
}
380359

381-
pysqlite_do_all_statements(self, ACTION_FINALIZE, 1);
360+
Py_CLEAR(self->statement_cache);
382361
connection_close(self);
383362

384363
Py_RETURN_NONE;
@@ -474,7 +453,7 @@ pysqlite_connection_rollback_impl(pysqlite_Connection *self)
474453
}
475454

476455
if (!sqlite3_get_autocommit(self->db)) {
477-
pysqlite_do_all_statements(self, ACTION_RESET, 1);
456+
pysqlite_do_all_statements(self);
478457

479458
Py_BEGIN_ALLOW_THREADS
480459
rc = sqlite3_prepare_v2(self->db, "ROLLBACK", 9, &statement, NULL);
@@ -774,37 +753,6 @@ _pysqlite_final_callback(sqlite3_context *context)
774753
PyGILState_Release(threadstate);
775754
}
776755

777-
static void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self)
778-
{
779-
PyObject* new_list;
780-
PyObject* weakref;
781-
int i;
782-
783-
/* we only need to do this once in a while */
784-
if (self->created_statements++ < 200) {
785-
return;
786-
}
787-
788-
self->created_statements = 0;
789-
790-
new_list = PyList_New(0);
791-
if (!new_list) {
792-
return;
793-
}
794-
795-
for (i = 0; i < PyList_Size(self->statements); i++) {
796-
weakref = PyList_GetItem(self->statements, i);
797-
if (PyWeakref_GetObject(weakref) != Py_None) {
798-
if (PyList_Append(new_list, weakref) != 0) {
799-
Py_DECREF(new_list);
800-
return;
801-
}
802-
}
803-
}
804-
805-
Py_SETREF(self->statements, new_list);
806-
}
807-
808756
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self)
809757
{
810758
PyObject* new_list;
@@ -1358,7 +1306,6 @@ pysqlite_connection_call(pysqlite_Connection *self, PyObject *args,
13581306
{
13591307
PyObject* sql;
13601308
pysqlite_Statement* statement;
1361-
PyObject* weakref;
13621309

13631310
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
13641311
return NULL;
@@ -1370,27 +1317,12 @@ pysqlite_connection_call(pysqlite_Connection *self, PyObject *args,
13701317
if (!PyArg_ParseTuple(args, "U", &sql))
13711318
return NULL;
13721319

1373-
_pysqlite_drop_unused_statement_references(self);
1374-
13751320
statement = pysqlite_statement_create(self, sql);
13761321
if (statement == NULL) {
13771322
return NULL;
13781323
}
13791324

1380-
weakref = PyWeakref_NewRef((PyObject*)statement, NULL);
1381-
if (weakref == NULL)
1382-
goto error;
1383-
if (PyList_Append(self->statements, weakref) != 0) {
1384-
Py_DECREF(weakref);
1385-
goto error;
1386-
}
1387-
Py_DECREF(weakref);
1388-
13891325
return (PyObject*)statement;
1390-
1391-
error:
1392-
Py_DECREF(statement);
1393-
return NULL;
13941326
}
13951327

13961328
/*[clinic input]

Modules/_sqlite/connection.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,10 @@ typedef struct
6060
PyObject *statement_cache;
6161

6262
/* Lists of weak references to statements and cursors used within this connection */
63-
PyObject* statements;
6463
PyObject* cursors;
6564

66-
/* Counters for how many statements/cursors were created in the connection. May be
65+
/* Counters for how many cursors were created in the connection. May be
6766
* reset to 0 at certain intervals */
68-
int created_statements;
6967
int created_cursors;
7068

7169
PyObject* row_factory;

Modules/_sqlite/statement.c

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
118118
self->st = stmt;
119119
self->in_use = 0;
120120
self->is_dml = is_dml;
121-
self->in_weakreflist = NULL;
122121

123122
PyObject_GC_Track(self);
124123
return self;
@@ -361,23 +360,6 @@ pysqlite_statement_bind_parameters(pysqlite_state *state,
361360
}
362361
}
363362

364-
int pysqlite_statement_finalize(pysqlite_Statement* self)
365-
{
366-
int rc;
367-
368-
rc = SQLITE_OK;
369-
if (self->st) {
370-
Py_BEGIN_ALLOW_THREADS
371-
rc = sqlite3_finalize(self->st);
372-
Py_END_ALLOW_THREADS
373-
self->st = NULL;
374-
}
375-
376-
self->in_use = 0;
377-
378-
return rc;
379-
}
380-
381363
int pysqlite_statement_reset(pysqlite_Statement* self)
382364
{
383365
int rc;
@@ -407,9 +389,6 @@ stmt_dealloc(pysqlite_Statement *self)
407389
{
408390
PyTypeObject *tp = Py_TYPE(self);
409391
PyObject_GC_UnTrack(self);
410-
if (self->in_weakreflist != NULL) {
411-
PyObject_ClearWeakRefs((PyObject*)self);
412-
}
413392
if (self->st) {
414393
Py_BEGIN_ALLOW_THREADS
415394
sqlite3_finalize(self->st);
@@ -497,12 +476,7 @@ static int pysqlite_check_remaining_sql(const char* tail)
497476
return 0;
498477
}
499478

500-
static PyMemberDef stmt_members[] = {
501-
{"__weaklistoffset__", T_PYSSIZET, offsetof(pysqlite_Statement, in_weakreflist), READONLY},
502-
{NULL},
503-
};
504479
static PyType_Slot stmt_slots[] = {
505-
{Py_tp_members, stmt_members},
506480
{Py_tp_dealloc, stmt_dealloc},
507481
{Py_tp_traverse, stmt_traverse},
508482
{0, NULL},

Modules/_sqlite/statement.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ typedef struct
3535
sqlite3_stmt* st;
3636
int in_use;
3737
int is_dml;
38-
PyObject* in_weakreflist; /* List of weak references */
3938
} pysqlite_Statement;
4039

4140
pysqlite_Statement *pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql);
@@ -45,7 +44,6 @@ void pysqlite_statement_bind_parameters(pysqlite_state *state,
4544
pysqlite_Statement *self,
4645
PyObject *parameters);
4746

48-
int pysqlite_statement_finalize(pysqlite_Statement* self);
4947
int pysqlite_statement_reset(pysqlite_Statement* self);
5048
void pysqlite_statement_mark_dirty(pysqlite_Statement* self);
5149

0 commit comments

Comments
 (0)