[Python-checkins] closes bpo-31525: require sqlite3_prepare_v2 (#3666)

Benjamin Peterson webhook-mailer at python.org
Wed Sep 20 10:36:21 EDT 2017


https://github.com/python/cpython/commit/525269430a3f9fbb7287e4bb6b365ac216004980
commit: 525269430a3f9fbb7287e4bb6b365ac216004980
branch: master
author: Benjamin Peterson <benjamin at python.org>
committer: GitHub <noreply at github.com>
date: 2017-09-20T07:36:18-07:00
summary:

closes bpo-31525: require sqlite3_prepare_v2 (#3666)

This is based on
https://github.com/ghaering/pysqlite/commit/40b349cadbd87c42f70fc92e5e1aee6d02564c6d#diff-0489411409cd2934730e88bf7767790,
though we can be a bit more aggressive about deleting code.

files:
A Misc/NEWS.d/next/Library/2017-09-19-18-48-21.bpo-31525.O2TIL2.rst
M Modules/_sqlite/connection.c
M Modules/_sqlite/cursor.c
M Modules/_sqlite/statement.c
M Modules/_sqlite/statement.h
M Modules/_sqlite/util.c
M Modules/_sqlite/util.h

diff --git a/Misc/NEWS.d/next/Library/2017-09-19-18-48-21.bpo-31525.O2TIL2.rst b/Misc/NEWS.d/next/Library/2017-09-19-18-48-21.bpo-31525.O2TIL2.rst
new file mode 100644
index 00000000000..7f09e57d9d1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-09-19-18-48-21.bpo-31525.O2TIL2.rst
@@ -0,0 +1 @@
+In the sqlite module, require the sqlite3_prepare_v2 API. Thus, the sqlite module now requires sqlite version at least 3.3.9.
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
index f596bcf7aca..27591164b82 100644
--- a/Modules/_sqlite/connection.c
+++ b/Modules/_sqlite/connection.c
@@ -375,7 +375,7 @@ PyObject* _pysqlite_connection_begin(pysqlite_Connection* self)
     sqlite3_stmt* statement;
 
     Py_BEGIN_ALLOW_THREADS
-    rc = SQLITE3_PREPARE(self->db, self->begin_statement, -1, &statement, &tail);
+    rc = sqlite3_prepare_v2(self->db, self->begin_statement, -1, &statement, &tail);
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK) {
@@ -417,7 +417,7 @@ PyObject* pysqlite_connection_commit(pysqlite_Connection* self, PyObject* args)
     if (!sqlite3_get_autocommit(self->db)) {
 
         Py_BEGIN_ALLOW_THREADS
-        rc = SQLITE3_PREPARE(self->db, "COMMIT", -1, &statement, &tail);
+        rc = sqlite3_prepare_v2(self->db, "COMMIT", -1, &statement, &tail);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
             _pysqlite_seterror(self->db, NULL);
@@ -460,7 +460,7 @@ PyObject* pysqlite_connection_rollback(pysqlite_Connection* self, PyObject* args
         pysqlite_do_all_statements(self, ACTION_RESET, 1);
 
         Py_BEGIN_ALLOW_THREADS
-        rc = SQLITE3_PREPARE(self->db, "ROLLBACK", -1, &statement, &tail);
+        rc = sqlite3_prepare_v2(self->db, "ROLLBACK", -1, &statement, &tail);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
             _pysqlite_seterror(self->db, NULL);
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index ba6e52db568..cfe2627aacd 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -536,47 +536,19 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
             goto error;
         }
 
-        /* Keep trying the SQL statement until the schema stops changing. */
-        while (1) {
-            /* Actually execute the SQL statement. */
-            rc = pysqlite_step(self->statement->st, self->connection);
+        rc = pysqlite_step(self->statement->st, self->connection);
+        if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
             if (PyErr_Occurred()) {
-                (void)pysqlite_statement_reset(self->statement);
-                goto error;
-            }
-            if (rc == SQLITE_DONE ||  rc == SQLITE_ROW) {
-                /* If it worked, let's get out of the loop */
-                break;
-            }
-#if SQLITE_VERSION_NUMBER < 3003009
-            /* Something went wrong.  Re-set the statement and try again. */
-            rc = pysqlite_statement_reset(self->statement);
-#endif
-            if (rc == SQLITE_SCHEMA) {
-                /* If this was a result of the schema changing, let's try
-                   again. */
-                rc = pysqlite_statement_recompile(self->statement, parameters);
-                if (rc == SQLITE_OK) {
-                    continue;
+                /* there was an error that occurred in a user-defined callback */
+                if (_enable_callback_tracebacks) {
+                    PyErr_Print();
                 } else {
-                    /* If the database gave us an error, promote it to Python. */
-                    (void)pysqlite_statement_reset(self->statement);
-                    _pysqlite_seterror(self->connection->db, NULL);
-                    goto error;
-                }
-            } else {
-                if (PyErr_Occurred()) {
-                    /* there was an error that occurred in a user-defined callback */
-                    if (_enable_callback_tracebacks) {
-                        PyErr_Print();
-                    } else {
-                        PyErr_Clear();
-                    }
+                    PyErr_Clear();
                 }
-                (void)pysqlite_statement_reset(self->statement);
-                _pysqlite_seterror(self->connection->db, NULL);
-                goto error;
             }
+            (void)pysqlite_statement_reset(self->statement);
+            _pysqlite_seterror(self->connection->db, NULL);
+            goto error;
         }
 
         if (pysqlite_build_row_cast_map(self) != 0) {
@@ -584,29 +556,28 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
             goto error;
         }
 
-        if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
-            Py_BEGIN_ALLOW_THREADS
-            numcols = sqlite3_column_count(self->statement->st);
-            Py_END_ALLOW_THREADS
-            if (self->description == Py_None && numcols > 0) {
-                Py_SETREF(self->description, PyTuple_New(numcols));
-                if (!self->description) {
+        assert(rc == SQLITE_ROW || rc == SQLITE_DONE);
+        Py_BEGIN_ALLOW_THREADS
+        numcols = sqlite3_column_count(self->statement->st);
+        Py_END_ALLOW_THREADS
+        if (self->description == Py_None && numcols > 0) {
+            Py_SETREF(self->description, PyTuple_New(numcols));
+            if (!self->description) {
+                goto error;
+            }
+            for (i = 0; i < numcols; i++) {
+                descriptor = PyTuple_New(7);
+                if (!descriptor) {
                     goto error;
                 }
-                for (i = 0; i < numcols; i++) {
-                    descriptor = PyTuple_New(7);
-                    if (!descriptor) {
-                        goto error;
-                    }
-                    PyTuple_SetItem(descriptor, 0, _pysqlite_build_column_name(sqlite3_column_name(self->statement->st, i)));
-                    Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 1, Py_None);
-                    Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 2, Py_None);
-                    Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 3, Py_None);
-                    Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 4, Py_None);
-                    Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 5, Py_None);
-                    Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 6, Py_None);
-                    PyTuple_SetItem(self->description, i, descriptor);
-                }
+                PyTuple_SetItem(descriptor, 0, _pysqlite_build_column_name(sqlite3_column_name(self->statement->st, i)));
+                Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 1, Py_None);
+                Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 2, Py_None);
+                Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 3, Py_None);
+                Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 4, Py_None);
+                Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 5, Py_None);
+                Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 6, Py_None);
+                PyTuple_SetItem(self->description, i, descriptor);
             }
         }
 
@@ -708,11 +679,11 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
 
     while (1) {
         Py_BEGIN_ALLOW_THREADS
-        rc = SQLITE3_PREPARE(self->connection->db,
-                             script_cstr,
-                             -1,
-                             &statement,
-                             &script_cstr);
+        rc = sqlite3_prepare_v2(self->connection->db,
+                                script_cstr,
+                                -1,
+                                &statement,
+                                &script_cstr);
         Py_END_ALLOW_THREADS
         if (rc != SQLITE_OK) {
             _pysqlite_seterror(self->connection->db, NULL);
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index bc0d9401d0f..38690884227 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -93,11 +93,11 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con
     }
 
     Py_BEGIN_ALLOW_THREADS
-    rc = SQLITE3_PREPARE(connection->db,
-                         sql_cstr,
-                         -1,
-                         &self->st,
-                         &tail);
+    rc = sqlite3_prepare_v2(connection->db,
+                            sql_cstr,
+                            -1,
+                            &self->st,
+                            &tail);
     Py_END_ALLOW_THREADS
 
     self->db = connection->db;
@@ -319,52 +319,6 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
     }
 }
 
-int pysqlite_statement_recompile(pysqlite_Statement* self, PyObject* params)
-{
-    const char* tail;
-    int rc;
-    const char* sql_cstr;
-    Py_ssize_t sql_len;
-    sqlite3_stmt* new_st;
-
-    sql_cstr = PyUnicode_AsUTF8AndSize(self->sql, &sql_len);
-    if (sql_cstr == NULL) {
-        rc = PYSQLITE_SQL_WRONG_TYPE;
-        return rc;
-    }
-
-    Py_BEGIN_ALLOW_THREADS
-    rc = SQLITE3_PREPARE(self->db,
-                         sql_cstr,
-                         -1,
-                         &new_st,
-                         &tail);
-    Py_END_ALLOW_THREADS
-
-    if (rc == SQLITE_OK) {
-        /* The efficient sqlite3_transfer_bindings is only available in SQLite
-         * version 3.2.2 or later. For older SQLite releases, that might not
-         * even define SQLITE_VERSION_NUMBER, we do it the manual way.
-         */
-        #ifdef SQLITE_VERSION_NUMBER
-        #if SQLITE_VERSION_NUMBER >= 3002002
-        /* The check for the number of parameters is necessary to not trigger a
-         * bug in certain SQLite versions (experienced in 3.2.8 and 3.3.4). */
-        if (sqlite3_bind_parameter_count(self->st) > 0) {
-            (void)sqlite3_transfer_bindings(self->st, new_st);
-        }
-        #endif
-        #else
-        statement_bind_parameters(self, params);
-        #endif
-
-        (void)sqlite3_finalize(self->st);
-        self->st = new_st;
-    }
-
-    return rc;
-}
-
 int pysqlite_statement_finalize(pysqlite_Statement* self)
 {
     int rc;
diff --git a/Modules/_sqlite/statement.h b/Modules/_sqlite/statement.h
index 8db10f6649c..fd88d7d6622 100644
--- a/Modules/_sqlite/statement.h
+++ b/Modules/_sqlite/statement.h
@@ -50,7 +50,6 @@ void pysqlite_statement_dealloc(pysqlite_Statement* self);
 int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter);
 void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* parameters);
 
-int pysqlite_statement_recompile(pysqlite_Statement* self, PyObject* parameters);
 int pysqlite_statement_finalize(pysqlite_Statement* self);
 int pysqlite_statement_reset(pysqlite_Statement* self);
 void pysqlite_statement_mark_dirty(pysqlite_Statement* self);
diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c
index b371aed99db..3fa671d052b 100644
--- a/Modules/_sqlite/util.c
+++ b/Modules/_sqlite/util.c
@@ -47,17 +47,7 @@ int pysqlite_step(sqlite3_stmt* statement, pysqlite_Connection* connection)
  */
 int _pysqlite_seterror(sqlite3* db, sqlite3_stmt* st)
 {
-    int errorcode;
-
-#if SQLITE_VERSION_NUMBER < 3003009
-    /* SQLite often doesn't report anything useful, unless you reset the statement first.
-       When using sqlite3_prepare_v2 this is not needed. */
-    if (st != NULL) {
-        (void)sqlite3_reset(st);
-    }
-#endif
-
-    errorcode = sqlite3_errcode(db);
+    int errorcode = sqlite3_errcode(db);
 
     switch (errorcode)
     {
diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h
index 9106fcaf54c..abaefd8b87b 100644
--- a/Modules/_sqlite/util.h
+++ b/Modules/_sqlite/util.h
@@ -39,12 +39,6 @@ int _pysqlite_seterror(sqlite3* db, sqlite3_stmt* st);
 PyObject * _pysqlite_long_from_int64(sqlite_int64 value);
 sqlite_int64 _pysqlite_long_as_int64(PyObject * value);
 
-#if SQLITE_VERSION_NUMBER >= 3003009
-#define SQLITE3_PREPARE sqlite3_prepare_v2
-#else
-#define SQLITE3_PREPARE sqlite3_prepare
-#endif
-
 #if SQLITE_VERSION_NUMBER >= 3007014
 #define SQLITE3_CLOSE sqlite3_close_v2
 #else



More information about the Python-checkins mailing list