]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-129928: Rework sqlite3 error helpers (#129929)
authorErlend E. Aasland <erlend@python.org>
Tue, 11 Feb 2025 07:49:25 +0000 (08:49 +0100)
committerGitHub <noreply@github.com>
Tue, 11 Feb 2025 07:49:25 +0000 (07:49 +0000)
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()

Modules/_sqlite/blob.c
Modules/_sqlite/connection.c
Modules/_sqlite/cursor.c
Modules/_sqlite/statement.c
Modules/_sqlite/util.c
Modules/_sqlite/util.h

index 390375628bfb4f6d23c403c55fb812cdb71eb5fb..35d090e3ca2dce35d2115adc6afd686fa5f6a51f 100644 (file)
@@ -119,7 +119,7 @@ static void
 blob_seterror(pysqlite_Blob *self, int rc)
 {
     assert(self->connection != NULL);
-    _pysqlite_seterror(self->connection->state, self->connection->db);
+    set_error_from_db(self->connection->state, self->connection->db);
 }
 
 static PyObject *
index a4191dd0a1cb2c4d0547b606eaa85a4a30567e0f..7997e5f4d986f3e03c7db4ba05a5f30fe7ccc36e 100644 (file)
@@ -188,7 +188,7 @@ connection_exec_stmt(pysqlite_Connection *self, const char *sql)
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK) {
-        (void)_pysqlite_seterror(self->state, self->db);
+        set_error_from_db(self->state, self->db);
         return -1;
     }
     return 0;
@@ -274,7 +274,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
 
     pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
     if (rc != SQLITE_OK) {
-        _pysqlite_seterror(state, db);
+        set_error_from_db(state, db);
         goto error;
     }
 
@@ -607,11 +607,11 @@ blobopen_impl(pysqlite_Connection *self, const char *table, const char *col,
     Py_END_ALLOW_THREADS
 
     if (rc == SQLITE_MISUSE) {
-        PyErr_Format(self->state->InterfaceError, sqlite3_errstr(rc));
+        set_error_from_code(self->state, rc);
         return NULL;
     }
     else if (rc != SQLITE_OK) {
-        _pysqlite_seterror(self->state, self->db);
+        set_error_from_db(self->state, self->db);
         return NULL;
     }
 
@@ -1352,9 +1352,9 @@ create_window_function_impl(pysqlite_Connection *self, PyTypeObject *cls,
     }
 
     if (rc != SQLITE_OK) {
-        // Errors are not set on the database connection, so we cannot
-        // use _pysqlite_seterror().
-        PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc));
+        /* Errors are not set on the database connection; use result code
+         * instead. */
+        set_error_from_code(self->state, rc);
         return NULL;
     }
     Py_RETURN_NONE;
@@ -2112,7 +2112,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
     Py_END_ALLOW_THREADS
 
     if (bck_handle == NULL) {
-        _pysqlite_seterror(self->state, bck_conn);
+        set_error_from_db(self->state, bck_conn);
         return NULL;
     }
 
@@ -2150,7 +2150,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK) {
-        _pysqlite_seterror(self->state, bck_conn);
+        set_error_from_db(self->state, bck_conn);
         return NULL;
     }
 
@@ -2208,7 +2208,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
         if (callable != Py_None) {
             free_callback_context(ctx);
         }
-        _pysqlite_seterror(self->state, self->db);
+        set_error_from_db(self->state, self->db);
         return NULL;
     }
 
@@ -2326,7 +2326,7 @@ deserialize_impl(pysqlite_Connection *self, Py_buffer *data,
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK) {
-        (void)_pysqlite_seterror(self->state, self->db);
+        set_error_from_db(self->state, self->db);
         return NULL;
     }
     Py_RETURN_NONE;
@@ -2521,7 +2521,7 @@ setconfig_impl(pysqlite_Connection *self, int op, int enable)
     int actual;
     int rc = sqlite3_db_config(self->db, op, enable, &actual);
     if (rc != SQLITE_OK) {
-        (void)_pysqlite_seterror(self->state, self->db);
+        set_error_from_db(self->state, self->db);
         return NULL;
     }
     if (enable != actual) {
@@ -2556,7 +2556,7 @@ getconfig_impl(pysqlite_Connection *self, int op)
     int current;
     int rc = sqlite3_db_config(self->db, op, -1, &current);
     if (rc != SQLITE_OK) {
-        (void)_pysqlite_seterror(self->state, self->db);
+        set_error_from_db(self->state, self->db);
         return -1;
     }
     return current;
index 02d598040775b04605e9c7c4062f7bebb4a8cfac..ad3587d88dd854a18484a149f3ee2cb4b79509c9 100644 (file)
@@ -505,7 +505,7 @@ begin_transaction(pysqlite_Connection *self)
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK) {
-        (void)_pysqlite_seterror(self->state, self->db);
+        set_error_from_db(self->state, self->db);
         return -1;
     }
 
@@ -715,7 +715,7 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
             if (rc != SQLITE_OK) {
                 PyObject *exc = PyErr_GetRaisedException();
                 sqlite3 *db = sqlite3_db_handle(self->st);
-                _pysqlite_seterror(state, db);
+                set_error_from_db(state, db);
                 _PyErr_ChainExceptions1(exc);
                 return;
             }
@@ -764,7 +764,7 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
             if (rc != SQLITE_OK) {
                 PyObject *exc = PyErr_GetRaisedException();
                 sqlite3 *db = sqlite3_db_handle(self->st);
-                _pysqlite_seterror(state, db);
+                set_error_from_db(state, db);
                 _PyErr_ChainExceptions1(exc);
                 return;
            }
@@ -896,7 +896,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
                     PyErr_Clear();
                 }
             }
-            _pysqlite_seterror(state, self->connection->db);
+            set_error_from_db(state, self->connection->db);
             goto error;
         }
 
@@ -1087,7 +1087,7 @@ pysqlite_cursor_executescript_impl(pysqlite_Cursor *self,
     return Py_NewRef((PyObject *)self);
 
 error:
-    _pysqlite_seterror(self->connection->state, db);
+    set_error_from_db(self->connection->state, db);
     return NULL;
 }
 
@@ -1122,8 +1122,7 @@ pysqlite_cursor_iternext(PyObject *op)
         Py_CLEAR(self->statement);
     }
     else if (rc != SQLITE_ROW) {
-        (void)_pysqlite_seterror(self->connection->state,
-                                 self->connection->db);
+        set_error_from_db(self->connection->state, self->connection->db);
         (void)stmt_reset(self->statement);
         Py_CLEAR(self->statement);
         Py_DECREF(row);
index facced0dfbfafd7ad9c99c9e0235813e5b68c7db..736e60fd7782876289802fc8c80692d65e31da33 100644 (file)
@@ -62,7 +62,7 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
     Py_END_ALLOW_THREADS
 
     if (rc != SQLITE_OK) {
-        _pysqlite_seterror(state, db);
+        set_error_from_db(state, db);
         return NULL;
     }
 
index b0622e66928f47e5d891ff8d5466a97c3c86f5e2..103248ff55aa0cc6103c6188895f800d94250ad2 100644 (file)
@@ -118,18 +118,31 @@ exit:
     Py_XDECREF(exc);
 }
 
+void
+set_error_from_code(pysqlite_state *state, int code)
+{
+    PyObject *exc_class = get_exception_class(state, code);
+    if (exc_class == NULL) {
+        // No new exception need be raised.
+        return;
+    }
+
+    const char *errmsg = sqlite3_errstr(code);
+    assert(errmsg != NULL);
+    raise_exception(exc_class, code, errmsg);
+}
+
 /**
  * Checks the SQLite error code and sets the appropriate DB-API exception.
- * Returns the error code (0 means no error occurred).
  */
-int
-_pysqlite_seterror(pysqlite_state *state, sqlite3 *db)
+void
+set_error_from_db(pysqlite_state *state, sqlite3 *db)
 {
     int errorcode = sqlite3_errcode(db);
     PyObject *exc_class = get_exception_class(state, errorcode);
     if (exc_class == NULL) {
-        // No new exception need be raised; just pass the error code
-        return errorcode;
+        // No new exception need be raised.
+        return;
     }
 
     /* Create and set the exception. */
@@ -137,7 +150,6 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db)
     // sqlite3_errmsg() always returns an UTF-8 encoded message
     const char *errmsg = sqlite3_errmsg(db);
     raise_exception(exc_class, extended_errcode, errmsg);
-    return extended_errcode;
 }
 
 #ifdef WORDS_BIGENDIAN
index 68b1a8cb67ace356c3fd8c5b13776aa1f2f91ab2..f8e45baffaefe320f2f0e6163713034e8a81b373 100644 (file)
@@ -30,9 +30,9 @@
 
 /**
  * Checks the SQLite error code and sets the appropriate DB-API exception.
- * Returns the error code (0 means no error occurred).
  */
-int _pysqlite_seterror(pysqlite_state *state, sqlite3 *db);
+void set_error_from_db(pysqlite_state *state, sqlite3 *db);
+void set_error_from_code(pysqlite_state *state, int code);
 
 sqlite_int64 _pysqlite_long_as_int64(PyObject * value);