Skip to content

Commit 3b366a4

Browse files
gh-129928: Rework sqlite3 error helpers (#129929)
Add a helper for raising DB-API compatible exceptions based on the result code of SQLite C APIs. Some APIs do not store the error indicator on the database pointer, so we need to be able to deduce the DB-API compatible exception directly from the error code. - rename _pysqlite_seterror() as set_error_from_db() - introduce set_error_from_code()
1 parent 3a2e7aa commit 3b366a4

File tree

6 files changed

+41
-30
lines changed

6 files changed

+41
-30
lines changed

Modules/_sqlite/blob.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ static void
119119
blob_seterror(pysqlite_Blob *self, int rc)
120120
{
121121
assert(self->connection != NULL);
122-
_pysqlite_seterror(self->connection->state, self->connection->db);
122+
set_error_from_db(self->connection->state, self->connection->db);
123123
}
124124

125125
static PyObject *

Modules/_sqlite/connection.c

+13-13
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ connection_exec_stmt(pysqlite_Connection *self, const char *sql)
188188
Py_END_ALLOW_THREADS
189189

190190
if (rc != SQLITE_OK) {
191-
(void)_pysqlite_seterror(self->state, self->db);
191+
set_error_from_db(self->state, self->db);
192192
return -1;
193193
}
194194
return 0;
@@ -274,7 +274,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
274274

275275
pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
276276
if (rc != SQLITE_OK) {
277-
_pysqlite_seterror(state, db);
277+
set_error_from_db(state, db);
278278
goto error;
279279
}
280280

@@ -607,11 +607,11 @@ blobopen_impl(pysqlite_Connection *self, const char *table, const char *col,
607607
Py_END_ALLOW_THREADS
608608

609609
if (rc == SQLITE_MISUSE) {
610-
PyErr_Format(self->state->InterfaceError, sqlite3_errstr(rc));
610+
set_error_from_code(self->state, rc);
611611
return NULL;
612612
}
613613
else if (rc != SQLITE_OK) {
614-
_pysqlite_seterror(self->state, self->db);
614+
set_error_from_db(self->state, self->db);
615615
return NULL;
616616
}
617617

@@ -1352,9 +1352,9 @@ create_window_function_impl(pysqlite_Connection *self, PyTypeObject *cls,
13521352
}
13531353

13541354
if (rc != SQLITE_OK) {
1355-
// Errors are not set on the database connection, so we cannot
1356-
// use _pysqlite_seterror().
1357-
PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc));
1355+
/* Errors are not set on the database connection; use result code
1356+
* instead. */
1357+
set_error_from_code(self->state, rc);
13581358
return NULL;
13591359
}
13601360
Py_RETURN_NONE;
@@ -2112,7 +2112,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
21122112
Py_END_ALLOW_THREADS
21132113

21142114
if (bck_handle == NULL) {
2115-
_pysqlite_seterror(self->state, bck_conn);
2115+
set_error_from_db(self->state, bck_conn);
21162116
return NULL;
21172117
}
21182118

@@ -2150,7 +2150,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
21502150
Py_END_ALLOW_THREADS
21512151

21522152
if (rc != SQLITE_OK) {
2153-
_pysqlite_seterror(self->state, bck_conn);
2153+
set_error_from_db(self->state, bck_conn);
21542154
return NULL;
21552155
}
21562156

@@ -2208,7 +2208,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
22082208
if (callable != Py_None) {
22092209
free_callback_context(ctx);
22102210
}
2211-
_pysqlite_seterror(self->state, self->db);
2211+
set_error_from_db(self->state, self->db);
22122212
return NULL;
22132213
}
22142214

@@ -2326,7 +2326,7 @@ deserialize_impl(pysqlite_Connection *self, Py_buffer *data,
23262326
Py_END_ALLOW_THREADS
23272327

23282328
if (rc != SQLITE_OK) {
2329-
(void)_pysqlite_seterror(self->state, self->db);
2329+
set_error_from_db(self->state, self->db);
23302330
return NULL;
23312331
}
23322332
Py_RETURN_NONE;
@@ -2521,7 +2521,7 @@ setconfig_impl(pysqlite_Connection *self, int op, int enable)
25212521
int actual;
25222522
int rc = sqlite3_db_config(self->db, op, enable, &actual);
25232523
if (rc != SQLITE_OK) {
2524-
(void)_pysqlite_seterror(self->state, self->db);
2524+
set_error_from_db(self->state, self->db);
25252525
return NULL;
25262526
}
25272527
if (enable != actual) {
@@ -2556,7 +2556,7 @@ getconfig_impl(pysqlite_Connection *self, int op)
25562556
int current;
25572557
int rc = sqlite3_db_config(self->db, op, -1, &current);
25582558
if (rc != SQLITE_OK) {
2559-
(void)_pysqlite_seterror(self->state, self->db);
2559+
set_error_from_db(self->state, self->db);
25602560
return -1;
25612561
}
25622562
return current;

Modules/_sqlite/cursor.c

+6-7
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ begin_transaction(pysqlite_Connection *self)
505505
Py_END_ALLOW_THREADS
506506

507507
if (rc != SQLITE_OK) {
508-
(void)_pysqlite_seterror(self->state, self->db);
508+
set_error_from_db(self->state, self->db);
509509
return -1;
510510
}
511511

@@ -715,7 +715,7 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
715715
if (rc != SQLITE_OK) {
716716
PyObject *exc = PyErr_GetRaisedException();
717717
sqlite3 *db = sqlite3_db_handle(self->st);
718-
_pysqlite_seterror(state, db);
718+
set_error_from_db(state, db);
719719
_PyErr_ChainExceptions1(exc);
720720
return;
721721
}
@@ -764,7 +764,7 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
764764
if (rc != SQLITE_OK) {
765765
PyObject *exc = PyErr_GetRaisedException();
766766
sqlite3 *db = sqlite3_db_handle(self->st);
767-
_pysqlite_seterror(state, db);
767+
set_error_from_db(state, db);
768768
_PyErr_ChainExceptions1(exc);
769769
return;
770770
}
@@ -896,7 +896,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
896896
PyErr_Clear();
897897
}
898898
}
899-
_pysqlite_seterror(state, self->connection->db);
899+
set_error_from_db(state, self->connection->db);
900900
goto error;
901901
}
902902

@@ -1087,7 +1087,7 @@ pysqlite_cursor_executescript_impl(pysqlite_Cursor *self,
10871087
return Py_NewRef((PyObject *)self);
10881088

10891089
error:
1090-
_pysqlite_seterror(self->connection->state, db);
1090+
set_error_from_db(self->connection->state, db);
10911091
return NULL;
10921092
}
10931093

@@ -1122,8 +1122,7 @@ pysqlite_cursor_iternext(PyObject *op)
11221122
Py_CLEAR(self->statement);
11231123
}
11241124
else if (rc != SQLITE_ROW) {
1125-
(void)_pysqlite_seterror(self->connection->state,
1126-
self->connection->db);
1125+
set_error_from_db(self->connection->state, self->connection->db);
11271126
(void)stmt_reset(self->statement);
11281127
Py_CLEAR(self->statement);
11291128
Py_DECREF(row);

Modules/_sqlite/statement.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
6262
Py_END_ALLOW_THREADS
6363

6464
if (rc != SQLITE_OK) {
65-
_pysqlite_seterror(state, db);
65+
set_error_from_db(state, db);
6666
return NULL;
6767
}
6868

Modules/_sqlite/util.c

+18-6
Original file line numberDiff line numberDiff line change
@@ -118,26 +118,38 @@ raise_exception(PyObject *type, int errcode, const char *errmsg)
118118
Py_XDECREF(exc);
119119
}
120120

121+
void
122+
set_error_from_code(pysqlite_state *state, int code)
123+
{
124+
PyObject *exc_class = get_exception_class(state, code);
125+
if (exc_class == NULL) {
126+
// No new exception need be raised.
127+
return;
128+
}
129+
130+
const char *errmsg = sqlite3_errstr(code);
131+
assert(errmsg != NULL);
132+
raise_exception(exc_class, code, errmsg);
133+
}
134+
121135
/**
122136
* Checks the SQLite error code and sets the appropriate DB-API exception.
123-
* Returns the error code (0 means no error occurred).
124137
*/
125-
int
126-
_pysqlite_seterror(pysqlite_state *state, sqlite3 *db)
138+
void
139+
set_error_from_db(pysqlite_state *state, sqlite3 *db)
127140
{
128141
int errorcode = sqlite3_errcode(db);
129142
PyObject *exc_class = get_exception_class(state, errorcode);
130143
if (exc_class == NULL) {
131-
// No new exception need be raised; just pass the error code
132-
return errorcode;
144+
// No new exception need be raised.
145+
return;
133146
}
134147

135148
/* Create and set the exception. */
136149
int extended_errcode = sqlite3_extended_errcode(db);
137150
// sqlite3_errmsg() always returns an UTF-8 encoded message
138151
const char *errmsg = sqlite3_errmsg(db);
139152
raise_exception(exc_class, extended_errcode, errmsg);
140-
return extended_errcode;
141153
}
142154

143155
#ifdef WORDS_BIGENDIAN

Modules/_sqlite/util.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030

3131
/**
3232
* Checks the SQLite error code and sets the appropriate DB-API exception.
33-
* Returns the error code (0 means no error occurred).
3433
*/
35-
int _pysqlite_seterror(pysqlite_state *state, sqlite3 *db);
34+
void set_error_from_db(pysqlite_state *state, sqlite3 *db);
35+
void set_error_from_code(pysqlite_state *state, int code);
3636

3737
sqlite_int64 _pysqlite_long_as_int64(PyObject * value);
3838

0 commit comments

Comments
 (0)