Skip to main content

MIGRATION_021

Constant MIGRATION_021 

Source
const MIGRATION_021: &str = r#"
INSERT INTO items_fts(items_fts) VALUES('rebuild');
"#;
Expand description

Discard and rebuild the FTS index from the items table.

Until DR-110, save_to_cache used INSERT OR REPLACE INTO items. REPLACE deletes the conflicting row and inserts a new one, but SQLite only fires AFTER DELETE triggers on that implicit delete when recursive_triggers is enabled — it is not (storage/mod.rs sets only foreign_keys and journal_mode), so items_ad never ran and the old index row was orphaned. Worse, items.id is a TEXT PRIMARY KEY, so the replacement row also took a fresh rowid and items_ai appended a second entry. Every catalog pass therefore left another duplicate behind, and existing installs carry one stale entry per item per sync since the database was created.

This was invisible in results — the JOIN items_fts fts ON fts.rowid = i.rowid drops rowids that no longer exist — but it degrades MATCH permanently, and it becomes a correctness problem the moment rowids are freed and reused: a new item landing on a freed rowid inherits the orphan’s index entry and matches queries for the deleted item’s title. The DR-110 deletion sweep frees rowids, so this rebuild must run before it.

'rebuild' is the FTS5 command for exactly this: it truncates the index and repopulates it from the external content table.

TRACES: UR-065 | DR-110