summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorErlend Egeberg Aasland <erlend.aasland@innova.no>2021-06-08 15:00:56 (GMT)
committerGitHub <noreply@github.com>2021-06-08 15:00:56 (GMT)
commit1c02655fb08043b3027748ca1179c416c21a4277 (patch)
tree3124796b69e7fac7a0100299f7705ac928a474b1 /Modules
parent3fe921cd49959181163671364c8b84faa88f7895 (diff)
downloadcpython-1c02655fb08043b3027748ca1179c416c21a4277.zip
cpython-1c02655fb08043b3027748ca1179c416c21a4277.tar.gz
cpython-1c02655fb08043b3027748ca1179c416c21a4277.tar.bz2
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.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_sqlite/statement.c78
1 files changed, 35 insertions, 43 deletions
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index 5c38b46..eca2258 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -51,15 +51,9 @@ typedef enum {
pysqlite_Statement *
pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
{
- const char* tail;
- int rc;
- const char* sql_cstr;
- Py_ssize_t sql_cstr_len;
- const char* p;
-
assert(PyUnicode_Check(sql));
-
- sql_cstr = PyUnicode_AsUTF8AndSize(sql, &sql_cstr_len);
+ Py_ssize_t size;
+ const char *sql_cstr = PyUnicode_AsUTF8AndSize(sql, &size);
if (sql_cstr == NULL) {
PyErr_Format(pysqlite_Warning,
"SQL is of wrong type ('%s'). Must be string.",
@@ -67,31 +61,40 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
return NULL;
}
- int max_length = sqlite3_limit(connection->db, SQLITE_LIMIT_LENGTH, -1);
- if (sql_cstr_len >= max_length) {
+ sqlite3 *db = connection->db;
+ int max_length = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
+ if (size >= max_length) {
PyErr_SetString(pysqlite_DataError, "query string is too large");
return NULL;
}
- if (strlen(sql_cstr) != (size_t)sql_cstr_len) {
+ if (strlen(sql_cstr) != (size_t)size) {
PyErr_SetString(PyExc_ValueError,
"the query contains a null character");
return NULL;
}
- pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
- pysqlite_StatementType);
- if (self == NULL) {
+ sqlite3_stmt *stmt;
+ const char *tail;
+ int rc;
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_prepare_v2(db, sql_cstr, (int)size + 1, &stmt, &tail);
+ Py_END_ALLOW_THREADS
+
+ if (rc != SQLITE_OK) {
+ _pysqlite_seterror(db);
return NULL;
}
- self->st = NULL;
- self->in_use = 0;
- self->is_dml = 0;
- self->in_weakreflist = NULL;
+ if (pysqlite_check_remaining_sql(tail)) {
+ PyErr_SetString(pysqlite_Warning,
+ "You can only execute one statement at a time.");
+ goto error;
+ }
/* Determine if the statement is a DML statement.
SELECT is the only exception. See #9924. */
- for (p = sql_cstr; *p != 0; p++) {
+ int is_dml = 0;
+ for (const char *p = sql_cstr; *p != 0; p++) {
switch (*p) {
case ' ':
case '\r':
@@ -100,40 +103,29 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
continue;
}
- self->is_dml = (PyOS_strnicmp(p, "insert", 6) == 0)
- || (PyOS_strnicmp(p, "update", 6) == 0)
- || (PyOS_strnicmp(p, "delete", 6) == 0)
- || (PyOS_strnicmp(p, "replace", 7) == 0);
+ is_dml = (PyOS_strnicmp(p, "insert", 6) == 0)
+ || (PyOS_strnicmp(p, "update", 6) == 0)
+ || (PyOS_strnicmp(p, "delete", 6) == 0)
+ || (PyOS_strnicmp(p, "replace", 7) == 0);
break;
}
- Py_BEGIN_ALLOW_THREADS
- rc = sqlite3_prepare_v2(connection->db,
- sql_cstr,
- (int)sql_cstr_len + 1,
- &self->st,
- &tail);
- Py_END_ALLOW_THREADS
-
- PyObject_GC_Track(self);
-
- if (rc != SQLITE_OK) {
- _pysqlite_seterror(connection->db);
+ pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
+ pysqlite_StatementType);
+ if (self == NULL) {
goto error;
}
- if (rc == SQLITE_OK && pysqlite_check_remaining_sql(tail)) {
- (void)sqlite3_finalize(self->st);
- self->st = NULL;
- PyErr_SetString(pysqlite_Warning,
- "You can only execute one statement at a time.");
- goto error;
- }
+ self->st = stmt;
+ self->in_use = 0;
+ self->is_dml = is_dml;
+ self->in_weakreflist = NULL;
+ PyObject_GC_Track(self);
return self;
error:
- Py_DECREF(self);
+ (void)sqlite3_finalize(stmt);
return NULL;
}