Skip to content

Commit 0516299

Browse files
author
Erlend Egeberg Aasland
authored
bpo-42064: Move sqlite3 exceptions to global state, part 2 of 2 (GH-26884)
Automerge-Triggered-By: GH:encukou
1 parent e5862f7 commit 0516299

File tree

8 files changed

+90
-92
lines changed

8 files changed

+90
-92
lines changed

Modules/_sqlite/connection.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,12 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
187187
self->Error = state->Error;
188188
self->InterfaceError = state->InterfaceError;
189189
self->DatabaseError = state->DatabaseError;
190-
self->DataError = pysqlite_DataError;
191-
self->OperationalError = pysqlite_OperationalError;
192-
self->IntegrityError = pysqlite_IntegrityError;
190+
self->DataError = state->DataError;
191+
self->OperationalError = state->OperationalError;
192+
self->IntegrityError = state->IntegrityError;
193193
self->InternalError = state->InternalError;
194-
self->ProgrammingError = pysqlite_ProgrammingError;
195-
self->NotSupportedError = pysqlite_NotSupportedError;
194+
self->ProgrammingError = state->ProgrammingError;
195+
self->NotSupportedError = state->NotSupportedError;
196196

197197
if (PySys_Audit("sqlite3.connect/handle", "O", self) < 0) {
198198
return -1;
@@ -390,13 +390,16 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
390390
*/
391391
int pysqlite_check_connection(pysqlite_Connection* con)
392392
{
393+
pysqlite_state *state = pysqlite_get_state(NULL);
393394
if (!con->initialized) {
394-
PyErr_SetString(pysqlite_ProgrammingError, "Base Connection.__init__ not called.");
395+
PyErr_SetString(state->ProgrammingError,
396+
"Base Connection.__init__ not called.");
395397
return 0;
396398
}
397399

398400
if (!con->db) {
399-
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed database.");
401+
PyErr_SetString(state->ProgrammingError,
402+
"Cannot operate on a closed database.");
400403
return 0;
401404
} else {
402405
return 1;
@@ -858,12 +861,12 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self,
858861

859862
if (deterministic) {
860863
#if SQLITE_VERSION_NUMBER < 3008003
861-
PyErr_SetString(pysqlite_NotSupportedError,
864+
PyErr_SetString(self->NotSupportedError,
862865
"deterministic=True requires SQLite 3.8.3 or higher");
863866
return NULL;
864867
#else
865868
if (sqlite3_libversion_number() < 3008003) {
866-
PyErr_SetString(pysqlite_NotSupportedError,
869+
PyErr_SetString(self->NotSupportedError,
867870
"deterministic=True requires SQLite 3.8.3 or higher");
868871
return NULL;
869872
}
@@ -882,7 +885,7 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self,
882885

883886
if (rc != SQLITE_OK) {
884887
/* Workaround for SQLite bug: no error code or string is available here */
885-
PyErr_SetString(pysqlite_OperationalError, "Error creating function");
888+
PyErr_SetString(self->OperationalError, "Error creating function");
886889
return NULL;
887890
}
888891
Py_RETURN_NONE;
@@ -921,7 +924,7 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self,
921924
&_destructor); // will decref func
922925
if (rc != SQLITE_OK) {
923926
/* Workaround for SQLite bug: no error code or string is available here */
924-
PyErr_SetString(pysqlite_OperationalError, "Error creating aggregate");
927+
PyErr_SetString(self->OperationalError, "Error creating aggregate");
925928
return NULL;
926929
}
927930
Py_RETURN_NONE;
@@ -1068,7 +1071,8 @@ pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self,
10681071
rc = sqlite3_set_authorizer(self->db, _authorizer_callback, authorizer_cb);
10691072
}
10701073
if (rc != SQLITE_OK) {
1071-
PyErr_SetString(pysqlite_OperationalError, "Error setting authorizer callback");
1074+
PyErr_SetString(self->OperationalError,
1075+
"Error setting authorizer callback");
10721076
Py_XSETREF(self->function_pinboard_authorizer_cb, NULL);
10731077
return NULL;
10741078
}
@@ -1181,7 +1185,8 @@ pysqlite_connection_enable_load_extension_impl(pysqlite_Connection *self,
11811185
rc = sqlite3_enable_load_extension(self->db, onoff);
11821186

11831187
if (rc != SQLITE_OK) {
1184-
PyErr_SetString(pysqlite_OperationalError, "Error enabling load extension");
1188+
PyErr_SetString(self->OperationalError,
1189+
"Error enabling load extension");
11851190
return NULL;
11861191
} else {
11871192
Py_RETURN_NONE;
@@ -1215,7 +1220,7 @@ pysqlite_connection_load_extension_impl(pysqlite_Connection *self,
12151220

12161221
rc = sqlite3_load_extension(self->db, extension_name, 0, &errmsg);
12171222
if (rc != 0) {
1218-
PyErr_SetString(pysqlite_OperationalError, errmsg);
1223+
PyErr_SetString(self->OperationalError, errmsg);
12191224
return NULL;
12201225
} else {
12211226
Py_RETURN_NONE;
@@ -1227,7 +1232,7 @@ int pysqlite_check_thread(pysqlite_Connection* self)
12271232
{
12281233
if (self->check_same_thread) {
12291234
if (PyThread_get_thread_ident() != self->thread_ident) {
1230-
PyErr_Format(pysqlite_ProgrammingError,
1235+
PyErr_Format(self->ProgrammingError,
12311236
"SQLite objects created in a thread can only be used in that same thread. "
12321237
"The object was created in thread id %lu and this is thread id %lu.",
12331238
self->thread_ident, PyThread_get_thread_ident());
@@ -1579,7 +1584,7 @@ pysqlite_connection_iterdump_impl(pysqlite_Connection *self)
15791584
pyfn_iterdump = _PyDict_GetItemIdWithError(module_dict, &PyId__iterdump);
15801585
if (!pyfn_iterdump) {
15811586
if (!PyErr_Occurred()) {
1582-
PyErr_SetString(pysqlite_OperationalError,
1587+
PyErr_SetString(self->OperationalError,
15831588
"Failed to obtain _iterdump() reference");
15841589
}
15851590
goto finally;
@@ -1634,7 +1639,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
16341639
/* Since 3.8.8 this is already done, per commit
16351640
https://www.sqlite.org/src/info/169b5505498c0a7e */
16361641
if (!sqlite3_get_autocommit(target->db)) {
1637-
PyErr_SetString(pysqlite_OperationalError, "target is in transaction");
1642+
PyErr_SetString(self->OperationalError, "target is in transaction");
16381643
return NULL;
16391644
}
16401645
#endif
@@ -1746,7 +1751,8 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
17461751
{
17471752
continue;
17481753
} else {
1749-
PyErr_SetString(pysqlite_ProgrammingError, "invalid character in collation name");
1754+
PyErr_SetString(self->ProgrammingError,
1755+
"invalid character in collation name");
17501756
goto finally;
17511757
}
17521758
}

Modules/_sqlite/cursor.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,12 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
351351
PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'",
352352
colname , text);
353353
error_msg = PyUnicode_Decode(buf, strlen(buf), "ascii", "replace");
354+
355+
PyObject *exc = self->connection->OperationalError;
354356
if (!error_msg) {
355-
PyErr_SetString(pysqlite_OperationalError, "Could not decode to UTF-8");
357+
PyErr_SetString(exc, "Could not decode to UTF-8");
356358
} else {
357-
PyErr_SetObject(pysqlite_OperationalError, error_msg);
359+
PyErr_SetObject(exc, error_msg);
358360
Py_DECREF(error_msg);
359361
}
360362
}
@@ -401,18 +403,23 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
401403
*/
402404
static int check_cursor(pysqlite_Cursor* cur)
403405
{
406+
pysqlite_state *state = pysqlite_get_state(NULL);
407+
404408
if (!cur->initialized) {
405-
PyErr_SetString(pysqlite_ProgrammingError, "Base Cursor.__init__ not called.");
409+
PyErr_SetString(state->ProgrammingError,
410+
"Base Cursor.__init__ not called.");
406411
return 0;
407412
}
408413

409414
if (cur->closed) {
410-
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
415+
PyErr_SetString(state->ProgrammingError,
416+
"Cannot operate on a closed cursor.");
411417
return 0;
412418
}
413419

414420
if (cur->locked) {
415-
PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed.");
421+
PyErr_SetString(state->ProgrammingError,
422+
"Recursive use of cursors not allowed.");
416423
return 0;
417424
}
418425

@@ -588,7 +595,8 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
588595
}
589596

590597
if (pysqlite_build_row_cast_map(self) != 0) {
591-
_PyErr_FormatFromCause(pysqlite_OperationalError, "Error while building row_cast_map");
598+
_PyErr_FormatFromCause(self->connection->OperationalError,
599+
"Error while building row_cast_map");
592600
goto error;
593601
}
594602

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

642650
if (rc == SQLITE_ROW) {
643651
if (multiple) {
644-
PyErr_SetString(pysqlite_ProgrammingError, "executemany() can only execute DML statements.");
652+
PyErr_SetString(self->connection->ProgrammingError,
653+
"executemany() can only execute DML "
654+
"statements.");
645655
goto error;
646656
}
647657

@@ -745,7 +755,8 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
745755
int max_length = sqlite3_limit(self->connection->db,
746756
SQLITE_LIMIT_LENGTH, -1);
747757
if (sql_len >= max_length) {
748-
PyErr_SetString(pysqlite_DataError, "query string is too large");
758+
PyErr_SetString(self->connection->DataError,
759+
"query string is too large");
749760
return NULL;
750761
}
751762
} else {
@@ -1018,7 +1029,8 @@ pysqlite_cursor_close_impl(pysqlite_Cursor *self)
10181029
/*[clinic end generated code: output=b6055e4ec6fe63b6 input=08b36552dbb9a986]*/
10191030
{
10201031
if (!self->connection) {
1021-
PyErr_SetString(pysqlite_ProgrammingError,
1032+
pysqlite_state *state = pysqlite_get_state(NULL);
1033+
PyErr_SetString(state->ProgrammingError,
10221034
"Base Cursor.__init__ not called.");
10231035
return NULL;
10241036
}

Modules/_sqlite/microprotocols.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ pysqlite_microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
143143
return Py_NewRef(alt);
144144
}
145145
/* else set the right exception and return NULL */
146-
PyErr_SetString(pysqlite_ProgrammingError, "can't adapt");
146+
pysqlite_state *state = pysqlite_get_state(NULL);
147+
PyErr_SetString(state->ProgrammingError, "can't adapt");
147148
return NULL;
148149
}

Modules/_sqlite/module.c

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ module _sqlite3
4242
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81e330492d57488e]*/
4343

4444
/* static objects at module-level */
45-
46-
PyObject *pysqlite_OperationalError = NULL;
47-
PyObject *pysqlite_ProgrammingError = NULL;
48-
PyObject *pysqlite_IntegrityError = NULL;
49-
PyObject *pysqlite_DataError = NULL;
50-
PyObject *pysqlite_NotSupportedError = NULL;
51-
5245
PyObject* _pysqlite_converters = NULL;
5346
int _pysqlite_enable_callback_tracebacks = 0;
5447
int pysqlite_BaseTypeAdapted = 0;
@@ -137,7 +130,8 @@ pysqlite_enable_shared_cache_impl(PyObject *module, int do_enable)
137130
rc = sqlite3_enable_shared_cache(do_enable);
138131

139132
if (rc != SQLITE_OK) {
140-
PyErr_SetString(pysqlite_OperationalError, "Changing the shared_cache flag failed");
133+
pysqlite_state *state = pysqlite_get_state(module);
134+
PyErr_SetString(state->OperationalError, "Changing the shared_cache flag failed");
141135
return NULL;
142136
} else {
143137
Py_RETURN_NONE;
@@ -357,17 +351,13 @@ do { \
357351
} \
358352
} while (0)
359353

360-
#define ADD_EXCEPTION(module, name, exc, base) \
361-
do { \
362-
exc = PyErr_NewException(MODULE_NAME "." name, base, NULL); \
363-
if (!exc) { \
364-
goto error; \
365-
} \
366-
int res = PyModule_AddObjectRef(module, name, exc); \
367-
Py_DECREF(exc); \
368-
if (res < 0) { \
369-
goto error; \
370-
} \
354+
#define ADD_EXCEPTION(module, state, exc, base) \
355+
do { \
356+
state->exc = PyErr_NewException(MODULE_NAME "." #exc, base, NULL); \
357+
if (state->exc == NULL) { \
358+
goto error; \
359+
} \
360+
ADD_TYPE(module, (PyTypeObject *)state->exc); \
371361
} while (0)
372362

373363
PyMODINIT_FUNC PyInit__sqlite3(void)
@@ -404,27 +394,20 @@ PyMODINIT_FUNC PyInit__sqlite3(void)
404394
ADD_TYPE(module, state->RowType);
405395

406396
/*** Create DB-API Exception hierarchy */
407-
ADD_EXCEPTION(module, "Error", state->Error, PyExc_Exception);
408-
ADD_EXCEPTION(module, "Warning", state->Warning, PyExc_Exception);
397+
ADD_EXCEPTION(module, state, Error, PyExc_Exception);
398+
ADD_EXCEPTION(module, state, Warning, PyExc_Exception);
409399

410400
/* Error subclasses */
411-
ADD_EXCEPTION(module, "InterfaceError", state->InterfaceError,
412-
state->Error);
413-
ADD_EXCEPTION(module, "DatabaseError", state->DatabaseError, state->Error);
401+
ADD_EXCEPTION(module, state, InterfaceError, state->Error);
402+
ADD_EXCEPTION(module, state, DatabaseError, state->Error);
414403

415404
/* 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);
405+
ADD_EXCEPTION(module, state, InternalError, state->DatabaseError);
406+
ADD_EXCEPTION(module, state, OperationalError, state->DatabaseError);
407+
ADD_EXCEPTION(module, state, ProgrammingError, state->DatabaseError);
408+
ADD_EXCEPTION(module, state, IntegrityError, state->DatabaseError);
409+
ADD_EXCEPTION(module, state, DataError, state->DatabaseError);
410+
ADD_EXCEPTION(module, state, NotSupportedError, state->DatabaseError);
428411

429412
/* Set integer constants */
430413
if (add_integer_constants(module) < 0) {

Modules/_sqlite/module.h

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

3232
typedef struct {
33+
PyObject *DataError;
3334
PyObject *DatabaseError;
3435
PyObject *Error;
36+
PyObject *IntegrityError;
3537
PyObject *InterfaceError;
3638
PyObject *InternalError;
39+
PyObject *NotSupportedError;
40+
PyObject *OperationalError;
41+
PyObject *ProgrammingError;
3742
PyObject *Warning;
43+
3844
PyObject *lru_cache;
45+
3946
PyTypeObject *ConnectionType;
4047
PyTypeObject *CursorType;
4148
PyTypeObject *PrepareProtocolType;
@@ -51,12 +58,6 @@ pysqlite_get_state(PyObject *Py_UNUSED(module))
5158
return &pysqlite_global_state;
5259
}
5360

54-
extern PyObject* pysqlite_OperationalError;
55-
extern PyObject* pysqlite_ProgrammingError;
56-
extern PyObject* pysqlite_IntegrityError;
57-
extern PyObject* pysqlite_DataError;
58-
extern PyObject* pysqlite_NotSupportedError;
59-
6061
/* A dictionary, mapping column types (INTEGER, VARCHAR, etc.) to converter
6162
* functions, that convert the SQL value to the appropriate Python value.
6263
* The key is uppercase.

0 commit comments

Comments
 (0)