Skip to content

Commit a50e283

Browse files
author
Erlend Egeberg Aasland
authored
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`.
1 parent 489699c commit a50e283

File tree

8 files changed

+67
-49
lines changed

8 files changed

+67
-49
lines changed

Lib/sqlite3/test/dbapi.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,24 @@ def test_in_transaction_ro(self):
208208
with self.assertRaises(AttributeError):
209209
self.cx.in_transaction = True
210210

211+
def test_connection_exceptions(self):
212+
exceptions = [
213+
"DataError",
214+
"DatabaseError",
215+
"Error",
216+
"IntegrityError",
217+
"InterfaceError",
218+
"NotSupportedError",
219+
"OperationalError",
220+
"ProgrammingError",
221+
"Warning",
222+
]
223+
for exc in exceptions:
224+
with self.subTest(exc=exc):
225+
self.assertTrue(hasattr(self.cx, exc))
226+
self.assertIs(getattr(sqlite, exc), getattr(self.cx, exc))
227+
228+
211229
class OpenTests(unittest.TestCase):
212230
_sql = "create table test(id integer)"
213231

Modules/_sqlite/connection.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,15 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
182182
return -1;
183183
}
184184

185-
self->Warning = pysqlite_Warning;
186-
self->Error = pysqlite_Error;
187-
self->InterfaceError = pysqlite_InterfaceError;
188-
self->DatabaseError = pysqlite_DatabaseError;
185+
pysqlite_state *state = pysqlite_get_state(NULL);
186+
self->Warning = state->Warning;
187+
self->Error = state->Error;
188+
self->InterfaceError = state->InterfaceError;
189+
self->DatabaseError = state->DatabaseError;
189190
self->DataError = pysqlite_DataError;
190191
self->OperationalError = pysqlite_OperationalError;
191192
self->IntegrityError = pysqlite_IntegrityError;
192-
self->InternalError = pysqlite_InternalError;
193+
self->InternalError = state->InternalError;
193194
self->ProgrammingError = pysqlite_ProgrammingError;
194195
self->NotSupportedError = pysqlite_NotSupportedError;
195196

Modules/_sqlite/cursor.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,8 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
272272
PyObject* error_msg;
273273

274274
if (self->reset) {
275-
PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
275+
PyObject *exc = self->connection->InterfaceError;
276+
PyErr_SetString(exc, errmsg_fetch_across_rollback);
276277
return NULL;
277278
}
278279

@@ -822,7 +823,8 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self)
822823
}
823824

824825
if (self->reset) {
825-
PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
826+
PyObject *exc = self->connection->InterfaceError;
827+
PyErr_SetString(exc, errmsg_fetch_across_rollback);
826828
return NULL;
827829
}
828830

Modules/_sqlite/module.c

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ module _sqlite3
4343

4444
/* static objects at module-level */
4545

46-
PyObject *pysqlite_Error = NULL;
47-
PyObject *pysqlite_Warning = NULL;
48-
PyObject *pysqlite_InterfaceError = NULL;
49-
PyObject *pysqlite_DatabaseError = NULL;
50-
PyObject *pysqlite_InternalError = NULL;
5146
PyObject *pysqlite_OperationalError = NULL;
5247
PyObject *pysqlite_ProgrammingError = NULL;
5348
PyObject *pysqlite_IntegrityError = NULL;
@@ -409,20 +404,27 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
409404
ADD_TYPE(module, state->RowType);
410405

411406
/*** Create DB-API Exception hierarchy */
412-
ADD_EXCEPTION(module, "Error", pysqlite_Error, PyExc_Exception);
413-
ADD_EXCEPTION(module, "Warning", pysqlite_Warning, PyExc_Exception);
407+
ADD_EXCEPTION(module, "Error", state->Error, PyExc_Exception);
408+
ADD_EXCEPTION(module, "Warning", state->Warning, PyExc_Exception);
414409

415410
/* Error subclasses */
416-
ADD_EXCEPTION(module, "InterfaceError", pysqlite_InterfaceError, pysqlite_Error);
417-
ADD_EXCEPTION(module, "DatabaseError", pysqlite_DatabaseError, pysqlite_Error);
418-
419-
/* pysqlite_DatabaseError subclasses */
420-
ADD_EXCEPTION(module, "InternalError", pysqlite_InternalError, pysqlite_DatabaseError);
421-
ADD_EXCEPTION(module, "OperationalError", pysqlite_OperationalError, pysqlite_DatabaseError);
422-
ADD_EXCEPTION(module, "ProgrammingError", pysqlite_ProgrammingError, pysqlite_DatabaseError);
423-
ADD_EXCEPTION(module, "IntegrityError", pysqlite_IntegrityError, pysqlite_DatabaseError);
424-
ADD_EXCEPTION(module, "DataError", pysqlite_DataError, pysqlite_DatabaseError);
425-
ADD_EXCEPTION(module, "NotSupportedError", pysqlite_NotSupportedError, pysqlite_DatabaseError);
411+
ADD_EXCEPTION(module, "InterfaceError", state->InterfaceError,
412+
state->Error);
413+
ADD_EXCEPTION(module, "DatabaseError", state->DatabaseError, state->Error);
414+
415+
/* DatabaseError subclasses */
416+
ADD_EXCEPTION(module, "InternalError", state->InternalError,
417+
state->DatabaseError);
418+
ADD_EXCEPTION(module, "OperationalError", pysqlite_OperationalError,
419+
state->DatabaseError);
420+
ADD_EXCEPTION(module, "ProgrammingError", pysqlite_ProgrammingError,
421+
state->DatabaseError);
422+
ADD_EXCEPTION(module, "IntegrityError", pysqlite_IntegrityError,
423+
state->DatabaseError);
424+
ADD_EXCEPTION(module, "DataError", pysqlite_DataError,
425+
state->DatabaseError);
426+
ADD_EXCEPTION(module, "NotSupportedError", pysqlite_NotSupportedError,
427+
state->DatabaseError);
426428

427429
/* Set integer constants */
428430
if (add_integer_constants(module) < 0) {

Modules/_sqlite/module.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
#define MODULE_NAME "sqlite3"
3131

3232
typedef struct {
33+
PyObject *DatabaseError;
34+
PyObject *Error;
35+
PyObject *InterfaceError;
36+
PyObject *InternalError;
37+
PyObject *Warning;
3338
PyObject *lru_cache;
3439
PyTypeObject *ConnectionType;
3540
PyTypeObject *CursorType;
@@ -46,11 +51,6 @@ pysqlite_get_state(PyObject *Py_UNUSED(module))
4651
return &pysqlite_global_state;
4752
}
4853

49-
extern PyObject* pysqlite_Error;
50-
extern PyObject* pysqlite_Warning;
51-
extern PyObject* pysqlite_InterfaceError;
52-
extern PyObject* pysqlite_DatabaseError;
53-
extern PyObject* pysqlite_InternalError;
5454
extern PyObject* pysqlite_OperationalError;
5555
extern PyObject* pysqlite_ProgrammingError;
5656
extern PyObject* pysqlite_IntegrityError;

Modules/_sqlite/statement.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ typedef enum {
5151
pysqlite_Statement *
5252
pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
5353
{
54+
pysqlite_state *state = pysqlite_get_state(NULL);
5455
assert(PyUnicode_Check(sql));
5556
Py_ssize_t size;
5657
const char *sql_cstr = PyUnicode_AsUTF8AndSize(sql, &size);
5758
if (sql_cstr == NULL) {
58-
PyErr_Format(pysqlite_Warning,
59-
"SQL is of wrong type ('%s'). Must be string.",
59+
PyObject *exc = connection->Warning;
60+
PyErr_Format(exc, "SQL is of wrong type ('%s'). Must be string.",
6061
Py_TYPE(sql)->tp_name);
6162
return NULL;
6263
}
@@ -86,8 +87,8 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
8687
}
8788

8889
if (pysqlite_check_remaining_sql(tail)) {
89-
PyErr_SetString(pysqlite_Warning,
90-
"You can only execute one statement at a time.");
90+
PyObject *exc = connection->Warning;
91+
PyErr_SetString(exc, "You can only execute one statement at a time.");
9192
goto error;
9293
}
9394

@@ -110,7 +111,6 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
110111
break;
111112
}
112113

113-
pysqlite_state *state = pysqlite_get_state(NULL);
114114
pysqlite_Statement *self = PyObject_GC_New(pysqlite_Statement,
115115
state->StatementType);
116116
if (self == NULL) {
@@ -288,7 +288,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
288288

289289
if (rc != SQLITE_OK) {
290290
if (!PyErr_Occurred()) {
291-
PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
291+
PyErr_Format(state->InterfaceError,
292+
"Error binding parameter %d - "
293+
"probably unsupported type.", i);
292294
}
293295
return;
294296
}
@@ -342,7 +344,9 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
342344

343345
if (rc != SQLITE_OK) {
344346
if (!PyErr_Occurred()) {
345-
PyErr_Format(pysqlite_InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
347+
PyErr_Format(state->InterfaceError,
348+
"Error binding parameter :%s - "
349+
"probably unsupported type.", binding_name);
346350
}
347351
return;
348352
}

Modules/_sqlite/util.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pysqlite_step(sqlite3_stmt *statement)
4343
int
4444
_pysqlite_seterror(sqlite3 *db)
4545
{
46+
pysqlite_state *state = pysqlite_get_state(NULL);
4647
int errorcode = sqlite3_errcode(db);
4748

4849
switch (errorcode)
@@ -52,7 +53,7 @@ _pysqlite_seterror(sqlite3 *db)
5253
break;
5354
case SQLITE_INTERNAL:
5455
case SQLITE_NOTFOUND:
55-
PyErr_SetString(pysqlite_InternalError, sqlite3_errmsg(db));
56+
PyErr_SetString(state->InternalError, sqlite3_errmsg(db));
5657
break;
5758
case SQLITE_NOMEM:
5859
(void)PyErr_NoMemory();
@@ -73,7 +74,7 @@ _pysqlite_seterror(sqlite3 *db)
7374
PyErr_SetString(pysqlite_OperationalError, sqlite3_errmsg(db));
7475
break;
7576
case SQLITE_CORRUPT:
76-
PyErr_SetString(pysqlite_DatabaseError, sqlite3_errmsg(db));
77+
PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db));
7778
break;
7879
case SQLITE_TOOBIG:
7980
PyErr_SetString(pysqlite_DataError, sqlite3_errmsg(db));
@@ -86,7 +87,7 @@ _pysqlite_seterror(sqlite3 *db)
8687
PyErr_SetString(pysqlite_ProgrammingError, sqlite3_errmsg(db));
8788
break;
8889
default:
89-
PyErr_SetString(pysqlite_DatabaseError, sqlite3_errmsg(db));
90+
PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db));
9091
break;
9192
}
9293

Tools/c-analyzer/cpython/ignored.tsv

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,6 @@ Modules/_io/_iomodule.h - _PyIO_str_write -
4949
Modules/_io/_iomodule.h - _PyIO_empty_str -
5050
Modules/_io/_iomodule.h - _PyIO_empty_bytes -
5151
Modules/_multiprocessing/multiprocessing.h - _PyMp_SemLockType -
52-
Modules/_sqlite/module.c - pysqlite_Error -
53-
Modules/_sqlite/module.c - pysqlite_Warning -
54-
Modules/_sqlite/module.c - pysqlite_InterfaceError -
55-
Modules/_sqlite/module.c - pysqlite_DatabaseError -
56-
Modules/_sqlite/module.c - pysqlite_InternalError -
5752
Modules/_sqlite/module.c - pysqlite_OperationalError -
5853
Modules/_sqlite/module.c - pysqlite_ProgrammingError -
5954
Modules/_sqlite/module.c - pysqlite_IntegrityError -
@@ -2371,11 +2366,6 @@ Modules/_ctypes/_ctypes.c - PyExc_ArgError -
23712366
Modules/_cursesmodule.c - PyCursesError -
23722367
Modules/_decimal/_decimal.c - DecimalException -
23732368
Modules/_queuemodule.c - EmptyError -
2374-
Modules/_sqlite/module.h - pysqlite_Error -
2375-
Modules/_sqlite/module.h - pysqlite_Warning -
2376-
Modules/_sqlite/module.h - pysqlite_InterfaceError -
2377-
Modules/_sqlite/module.h - pysqlite_DatabaseError -
2378-
Modules/_sqlite/module.h - pysqlite_InternalError -
23792369
Modules/_sqlite/module.h - pysqlite_OperationalError -
23802370
Modules/_sqlite/module.h - pysqlite_ProgrammingError -
23812371
Modules/_sqlite/module.h - pysqlite_IntegrityError -

0 commit comments

Comments
 (0)