Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-42064: Move sqlite3 exceptions to global state, part 2 of 2 #26884

Merged
merged 5 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Move the rest of the exceptions to global state
  • Loading branch information
Erlend E. Aasland committed Jun 23, 2021
commit 158a638c5feab8158d633d24114a526a215a93be
42 changes: 24 additions & 18 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,12 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
self->Error = state->Error;
self->InterfaceError = state->InterfaceError;
self->DatabaseError = state->DatabaseError;
self->DataError = pysqlite_DataError;
self->OperationalError = pysqlite_OperationalError;
self->IntegrityError = pysqlite_IntegrityError;
self->DataError = state->DataError;
self->OperationalError = state->OperationalError;
self->IntegrityError = state->IntegrityError;
self->InternalError = state->InternalError;
self->ProgrammingError = pysqlite_ProgrammingError;
self->NotSupportedError = pysqlite_NotSupportedError;
self->ProgrammingError = state->ProgrammingError;
self->NotSupportedError = state->NotSupportedError;

if (PySys_Audit("sqlite3.connect/handle", "O", self) < 0) {
return -1;
Expand Down Expand Up @@ -390,13 +390,16 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
*/
int pysqlite_check_connection(pysqlite_Connection* con)
{
pysqlite_state *state = pysqlite_get_state(NULL);
if (!con->initialized) {
PyErr_SetString(pysqlite_ProgrammingError, "Base Connection.__init__ not called.");
PyErr_SetString(state->ProgrammingError,
"Base Connection.__init__ not called.");
return 0;
}

if (!con->db) {
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed database.");
PyErr_SetString(state->ProgrammingError,
"Cannot operate on a closed database.");
return 0;
} else {
return 1;
Expand Down Expand Up @@ -858,12 +861,12 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self,

if (deterministic) {
#if SQLITE_VERSION_NUMBER < 3008003
PyErr_SetString(pysqlite_NotSupportedError,
PyErr_SetString(self->NotSupportedError,
"deterministic=True requires SQLite 3.8.3 or higher");
return NULL;
#else
if (sqlite3_libversion_number() < 3008003) {
PyErr_SetString(pysqlite_NotSupportedError,
PyErr_SetString(self->NotSupportedError,
"deterministic=True requires SQLite 3.8.3 or higher");
return NULL;
}
Expand All @@ -882,7 +885,7 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self,

if (rc != SQLITE_OK) {
/* Workaround for SQLite bug: no error code or string is available here */
PyErr_SetString(pysqlite_OperationalError, "Error creating function");
PyErr_SetString(self->OperationalError, "Error creating function");
return NULL;
}
Py_RETURN_NONE;
Expand Down Expand Up @@ -921,7 +924,7 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self,
&_destructor); // will decref func
if (rc != SQLITE_OK) {
/* Workaround for SQLite bug: no error code or string is available here */
PyErr_SetString(pysqlite_OperationalError, "Error creating aggregate");
PyErr_SetString(self->OperationalError, "Error creating aggregate");
return NULL;
}
Py_RETURN_NONE;
Expand Down Expand Up @@ -1061,7 +1064,8 @@ pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self,

rc = sqlite3_set_authorizer(self->db, _authorizer_callback, (void*)authorizer_cb);
if (rc != SQLITE_OK) {
PyErr_SetString(pysqlite_OperationalError, "Error setting authorizer callback");
PyErr_SetString(self->OperationalError,
"Error setting authorizer callback");
Py_XSETREF(self->function_pinboard_authorizer_cb, NULL);
return NULL;
} else {
Expand Down Expand Up @@ -1177,7 +1181,8 @@ pysqlite_connection_enable_load_extension_impl(pysqlite_Connection *self,
rc = sqlite3_enable_load_extension(self->db, onoff);

if (rc != SQLITE_OK) {
PyErr_SetString(pysqlite_OperationalError, "Error enabling load extension");
PyErr_SetString(self->OperationalError,
"Error enabling load extension");
return NULL;
} else {
Py_RETURN_NONE;
Expand Down Expand Up @@ -1211,7 +1216,7 @@ pysqlite_connection_load_extension_impl(pysqlite_Connection *self,

rc = sqlite3_load_extension(self->db, extension_name, 0, &errmsg);
if (rc != 0) {
PyErr_SetString(pysqlite_OperationalError, errmsg);
PyErr_SetString(self->OperationalError, errmsg);
return NULL;
} else {
Py_RETURN_NONE;
Expand All @@ -1223,7 +1228,7 @@ int pysqlite_check_thread(pysqlite_Connection* self)
{
if (self->check_same_thread) {
if (PyThread_get_thread_ident() != self->thread_ident) {
PyErr_Format(pysqlite_ProgrammingError,
PyErr_Format(self->ProgrammingError,
"SQLite objects created in a thread can only be used in that same thread. "
"The object was created in thread id %lu and this is thread id %lu.",
self->thread_ident, PyThread_get_thread_ident());
Expand Down Expand Up @@ -1575,7 +1580,7 @@ pysqlite_connection_iterdump_impl(pysqlite_Connection *self)
pyfn_iterdump = _PyDict_GetItemIdWithError(module_dict, &PyId__iterdump);
if (!pyfn_iterdump) {
if (!PyErr_Occurred()) {
PyErr_SetString(pysqlite_OperationalError,
PyErr_SetString(self->OperationalError,
"Failed to obtain _iterdump() reference");
}
goto finally;
Expand Down Expand Up @@ -1630,7 +1635,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
/* Since 3.8.8 this is already done, per commit
https://www.sqlite.org/src/info/169b5505498c0a7e */
if (!sqlite3_get_autocommit(target->db)) {
PyErr_SetString(pysqlite_OperationalError, "target is in transaction");
PyErr_SetString(self->OperationalError, "target is in transaction");
return NULL;
}
#endif
Expand Down Expand Up @@ -1742,7 +1747,8 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
{
continue;
} else {
PyErr_SetString(pysqlite_ProgrammingError, "invalid character in collation name");
PyErr_SetString(self->ProgrammingError,
"invalid character in collation name");
goto finally;
}
}
Expand Down
30 changes: 21 additions & 9 deletions Modules/_sqlite/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,10 +351,12 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'",
colname , text);
error_msg = PyUnicode_Decode(buf, strlen(buf), "ascii", "replace");

PyObject *exc = self->connection->OperationalError;
if (!error_msg) {
PyErr_SetString(pysqlite_OperationalError, "Could not decode to UTF-8");
PyErr_SetString(exc, "Could not decode to UTF-8");
} else {
PyErr_SetObject(pysqlite_OperationalError, error_msg);
PyErr_SetObject(exc, error_msg);
Py_DECREF(error_msg);
}
}
Expand Down Expand Up @@ -401,18 +403,23 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
*/
static int check_cursor(pysqlite_Cursor* cur)
{
pysqlite_state *state = pysqlite_get_state(NULL);

if (!cur->initialized) {
PyErr_SetString(pysqlite_ProgrammingError, "Base Cursor.__init__ not called.");
PyErr_SetString(state->ProgrammingError,
"Base Cursor.__init__ not called.");
return 0;
}

if (cur->closed) {
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
PyErr_SetString(state->ProgrammingError,
"Cannot operate on a closed cursor.");
return 0;
}

if (cur->locked) {
PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed.");
PyErr_SetString(state->ProgrammingError,
"Recursive use of cursors not allowed.");
return 0;
}

Expand Down Expand Up @@ -588,7 +595,8 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
}

if (pysqlite_build_row_cast_map(self) != 0) {
_PyErr_FormatFromCause(pysqlite_OperationalError, "Error while building row_cast_map");
_PyErr_FormatFromCause(self->connection->OperationalError,
"Error while building row_cast_map");
goto error;
}

Expand Down Expand Up @@ -641,7 +649,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation

if (rc == SQLITE_ROW) {
if (multiple) {
PyErr_SetString(pysqlite_ProgrammingError, "executemany() can only execute DML statements.");
PyErr_SetString(self->connection->ProgrammingError,
"executemany() can only execute DML "
"statements.");
goto error;
}

Expand Down Expand Up @@ -745,7 +755,8 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
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");
PyErr_SetString(self->connection->DataError,
"query string is too large");
return NULL;
}
} else {
Expand Down Expand Up @@ -1018,7 +1029,8 @@ pysqlite_cursor_close_impl(pysqlite_Cursor *self)
/*[clinic end generated code: output=b6055e4ec6fe63b6 input=08b36552dbb9a986]*/
{
if (!self->connection) {
PyErr_SetString(pysqlite_ProgrammingError,
pysqlite_state *state = pysqlite_get_state(NULL);
PyErr_SetString(state->ProgrammingError,
"Base Cursor.__init__ not called.");
return NULL;
}
Expand Down
3 changes: 2 additions & 1 deletion Modules/_sqlite/microprotocols.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pysqlite_microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
return Py_NewRef(alt);
}
/* else set the right exception and return NULL */
PyErr_SetString(pysqlite_ProgrammingError, "can't adapt");
pysqlite_state *state = pysqlite_get_state(NULL);
PyErr_SetString(state->ProgrammingError, "can't adapt");
return NULL;
}
21 changes: 7 additions & 14 deletions Modules/_sqlite/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ module _sqlite3
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81e330492d57488e]*/

/* static objects at module-level */

PyObject *pysqlite_OperationalError = NULL;
PyObject *pysqlite_ProgrammingError = NULL;
PyObject *pysqlite_IntegrityError = NULL;
PyObject *pysqlite_DataError = NULL;
PyObject *pysqlite_NotSupportedError = NULL;

PyObject* _pysqlite_converters = NULL;
int _pysqlite_enable_callback_tracebacks = 0;
int pysqlite_BaseTypeAdapted = 0;
Expand Down Expand Up @@ -137,7 +130,8 @@ pysqlite_enable_shared_cache_impl(PyObject *module, int do_enable)
rc = sqlite3_enable_shared_cache(do_enable);

if (rc != SQLITE_OK) {
PyErr_SetString(pysqlite_OperationalError, "Changing the shared_cache flag failed");
pysqlite_state *state = pysqlite_get_state(module);
PyErr_SetString(state->OperationalError, "Changing the shared_cache flag failed");
return NULL;
} else {
Py_RETURN_NONE;
Expand Down Expand Up @@ -415,15 +409,14 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
/* DatabaseError subclasses */
ADD_EXCEPTION(module, "InternalError", state->InternalError,
state->DatabaseError);
ADD_EXCEPTION(module, "OperationalError", pysqlite_OperationalError,
state->DatabaseError);
ADD_EXCEPTION(module, "ProgrammingError", pysqlite_ProgrammingError,
ADD_EXCEPTION(module, "OperationalError", state->OperationalError,
state->DatabaseError);
ADD_EXCEPTION(module, "IntegrityError", pysqlite_IntegrityError,
ADD_EXCEPTION(module, "ProgrammingError", state->ProgrammingError,
state->DatabaseError);
ADD_EXCEPTION(module, "DataError", pysqlite_DataError,
ADD_EXCEPTION(module, "IntegrityError", state->IntegrityError,
state->DatabaseError);
ADD_EXCEPTION(module, "NotSupportedError", pysqlite_NotSupportedError,
ADD_EXCEPTION(module, "DataError", state->DataError, state->DatabaseError);
ADD_EXCEPTION(module, "NotSupportedError", state->NotSupportedError,
state->DatabaseError);

/* Set integer constants */
Expand Down
13 changes: 7 additions & 6 deletions Modules/_sqlite/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,19 @@
#define MODULE_NAME "sqlite3"

typedef struct {
PyObject *DataError;
PyObject *DatabaseError;
PyObject *Error;
PyObject *IntegrityError;
PyObject *InterfaceError;
PyObject *InternalError;
PyObject *NotSupportedError;
PyObject *OperationalError;
PyObject *ProgrammingError;
PyObject *Warning;

PyObject *lru_cache;

PyTypeObject *ConnectionType;
PyTypeObject *CursorType;
PyTypeObject *PrepareProtocolType;
Expand All @@ -51,12 +58,6 @@ pysqlite_get_state(PyObject *Py_UNUSED(module))
return &pysqlite_global_state;
}

extern PyObject* pysqlite_OperationalError;
extern PyObject* pysqlite_ProgrammingError;
extern PyObject* pysqlite_IntegrityError;
extern PyObject* pysqlite_DataError;
extern PyObject* pysqlite_NotSupportedError;

/* A dictionary, mapping column types (INTEGER, VARCHAR, etc.) to converter
* functions, that convert the SQL value to the appropriate Python value.
* The key is uppercase.
Expand Down
21 changes: 13 additions & 8 deletions Modules/_sqlite/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,17 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
Py_ssize_t size;
const char *sql_cstr = PyUnicode_AsUTF8AndSize(sql, &size);
if (sql_cstr == NULL) {
PyObject *exc = connection->Warning;
PyErr_Format(exc, "SQL is of wrong type ('%s'). Must be string.",
PyErr_Format(connection->Warning,
"SQL is of wrong type ('%s'). Must be string.",
Py_TYPE(sql)->tp_name);
return NULL;
}

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");
PyErr_SetString(connection->DataError,
"query string is too large");
return NULL;
}
if (strlen(sql_cstr) != (size_t)size) {
Expand All @@ -87,8 +88,8 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
}

if (pysqlite_check_remaining_sql(tail)) {
PyObject *exc = connection->Warning;
PyErr_SetString(exc, "You can only execute one statement at a time.");
PyErr_SetString(connection->Warning,
"You can only execute one statement at a time.");
goto error;
}

Expand Down Expand Up @@ -250,7 +251,7 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
}
}
if (num_params != num_params_needed) {
PyErr_Format(pysqlite_ProgrammingError,
PyErr_Format(state->ProgrammingError,
"Incorrect number of bindings supplied. The current "
"statement uses %d, and there are %zd supplied.",
num_params_needed, num_params);
Expand Down Expand Up @@ -303,7 +304,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
binding_name = sqlite3_bind_parameter_name(self->st, i);
Py_END_ALLOW_THREADS
if (!binding_name) {
PyErr_Format(pysqlite_ProgrammingError, "Binding %d has no name, but you supplied a dictionary (which has only names).", i);
PyErr_Format(state->ProgrammingError,
"Binding %d has no name, but you supplied a "
"dictionary (which has only names).", i);
return;
}

Expand All @@ -321,7 +324,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
Py_DECREF(binding_name_obj);
if (!current_param) {
if (!PyErr_Occurred() || PyErr_ExceptionMatches(PyExc_LookupError)) {
PyErr_Format(pysqlite_ProgrammingError, "You did not supply a value for binding parameter :%s.", binding_name);
PyErr_Format(state->ProgrammingError,
"You did not supply a value for binding "
"parameter :%s.", binding_name);
}
return;
}
Expand Down
8 changes: 4 additions & 4 deletions Modules/_sqlite/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,20 @@ _pysqlite_seterror(sqlite3 *db)
case SQLITE_PROTOCOL:
case SQLITE_EMPTY:
case SQLITE_SCHEMA:
PyErr_SetString(pysqlite_OperationalError, sqlite3_errmsg(db));
PyErr_SetString(state->OperationalError, sqlite3_errmsg(db));
break;
case SQLITE_CORRUPT:
PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db));
break;
case SQLITE_TOOBIG:
PyErr_SetString(pysqlite_DataError, sqlite3_errmsg(db));
PyErr_SetString(state->DataError, sqlite3_errmsg(db));
break;
case SQLITE_CONSTRAINT:
case SQLITE_MISMATCH:
PyErr_SetString(pysqlite_IntegrityError, sqlite3_errmsg(db));
PyErr_SetString(state->IntegrityError, sqlite3_errmsg(db));
break;
case SQLITE_MISUSE:
PyErr_SetString(pysqlite_ProgrammingError, sqlite3_errmsg(db));
PyErr_SetString(state->ProgrammingError, sqlite3_errmsg(db));
break;
default:
PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db));
Expand Down