- migration 0003: an FTS5 index over media_items as an external-content table, so the index stores no copy of the text. Triggers keep it in sync for every write path, including the scanner's bulk inserts. - migrate: splitStatements now tracks BEGIN...END depth, so CREATE TRIGGER bodies survive as one statement. Without this, the trigger's internal semicolons would tear it apart. - search: every whitespace term is quoted before it reaches FTS5. Unquoted input like a bare quote, a hyphen, or the word OR is valid FTS5 syntax and would either error or silently change the query's meaning. Tested against a list of hostile inputs, including a DROP TABLE attempt. - scoped through the same VisibleLibraryIDs chokepoint; an empty library set returns nothing, never everything. - web: search box in the topbar and a results view. Verified live: finds items across libraries, hostile input returns 200 with no results, index stays in sync on insert/update/delete.
32 lines
1.2 KiB
SQL
32 lines
1.2 KiB
SQL
-- 0003_search.sql — full-text search over items.
|
|
--
|
|
-- FTS5 with an external content table: the index stores no copy of the text,
|
|
-- it points back at media_items, so the database does not double in size.
|
|
-- Triggers keep the index in sync for every write path, including the scanner's
|
|
-- bulk inserts and any future module's.
|
|
|
|
CREATE VIRTUAL TABLE media_search USING fts5(
|
|
title,
|
|
path,
|
|
content='media_items',
|
|
content_rowid='id',
|
|
tokenize='unicode61 remove_diacritics 2'
|
|
);
|
|
|
|
-- Populate the index from any rows that already exist.
|
|
INSERT INTO media_search(media_search) VALUES ('rebuild');
|
|
|
|
CREATE TRIGGER media_items_ai AFTER INSERT ON media_items BEGIN
|
|
INSERT INTO media_search(rowid, title, path) VALUES (new.id, new.title, new.path);
|
|
END;
|
|
|
|
CREATE TRIGGER media_items_ad AFTER DELETE ON media_items BEGIN
|
|
INSERT INTO media_search(media_search, rowid, title, path)
|
|
VALUES ('delete', old.id, old.title, old.path);
|
|
END;
|
|
|
|
CREATE TRIGGER media_items_au AFTER UPDATE ON media_items BEGIN
|
|
INSERT INTO media_search(media_search, rowid, title, path)
|
|
VALUES ('delete', old.id, old.title, old.path);
|
|
INSERT INTO media_search(rowid, title, path) VALUES (new.id, new.title, new.path);
|
|
END;
|