From 83ab267abe9985664a5989488bd93e09aeefc963 Mon Sep 17 00:00:00 2001 From: palaviv Date: Thu, 13 Apr 2017 12:39:08 +0300 Subject: [PATCH 01/30] sqlite3 module expose sqlite error code and name in exceptions --- Doc/includes/sqlite3/complete_statement.py | 5 +- Doc/library/sqlite3.rst | 20 +++++ Lib/sqlite3/test/dbapi.py | 8 ++ Modules/_sqlite/module.c | 96 ++++++++++++++++++++-- Modules/_sqlite/module.h | 2 + Modules/_sqlite/util.c | 64 +++++++++++++-- 6 files changed, 179 insertions(+), 16 deletions(-) diff --git a/Doc/includes/sqlite3/complete_statement.py b/Doc/includes/sqlite3/complete_statement.py index cd38d7305bb69c..7094264adb7ecc 100644 --- a/Doc/includes/sqlite3/complete_statement.py +++ b/Doc/includes/sqlite3/complete_statement.py @@ -24,7 +24,10 @@ if buffer.lstrip().upper().startswith("SELECT"): print(cur.fetchall()) except sqlite3.Error as e: - print("An error occurred:", e.args[0]) + msg = str(e)) + error_code = e.sqlite_errorcode + error_name = e.sqlite_name + print(f"Error {error_name} [Errno {error_code}]: {msg}") buffer = "" con.close() diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 37087ac5af492a..97f1c0be1c3979 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -270,6 +270,26 @@ Module functions and constants disable the feature again. +.. exception:: Error + + Raised to signal an error from the underlying SQLite library. + + .. attribute:: sqlite_errorcode + + The numeric error code from the `SQLite API + `_. + + .. versionadded:: 3.7 + + .. attribute:: sqlite_errorname + + The symbolic name of the numeric error code + from the `SQLite API + `_. + + .. versionadded:: 3.7 + + .. _sqlite3-connection-objects: Connection Objects diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py index 7c259d2af418fe..ba8c8939dc6148 100644 --- a/Lib/sqlite3/test/dbapi.py +++ b/Lib/sqlite3/test/dbapi.py @@ -83,6 +83,14 @@ def CheckNotSupportedError(self): sqlite.DatabaseError), "NotSupportedError is not a subclass of DatabaseError") + def CheckErrorCodeOnException(self): + with self.assertRaises(sqlite.Error) as cm: + db = sqlite.connect('/no/such/file/exists') + e = cm.exception + self.assertEqual(e.sqlite_errorcode, sqlite.SQLITE_CANTOPEN) + self.assertEqual(e.sqlite_errorname, "SQLITE_CANTOPEN") + self.assertEqual(str(e), "unable to open database file") + class ConnectionTests(unittest.TestCase): def setUp(self): diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 274ee13c375eeb..96a5896fea3130 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -271,13 +271,70 @@ struct _IntConstantPair { typedef struct _IntConstantPair IntConstantPair; +/* sqlite API error codes */ +static const IntConstantPair _error_codes[] = { + {"SQLITE_OK", SQLITE_OK}, + {"SQLITE_ERROR", SQLITE_ERROR}, + {"SQLITE_INTERNAL", SQLITE_INTERNAL}, + {"SQLITE_PERM", SQLITE_PERM}, + {"SQLITE_ABORT", SQLITE_ABORT}, + {"SQLITE_BUSY", SQLITE_BUSY}, + {"SQLITE_LOCKED", SQLITE_LOCKED}, + {"SQLITE_NOMEM", SQLITE_NOMEM}, + {"SQLITE_READONLY", SQLITE_READONLY}, + {"SQLITE_INTERRUPT", SQLITE_INTERRUPT}, + {"SQLITE_IOERR", SQLITE_IOERR}, + {"SQLITE_CORRUPT", SQLITE_CORRUPT}, + {"SQLITE_NOTFOUND", SQLITE_NOTFOUND}, + {"SQLITE_FULL", SQLITE_FULL}, + {"SQLITE_CANTOPEN", SQLITE_CANTOPEN}, + {"SQLITE_PROTOCOL", SQLITE_PROTOCOL}, + {"SQLITE_EMPTY", SQLITE_EMPTY}, + {"SQLITE_SCHEMA", SQLITE_SCHEMA}, + {"SQLITE_TOOBIG", SQLITE_TOOBIG}, + {"SQLITE_CONSTRAINT", SQLITE_CONSTRAINT}, + {"SQLITE_MISMATCH", SQLITE_MISMATCH}, + {"SQLITE_MISUSE", SQLITE_MISUSE}, +#ifdef SQLITE_NOLFS + {"SQLITE_NOLFS", SQLITE_NOLFS}, +#endif +#ifdef SQLITE_AUTH + {"SQLITE_AUTH", SQLITE_AUTH}, +#endif +#ifdef SQLITE_FORMAT + {"SQLITE_FORMAT", SQLITE_FORMAT}, +#endif +#ifdef SQLITE_RANGE + {"SQLITE_RANGE", SQLITE_RANGE}, +#endif +#ifdef SQLITE_NOTADB + {"SQLITE_NOTADB", SQLITE_NOTADB}, +#endif + {"SQLITE_DONE", SQLITE_DONE}, + {"SQLITE_ROW", SQLITE_ROW}, + {(char*)NULL, 0}, + {"SQLITE_UNKNOWN", -1} +}; + +const char *sqlite3ErrName(int rc) { + int i; + for (i = 0; _error_codes[i].constant_name != 0; i++) { + if (_error_codes[i].constant_value == rc) + return _error_codes[i].constant_name; + } + // No error code matched. + return _error_codes[i+1].constant_name; +} + static const IntConstantPair _int_constants[] = { {"PARSE_DECLTYPES", PARSE_DECLTYPES}, {"PARSE_COLNAMES", PARSE_COLNAMES}, - {"SQLITE_OK", SQLITE_OK}, + /* enumerated return values for sqlite3_set_authorizer() callback */ {"SQLITE_DENY", SQLITE_DENY}, {"SQLITE_IGNORE", SQLITE_IGNORE}, + + /* enumerated values for sqlite3_set_authorizer() callback */ {"SQLITE_CREATE_INDEX", SQLITE_CREATE_INDEX}, {"SQLITE_CREATE_TABLE", SQLITE_CREATE_TABLE}, {"SQLITE_CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX}, @@ -342,6 +399,29 @@ static struct PyModuleDef _sqlite3module = { NULL }; + +static int add_to_dict(PyObject *dict, const char *key, int value) +{ + int sawerror; + PyObject *value_obj = PyLong_FromLong(value); + PyObject *name = PyUnicode_FromString(key); + + if (!value_obj || !name) { + Py_XDECREF(name); + Py_XDECREF(value_obj); + return 1; + } + + sawerror = PyDict_SetItem(dict, name, value_obj) < 0; + + Py_DECREF(value_obj); + Py_DECREF(name); + + if (sawerror) + return 1; + return 0; +} + PyMODINIT_FUNC PyInit__sqlite3(void) { PyObject *module, *dict; @@ -445,12 +525,16 @@ PyMODINIT_FUNC PyInit__sqlite3(void) /* Set integer constants */ for (i = 0; _int_constants[i].constant_name != NULL; i++) { - tmp_obj = PyLong_FromLong(_int_constants[i].constant_value); - if (!tmp_obj) { + if (add_to_dict(dict, _int_constants[i].constant_name, + _int_constants[i].constant_value) != 0) + goto error; + } + + /* Set error constants */ + for (i = 0; _error_codes[i].constant_name != 0; i++) { + if (add_to_dict(dict, _error_codes[i].constant_name, + _error_codes[i].constant_value) != 0) goto error; - } - PyDict_SetItemString(dict, _int_constants[i].constant_name, tmp_obj); - Py_DECREF(tmp_obj); } if (!(tmp_obj = PyUnicode_FromString(PYSQLITE_VERSION))) { diff --git a/Modules/_sqlite/module.h b/Modules/_sqlite/module.h index 3185ec97888567..8db22339e7437f 100644 --- a/Modules/_sqlite/module.h +++ b/Modules/_sqlite/module.h @@ -48,6 +48,8 @@ extern PyObject* _pysqlite_converters; extern int _pysqlite_enable_callback_tracebacks; extern int pysqlite_BaseTypeAdapted; +extern const char *sqlite3ErrName(int rc); + #define PARSE_DECLTYPES 1 #define PARSE_COLNAMES 2 #endif diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 3fa671d052b0d8..ecee9e16d95266 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -47,20 +47,21 @@ int pysqlite_step(sqlite3_stmt* statement, pysqlite_Connection* connection) */ int _pysqlite_seterror(sqlite3* db, sqlite3_stmt* st) { + PyObject *exc_class; int errorcode = sqlite3_errcode(db); switch (errorcode) { case SQLITE_OK: PyErr_Clear(); - break; + return errorcode; case SQLITE_INTERNAL: case SQLITE_NOTFOUND: - PyErr_SetString(pysqlite_InternalError, sqlite3_errmsg(db)); + exc_class = pysqlite_InternalError; break; case SQLITE_NOMEM: (void)PyErr_NoMemory(); - break; + return errorcode; case SQLITE_ERROR: case SQLITE_PERM: case SQLITE_ABORT: @@ -74,26 +75,71 @@ int _pysqlite_seterror(sqlite3* db, sqlite3_stmt* st) case SQLITE_PROTOCOL: case SQLITE_EMPTY: case SQLITE_SCHEMA: - PyErr_SetString(pysqlite_OperationalError, sqlite3_errmsg(db)); + exc_class = pysqlite_OperationalError; break; case SQLITE_CORRUPT: - PyErr_SetString(pysqlite_DatabaseError, sqlite3_errmsg(db)); + exc_class = pysqlite_DatabaseError; break; case SQLITE_TOOBIG: - PyErr_SetString(pysqlite_DataError, sqlite3_errmsg(db)); + exc_class = pysqlite_DataError; break; case SQLITE_CONSTRAINT: case SQLITE_MISMATCH: - PyErr_SetString(pysqlite_IntegrityError, sqlite3_errmsg(db)); + exc_class = pysqlite_IntegrityError; break; case SQLITE_MISUSE: - PyErr_SetString(pysqlite_ProgrammingError, sqlite3_errmsg(db)); + exc_class = pysqlite_ProgrammingError; break; default: - PyErr_SetString(pysqlite_DatabaseError, sqlite3_errmsg(db)); + exc_class = pysqlite_DatabaseError; break; } + /* Create and set the exception. */ + { + const char *error_msg; + const char *error_name; + PyObject *exc = NULL; + PyObject *args = NULL; + PyObject *py_code = NULL; + PyObject *py_name = NULL; + + error_name = sqlite3ErrName(errorcode); + + error_msg = sqlite3_errmsg(db); + + args = Py_BuildValue("(s)", error_msg); + if (!args) + goto error; + + exc = PyObject_Call(exc_class, args, NULL); + if (!exc) + goto error; + + py_code = Py_BuildValue("i", errorcode); + if (!py_code) + goto error; + + if (PyObject_SetAttrString(exc, "sqlite_errorcode", py_code) < 0) + goto error; + + py_name = Py_BuildValue("s", error_name); + if (!py_name) + goto error; + + if (PyObject_SetAttrString(exc, "sqlite_errorname", py_name) < 0) + goto error; + + PyErr_SetObject((PyObject *) Py_TYPE(exc), exc); + + error: + Py_XDECREF(py_code); + Py_XDECREF(py_name); + Py_XDECREF(args); + Py_XDECREF(exc); + } + + return errorcode; } From eeb10f4b17a5c9c3b45fd23aae8c7a706478d715 Mon Sep 17 00:00:00 2001 From: palaviv Date: Thu, 13 Apr 2017 19:09:06 +0300 Subject: [PATCH 02/30] Fix syntax error --- Doc/includes/sqlite3/complete_statement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/includes/sqlite3/complete_statement.py b/Doc/includes/sqlite3/complete_statement.py index 7094264adb7ecc..8b52087368f503 100644 --- a/Doc/includes/sqlite3/complete_statement.py +++ b/Doc/includes/sqlite3/complete_statement.py @@ -24,7 +24,7 @@ if buffer.lstrip().upper().startswith("SELECT"): print(cur.fetchall()) except sqlite3.Error as e: - msg = str(e)) + msg = str(e) error_code = e.sqlite_errorcode error_name = e.sqlite_name print(f"Error {error_name} [Errno {error_code}]: {msg}") From 42636f9a96d451223cb73f3d51d63e7d7bb7e295 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Wed, 8 May 2019 15:15:14 +0300 Subject: [PATCH 03/30] Add NEWS entry --- .../next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst diff --git a/Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst b/Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst new file mode 100644 index 00000000000000..2b5d657bebc011 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst @@ -0,0 +1,2 @@ +Add sqlite error code and name to the exceptions of the sqlite3 module. +Patch by Aviv Palivoda based on work by Daniel Shahaf. From f2242237c75dc45c32af68585270a821a019d2ed Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Wed, 8 May 2019 15:22:34 +0300 Subject: [PATCH 04/30] Update version --- Doc/library/sqlite3.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 97f1c0be1c3979..c1b1617d9c0461 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -279,7 +279,7 @@ Module functions and constants The numeric error code from the `SQLite API `_. - .. versionadded:: 3.7 + .. versionadded:: 3.8 .. attribute:: sqlite_errorname @@ -287,7 +287,7 @@ Module functions and constants from the `SQLite API `_. - .. versionadded:: 3.7 + .. versionadded:: 3.8 .. _sqlite3-connection-objects: From 31467e3db0f7c47a9437843a0ead852b3c3a2ca7 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Wed, 8 May 2019 15:36:55 +0300 Subject: [PATCH 05/30] Fix whitespace --- Lib/sqlite3/test/dbapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py index ba8c8939dc6148..001e8383be648b 100644 --- a/Lib/sqlite3/test/dbapi.py +++ b/Lib/sqlite3/test/dbapi.py @@ -85,7 +85,7 @@ def CheckNotSupportedError(self): def CheckErrorCodeOnException(self): with self.assertRaises(sqlite.Error) as cm: - db = sqlite.connect('/no/such/file/exists') + db = sqlite.connect('/no/such/file/exists') e = cm.exception self.assertEqual(e.sqlite_errorcode, sqlite.SQLITE_CANTOPEN) self.assertEqual(e.sqlite_errorname, "SQLITE_CANTOPEN") From 8aa0859224c48e795ef4ca8318b7a036c9172774 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Aug 2021 23:18:18 +0200 Subject: [PATCH 06/30] Move exception documentation to the exceptions section --- Doc/library/sqlite3.rst | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index dd66ddc00d7941..b700fd48897ef3 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -276,26 +276,6 @@ Module functions and constants disable the feature again. -.. exception:: Error - - Raised to signal an error from the underlying SQLite library. - - .. attribute:: sqlite_errorcode - - The numeric error code from the `SQLite API - `_. - - .. versionadded:: 3.8 - - .. attribute:: sqlite_errorname - - The symbolic name of the numeric error code - from the `SQLite API - `_. - - .. versionadded:: 3.8 - - .. _sqlite3-connection-objects: Connection Objects @@ -856,6 +836,20 @@ Exceptions The base class of the other exceptions in this module. It is a subclass of :exc:`Exception`. + .. attribute:: sqlite_errorcode + + The numeric error code from the + `SQLite API `_. + + .. versionadded:: 3.11 + + .. attribute:: sqlite_errorname + + The symbolic name of the numeric error code + from the `SQLite API `_. + + .. versionadded:: 3.11 + .. exception:: DatabaseError Exception raised for errors that are related to the database. From e4195c0d596a8d6c6f49da4a37dfd12d57711b00 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Aug 2021 23:26:25 +0200 Subject: [PATCH 07/30] Use PyModule_AddObjectRef to add error codes --- Modules/_sqlite/module.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index fd28257d992a53..4769b2d2c94479 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -390,25 +390,20 @@ static int add_integer_constants(PyObject *module) { return ret; } -static int add_to_dict(PyObject *dict, const char *key, int value) +static int +add_error_constant(PyObject *module, const char *name, int constant) { - int sawerror; - PyObject *value_obj = PyLong_FromLong(value); - PyObject *name = PyUnicode_FromString(key); - - if (!value_obj || !name) { - Py_XDECREF(name); - Py_XDECREF(value_obj); + PyObject *value = PyLong_FromLong(constant); + if (value == NULL) { + Py_DECREF(value); return 1; } - sawerror = PyDict_SetItem(dict, name, value_obj) < 0; - - Py_DECREF(value_obj); - Py_DECREF(name); - - if (sawerror) + int rc = PyModule_AddObjectRef(module, name, value); + Py_DECREF(value); + if (rc < 0) { return 1; + } return 0; } @@ -490,14 +485,11 @@ PyMODINIT_FUNC PyInit__sqlite3(void) ADD_EXCEPTION(module, state, NotSupportedError, state->DatabaseError); /* Set error constants */ - PyObject *dict = PyModule_GetDict(module); - if (dict == NULL) { - goto error; - } for (int i = 0; _error_codes[i].constant_name != 0; i++) { - if (add_to_dict(dict, _error_codes[i].constant_name, - _error_codes[i].constant_value) != 0) + if (add_error_constant(module, _error_codes[i].constant_name, + _error_codes[i].constant_value) < 0) { goto error; + } } /* Set integer constants */ From a4a076241c87b37fcfe0a413e35182c383274198 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Aug 2021 23:30:42 +0200 Subject: [PATCH 08/30] Refactor: add add_error_constants() --- Modules/_sqlite/module.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 4769b2d2c94479..2662e562a7998b 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -407,6 +407,19 @@ add_error_constant(PyObject *module, const char *name, int constant) return 0; } +static int +add_error_constants(PyObject *module) +{ + for (int i = 0; _error_codes[i].constant_name != 0; i++) { + if (add_error_constant(module, _error_codes[i].constant_name, + _error_codes[i].constant_value) < 0) + { + return -1; + } + } + return 0; +} + static struct PyModuleDef _sqlite3module = { PyModuleDef_HEAD_INIT, "_sqlite3", @@ -485,11 +498,8 @@ PyMODINIT_FUNC PyInit__sqlite3(void) ADD_EXCEPTION(module, state, NotSupportedError, state->DatabaseError); /* Set error constants */ - for (int i = 0; _error_codes[i].constant_name != 0; i++) { - if (add_error_constant(module, _error_codes[i].constant_name, - _error_codes[i].constant_value) < 0) { - goto error; - } + if (add_error_constants(module) < 0) { + goto error; } /* Set integer constants */ From c18d22752f20c609226e422b8b76968c8e30b69a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Aug 2021 23:32:48 +0200 Subject: [PATCH 09/30] Sort error codes alphabetically --- Modules/_sqlite/module.c | 50 ++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 2662e562a7998b..d5edaa917b38e6 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -291,45 +291,35 @@ typedef struct _IntConstantPair IntConstantPair; /* sqlite API error codes */ static const IntConstantPair _error_codes[] = { - {"SQLITE_OK", SQLITE_OK}, - {"SQLITE_ERROR", SQLITE_ERROR}, - {"SQLITE_INTERNAL", SQLITE_INTERNAL}, - {"SQLITE_PERM", SQLITE_PERM}, {"SQLITE_ABORT", SQLITE_ABORT}, + {"SQLITE_AUTH", SQLITE_AUTH}, {"SQLITE_BUSY", SQLITE_BUSY}, - {"SQLITE_LOCKED", SQLITE_LOCKED}, - {"SQLITE_NOMEM", SQLITE_NOMEM}, - {"SQLITE_READONLY", SQLITE_READONLY}, - {"SQLITE_INTERRUPT", SQLITE_INTERRUPT}, - {"SQLITE_IOERR", SQLITE_IOERR}, - {"SQLITE_CORRUPT", SQLITE_CORRUPT}, - {"SQLITE_NOTFOUND", SQLITE_NOTFOUND}, - {"SQLITE_FULL", SQLITE_FULL}, {"SQLITE_CANTOPEN", SQLITE_CANTOPEN}, - {"SQLITE_PROTOCOL", SQLITE_PROTOCOL}, - {"SQLITE_EMPTY", SQLITE_EMPTY}, - {"SQLITE_SCHEMA", SQLITE_SCHEMA}, - {"SQLITE_TOOBIG", SQLITE_TOOBIG}, {"SQLITE_CONSTRAINT", SQLITE_CONSTRAINT}, + {"SQLITE_CORRUPT", SQLITE_CORRUPT}, + {"SQLITE_DONE", SQLITE_DONE}, + {"SQLITE_EMPTY", SQLITE_EMPTY}, + {"SQLITE_ERROR", SQLITE_ERROR}, + {"SQLITE_FORMAT", SQLITE_FORMAT}, + {"SQLITE_FULL", SQLITE_FULL}, + {"SQLITE_INTERNAL", SQLITE_INTERNAL}, + {"SQLITE_INTERRUPT", SQLITE_INTERRUPT}, + {"SQLITE_IOERR", SQLITE_IOERR}, + {"SQLITE_LOCKED", SQLITE_LOCKED}, {"SQLITE_MISMATCH", SQLITE_MISMATCH}, {"SQLITE_MISUSE", SQLITE_MISUSE}, -#ifdef SQLITE_NOLFS {"SQLITE_NOLFS", SQLITE_NOLFS}, -#endif -#ifdef SQLITE_AUTH - {"SQLITE_AUTH", SQLITE_AUTH}, -#endif -#ifdef SQLITE_FORMAT - {"SQLITE_FORMAT", SQLITE_FORMAT}, -#endif -#ifdef SQLITE_RANGE - {"SQLITE_RANGE", SQLITE_RANGE}, -#endif -#ifdef SQLITE_NOTADB + {"SQLITE_NOMEM", SQLITE_NOMEM}, {"SQLITE_NOTADB", SQLITE_NOTADB}, -#endif - {"SQLITE_DONE", SQLITE_DONE}, + {"SQLITE_NOTFOUND", SQLITE_NOTFOUND}, + {"SQLITE_OK", SQLITE_OK}, + {"SQLITE_PERM", SQLITE_PERM}, + {"SQLITE_PROTOCOL", SQLITE_PROTOCOL}, + {"SQLITE_RANGE", SQLITE_RANGE}, + {"SQLITE_READONLY", SQLITE_READONLY}, {"SQLITE_ROW", SQLITE_ROW}, + {"SQLITE_SCHEMA", SQLITE_SCHEMA}, + {"SQLITE_TOOBIG", SQLITE_TOOBIG}, {(char*)NULL, 0}, {"SQLITE_UNKNOWN", -1} }; From 67e49e8a60ad1654cd1e9236d1433d645b1c1cf9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Aug 2021 23:33:35 +0200 Subject: [PATCH 10/30] Normalise style with the rest of the code base (PEP 7, etc.) --- Modules/_sqlite/module.c | 71 +++++++++++++++++++------------------- Modules/_sqlite/util.c | 73 ++++++++++++++++++++-------------------- 2 files changed, 74 insertions(+), 70 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index d5edaa917b38e6..9b1d2934d6f8be 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -291,44 +291,47 @@ typedef struct _IntConstantPair IntConstantPair; /* sqlite API error codes */ static const IntConstantPair _error_codes[] = { - {"SQLITE_ABORT", SQLITE_ABORT}, - {"SQLITE_AUTH", SQLITE_AUTH}, - {"SQLITE_BUSY", SQLITE_BUSY}, - {"SQLITE_CANTOPEN", SQLITE_CANTOPEN}, - {"SQLITE_CONSTRAINT", SQLITE_CONSTRAINT}, - {"SQLITE_CORRUPT", SQLITE_CORRUPT}, - {"SQLITE_DONE", SQLITE_DONE}, - {"SQLITE_EMPTY", SQLITE_EMPTY}, - {"SQLITE_ERROR", SQLITE_ERROR}, - {"SQLITE_FORMAT", SQLITE_FORMAT}, - {"SQLITE_FULL", SQLITE_FULL}, - {"SQLITE_INTERNAL", SQLITE_INTERNAL}, - {"SQLITE_INTERRUPT", SQLITE_INTERRUPT}, - {"SQLITE_IOERR", SQLITE_IOERR}, - {"SQLITE_LOCKED", SQLITE_LOCKED}, - {"SQLITE_MISMATCH", SQLITE_MISMATCH}, - {"SQLITE_MISUSE", SQLITE_MISUSE}, - {"SQLITE_NOLFS", SQLITE_NOLFS}, - {"SQLITE_NOMEM", SQLITE_NOMEM}, - {"SQLITE_NOTADB", SQLITE_NOTADB}, - {"SQLITE_NOTFOUND", SQLITE_NOTFOUND}, - {"SQLITE_OK", SQLITE_OK}, - {"SQLITE_PERM", SQLITE_PERM}, - {"SQLITE_PROTOCOL", SQLITE_PROTOCOL}, - {"SQLITE_RANGE", SQLITE_RANGE}, - {"SQLITE_READONLY", SQLITE_READONLY}, - {"SQLITE_ROW", SQLITE_ROW}, - {"SQLITE_SCHEMA", SQLITE_SCHEMA}, - {"SQLITE_TOOBIG", SQLITE_TOOBIG}, - {(char*)NULL, 0}, - {"SQLITE_UNKNOWN", -1} + {"SQLITE_ABORT", SQLITE_ABORT}, + {"SQLITE_AUTH", SQLITE_AUTH}, + {"SQLITE_BUSY", SQLITE_BUSY}, + {"SQLITE_CANTOPEN", SQLITE_CANTOPEN}, + {"SQLITE_CONSTRAINT", SQLITE_CONSTRAINT}, + {"SQLITE_CORRUPT", SQLITE_CORRUPT}, + {"SQLITE_DONE", SQLITE_DONE}, + {"SQLITE_EMPTY", SQLITE_EMPTY}, + {"SQLITE_ERROR", SQLITE_ERROR}, + {"SQLITE_FORMAT", SQLITE_FORMAT}, + {"SQLITE_FULL", SQLITE_FULL}, + {"SQLITE_INTERNAL", SQLITE_INTERNAL}, + {"SQLITE_INTERRUPT", SQLITE_INTERRUPT}, + {"SQLITE_IOERR", SQLITE_IOERR}, + {"SQLITE_LOCKED", SQLITE_LOCKED}, + {"SQLITE_MISMATCH", SQLITE_MISMATCH}, + {"SQLITE_MISUSE", SQLITE_MISUSE}, + {"SQLITE_NOLFS", SQLITE_NOLFS}, + {"SQLITE_NOMEM", SQLITE_NOMEM}, + {"SQLITE_NOTADB", SQLITE_NOTADB}, + {"SQLITE_NOTFOUND", SQLITE_NOTFOUND}, + {"SQLITE_OK", SQLITE_OK}, + {"SQLITE_PERM", SQLITE_PERM}, + {"SQLITE_PROTOCOL", SQLITE_PROTOCOL}, + {"SQLITE_RANGE", SQLITE_RANGE}, + {"SQLITE_READONLY", SQLITE_READONLY}, + {"SQLITE_ROW", SQLITE_ROW}, + {"SQLITE_SCHEMA", SQLITE_SCHEMA}, + {"SQLITE_TOOBIG", SQLITE_TOOBIG}, + {NULL, 0}, + {"SQLITE_UNKNOWN", -1} }; -const char *sqlite3ErrName(int rc) { +const char * +sqlite3ErrName(int rc) +{ int i; for (i = 0; _error_codes[i].constant_name != 0; i++) { - if (_error_codes[i].constant_value == rc) - return _error_codes[i].constant_name; + if (_error_codes[i].constant_value == rc) { + return _error_codes[i].constant_name; + } } // No error code matched. return _error_codes[i+1].constant_name; diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 1f667995f938d9..2c960ca17a6696 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -92,50 +92,51 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) } /* Create and set the exception. */ - { - const char *error_msg; - const char *error_name; - PyObject *exc = NULL; - PyObject *args = NULL; - PyObject *py_code = NULL; - PyObject *py_name = NULL; - - error_name = sqlite3ErrName(errorcode); - - error_msg = sqlite3_errmsg(db); - - args = Py_BuildValue("(s)", error_msg); - if (!args) - goto error; - - exc = PyObject_Call(exc_class, args, NULL); - if (!exc) - goto error; - - py_code = Py_BuildValue("i", errorcode); - if (!py_code) - goto error; + const char *error_msg; + const char *error_name; + PyObject *exc = NULL; + PyObject *args = NULL; + PyObject *py_code = NULL; + PyObject *py_name = NULL; + + error_name = sqlite3ErrName(errorcode); + error_msg = sqlite3_errmsg(db); + + args = Py_BuildValue("(s)", error_msg); + if (args == NULL) { + goto error; + } - if (PyObject_SetAttrString(exc, "sqlite_errorcode", py_code) < 0) - goto error; + exc = PyObject_Call(exc_class, args, NULL); + if (exc == NULL) { + goto error; + } - py_name = Py_BuildValue("s", error_name); - if (!py_name) - goto error; + py_code = Py_BuildValue("i", errorcode); + if (py_code == NULL) { + goto error; + } - if (PyObject_SetAttrString(exc, "sqlite_errorname", py_name) < 0) - goto error; + if (PyObject_SetAttrString(exc, "sqlite_errorcode", py_code) < 0) { + goto error; + } - PyErr_SetObject((PyObject *) Py_TYPE(exc), exc); + py_name = Py_BuildValue("s", error_name); + if (py_name == NULL) { + goto error; + } - error: - Py_XDECREF(py_code); - Py_XDECREF(py_name); - Py_XDECREF(args); - Py_XDECREF(exc); + if (PyObject_SetAttrString(exc, "sqlite_errorname", py_name) < 0) { + goto error; } + PyErr_SetObject((PyObject *) Py_TYPE(exc), exc); +error: + Py_XDECREF(py_code); + Py_XDECREF(py_name); + Py_XDECREF(args); + Py_XDECREF(exc); return errorcode; } From 1893ced1c2d72f6820c1ad2f4d9f775a8db20d9f Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Aug 2021 23:44:26 +0200 Subject: [PATCH 11/30] Improve "get error name" function - Naming: sqlite3ErrName => pysqlite_error_name - Error handling: * return NULL if no exception matched * receiver handles errors * don't use error table to store SQLITE_UNKNOWN string --- Modules/_sqlite/module.c | 8 +++----- Modules/_sqlite/module.h | 2 +- Modules/_sqlite/util.c | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 9b1d2934d6f8be..95968489638efe 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -321,20 +321,18 @@ static const IntConstantPair _error_codes[] = { {"SQLITE_SCHEMA", SQLITE_SCHEMA}, {"SQLITE_TOOBIG", SQLITE_TOOBIG}, {NULL, 0}, - {"SQLITE_UNKNOWN", -1} }; const char * -sqlite3ErrName(int rc) +pysqlite_error_name(int rc) { - int i; - for (i = 0; _error_codes[i].constant_name != 0; i++) { + for (int i = 0; _error_codes[i].constant_name != 0; i++) { if (_error_codes[i].constant_value == rc) { return _error_codes[i].constant_name; } } // No error code matched. - return _error_codes[i+1].constant_name; + return NULL; } static int add_integer_constants(PyObject *module) { diff --git a/Modules/_sqlite/module.h b/Modules/_sqlite/module.h index b23caaedf7a0f0..c273c1f9ed9f29 100644 --- a/Modules/_sqlite/module.h +++ b/Modules/_sqlite/module.h @@ -81,7 +81,7 @@ pysqlite_get_state_by_type(PyTypeObject *Py_UNUSED(tp)) return &pysqlite_global_state; } -extern const char *sqlite3ErrName(int rc); +extern const char *pysqlite_error_name(int rc); #define PARSE_DECLTYPES 1 #define PARSE_COLNAMES 2 diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 2c960ca17a6696..efa5bee6a1ad83 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -99,7 +99,7 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) PyObject *py_code = NULL; PyObject *py_name = NULL; - error_name = sqlite3ErrName(errorcode); + error_name = pysqlite_error_name(errorcode); error_msg = sqlite3_errmsg(db); args = Py_BuildValue("(s)", error_msg); @@ -121,7 +121,7 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) goto error; } - py_name = Py_BuildValue("s", error_name); + py_name = Py_BuildValue("s", error_name ? error_name : "SQLITE_UNKNOWN"); if (py_name == NULL) { goto error; } From 67ea5f26911dc3a48fcc81ed8c64d76109c2fa27 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Aug 2021 23:54:21 +0200 Subject: [PATCH 12/30] Refactor _pysqlite_seterror changes - Use intermingled declarations - Simplify ref count handling --- Modules/_sqlite/util.c | 49 +++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index efa5bee6a1ad83..b66c67a3b3345d 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -92,50 +92,45 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) } /* Create and set the exception. */ - const char *error_msg; - const char *error_name; PyObject *exc = NULL; - PyObject *args = NULL; - PyObject *py_code = NULL; - PyObject *py_name = NULL; - - error_name = pysqlite_error_name(errorcode); - error_msg = sqlite3_errmsg(db); - - args = Py_BuildValue("(s)", error_msg); + const char *error_msg = sqlite3_errmsg(db); + PyObject *args = Py_BuildValue("(s)", error_msg); if (args == NULL) { - goto error; + goto exit; } exc = PyObject_Call(exc_class, args, NULL); + Py_DECREF(args); if (exc == NULL) { - goto error; + goto exit; } - py_code = Py_BuildValue("i", errorcode); - if (py_code == NULL) { - goto error; + PyObject *code = Py_BuildValue("i", errorcode); + if (code == NULL) { + goto exit; } - if (PyObject_SetAttrString(exc, "sqlite_errorcode", py_code) < 0) { - goto error; + int rc = PyObject_SetAttrString(exc, "sqlite_errorcode", code); + Py_DECREF(code); + if (rc < 0) { + goto exit; } - py_name = Py_BuildValue("s", error_name ? error_name : "SQLITE_UNKNOWN"); - if (py_name == NULL) { - goto error; + const char *error_name = pysqlite_error_name(errorcode); + PyObject *name = Py_BuildValue("s", error_name ? error_name : "SQLITE_UNKNOWN"); + if (name == NULL) { + goto exit; } - if (PyObject_SetAttrString(exc, "sqlite_errorname", py_name) < 0) { - goto error; + rc = PyObject_SetAttrString(exc, "sqlite_errorname", name); + Py_DECREF(name); + if (rc < 0) { + goto exit; } - PyErr_SetObject((PyObject *) Py_TYPE(exc), exc); + PyErr_SetObject((PyObject *)Py_TYPE(exc), exc); -error: - Py_XDECREF(py_code); - Py_XDECREF(py_name); - Py_XDECREF(args); +exit: Py_XDECREF(exc); return errorcode; } From 6ced38c4d4128d0a8d831890441793b26269f455 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 7 Aug 2021 00:01:26 +0200 Subject: [PATCH 13/30] Refactor error code table - Declutter add_error_constants() - No need to typedef struct - Simplify naming - Use PyModule_AddIntConstant --- Modules/_sqlite/module.c | 63 ++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 95968489638efe..039d65a5d8a865 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -282,15 +282,11 @@ static PyMethodDef module_methods[] = { {NULL, NULL} }; -struct _IntConstantPair { - const char *constant_name; - int constant_value; -}; - -typedef struct _IntConstantPair IntConstantPair; - -/* sqlite API error codes */ -static const IntConstantPair _error_codes[] = { +/* SQLite API error codes */ +static const struct { + const char *name; + long value; +} error_codes[] = { {"SQLITE_ABORT", SQLITE_ABORT}, {"SQLITE_AUTH", SQLITE_AUTH}, {"SQLITE_BUSY", SQLITE_BUSY}, @@ -323,12 +319,25 @@ static const IntConstantPair _error_codes[] = { {NULL, 0}, }; +static int +add_error_constants(PyObject *module) +{ + for (int i = 0; error_codes[i].name != 0; i++) { + const char *name = error_codes[i].name; + const long value = error_codes[i].value; + if (PyModule_AddIntConstant(module, name, value) < 0) { + return -1; + } + } + return 0; +} + const char * pysqlite_error_name(int rc) { - for (int i = 0; _error_codes[i].constant_name != 0; i++) { - if (_error_codes[i].constant_value == rc) { - return _error_codes[i].constant_name; + for (int i = 0; error_codes[i].name != 0; i++) { + if (error_codes[i].value == rc) { + return error_codes[i].name; } } // No error code matched. @@ -381,36 +390,6 @@ static int add_integer_constants(PyObject *module) { return ret; } -static int -add_error_constant(PyObject *module, const char *name, int constant) -{ - PyObject *value = PyLong_FromLong(constant); - if (value == NULL) { - Py_DECREF(value); - return 1; - } - - int rc = PyModule_AddObjectRef(module, name, value); - Py_DECREF(value); - if (rc < 0) { - return 1; - } - return 0; -} - -static int -add_error_constants(PyObject *module) -{ - for (int i = 0; _error_codes[i].constant_name != 0; i++) { - if (add_error_constant(module, _error_codes[i].constant_name, - _error_codes[i].constant_value) < 0) - { - return -1; - } - } - return 0; -} - static struct PyModuleDef _sqlite3module = { PyModuleDef_HEAD_INIT, "_sqlite3", From 467f7bad1fb8c1d42ef72bf2965bef7bc758c977 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 7 Aug 2021 00:12:11 +0200 Subject: [PATCH 14/30] Use macro to create error table To avoid mismatch between char *name and constant --- Modules/_sqlite/module.c | 60 +++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 039d65a5d8a865..deb971e1fb5217 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -287,35 +287,37 @@ static const struct { const char *name; long value; } error_codes[] = { - {"SQLITE_ABORT", SQLITE_ABORT}, - {"SQLITE_AUTH", SQLITE_AUTH}, - {"SQLITE_BUSY", SQLITE_BUSY}, - {"SQLITE_CANTOPEN", SQLITE_CANTOPEN}, - {"SQLITE_CONSTRAINT", SQLITE_CONSTRAINT}, - {"SQLITE_CORRUPT", SQLITE_CORRUPT}, - {"SQLITE_DONE", SQLITE_DONE}, - {"SQLITE_EMPTY", SQLITE_EMPTY}, - {"SQLITE_ERROR", SQLITE_ERROR}, - {"SQLITE_FORMAT", SQLITE_FORMAT}, - {"SQLITE_FULL", SQLITE_FULL}, - {"SQLITE_INTERNAL", SQLITE_INTERNAL}, - {"SQLITE_INTERRUPT", SQLITE_INTERRUPT}, - {"SQLITE_IOERR", SQLITE_IOERR}, - {"SQLITE_LOCKED", SQLITE_LOCKED}, - {"SQLITE_MISMATCH", SQLITE_MISMATCH}, - {"SQLITE_MISUSE", SQLITE_MISUSE}, - {"SQLITE_NOLFS", SQLITE_NOLFS}, - {"SQLITE_NOMEM", SQLITE_NOMEM}, - {"SQLITE_NOTADB", SQLITE_NOTADB}, - {"SQLITE_NOTFOUND", SQLITE_NOTFOUND}, - {"SQLITE_OK", SQLITE_OK}, - {"SQLITE_PERM", SQLITE_PERM}, - {"SQLITE_PROTOCOL", SQLITE_PROTOCOL}, - {"SQLITE_RANGE", SQLITE_RANGE}, - {"SQLITE_READONLY", SQLITE_READONLY}, - {"SQLITE_ROW", SQLITE_ROW}, - {"SQLITE_SCHEMA", SQLITE_SCHEMA}, - {"SQLITE_TOOBIG", SQLITE_TOOBIG}, +#define DECLARE_ERROR_CODE(code) {#code, code} + DECLARE_ERROR_CODE(SQLITE_ABORT), + DECLARE_ERROR_CODE(SQLITE_AUTH), + DECLARE_ERROR_CODE(SQLITE_BUSY), + DECLARE_ERROR_CODE(SQLITE_CANTOPEN), + DECLARE_ERROR_CODE(SQLITE_CONSTRAINT), + DECLARE_ERROR_CODE(SQLITE_CORRUPT), + DECLARE_ERROR_CODE(SQLITE_DONE), + DECLARE_ERROR_CODE(SQLITE_EMPTY), + DECLARE_ERROR_CODE(SQLITE_ERROR), + DECLARE_ERROR_CODE(SQLITE_ERROR), + DECLARE_ERROR_CODE(SQLITE_FORMAT), + DECLARE_ERROR_CODE(SQLITE_FULL), + DECLARE_ERROR_CODE(SQLITE_INTERNAL), + DECLARE_ERROR_CODE(SQLITE_INTERRUPT), + DECLARE_ERROR_CODE(SQLITE_IOERR), + DECLARE_ERROR_CODE(SQLITE_LOCKED), + DECLARE_ERROR_CODE(SQLITE_MISMATCH), + DECLARE_ERROR_CODE(SQLITE_MISUSE), + DECLARE_ERROR_CODE(SQLITE_NOLFS), + DECLARE_ERROR_CODE(SQLITE_NOMEM), + DECLARE_ERROR_CODE(SQLITE_NOTADB), + DECLARE_ERROR_CODE(SQLITE_NOTFOUND), + DECLARE_ERROR_CODE(SQLITE_OK), + DECLARE_ERROR_CODE(SQLITE_PERM), + DECLARE_ERROR_CODE(SQLITE_PROTOCOL), + DECLARE_ERROR_CODE(SQLITE_READONLY), + DECLARE_ERROR_CODE(SQLITE_ROW), + DECLARE_ERROR_CODE(SQLITE_SCHEMA), + DECLARE_ERROR_CODE(SQLITE_TOOBIG), +#undef DECLARE_ERROR_CODE {NULL, 0}, }; From 4abd093a431e3577230614947c391ad53908c99b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 7 Aug 2021 00:13:29 +0200 Subject: [PATCH 15/30] Add missing SQLITE_NOTICE and SQLITE_WARNING codes --- Modules/_sqlite/module.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index deb971e1fb5217..687f7629b75123 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -317,6 +317,10 @@ static const struct { DECLARE_ERROR_CODE(SQLITE_ROW), DECLARE_ERROR_CODE(SQLITE_SCHEMA), DECLARE_ERROR_CODE(SQLITE_TOOBIG), +#if SQLITE_VERSION_NUMBER >= 3007017 + DECLARE_ERROR_CODE(SQLITE_NOTICE), + DECLARE_ERROR_CODE(SQLITE_WARNING), +#endif #undef DECLARE_ERROR_CODE {NULL, 0}, }; From 70507dd18747628e5001a387149c30707ffc1ea5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 7 Aug 2021 00:18:28 +0200 Subject: [PATCH 16/30] Add comment --- Modules/_sqlite/module.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 687f7629b75123..510fa545f86c78 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -288,6 +288,7 @@ static const struct { long value; } error_codes[] = { #define DECLARE_ERROR_CODE(code) {#code, code} + // Primary result code list DECLARE_ERROR_CODE(SQLITE_ABORT), DECLARE_ERROR_CODE(SQLITE_AUTH), DECLARE_ERROR_CODE(SQLITE_BUSY), From db053b9069fc3e3ea73fa0c82c263cd83897bf97 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 20:44:16 +0200 Subject: [PATCH 17/30] Assert exception class is always set --- Modules/_sqlite/util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index b66c67a3b3345d..6b659e9695702a 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -43,7 +43,7 @@ pysqlite_step(sqlite3_stmt *statement) int _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) { - PyObject *exc_class; + PyObject *exc_class = NULL; int errorcode = sqlite3_errcode(db); switch (errorcode) @@ -90,6 +90,7 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) exc_class = state->DatabaseError; break; } + assert(exc_class != NULL); /* Create and set the exception. */ PyObject *exc = NULL; From 98106dd0d259e4c05a8f741ea32e0e0cd0d2bec5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 20:57:05 +0200 Subject: [PATCH 18/30] Use explicit API's iso. Py_BuildValue, etc. --- Modules/_sqlite/util.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 6b659e9695702a..6030538fca5cd5 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -95,41 +95,49 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) /* Create and set the exception. */ PyObject *exc = NULL; const char *error_msg = sqlite3_errmsg(db); - PyObject *args = Py_BuildValue("(s)", error_msg); - if (args == NULL) { + PyObject *args[] = { PyUnicode_FromString(error_msg), }; + if (args[0] == NULL) { goto exit; } - exc = PyObject_Call(exc_class, args, NULL); - Py_DECREF(args); + exc = PyObject_Vectorcall(exc_class, args, 1, NULL); + Py_DECREF(args[0]); if (exc == NULL) { goto exit; } - PyObject *code = Py_BuildValue("i", errorcode); + PyObject *code = PyLong_FromLong(errorcode); if (code == NULL) { goto exit; } - int rc = PyObject_SetAttrString(exc, "sqlite_errorcode", code); + _Py_IDENTIFIER(sqlite_errorcode); + int rc = _PyObject_SetAttrId(exc, &PyId_sqlite_errorcode, code); Py_DECREF(code); if (rc < 0) { goto exit; } const char *error_name = pysqlite_error_name(errorcode); - PyObject *name = Py_BuildValue("s", error_name ? error_name : "SQLITE_UNKNOWN"); + PyObject *name; + if (error_name) { + name = PyUnicode_FromString(error_name); + } + else { + name = PyUnicode_InternFromString("SQLITE_UNKNOWN"); + } if (name == NULL) { goto exit; } - rc = PyObject_SetAttrString(exc, "sqlite_errorname", name); + _Py_IDENTIFIER(sqlite_errorname); + rc = _PyObject_SetAttrId(exc, &PyId_sqlite_errorname, name); Py_DECREF(name); if (rc < 0) { goto exit; } - PyErr_SetObject((PyObject *)Py_TYPE(exc), exc); + PyErr_SetObject(exc_class, exc); exit: Py_XDECREF(exc); From 056793822ad8f7622c20fbb188e5a9c0cd66dd57 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 20:58:46 +0200 Subject: [PATCH 19/30] Remove duplicate return code entries --- Modules/_sqlite/module.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 510fa545f86c78..3e3d10a3fdd2ba 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -298,7 +298,6 @@ static const struct { DECLARE_ERROR_CODE(SQLITE_DONE), DECLARE_ERROR_CODE(SQLITE_EMPTY), DECLARE_ERROR_CODE(SQLITE_ERROR), - DECLARE_ERROR_CODE(SQLITE_ERROR), DECLARE_ERROR_CODE(SQLITE_FORMAT), DECLARE_ERROR_CODE(SQLITE_FULL), DECLARE_ERROR_CODE(SQLITE_INTERNAL), @@ -356,7 +355,6 @@ static int add_integer_constants(PyObject *module) { ret += PyModule_AddIntMacro(module, PARSE_DECLTYPES); ret += PyModule_AddIntMacro(module, PARSE_COLNAMES); - ret += PyModule_AddIntMacro(module, SQLITE_OK); ret += PyModule_AddIntMacro(module, SQLITE_DENY); ret += PyModule_AddIntMacro(module, SQLITE_IGNORE); ret += PyModule_AddIntMacro(module, SQLITE_CREATE_INDEX); From 16889a1eba2115563a2cb4f5495a751ad79a4d19 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 21:05:42 +0200 Subject: [PATCH 20/30] Group stuff --- Modules/_sqlite/util.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 6030538fca5cd5..5a8d2c303f0b74 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -99,25 +99,24 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) if (args[0] == NULL) { goto exit; } - exc = PyObject_Vectorcall(exc_class, args, 1, NULL); Py_DECREF(args[0]); if (exc == NULL) { goto exit; } + _Py_IDENTIFIER(sqlite_errorcode); PyObject *code = PyLong_FromLong(errorcode); if (code == NULL) { goto exit; } - - _Py_IDENTIFIER(sqlite_errorcode); int rc = _PyObject_SetAttrId(exc, &PyId_sqlite_errorcode, code); Py_DECREF(code); if (rc < 0) { goto exit; } + _Py_IDENTIFIER(sqlite_errorname); const char *error_name = pysqlite_error_name(errorcode); PyObject *name; if (error_name) { @@ -129,8 +128,6 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) if (name == NULL) { goto exit; } - - _Py_IDENTIFIER(sqlite_errorname); rc = _PyObject_SetAttrId(exc, &PyId_sqlite_errorname, name); Py_DECREF(name); if (rc < 0) { From a7a1cf8b2dd239b72fcf5180937ddde0fc005690 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 21:10:32 +0200 Subject: [PATCH 21/30] Use 'unknown' when a proper SQLite exception cannot be found IMO, we should not pollute the SQLITE_* namespace --- Modules/_sqlite/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 5a8d2c303f0b74..677972eecbb11b 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -123,7 +123,7 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) name = PyUnicode_FromString(error_name); } else { - name = PyUnicode_InternFromString("SQLITE_UNKNOWN"); + name = PyUnicode_InternFromString("unknown"); } if (name == NULL) { goto exit; From 772a29c344da3c9a1b15c8903e6ebfc239472d51 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 21:24:10 +0200 Subject: [PATCH 22/30] Fix complete_statement.py example - Use correct attribute name - Normalise error variable naming - Remove 'Errno' from printed string to avoid confusion --- Doc/includes/sqlite3/complete_statement.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/includes/sqlite3/complete_statement.py b/Doc/includes/sqlite3/complete_statement.py index 8b52087368f503..a5c947969910d4 100644 --- a/Doc/includes/sqlite3/complete_statement.py +++ b/Doc/includes/sqlite3/complete_statement.py @@ -24,10 +24,10 @@ if buffer.lstrip().upper().startswith("SELECT"): print(cur.fetchall()) except sqlite3.Error as e: - msg = str(e) - error_code = e.sqlite_errorcode - error_name = e.sqlite_name - print(f"Error {error_name} [Errno {error_code}]: {msg}") + err_msg = str(e) + err_code = e.sqlite_errorcode + err_name = e.sqlite_errorname + print(f"{err_name} ({err_code}): {err_msg}") buffer = "" con.close() From fa5a1af8821cfca4302b04374d3a87920b15afa8 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 21:27:21 +0200 Subject: [PATCH 23/30] Improve unit tests - Use assertRaisesRegex iso. two assert functions - Normalise quotes - Test that constants are added to the module --- Lib/sqlite3/test/dbapi.py | 80 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py index 6bcc421ccbac90..5054d6446f68e6 100644 --- a/Lib/sqlite3/test/dbapi.py +++ b/Lib/sqlite3/test/dbapi.py @@ -96,13 +96,87 @@ def test_not_supported_error(self): sqlite.DatabaseError), "NotSupportedError is not a subclass of DatabaseError") + def test_module_constants(self): + consts = [ + "SQLITE_ABORT", + "SQLITE_ALTER_TABLE", + "SQLITE_ANALYZE", + "SQLITE_ATTACH", + "SQLITE_AUTH", + "SQLITE_BUSY", + "SQLITE_CANTOPEN", + "SQLITE_CONSTRAINT", + "SQLITE_CORRUPT", + "SQLITE_CREATE_INDEX", + "SQLITE_CREATE_TABLE", + "SQLITE_CREATE_TEMP_INDEX", + "SQLITE_CREATE_TEMP_TABLE", + "SQLITE_CREATE_TEMP_TRIGGER", + "SQLITE_CREATE_TEMP_VIEW", + "SQLITE_CREATE_TRIGGER", + "SQLITE_CREATE_VIEW", + "SQLITE_CREATE_VTABLE", + "SQLITE_DELETE", + "SQLITE_DENY", + "SQLITE_DETACH", + "SQLITE_DONE", + "SQLITE_DROP_INDEX", + "SQLITE_DROP_TABLE", + "SQLITE_DROP_TEMP_INDEX", + "SQLITE_DROP_TEMP_TABLE", + "SQLITE_DROP_TEMP_TRIGGER", + "SQLITE_DROP_TEMP_VIEW", + "SQLITE_DROP_TRIGGER", + "SQLITE_DROP_VIEW", + "SQLITE_DROP_VTABLE", + "SQLITE_EMPTY", + "SQLITE_ERROR", + "SQLITE_FORMAT", + "SQLITE_FULL", + "SQLITE_FUNCTION", + "SQLITE_IGNORE", + "SQLITE_INSERT", + "SQLITE_INTERNAL", + "SQLITE_INTERRUPT", + "SQLITE_IOERR", + "SQLITE_LOCKED", + "SQLITE_MISMATCH", + "SQLITE_MISUSE", + "SQLITE_NOLFS", + "SQLITE_NOMEM", + "SQLITE_NOTADB", + "SQLITE_NOTFOUND", + "SQLITE_OK", + "SQLITE_PERM", + "SQLITE_PRAGMA", + "SQLITE_PROTOCOL", + "SQLITE_READ", + "SQLITE_READONLY", + "SQLITE_REINDEX", + "SQLITE_ROW", + "SQLITE_SAVEPOINT", + "SQLITE_SCHEMA", + "SQLITE_SELECT", + "SQLITE_TOOBIG", + "SQLITE_TRANSACTION", + "SQLITE_UPDATE", + ] + if sqlite.version_info >= (3, 7, 17): + consts += ["SQLITE_NOTICE", "SQLITE_WARNING"] + if sqlite.version_info >= (3, 8, 3): + consts.append("SQLITE_RECURSIVE") + consts += ["PARSE_DECLTYPES", "PARSE_COLNAMES"] + for const in consts: + with self.subTest(const=const): + self.assertTrue(hasattr(sqlite, const)) + def test_error_code_on_exception(self): - with self.assertRaises(sqlite.Error) as cm: - db = sqlite.connect('/no/such/file/exists') + err_msg = "unable to open database file" + with self.assertRaisesRegex(sqlite.Error, err_msg) as cm: + sqlite.connect("/no/such/file/exists") e = cm.exception self.assertEqual(e.sqlite_errorcode, sqlite.SQLITE_CANTOPEN) self.assertEqual(e.sqlite_errorname, "SQLITE_CANTOPEN") - self.assertEqual(str(e), "unable to open database file") # sqlite3_enable_shared_cache() is deprecated on macOS and calling it may raise # OperationalError on some buildbots. From cf551b12d32366f0caaa07efa2be38347297cc4b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 21:44:07 +0200 Subject: [PATCH 24/30] Adjust NEWS entry and update What's New --- Doc/whatsnew/3.11.rst | 6 ++++++ .../next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 88b6f8fa7314e0..9a867bb6b8769d 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -218,6 +218,12 @@ sqlite3 now raise :exc:`UnicodeEncodeError` instead of :exc:`sqlite3.ProgrammingError`. (Contributed by Erlend E. Aasland in :issue:`44688`.) +* :mod:`sqlite3` exceptions now include the SQLite error code as + :attr:`~sqlite3.Error.sqlite_errorcode` and the SQLite error name as + :attr:`~sqlite3.Error.sqlite_errorname`. + (Contributed by Aviv Palivoda, Daniel Shahaf, and Erlend E. Aasland in + :issue:`16379`.) + Removed ======= diff --git a/Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst b/Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst index 2b5d657bebc011..874a9cf77d8c01 100644 --- a/Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst +++ b/Misc/NEWS.d/next/Library/2019-05-08-15-14-32.bpo-16379.rN5JVe.rst @@ -1,2 +1,2 @@ -Add sqlite error code and name to the exceptions of the sqlite3 module. -Patch by Aviv Palivoda based on work by Daniel Shahaf. +Add SQLite error code and name to :mod:`sqlite3` exceptions. +Patch by Aviv Palivoda, Daniel Shahaf, and Erlend E. Aasland. From a3646c9f39e30ce590a4d2d63646741099d023d9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 22:26:02 +0200 Subject: [PATCH 25/30] Use PyObject_SetAttrString iso. _PyObject_SetAttrId => slow path/readability --- Modules/_sqlite/util.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 677972eecbb11b..b3554e96590bae 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -105,18 +105,16 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) goto exit; } - _Py_IDENTIFIER(sqlite_errorcode); PyObject *code = PyLong_FromLong(errorcode); if (code == NULL) { goto exit; } - int rc = _PyObject_SetAttrId(exc, &PyId_sqlite_errorcode, code); + int rc = PyObject_SetAttrString(exc, "sqlite_errorcode", code); Py_DECREF(code); if (rc < 0) { goto exit; } - _Py_IDENTIFIER(sqlite_errorname); const char *error_name = pysqlite_error_name(errorcode); PyObject *name; if (error_name) { @@ -128,7 +126,7 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) if (name == NULL) { goto exit; } - rc = _PyObject_SetAttrId(exc, &PyId_sqlite_errorname, name); + rc = PyObject_SetAttrString(exc, "sqlite_errorname", name); Py_DECREF(name); if (rc < 0) { goto exit; From 8a496596f07c9910cf8325f9cab7b71256dc6bb4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 22:40:05 +0200 Subject: [PATCH 26/30] Refactor _pysqlite_seterror --- Modules/_sqlite/util.c | 75 ++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index b3554e96590bae..58891bd464e9aa 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -36,28 +36,18 @@ 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) +static PyObject * +get_exception_class(pysqlite_state *state, int errorcode) { - PyObject *exc_class = NULL; - int errorcode = sqlite3_errcode(db); - - switch (errorcode) - { + switch (errorcode) { case SQLITE_OK: PyErr_Clear(); - return errorcode; + return NULL; case SQLITE_INTERNAL: case SQLITE_NOTFOUND: - exc_class = state->InternalError; - break; + return state->InternalError; case SQLITE_NOMEM: - (void)PyErr_NoMemory(); - return errorcode; + return PyErr_NoMemory(); case SQLITE_ERROR: case SQLITE_PERM: case SQLITE_ABORT: @@ -71,41 +61,36 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) case SQLITE_PROTOCOL: case SQLITE_EMPTY: case SQLITE_SCHEMA: - exc_class = state->OperationalError; - break; + return state->OperationalError; case SQLITE_CORRUPT: - exc_class = state->DatabaseError; - break; + return state->DatabaseError; case SQLITE_TOOBIG: - exc_class = state->DataError; - break; + return state->DataError; case SQLITE_CONSTRAINT: case SQLITE_MISMATCH: - exc_class = state->IntegrityError; - break; + return state->IntegrityError; case SQLITE_MISUSE: - exc_class = state->ProgrammingError; - break; + return state->ProgrammingError; default: - exc_class = state->DatabaseError; - break; + return state->DatabaseError; } - assert(exc_class != NULL); +} - /* Create and set the exception. */ +static void +raise_exception(PyObject *type, int errcode, const char *errmsg) +{ PyObject *exc = NULL; - const char *error_msg = sqlite3_errmsg(db); - PyObject *args[] = { PyUnicode_FromString(error_msg), }; + PyObject *args[] = { PyUnicode_FromString(errmsg), }; if (args[0] == NULL) { goto exit; } - exc = PyObject_Vectorcall(exc_class, args, 1, NULL); + exc = PyObject_Vectorcall(type, args, 1, NULL); Py_DECREF(args[0]); if (exc == NULL) { goto exit; } - PyObject *code = PyLong_FromLong(errorcode); + PyObject *code = PyLong_FromLong(errcode); if (code == NULL) { goto exit; } @@ -115,7 +100,7 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) goto exit; } - const char *error_name = pysqlite_error_name(errorcode); + const char *error_name = pysqlite_error_name(errcode); PyObject *name; if (error_name) { name = PyUnicode_FromString(error_name); @@ -132,10 +117,28 @@ _pysqlite_seterror(pysqlite_state *state, sqlite3 *db) goto exit; } - PyErr_SetObject(exc_class, exc); + 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) { + return errorcode; + } + + /* Create and set the exception. */ + const char *errmsg = sqlite3_errmsg(db); + raise_exception(exc_class, errorcode, errmsg); return errorcode; } From 8d11bc5e5bd2f3f0aec01947e68b3c0f2053a02c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 9 Aug 2021 23:11:05 +0200 Subject: [PATCH 27/30] Link to sqlite.org/rescode.html iso. sqlite.org/c3ref/c_abort.html --- Doc/library/sqlite3.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index b700fd48897ef3..7c60188bc70b59 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -839,14 +839,14 @@ Exceptions .. attribute:: sqlite_errorcode The numeric error code from the - `SQLite API `_. + `SQLite API `_ .. versionadded:: 3.11 .. attribute:: sqlite_errorname The symbolic name of the numeric error code - from the `SQLite API `_. + from the `SQLite API `_ .. versionadded:: 3.11 From 7a69798c0e9ced31aedc088544d5771f96206617 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 18 Aug 2021 13:38:13 +0200 Subject: [PATCH 28/30] Use test.support.os_helper.temp_dir() in test_error_code_on_exception() --- Lib/sqlite3/test/dbapi.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Lib/sqlite3/test/dbapi.py b/Lib/sqlite3/test/dbapi.py index 5054d6446f68e6..8c5066b0f4433f 100644 --- a/Lib/sqlite3/test/dbapi.py +++ b/Lib/sqlite3/test/dbapi.py @@ -27,7 +27,7 @@ import unittest from test.support import check_disallow_instantiation, threading_helper, bigmemtest -from test.support.os_helper import TESTFN, unlink +from test.support.os_helper import TESTFN, unlink, temp_dir # Helper for tests using TESTFN @@ -172,11 +172,12 @@ def test_module_constants(self): def test_error_code_on_exception(self): err_msg = "unable to open database file" - with self.assertRaisesRegex(sqlite.Error, err_msg) as cm: - sqlite.connect("/no/such/file/exists") - e = cm.exception - self.assertEqual(e.sqlite_errorcode, sqlite.SQLITE_CANTOPEN) - self.assertEqual(e.sqlite_errorname, "SQLITE_CANTOPEN") + with temp_dir() as db: + with self.assertRaisesRegex(sqlite.Error, err_msg) as cm: + sqlite.connect(db) + e = cm.exception + self.assertEqual(e.sqlite_errorcode, sqlite.SQLITE_CANTOPEN) + self.assertEqual(e.sqlite_errorname, "SQLITE_CANTOPEN") # sqlite3_enable_shared_cache() is deprecated on macOS and calling it may raise # OperationalError on some buildbots. From 3589a6a7163d0148bf0c524d0be3f56b563e9d19 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 25 Aug 2021 13:08:55 +0200 Subject: [PATCH 29/30] Address review: document get_exception_class() return value --- Modules/_sqlite/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c index 58891bd464e9aa..cfd189dfc33608 100644 --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -36,6 +36,7 @@ pysqlite_step(sqlite3_stmt *statement) return rc; } +// Returns non-NULL if a new exception should be raised static PyObject * get_exception_class(pysqlite_state *state, int errorcode) { @@ -133,6 +134,7 @@ _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; } From 5a5683cb576c801094e54666790b4dde2e8892d9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 26 Aug 2021 21:34:14 +0200 Subject: [PATCH 30/30] Address review: compare char ptr with NULL iso. 0 --- Modules/_sqlite/module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 3e3d10a3fdd2ba..47b1f7a9d0720c 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -328,7 +328,7 @@ static const struct { static int add_error_constants(PyObject *module) { - for (int i = 0; error_codes[i].name != 0; i++) { + for (int i = 0; error_codes[i].name != NULL; i++) { const char *name = error_codes[i].name; const long value = error_codes[i].value; if (PyModule_AddIntConstant(module, name, value) < 0) { @@ -341,7 +341,7 @@ add_error_constants(PyObject *module) const char * pysqlite_error_name(int rc) { - for (int i = 0; error_codes[i].name != 0; i++) { + for (int i = 0; error_codes[i].name != NULL; i++) { if (error_codes[i].value == rc) { return error_codes[i].name; }