From 525269430a3f9fbb7287e4bb6b365ac216004980 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Wed, 20 Sep 2017 07:36:18 -0700 Subject: [PATCH] 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. --- .../2017-09-19-18-48-21.bpo-31525.O2TIL2.rst | 1 + Modules/_sqlite/connection.c | 6 +- Modules/_sqlite/cursor.c | 97 +++++++------------ Modules/_sqlite/statement.c | 56 +---------- Modules/_sqlite/statement.h | 1 - Modules/_sqlite/util.c | 12 +-- Modules/_sqlite/util.h | 6 -- 7 files changed, 44 insertions(+), 135 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2017-09-19-18-48-21.bpo-31525.O2TIL2.rst 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 0000000000..7f09e57d9d --- /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 f596bcf7ac..27591164b8 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 ba6e52db56..cfe2627aac 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 bc0d9401d0..3869088422 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 8db10f6649..fd88d7d662 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 b371aed99d..3fa671d052 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 9106fcaf54..abaefd8b87 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 -- 2.40.0