Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 84d80f5

Browse files
author
Erlend Egeberg Aasland
authored
[3.10] bpo-42972: Track sqlite3 statement objects (GH-26475) (GH-26515)
Allocate and track statement objects in pysqlite_statement_create. By allocating and tracking creation of statement object in pysqlite_statement_create(), the caller does not need to worry about GC syncronization, and eliminates the possibility of getting a badly created object. All related fault handling is moved to pysqlite_statement_create(). Co-authored-by: Victor Stinner <[email protected]>. (cherry picked from commit fffa0f9) Co-authored-by: Erlend Egeberg Aasland <[email protected]>
1 parent 4131780 commit 84d80f5

File tree

4 files changed

+40
-48
lines changed

4 files changed

+40
-48
lines changed

Modules/_sqlite/connection.c

+2-23
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,6 @@ pysqlite_connection_call(pysqlite_Connection *self, PyObject *args,
13371337
PyObject* sql;
13381338
pysqlite_Statement* statement;
13391339
PyObject* weakref;
1340-
int rc;
13411340

13421341
if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) {
13431342
return NULL;
@@ -1351,31 +1350,11 @@ pysqlite_connection_call(pysqlite_Connection *self, PyObject *args,
13511350

13521351
_pysqlite_drop_unused_statement_references(self);
13531352

1354-
statement = PyObject_GC_New(pysqlite_Statement, pysqlite_StatementType);
1355-
if (!statement) {
1353+
statement = pysqlite_statement_create(self, sql);
1354+
if (statement == NULL) {
13561355
return NULL;
13571356
}
13581357

1359-
statement->db = NULL;
1360-
statement->st = NULL;
1361-
statement->sql = NULL;
1362-
statement->in_use = 0;
1363-
statement->in_weakreflist = NULL;
1364-
1365-
rc = pysqlite_statement_create(statement, self, sql);
1366-
if (rc != SQLITE_OK) {
1367-
if (rc == PYSQLITE_TOO_MUCH_SQL) {
1368-
PyErr_SetString(pysqlite_Warning, "You can only execute one statement at a time.");
1369-
} else if (rc == PYSQLITE_SQL_WRONG_TYPE) {
1370-
if (PyErr_ExceptionMatches(PyExc_TypeError))
1371-
PyErr_SetString(pysqlite_Warning, "SQL is of wrong type. Must be string.");
1372-
} else {
1373-
(void)pysqlite_statement_reset(statement);
1374-
_pysqlite_seterror(self->db, NULL);
1375-
}
1376-
goto error;
1377-
}
1378-
13791358
weakref = PyWeakref_NewRef((PyObject*)statement, NULL);
13801359
if (weakref == NULL)
13811360
goto error;

Modules/_sqlite/cursor.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -507,13 +507,8 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
507507

508508
if (self->statement->in_use) {
509509
Py_SETREF(self->statement,
510-
PyObject_GC_New(pysqlite_Statement, pysqlite_StatementType));
511-
if (!self->statement) {
512-
goto error;
513-
}
514-
rc = pysqlite_statement_create(self->statement, self->connection, operation);
515-
if (rc != SQLITE_OK) {
516-
Py_CLEAR(self->statement);
510+
pysqlite_statement_create(self->connection, operation));
511+
if (self->statement == NULL) {
517512
goto error;
518513
}
519514
}

Modules/_sqlite/statement.c

+35-14
Original file line numberDiff line numberDiff line change
@@ -48,35 +48,45 @@ typedef enum {
4848
TYPE_UNKNOWN
4949
} parameter_type;
5050

51-
int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* connection, PyObject* sql)
51+
pysqlite_Statement *
52+
pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
5253
{
5354
const char* tail;
5455
int rc;
5556
const char* sql_cstr;
5657
Py_ssize_t sql_cstr_len;
5758
const char* p;
5859

59-
self->st = NULL;
60-
self->in_use = 0;
61-
6260
assert(PyUnicode_Check(sql));
6361

6462
sql_cstr = PyUnicode_AsUTF8AndSize(sql, &sql_cstr_len);
6563
if (sql_cstr == NULL) {
66-
rc = PYSQLITE_SQL_WRONG_TYPE;
67-
return rc;
64+
PyErr_Format(pysqlite_Warning,
65+
"SQL is of wrong type ('%s'). Must be string.",
66+
Py_TYPE(sql)->tp_name);
67+
return NULL;
6868
}
6969
if (strlen(sql_cstr) != (size_t)sql_cstr_len) {
70-
PyErr_SetString(PyExc_ValueError, "the query contains a null character");
71-
return PYSQLITE_SQL_WRONG_TYPE;
70+
PyErr_SetString(PyExc_ValueError,
71+
"the query contains a null character");
72+
return NULL;
7273
}
7374

74-
self->in_weakreflist = NULL;
75+
pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
76+
pysqlite_StatementType);
77+
if (self == NULL) {
78+
return NULL;
79+
}
80+
81+
self->db = connection->db;
82+
self->st = NULL;
7583
self->sql = Py_NewRef(sql);
84+
self->in_use = 0;
85+
self->is_dml = 0;
86+
self->in_weakreflist = NULL;
7687

7788
/* Determine if the statement is a DML statement.
7889
SELECT is the only exception. See #9924. */
79-
self->is_dml = 0;
8090
for (p = sql_cstr; *p != 0; p++) {
8191
switch (*p) {
8292
case ' ':
@@ -94,22 +104,33 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con
94104
}
95105

96106
Py_BEGIN_ALLOW_THREADS
97-
rc = sqlite3_prepare_v2(connection->db,
107+
rc = sqlite3_prepare_v2(self->db,
98108
sql_cstr,
99109
-1,
100110
&self->st,
101111
&tail);
102112
Py_END_ALLOW_THREADS
103113

104-
self->db = connection->db;
114+
PyObject_GC_Track(self);
115+
116+
if (rc != SQLITE_OK) {
117+
_pysqlite_seterror(self->db, NULL);
118+
goto error;
119+
}
105120

106121
if (rc == SQLITE_OK && pysqlite_check_remaining_sql(tail)) {
107122
(void)sqlite3_finalize(self->st);
108123
self->st = NULL;
109-
rc = PYSQLITE_TOO_MUCH_SQL;
124+
PyErr_SetString(pysqlite_Warning,
125+
"You can only execute one statement at a time.");
126+
goto error;
110127
}
111128

112-
return rc;
129+
return self;
130+
131+
error:
132+
Py_DECREF(self);
133+
return NULL;
113134
}
114135

115136
int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter)

Modules/_sqlite/statement.h

+1-4
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@
2929
#include "connection.h"
3030
#include "sqlite3.h"
3131

32-
#define PYSQLITE_TOO_MUCH_SQL (-100)
33-
#define PYSQLITE_SQL_WRONG_TYPE (-101)
34-
3532
typedef struct
3633
{
3734
PyObject_HEAD
@@ -45,7 +42,7 @@ typedef struct
4542

4643
extern PyTypeObject *pysqlite_StatementType;
4744

48-
int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* connection, PyObject* sql);
45+
pysqlite_Statement *pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql);
4946

5047
int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter);
5148
void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* parameters);

0 commit comments

Comments
 (0)