From 065f0916560edcd7cc93e33d7ac4bb3df5ea7937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Tue, 30 Apr 2024 17:13:17 +0100 Subject: [PATCH] Handle NULL values in the path column As I was devving, I did something wrong and had 'beet mv' command fail on me. Later, having spent an hour investigating why beets kept throwing me 'User-defined function raised exception' I discovered that it was failing because that previous 'beet mv' command ended up writing value 'NULL' in one of the items 'path' column. This was not handled well by the 'BYTELOWER' implementation. Since we do not have a NOT NULL constraint for the 'path' column, it's best to insure ourselves against this kind of stuff anyways. --- beets/dbcore/db.py | 15 +++++++++++++++ beets/library.py | 16 ---------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/beets/dbcore/db.py b/beets/dbcore/db.py index fd6dd0c10..7fbf646dc 100755 --- a/beets/dbcore/db.py +++ b/beets/dbcore/db.py @@ -29,6 +29,7 @@ from sqlite3 import Connection from types import TracebackType from typing import ( Any, + AnyStr, Callable, DefaultDict, Dict, @@ -1088,8 +1089,22 @@ class Database: value = value.decode() return re.search(pattern, str(value)) is not None + def bytelower(bytestring: Optional[AnyStr]) -> Optional[AnyStr]: + """A custom ``bytelower`` sqlite function so we can compare + bytestrings in a semi case insensitive fashion. + + This is to work around sqlite builds are that compiled with + ``-DSQLITE_LIKE_DOESNT_MATCH_BLOBS``. See + ``https://github.com/beetbox/beets/issues/2172`` for details. + """ + if bytestring is not None: + return bytestring.lower() + + return bytestring + conn.create_function("regexp", 2, regexp) conn.create_function("unidecode", 1, unidecode) + conn.create_function("bytelower", 1, bytelower) def _close(self): """Close the all connections to the underlying SQLite database diff --git a/beets/library.py b/beets/library.py index 754583f57..367b184ef 100644 --- a/beets/library.py +++ b/beets/library.py @@ -1550,17 +1550,6 @@ def parse_query_string(s, model_cls): return parse_query_parts(parts, model_cls) -def _sqlite_bytelower(bytestring): - """A custom ``bytelower`` sqlite function so we can compare - bytestrings in a semi case insensitive fashion. - - This is to work around sqlite builds are that compiled with - ``-DSQLITE_LIKE_DOESNT_MATCH_BLOBS``. See - ``https://github.com/beetbox/beets/issues/2172`` for details. - """ - return bytestring.lower() - - # The Library: interface to the database. @@ -1585,11 +1574,6 @@ class Library(dbcore.Database): self._memotable = {} # Used for template substitution performance. - def _create_connection(self): - conn = super()._create_connection() - conn.create_function("bytelower", 1, _sqlite_bytelower) - return conn - # Adding objects to the database. def add(self, obj):