mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
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()
This commit is contained in:
parent
3a2e7aacf6
commit
3b366a4a4b
6 changed files with 41 additions and 30 deletions
|
@ -119,7 +119,7 @@ static void
|
||||||
blob_seterror(pysqlite_Blob *self, int rc)
|
blob_seterror(pysqlite_Blob *self, int rc)
|
||||||
{
|
{
|
||||||
assert(self->connection != NULL);
|
assert(self->connection != NULL);
|
||||||
_pysqlite_seterror(self->connection->state, self->connection->db);
|
set_error_from_db(self->connection->state, self->connection->db);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
|
@ -188,7 +188,7 @@ connection_exec_stmt(pysqlite_Connection *self, const char *sql)
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
(void)_pysqlite_seterror(self->state, self->db);
|
set_error_from_db(self->state, self->db);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
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));
|
pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
_pysqlite_seterror(state, db);
|
set_error_from_db(state, db);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,11 +607,11 @@ blobopen_impl(pysqlite_Connection *self, const char *table, const char *col,
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (rc == SQLITE_MISUSE) {
|
if (rc == SQLITE_MISUSE) {
|
||||||
PyErr_Format(self->state->InterfaceError, sqlite3_errstr(rc));
|
set_error_from_code(self->state, rc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (rc != SQLITE_OK) {
|
else if (rc != SQLITE_OK) {
|
||||||
_pysqlite_seterror(self->state, self->db);
|
set_error_from_db(self->state, self->db);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1352,9 +1352,9 @@ create_window_function_impl(pysqlite_Connection *self, PyTypeObject *cls,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
// Errors are not set on the database connection, so we cannot
|
/* Errors are not set on the database connection; use result code
|
||||||
// use _pysqlite_seterror().
|
* instead. */
|
||||||
PyErr_SetString(self->ProgrammingError, sqlite3_errstr(rc));
|
set_error_from_code(self->state, rc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -2112,7 +2112,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (bck_handle == NULL) {
|
if (bck_handle == NULL) {
|
||||||
_pysqlite_seterror(self->state, bck_conn);
|
set_error_from_db(self->state, bck_conn);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2150,7 +2150,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
_pysqlite_seterror(self->state, bck_conn);
|
set_error_from_db(self->state, bck_conn);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2208,7 +2208,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
|
||||||
if (callable != Py_None) {
|
if (callable != Py_None) {
|
||||||
free_callback_context(ctx);
|
free_callback_context(ctx);
|
||||||
}
|
}
|
||||||
_pysqlite_seterror(self->state, self->db);
|
set_error_from_db(self->state, self->db);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2326,7 +2326,7 @@ deserialize_impl(pysqlite_Connection *self, Py_buffer *data,
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
(void)_pysqlite_seterror(self->state, self->db);
|
set_error_from_db(self->state, self->db);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -2521,7 +2521,7 @@ setconfig_impl(pysqlite_Connection *self, int op, int enable)
|
||||||
int actual;
|
int actual;
|
||||||
int rc = sqlite3_db_config(self->db, op, enable, &actual);
|
int rc = sqlite3_db_config(self->db, op, enable, &actual);
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
(void)_pysqlite_seterror(self->state, self->db);
|
set_error_from_db(self->state, self->db);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (enable != actual) {
|
if (enable != actual) {
|
||||||
|
@ -2556,7 +2556,7 @@ getconfig_impl(pysqlite_Connection *self, int op)
|
||||||
int current;
|
int current;
|
||||||
int rc = sqlite3_db_config(self->db, op, -1, ¤t);
|
int rc = sqlite3_db_config(self->db, op, -1, ¤t);
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
(void)_pysqlite_seterror(self->state, self->db);
|
set_error_from_db(self->state, self->db);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
|
|
|
@ -505,7 +505,7 @@ begin_transaction(pysqlite_Connection *self)
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
(void)_pysqlite_seterror(self->state, self->db);
|
set_error_from_db(self->state, self->db);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,7 +715,7 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
PyObject *exc = PyErr_GetRaisedException();
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
sqlite3 *db = sqlite3_db_handle(self->st);
|
sqlite3 *db = sqlite3_db_handle(self->st);
|
||||||
_pysqlite_seterror(state, db);
|
set_error_from_db(state, db);
|
||||||
_PyErr_ChainExceptions1(exc);
|
_PyErr_ChainExceptions1(exc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -764,7 +764,7 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
PyObject *exc = PyErr_GetRaisedException();
|
PyObject *exc = PyErr_GetRaisedException();
|
||||||
sqlite3 *db = sqlite3_db_handle(self->st);
|
sqlite3 *db = sqlite3_db_handle(self->st);
|
||||||
_pysqlite_seterror(state, db);
|
set_error_from_db(state, db);
|
||||||
_PyErr_ChainExceptions1(exc);
|
_PyErr_ChainExceptions1(exc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -896,7 +896,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_pysqlite_seterror(state, self->connection->db);
|
set_error_from_db(state, self->connection->db);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,7 +1087,7 @@ pysqlite_cursor_executescript_impl(pysqlite_Cursor *self,
|
||||||
return Py_NewRef((PyObject *)self);
|
return Py_NewRef((PyObject *)self);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
_pysqlite_seterror(self->connection->state, db);
|
set_error_from_db(self->connection->state, db);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,8 +1122,7 @@ pysqlite_cursor_iternext(PyObject *op)
|
||||||
Py_CLEAR(self->statement);
|
Py_CLEAR(self->statement);
|
||||||
}
|
}
|
||||||
else if (rc != SQLITE_ROW) {
|
else if (rc != SQLITE_ROW) {
|
||||||
(void)_pysqlite_seterror(self->connection->state,
|
set_error_from_db(self->connection->state, self->connection->db);
|
||||||
self->connection->db);
|
|
||||||
(void)stmt_reset(self->statement);
|
(void)stmt_reset(self->statement);
|
||||||
Py_CLEAR(self->statement);
|
Py_CLEAR(self->statement);
|
||||||
Py_DECREF(row);
|
Py_DECREF(row);
|
||||||
|
|
|
@ -62,7 +62,7 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
_pysqlite_seterror(state, db);
|
set_error_from_db(state, db);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,18 +118,31 @@ exit:
|
||||||
Py_XDECREF(exc);
|
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.
|
* Checks the SQLite error code and sets the appropriate DB-API exception.
|
||||||
* Returns the error code (0 means no error occurred).
|
|
||||||
*/
|
*/
|
||||||
int
|
void
|
||||||
_pysqlite_seterror(pysqlite_state *state, sqlite3 *db)
|
set_error_from_db(pysqlite_state *state, sqlite3 *db)
|
||||||
{
|
{
|
||||||
int errorcode = sqlite3_errcode(db);
|
int errorcode = sqlite3_errcode(db);
|
||||||
PyObject *exc_class = get_exception_class(state, errorcode);
|
PyObject *exc_class = get_exception_class(state, errorcode);
|
||||||
if (exc_class == NULL) {
|
if (exc_class == NULL) {
|
||||||
// No new exception need be raised; just pass the error code
|
// No new exception need be raised.
|
||||||
return errorcode;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create and set the exception. */
|
/* 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
|
// sqlite3_errmsg() always returns an UTF-8 encoded message
|
||||||
const char *errmsg = sqlite3_errmsg(db);
|
const char *errmsg = sqlite3_errmsg(db);
|
||||||
raise_exception(exc_class, extended_errcode, errmsg);
|
raise_exception(exc_class, extended_errcode, errmsg);
|
||||||
return extended_errcode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the SQLite error code and sets the appropriate DB-API exception.
|
* 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);
|
sqlite_int64 _pysqlite_long_as_int64(PyObject * value);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue