aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules/_sqlite/util.c
diff options
context:
space:
mode:
authorErlend Egeberg Aasland <erlend.aasland@innova.no>2021-08-30 20:32:21 +0200
committerGitHub <noreply@github.com>2021-08-30 19:32:21 +0100
commit86d8b465231473f850cc5e906013ba8581ddb503 (patch)
tree38821067898cf1fb5fec7b0102e08776ce9df3fe /Modules/_sqlite/util.c
parentf62763d26755260c31c717fb396550e00eb6b2a0 (diff)
downloadcpython-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.c105
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;
}