diff options
author | Florian Bruhin <me@the-compiler.org> | 2022-08-26 17:15:04 +0200 |
---|---|---|
committer | Florian Bruhin <me@the-compiler.org> | 2022-08-26 19:08:49 +0200 |
commit | 6ffc5174eade1d99f3069e4128af7026e69f9ab1 (patch) | |
tree | 5c3bdab6b1eced7b2b6a9509ec9af9b31999f3e3 | |
parent | 815374c6b602e2ad055dabad68cda3c54c1c9739 (diff) | |
download | qutebrowser-6ffc5174eade1d99f3069e4128af7026e69f9ab1.tar.gz qutebrowser-6ffc5174eade1d99f3069e4128af7026e69f9ab1.zip |
sql: Handle sqlite extended error codes
Qt 6.1 switched to using extended sqlite error codes:
https://codereview.qt-project.org/c/qt/qtbase/+/329472
This is neat because it gives us more granularity for errors, but it
also means that we now need to account for that by masking the error
codes accordingly for checking their category.
See unhandled I/O error here:
https://crashes.qutebrowser.org/view/d9b26c2f
-rw-r--r-- | qutebrowser/misc/sql.py | 32 | ||||
-rw-r--r-- | tests/unit/misc/test_sql.py | 10 |
2 files changed, 27 insertions, 15 deletions
diff --git a/qutebrowser/misc/sql.py b/qutebrowser/misc/sql.py index d7b3dda0d..6c588c980 100644 --- a/qutebrowser/misc/sql.py +++ b/qutebrowser/misc/sql.py @@ -77,16 +77,16 @@ class SqliteErrorCode: in qutebrowser here. """ - ERROR = '1' # generic error code - BUSY = '5' # database is locked - READONLY = '8' # attempt to write a readonly database - IOERR = '10' # disk I/O error - CORRUPT = '11' # database disk image is malformed - FULL = '13' # database or disk is full - CANTOPEN = '14' # unable to open database file - PROTOCOL = '15' # locking protocol error - CONSTRAINT = '19' # UNIQUE constraint failed - NOTADB = '26' # file is not a database + ERROR = 1 # generic error code + BUSY = 5 # database is locked + READONLY = 8 # attempt to write a readonly database + IOERR = 10 # disk I/O error + CORRUPT = 11 # database disk image is malformed + FULL = 13 # database or disk is full + CANTOPEN = 14 # unable to open database file + PROTOCOL = 15 # locking protocol error + CONSTRAINT = 19 # UNIQUE constraint failed + NOTADB = 26 # file is not a database class Error(Exception): @@ -128,6 +128,12 @@ class BugError(Error): def raise_sqlite_error(msg: str, error: QSqlError) -> None: """Raise either a BugError or KnownError.""" error_code = error.nativeErrorCode() + try: + # https://sqlite.org/rescode.html#pve + primary_error_code = int(error_code) & 0xff + except ValueError: + primary_error_code = None + database_text = error.databaseText() driver_text = error.driverText() @@ -135,7 +141,7 @@ def raise_sqlite_error(msg: str, error: QSqlError) -> None: log.sql.debug(f"type: {debug.qenum_key(QSqlError, error.type())}") log.sql.debug(f"database text: {database_text}") log.sql.debug(f"driver text: {driver_text}") - log.sql.debug(f"error code: {error_code}") + log.sql.debug(f"error code: {error_code} -> {primary_error_code}") known_errors = [ SqliteErrorCode.BUSY, @@ -151,12 +157,12 @@ def raise_sqlite_error(msg: str, error: QSqlError) -> None: # https://github.com/qutebrowser/qutebrowser/issues/4681 # If the query we built was too long too_long_err = ( - error_code == SqliteErrorCode.ERROR and + primary_error_code == SqliteErrorCode.ERROR and (database_text.startswith("Expression tree is too large") or database_text in ["too many SQL variables", "LIKE or GLOB pattern too complex"])) - if error_code in known_errors or too_long_err: + if primary_error_code in known_errors or too_long_err: raise KnownError(msg, error) raise BugError(msg, error) diff --git a/tests/unit/misc/test_sql.py b/tests/unit/misc/test_sql.py index da72c5bb1..3e16ff337 100644 --- a/tests/unit/misc/test_sql.py +++ b/tests/unit/misc/test_sql.py @@ -93,10 +93,16 @@ class TestSqlError: @pytest.mark.parametrize('error_code, exception', [ (sql.SqliteErrorCode.BUSY, sql.KnownError), (sql.SqliteErrorCode.CONSTRAINT, sql.BugError), + # extended error codes + (sql.SqliteErrorCode.IOERR | (1<<8), sql.KnownError), # SQLITE_IOERR_READ + ( + sql.SqliteErrorCode.CONSTRAINT | (1<<8), # SQLITE_CONSTRAINT_CHECK + sql.BugError + ), ]) def test_known(self, error_code, exception): sql_err = QSqlError("driver text", "db text", QSqlError.ErrorType.UnknownError, - error_code) + str(error_code)) with pytest.raises(exception): sql.raise_sqlite_error("Message", sql_err) @@ -109,7 +115,7 @@ class TestSqlError: 'type: UnknownError', 'database text: db text', 'driver text: driver text', - 'error code: 23'] + 'error code: 23 -> 23'] assert caplog.messages == expected |