summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2022-08-26 17:15:04 +0200
committerFlorian Bruhin <me@the-compiler.org>2022-08-26 19:08:49 +0200
commit6ffc5174eade1d99f3069e4128af7026e69f9ab1 (patch)
tree5c3bdab6b1eced7b2b6a9509ec9af9b31999f3e3
parent815374c6b602e2ad055dabad68cda3c54c1c9739 (diff)
downloadqutebrowser-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.py32
-rw-r--r--tests/unit/misc/test_sql.py10
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