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 3 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
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;
}
59 changes: 23 additions & 36 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 @@ -357,17 +351,17 @@ do { \
} \
} while (0)

#define ADD_EXCEPTION(module, name, exc, base) \
do { \
exc = PyErr_NewException(MODULE_NAME "." name, base, NULL); \
if (!exc) { \
goto error; \
} \
int res = PyModule_AddObjectRef(module, name, exc); \
Py_DECREF(exc); \
if (res < 0) { \
goto error; \
} \
#define ADD_EXCEPTION(module, state, name, base) \
do { \
state->name = PyErr_NewException(MODULE_NAME "." #name, base, NULL); \
if (state->name == NULL) { \
goto error; \
} \
int res = PyModule_AddObjectRef(module, #name, state->name); \
Py_DECREF(state->name); \
if (res < 0) { \
goto error; \
} \
erlend-aasland marked this conversation as resolved.
Show resolved Hide resolved
} while (0)

PyMODINIT_FUNC PyInit__sqlite3(void)
Expand Down Expand Up @@ -404,27 +398,20 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
ADD_TYPE(module, state->RowType);

/*** Create DB-API Exception hierarchy */
ADD_EXCEPTION(module, "Error", state->Error, PyExc_Exception);
ADD_EXCEPTION(module, "Warning", state->Warning, PyExc_Exception);
ADD_EXCEPTION(module, state, Error, PyExc_Exception);
ADD_EXCEPTION(module, state, Warning, PyExc_Exception);

/* Error subclasses */
ADD_EXCEPTION(module, "InterfaceError", state->InterfaceError,
state->Error);
ADD_EXCEPTION(module, "DatabaseError", state->DatabaseError, state->Error);
ADD_EXCEPTION(module, state, InterfaceError, state->Error);
ADD_EXCEPTION(module, state, DatabaseError, state->Error);

/* DatabaseError subclasses */
ADD_EXCEPTION(module, "InternalError", state->InternalError,
state->DatabaseError);
ADD_EXCEPTION(module, "OperationalError", pysqlite_OperationalError,
state->DatabaseError);
ADD_EXCEPTION(module, "ProgrammingError", pysqlite_ProgrammingError,
state->DatabaseError);
ADD_EXCEPTION(module, "IntegrityError", pysqlite_IntegrityError,
state->DatabaseError);
ADD_EXCEPTION(module, "DataError", pysqlite_DataError,
state->DatabaseError);
ADD_EXCEPTION(module, "NotSupportedError", pysqlite_NotSupportedError,
state->DatabaseError);
ADD_EXCEPTION(module, state, InternalError, state->DatabaseError);
ADD_EXCEPTION(module, state, OperationalError, state->DatabaseError);
ADD_EXCEPTION(module, state, ProgrammingError, state->DatabaseError);
ADD_EXCEPTION(module, state, IntegrityError, state->DatabaseError);
ADD_EXCEPTION(module, state, DataError, state->DatabaseError);
ADD_EXCEPTION(module, state, NotSupportedError, state->DatabaseError);

/* Set integer constants */
if (add_integer_constants(module) < 0) {
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
Loading