From ba2566828c12632b93d85b6b95335d9501dd6396 Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Tue, 5 May 2026 12:05:12 +0100 Subject: [PATCH] Fix FTS5 crashes when searching with special characters Always wrap FTS5 query terms in phrase double-quotes instead of checking a hardcoded list of special characters. Characters like |, ;, +, #, @ were missing from the list, causing FTS5 syntax errors (production errors #1 and #1398). Phrase-quoting every term produces identical results for normal ASCII search (verified via SQL) while safely handling any character FTS5 chokes on. Add regression tests for bare special characters and special characters mixed with normal words. --- lib/music_library/records/search.ex | 8 ++------ test/music_library/records/search_test.exs | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/music_library/records/search.ex b/lib/music_library/records/search.ex index cb30cfdd..1e4dd61c 100644 --- a/lib/music_library/records/search.ex +++ b/lib/music_library/records/search.ex @@ -47,12 +47,8 @@ defmodule MusicLibrary.Records.Search do end defp fts_escape(term) do - if String.contains?(term, ["'", " ", "\"", "(", ")", "^", "-", ":", "?", ".", "&"]) do - escaped = String.replace(term, "\"", "\"\"") - "\"#{escaped}\"*" - else - "#{term}*" - end + escaped = String.replace(term, "\"", "\"\"") + "\"#{escaped}\"*" end defp fts_query_escape(query) do diff --git a/test/music_library/records/search_test.exs b/test/music_library/records/search_test.exs index be61667a..1237287f 100644 --- a/test/music_library/records/search_test.exs +++ b/test/music_library/records/search_test.exs @@ -59,6 +59,17 @@ defmodule MusicLibrary.Records.SearchTest do assert [greatest_show_on_earth.id] == search("mbid:#{airbag_mbid}", 10, 0) assert [libertad.id] == search("mbid:#{airbag_au_mbid}", 10, 0) end + + test "bare special characters return empty results without crashing" do + for char <- ["|", ";", "&", "+", "#", "@"] do + assert [] == search(char, 10, 0) + end + end + + test "special characters mixed with normal words return matching results" do + assert [] == search("brave &", 10, 0) + assert [] == search("hello ;", 10, 0) + end end describe "search_records_count/2" do @@ -94,5 +105,16 @@ defmodule MusicLibrary.Records.SearchTest do assert 1 == Search.search_records_count(SearchIndex, "mbid:#{airbag_au_mbid}") end + + test "bare special characters do not crash and return zero" do + for char <- ["|", ";", "&", "+", "#", "@"] do + assert 0 == Search.search_records_count(SearchIndex, char) + end + end + + test "special characters mixed with normal words do not crash" do + assert 0 == Search.search_records_count(SearchIndex, "brave &") + assert 0 == Search.search_records_count(SearchIndex, "hello ;") + end end end