Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 3 additions & 3 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
97 changes: 34 additions & 63 deletions Modules/_sqlite/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,77 +536,48 @@ 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) {
PyErr_SetString(pysqlite_OperationalError, "Error while building row_cast_map");
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);
}
}

Expand Down Expand Up @@ -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);
Expand Down
56 changes: 5 additions & 51 deletions Modules/_sqlite/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion Modules/_sqlite/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 1 addition & 11 deletions Modules/_sqlite/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
6 changes: 0 additions & 6 deletions Modules/_sqlite/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down