[Python-checkins] bpo-44165: Optimise sqlite3 statement preparation by passing string size (GH-26206)

pablogsal webhook-mailer at python.org
Wed Jun 2 08:26:14 EDT 2021


https://github.com/python/cpython/commit/a384b6c04054a2c5050a99059836175cf73e2016
commit: a384b6c04054a2c5050a99059836175cf73e2016
branch: main
author: Erlend Egeberg Aasland <erlend.aasland at innova.no>
committer: pablogsal <Pablogsal at gmail.com>
date: 2021-06-02T13:26:06+01:00
summary:

bpo-44165: Optimise sqlite3 statement preparation by passing string size (GH-26206)

files:
M Modules/_sqlite/connection.c
M Modules/_sqlite/cursor.c
M Modules/_sqlite/statement.c

diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index 7252ccab10b4b..e15629c8aba24 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -451,7 +451,7 @@ pysqlite_connection_commit_impl(pysqlite_Connection *self)
     if (!sqlite3_get_autocommit(self->db)) {
 
         Py_BEGIN_ALLOW_THREADS
-        rc = sqlite3_prepare_v2(self->db, "COMMIT", -1, &statement, NULL);
+        rc = sqlite3_prepare_v2(self->db, "COMMIT", 7, &statement, NULL);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
             _pysqlite_seterror(self->db);
@@ -501,7 +501,7 @@ pysqlite_connection_rollback_impl(pysqlite_Connection *self)
         pysqlite_do_all_statements(self, ACTION_RESET, 1);
 
         Py_BEGIN_ALLOW_THREADS
-        rc = sqlite3_prepare_v2(self->db, "ROLLBACK", -1, &statement, NULL);
+        rc = sqlite3_prepare_v2(self->db, "ROLLBACK", 9, &statement, NULL);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
             _pysqlite_seterror(self->db);
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index 7656c903a4acf..757c389c6a44b 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -696,6 +696,7 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
     const char* script_cstr;
     sqlite3_stmt* statement;
     int rc;
+    Py_ssize_t sql_len;
     PyObject* result;
 
     if (!check_cursor(self)) {
@@ -705,10 +706,17 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
     self->reset = 0;
 
     if (PyUnicode_Check(script_obj)) {
-        script_cstr = PyUnicode_AsUTF8(script_obj);
+        script_cstr = PyUnicode_AsUTF8AndSize(script_obj, &sql_len);
         if (!script_cstr) {
             return NULL;
         }
+
+        int max_length = sqlite3_limit(self->connection->db,
+                                       SQLITE_LIMIT_LENGTH, -1);
+        if (sql_len >= max_length) {
+            PyErr_SetString(pysqlite_DataError, "query string is too large");
+            return NULL;
+        }
     } else {
         PyErr_SetString(PyExc_ValueError, "script argument must be unicode.");
         return NULL;
@@ -722,12 +730,14 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
     Py_DECREF(result);
 
     while (1) {
+        const char *tail;
+
         Py_BEGIN_ALLOW_THREADS
         rc = sqlite3_prepare_v2(self->connection->db,
                                 script_cstr,
-                                -1,
+                                (int)sql_len + 1,
                                 &statement,
-                                &script_cstr);
+                                &tail);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
             _pysqlite_seterror(self->connection->db);
@@ -755,9 +765,11 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
             goto error;
         }
 
-        if (*script_cstr == (char)0) {
+        if (*tail == (char)0) {
             break;
         }
+        sql_len -= (tail - script_cstr);
+        script_cstr = tail;
     }
 
 error:
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index 3a18ad8331f69..c4a790c424e35 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -66,6 +66,12 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
                      Py_TYPE(sql)->tp_name);
         return NULL;
     }
+
+    int max_length = sqlite3_limit(connection->db, SQLITE_LIMIT_LENGTH, -1);
+    if (sql_cstr_len >= max_length) {
+        PyErr_SetString(pysqlite_DataError, "query string is too large");
+        return PYSQLITE_TOO_MUCH_SQL;
+    }
     if (strlen(sql_cstr) != (size_t)sql_cstr_len) {
         PyErr_SetString(PyExc_ValueError,
                         "the query contains a null character");
@@ -106,7 +112,7 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
     Py_BEGIN_ALLOW_THREADS
     rc = sqlite3_prepare_v2(self->db,
                             sql_cstr,
-                            -1,
+                            (int)sql_cstr_len + 1,
                             &self->st,
                             &tail);
     Py_END_ALLOW_THREADS



More information about the Python-checkins mailing list