bpo-42064: Move sqlite3 exceptions to global state, part 1 of 2 (GH-26745)

Also adds a test to verify the (borrowed) exceptions in `sqlite3.Connection`.
This commit is contained in:
Erlend Egeberg Aasland 2021-06-23 14:56:40 +02:00 committed by GitHub
parent 489699ca05
commit a50e28377b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 66 additions and 48 deletions

View file

@ -208,6 +208,24 @@ def test_in_transaction_ro(self):
with self.assertRaises(AttributeError):
self.cx.in_transaction = True
def test_connection_exceptions(self):
exceptions = [
"DataError",
"DatabaseError",
"Error",
"IntegrityError",
"InterfaceError",
"NotSupportedError",
"OperationalError",
"ProgrammingError",
"Warning",
]
for exc in exceptions:
with self.subTest(exc=exc):
self.assertTrue(hasattr(self.cx, exc))
self.assertIs(getattr(sqlite, exc), getattr(self.cx, exc))
class OpenTests(unittest.TestCase):
_sql = "create table test(id integer)"

View file

@ -182,14 +182,15 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
return -1;
}
self->Warning = pysqlite_Warning;
self->Error = pysqlite_Error;
self->InterfaceError = pysqlite_InterfaceError;
self->DatabaseError = pysqlite_DatabaseError;
pysqlite_state *state = pysqlite_get_state(NULL);
self->Warning = state->Warning;
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->InternalError = pysqlite_InternalError;
self->InternalError = state->InternalError;
self->ProgrammingError = pysqlite_ProgrammingError;
self->NotSupportedError = pysqlite_NotSupportedError;

View file

@ -272,7 +272,8 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
PyObject* error_msg;
if (self->reset) {
PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
PyObject *exc = self->connection->InterfaceError;
PyErr_SetString(exc, errmsg_fetch_across_rollback);
return NULL;
}
@ -822,7 +823,8 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self)
}
if (self->reset) {
PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
PyObject *exc = self->connection->InterfaceError;
PyErr_SetString(exc, errmsg_fetch_across_rollback);
return NULL;
}

View file

@ -43,11 +43,6 @@ module _sqlite3
/* static objects at module-level */
PyObject *pysqlite_Error = NULL;
PyObject *pysqlite_Warning = NULL;
PyObject *pysqlite_InterfaceError = NULL;
PyObject *pysqlite_DatabaseError = NULL;
PyObject *pysqlite_InternalError = NULL;
PyObject *pysqlite_OperationalError = NULL;
PyObject *pysqlite_ProgrammingError = NULL;
PyObject *pysqlite_IntegrityError = NULL;
@ -409,20 +404,27 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
ADD_TYPE(module, state->RowType);
/*** Create DB-API Exception hierarchy */
ADD_EXCEPTION(module, "Error", pysqlite_Error, PyExc_Exception);
ADD_EXCEPTION(module, "Warning", pysqlite_Warning, PyExc_Exception);
ADD_EXCEPTION(module, "Error", state->Error, PyExc_Exception);
ADD_EXCEPTION(module, "Warning", state->Warning, PyExc_Exception);
/* Error subclasses */
ADD_EXCEPTION(module, "InterfaceError", pysqlite_InterfaceError, pysqlite_Error);
ADD_EXCEPTION(module, "DatabaseError", pysqlite_DatabaseError, pysqlite_Error);
ADD_EXCEPTION(module, "InterfaceError", state->InterfaceError,
state->Error);
ADD_EXCEPTION(module, "DatabaseError", state->DatabaseError, state->Error);
/* pysqlite_DatabaseError subclasses */
ADD_EXCEPTION(module, "InternalError", pysqlite_InternalError, pysqlite_DatabaseError);
ADD_EXCEPTION(module, "OperationalError", pysqlite_OperationalError, pysqlite_DatabaseError);
ADD_EXCEPTION(module, "ProgrammingError", pysqlite_ProgrammingError, pysqlite_DatabaseError);
ADD_EXCEPTION(module, "IntegrityError", pysqlite_IntegrityError, pysqlite_DatabaseError);
ADD_EXCEPTION(module, "DataError", pysqlite_DataError, pysqlite_DatabaseError);
ADD_EXCEPTION(module, "NotSupportedError", pysqlite_NotSupportedError, pysqlite_DatabaseError);
/* 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);
/* Set integer constants */
if (add_integer_constants(module) < 0) {

View file

@ -30,6 +30,11 @@
#define MODULE_NAME "sqlite3"
typedef struct {
PyObject *DatabaseError;
PyObject *Error;
PyObject *InterfaceError;
PyObject *InternalError;
PyObject *Warning;
PyObject *lru_cache;
PyTypeObject *ConnectionType;
PyTypeObject *CursorType;
@ -46,11 +51,6 @@ pysqlite_get_state(PyObject *Py_UNUSED(module))
return &pysqlite_global_state;
}
extern PyObject* pysqlite_Error;
extern PyObject* pysqlite_Warning;
extern PyObject* pysqlite_InterfaceError;
extern PyObject* pysqlite_DatabaseError;
extern PyObject* pysqlite_InternalError;
extern PyObject* pysqlite_OperationalError;
extern PyObject* pysqlite_ProgrammingError;
extern PyObject* pysqlite_IntegrityError;

View file

@ -51,12 +51,13 @@ typedef enum {
pysqlite_Statement *
pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
{
pysqlite_state *state = pysqlite_get_state(NULL);
assert(PyUnicode_Check(sql));
Py_ssize_t size;
const char *sql_cstr = PyUnicode_AsUTF8AndSize(sql, &size);
if (sql_cstr == NULL) {
PyErr_Format(pysqlite_Warning,
"SQL is of wrong type ('%s'). Must be string.",
PyObject *exc = connection->Warning;
PyErr_Format(exc, "SQL is of wrong type ('%s'). Must be string.",
Py_TYPE(sql)->tp_name);
return NULL;
}
@ -86,8 +87,8 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
}
if (pysqlite_check_remaining_sql(tail)) {
PyErr_SetString(pysqlite_Warning,
"You can only execute one statement at a time.");
PyObject *exc = connection->Warning;
PyErr_SetString(exc, "You can only execute one statement at a time.");
goto error;
}
@ -110,7 +111,6 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
break;
}
pysqlite_state *state = pysqlite_get_state(NULL);
pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
state->StatementType);
if (self == NULL) {
@ -288,7 +288,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
if (rc != SQLITE_OK) {
if (!PyErr_Occurred()) {
PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
PyErr_Format(state->InterfaceError,
"Error binding parameter %d - "
"probably unsupported type.", i);
}
return;
}
@ -342,7 +344,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
if (rc != SQLITE_OK) {
if (!PyErr_Occurred()) {
PyErr_Format(pysqlite_InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
PyErr_Format(state->InterfaceError,
"Error binding parameter :%s - "
"probably unsupported type.", binding_name);
}
return;
}

View file

@ -43,6 +43,7 @@ pysqlite_step(sqlite3_stmt *statement)
int
_pysqlite_seterror(sqlite3 *db)
{
pysqlite_state *state = pysqlite_get_state(NULL);
int errorcode = sqlite3_errcode(db);
switch (errorcode)
@ -52,7 +53,7 @@ _pysqlite_seterror(sqlite3 *db)
break;
case SQLITE_INTERNAL:
case SQLITE_NOTFOUND:
PyErr_SetString(pysqlite_InternalError, sqlite3_errmsg(db));
PyErr_SetString(state->InternalError, sqlite3_errmsg(db));
break;
case SQLITE_NOMEM:
(void)PyErr_NoMemory();
@ -73,7 +74,7 @@ _pysqlite_seterror(sqlite3 *db)
PyErr_SetString(pysqlite_OperationalError, sqlite3_errmsg(db));
break;
case SQLITE_CORRUPT:
PyErr_SetString(pysqlite_DatabaseError, sqlite3_errmsg(db));
PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db));
break;
case SQLITE_TOOBIG:
PyErr_SetString(pysqlite_DataError, sqlite3_errmsg(db));
@ -86,7 +87,7 @@ _pysqlite_seterror(sqlite3 *db)
PyErr_SetString(pysqlite_ProgrammingError, sqlite3_errmsg(db));
break;
default:
PyErr_SetString(pysqlite_DatabaseError, sqlite3_errmsg(db));
PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db));
break;
}

View file

@ -49,11 +49,6 @@ Modules/_io/_iomodule.h - _PyIO_str_write -
Modules/_io/_iomodule.h - _PyIO_empty_str -
Modules/_io/_iomodule.h - _PyIO_empty_bytes -
Modules/_multiprocessing/multiprocessing.h - _PyMp_SemLockType -
Modules/_sqlite/module.c - pysqlite_Error -
Modules/_sqlite/module.c - pysqlite_Warning -
Modules/_sqlite/module.c - pysqlite_InterfaceError -
Modules/_sqlite/module.c - pysqlite_DatabaseError -
Modules/_sqlite/module.c - pysqlite_InternalError -
Modules/_sqlite/module.c - pysqlite_OperationalError -
Modules/_sqlite/module.c - pysqlite_ProgrammingError -
Modules/_sqlite/module.c - pysqlite_IntegrityError -
@ -2371,11 +2366,6 @@ Modules/_ctypes/_ctypes.c - PyExc_ArgError -
Modules/_cursesmodule.c - PyCursesError -
Modules/_decimal/_decimal.c - DecimalException -
Modules/_queuemodule.c - EmptyError -
Modules/_sqlite/module.h - pysqlite_Error -
Modules/_sqlite/module.h - pysqlite_Warning -
Modules/_sqlite/module.h - pysqlite_InterfaceError -
Modules/_sqlite/module.h - pysqlite_DatabaseError -
Modules/_sqlite/module.h - pysqlite_InternalError -
Modules/_sqlite/module.h - pysqlite_OperationalError -
Modules/_sqlite/module.h - pysqlite_ProgrammingError -
Modules/_sqlite/module.h - pysqlite_IntegrityError -

Can't render this file because it has a wrong number of fields in line 4.