Skip to content

Commit 1c02655

Browse files
author
Erlend Egeberg Aasland
authored
bpo-44329: Refactor sqlite3 statement creation (GH-26566)
Call SQLite API's first, and return early in case of error. At the end, allocate the object and initialise members. We now avoid unneeded alloc/dealloc's in case the statement creation fails.
1 parent 3fe921c commit 1c02655

File tree

1 file changed

+35
-43
lines changed

1 file changed

+35
-43
lines changed

Modules/_sqlite/statement.c

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -51,47 +51,50 @@ typedef enum {
5151
pysqlite_Statement *
5252
pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
5353
{
54-
const char* tail;
55-
int rc;
56-
const char* sql_cstr;
57-
Py_ssize_t sql_cstr_len;
58-
const char* p;
59-
6054
assert(PyUnicode_Check(sql));
61-
62-
sql_cstr = PyUnicode_AsUTF8AndSize(sql, &sql_cstr_len);
55+
Py_ssize_t size;
56+
const char *sql_cstr = PyUnicode_AsUTF8AndSize(sql, &size);
6357
if (sql_cstr == NULL) {
6458
PyErr_Format(pysqlite_Warning,
6559
"SQL is of wrong type ('%s'). Must be string.",
6660
Py_TYPE(sql)->tp_name);
6761
return NULL;
6862
}
6963

70-
int max_length = sqlite3_limit(connection->db, SQLITE_LIMIT_LENGTH, -1);
71-
if (sql_cstr_len >= max_length) {
64+
sqlite3 *db = connection->db;
65+
int max_length = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
66+
if (size >= max_length) {
7267
PyErr_SetString(pysqlite_DataError, "query string is too large");
7368
return NULL;
7469
}
75-
if (strlen(sql_cstr) != (size_t)sql_cstr_len) {
70+
if (strlen(sql_cstr) != (size_t)size) {
7671
PyErr_SetString(PyExc_ValueError,
7772
"the query contains a null character");
7873
return NULL;
7974
}
8075

81-
pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
82-
pysqlite_StatementType);
83-
if (self == NULL) {
76+
sqlite3_stmt *stmt;
77+
const char *tail;
78+
int rc;
79+
Py_BEGIN_ALLOW_THREADS
80+
rc = sqlite3_prepare_v2(db, sql_cstr, (int)size + 1, &stmt, &tail);
81+
Py_END_ALLOW_THREADS
82+
83+
if (rc != SQLITE_OK) {
84+
_pysqlite_seterror(db);
8485
return NULL;
8586
}
8687

87-
self->st = NULL;
88-
self->in_use = 0;
89-
self->is_dml = 0;
90-
self->in_weakreflist = NULL;
88+
if (pysqlite_check_remaining_sql(tail)) {
89+
PyErr_SetString(pysqlite_Warning,
90+
"You can only execute one statement at a time.");
91+
goto error;
92+
}
9193

9294
/* Determine if the statement is a DML statement.
9395
SELECT is the only exception. See #9924. */
94-
for (p = sql_cstr; *p != 0; p++) {
96+
int is_dml = 0;
97+
for (const char *p = sql_cstr; *p != 0; p++) {
9598
switch (*p) {
9699
case ' ':
97100
case '\r':
@@ -100,40 +103,29 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
100103
continue;
101104
}
102105

103-
self->is_dml = (PyOS_strnicmp(p, "insert", 6) == 0)
104-
|| (PyOS_strnicmp(p, "update", 6) == 0)
105-
|| (PyOS_strnicmp(p, "delete", 6) == 0)
106-
|| (PyOS_strnicmp(p, "replace", 7) == 0);
106+
is_dml = (PyOS_strnicmp(p, "insert", 6) == 0)
107+
|| (PyOS_strnicmp(p, "update", 6) == 0)
108+
|| (PyOS_strnicmp(p, "delete", 6) == 0)
109+
|| (PyOS_strnicmp(p, "replace", 7) == 0);
107110
break;
108111
}
109112

110-
Py_BEGIN_ALLOW_THREADS
111-
rc = sqlite3_prepare_v2(connection->db,
112-
sql_cstr,
113-
(int)sql_cstr_len + 1,
114-
&self->st,
115-
&tail);
116-
Py_END_ALLOW_THREADS
117-
118-
PyObject_GC_Track(self);
119-
120-
if (rc != SQLITE_OK) {
121-
_pysqlite_seterror(connection->db);
113+
pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
114+
pysqlite_StatementType);
115+
if (self == NULL) {
122116
goto error;
123117
}
124118

125-
if (rc == SQLITE_OK && pysqlite_check_remaining_sql(tail)) {
126-
(void)sqlite3_finalize(self->st);
127-
self->st = NULL;
128-
PyErr_SetString(pysqlite_Warning,
129-
"You can only execute one statement at a time.");
130-
goto error;
131-
}
119+
self->st = stmt;
120+
self->in_use = 0;
121+
self->is_dml = is_dml;
122+
self->in_weakreflist = NULL;
132123

124+
PyObject_GC_Track(self);
133125
return self;
134126

135127
error:
136-
Py_DECREF(self);
128+
(void)sqlite3_finalize(stmt);
137129
return NULL;
138130
}
139131

0 commit comments

Comments
 (0)