diff options
author | Erlend Egeberg Aasland <erlend.aasland@innova.no> | 2021-08-30 20:32:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-30 19:32:21 +0100 |
commit | 86d8b465231473f850cc5e906013ba8581ddb503 (patch) | |
tree | 38821067898cf1fb5fec7b0102e08776ce9df3fe /Modules/_sqlite/util.c | |
parent | f62763d26755260c31c717fb396550e00eb6b2a0 (diff) | |
download | cpython-86d8b465231473f850cc5e906013ba8581ddb503.tar.gz cpython-86d8b465231473f850cc5e906013ba8581ddb503.zip |
bpo-16379: expose SQLite error codes and error names in `sqlite3` (GH-27786)
Diffstat (limited to 'Modules/_sqlite/util.c')
-rw-r--r-- | Modules/_sqlite/util.c | 105 |
1 files changed, 78 insertions, 27 deletions
diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 24cefc626b6..cfd189dfc33 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -36,27 +36,19 @@ pysqlite_step(sqlite3_stmt *statement) return rc; } -/** - * 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) +// Returns non-NULL if a new exception should be raised +static PyObject * +get_exception_class(pysqlite_state *state, int errorcode) { - int errorcode = sqlite3_errcode(db); - - switch (errorcode) - { + switch (errorcode) { case SQLITE_OK: PyErr_Clear(); - break; + return NULL; case SQLITE_INTERNAL: case SQLITE_NOTFOUND: - PyErr_SetString(state->InternalError, sqlite3_errmsg(db)); - break; + return state->InternalError; case SQLITE_NOMEM: - (void)PyErr_NoMemory(); - break; + return PyErr_NoMemory(); case SQLITE_ERROR: case SQLITE_PERM: case SQLITE_ABORT: @@ -70,26 +62,85 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) case SQLITE_PROTOCOL: case SQLITE_EMPTY: case SQLITE_SCHEMA: - PyErr_SetString(state->OperationalError, sqlite3_errmsg(db)); - break; + return state->OperationalError; case SQLITE_CORRUPT: - PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db)); - break; + return state->DatabaseError; case SQLITE_TOOBIG: - PyErr_SetString(state->DataError, sqlite3_errmsg(db)); - break; + return state->DataError; case SQLITE_CONSTRAINT: case SQLITE_MISMATCH: - PyErr_SetString(state->IntegrityError, sqlite3_errmsg(db)); - break; + return state->IntegrityError; case SQLITE_MISUSE: - PyErr_SetString(state->ProgrammingError, sqlite3_errmsg(db)); - break; + return state->ProgrammingError; default: - PyErr_SetString(state->DatabaseError, sqlite3_errmsg(db)); - break; + return state->DatabaseError; + } +} + +static void +raise_exception(PyObject *type, int errcode, const char *errmsg) +{ + PyObject *exc = NULL; + PyObject *args[] = { PyUnicode_FromString(errmsg), }; + if (args[0] == NULL) { + goto exit; + } + exc = PyObject_Vectorcall(type, args, 1, NULL); + Py_DECREF(args[0]); + if (exc == NULL) { + goto exit; + } + + PyObject *code = PyLong_FromLong(errcode); + if (code == NULL) { + goto exit; + } + int rc = PyObject_SetAttrString(exc, "sqlite_errorcode", code); + Py_DECREF(code); + if (rc < 0) { + goto exit; + } + + const char *error_name = pysqlite_error_name(errcode); + PyObject *name; + if (error_name) { + name = PyUnicode_FromString(error_name); + } + else { + name = PyUnicode_InternFromString("unknown"); + } + if (name == NULL) { + goto exit; + } + rc = PyObject_SetAttrString(exc, "sqlite_errorname", name); + Py_DECREF(name); + if (rc < 0) { + goto exit; + } + + PyErr_SetObject(type, exc); + +exit: + Py_XDECREF(exc); +} + +/** + * 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) +{ + 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; } + /* Create and set the exception. */ + const char *errmsg = sqlite3_errmsg(db); + raise_exception(exc_class, errorcode, errmsg); return errorcode; } |