From 7b7dda3879abd75d475dfe8ff38d4082806f4bdb Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 24 Mar 2026 13:50:14 -0400 Subject: [PATCH] fix FTS --- synapse/storage/database.py | 2 ++ synapse/storage/engines/_base.py | 6 ++++++ synapse/storage/engines/sqlite.py | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/synapse/storage/database.py b/synapse/storage/database.py index 979dfd05e9..fa850a98af 100644 --- a/synapse/storage/database.py +++ b/synapse/storage/database.py @@ -607,6 +607,8 @@ class DatabasePool: # Create a new in-memory DB and copy schema+data from the template fresh_conn = sqlite3.connect(":memory:", check_same_thread=False) source_conn.backup(fresh_conn) + # Re-register custom functions that don't survive backup() + engine.register_custom_functions(fresh_conn) initial_conn = fresh_conn self._db_pool = NativeConnectionPool( diff --git a/synapse/storage/engines/_base.py b/synapse/storage/engines/_base.py index 026b742aad..336abdc39e 100644 --- a/synapse/storage/engines/_base.py +++ b/synapse/storage/engines/_base.py @@ -84,6 +84,12 @@ class BaseDatabaseEngine(Generic[ConnectionType, CursorType], metaclass=abc.ABCM @abc.abstractmethod def on_new_connection(self, db_conn: "LoggingDatabaseConnection") -> None: ... + def register_custom_functions(self, raw_conn: "Any") -> None: + """Register custom database functions on a raw connection. + + Override in subclasses that need custom functions (e.g. SQLite rank()). + """ + @abc.abstractmethod def is_deadlock(self, error: Exception) -> bool: ... diff --git a/synapse/storage/engines/sqlite.py b/synapse/storage/engines/sqlite.py index 3b1b19c00e..2eaab273df 100644 --- a/synapse/storage/engines/sqlite.py +++ b/synapse/storage/engines/sqlite.py @@ -86,6 +86,14 @@ class Sqlite3Engine(BaseDatabaseEngine[sqlite3.Connection, sqlite3.Cursor]): def convert_param_style(self, sql: str) -> str: return sql + def register_custom_functions(self, raw_conn: sqlite3.Connection) -> None: + """Register custom SQLite functions on a raw connection. + + This must be called on any connection created outside the normal + on_new_connection path (e.g. connections created via backup()). + """ + raw_conn.create_function("rank", 1, _rank) + def on_new_connection(self, db_conn: "LoggingDatabaseConnection") -> None: # We need to import here to avoid an import loop. from synapse.storage.prepare_database import prepare_database