From 8d8dcfe181b07aa741acd11f1084c0e235b5c17d Mon Sep 17 00:00:00 2001 From: Darek Date: Wed, 14 Oct 2026 06:17:30 +0200 Subject: [PATCH] fix(fts): keep the case of ignore_pattern CREATE_FTS_INDEX lowercased ignore_pattern before compiling it, but the pattern is matched against the text before the text is lowercased, so capitals in the pattern changed meaning: [^A-Za-z]+ stripped capital letters, and \W+ became \w+, which strips every word. The pattern is now used as written. Indexes created earlier keep their stored pattern and tokenize as before. Co-Authored-By: Claude Opus 5.5 --- fts/src/function/fts_config.cpp | 2 +- fts/test/test_files/ignore_pattern.test | 34 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/fts/src/function/fts_config.cpp b/fts/src/function/fts_config.cpp index bfb63289..524837ea 100644 --- a/fts/src/function/fts_config.cpp +++ b/fts/src/function/fts_config.cpp @@ -144,7 +144,7 @@ CreateFTSConfig::CreateFTSConfig(main::ClientContext& context, common::table_id_ StopWords::bind(context, tableID, indexName, value.getValue()); } else if (IgnorePattern::NAME == lowerCaseName) { value.validateType(IgnorePattern::TYPE); - ignorePattern = common::StringUtils::getLower(value.getValue()); + ignorePattern = value.getValue(); // Wildcard characters ('*' and '?') are protected from the ignore pattern during // query normalization (see FTSUtils::normalizeQuery), so the same pattern is used // for indexing and for queries. diff --git a/fts/test/test_files/ignore_pattern.test b/fts/test/test_files/ignore_pattern.test index 7cb8289a..01091b9a 100644 --- a/fts/test/test_files/ignore_pattern.test +++ b/fts/test/test_files/ignore_pattern.test @@ -48,3 +48,37 @@ -STATEMENT CALL QUERY_FTS_INDEX('emails', 'fileIdx', '102') RETURN node.id; ---- 1 10 + +# The pattern is matched against the text as written, before it is lowercased, so the case of +# letters in the pattern must be kept. +-CASE ignorePatternKeepsCase +-LOAD_DYNAMIC_EXTENSION fts +-STATEMENT CREATE NODE TABLE Doc(id INT64 PRIMARY KEY, body STRING); +---- ok +-STATEMENT CREATE (:Doc {id: 1, body: 'Ladybug Graph'}); +---- ok +-STATEMENT CALL CREATE_FTS_INDEX('Doc', 'letters', ['body'], stemmer := 'none', ignore_pattern := '[^A-Za-z]+'); +---- ok +-STATEMENT CALL CREATE_FTS_INDEX('Doc', 'words', ['body'], stemmer := 'none', ignore_pattern := '\\W+'); +---- ok +-STATEMENT CREATE (:Doc {id: 2, body: 'Quiet Morning'}); +---- ok +-STATEMENT CALL QUERY_FTS_INDEX('Doc', 'letters', 'ladybug') RETURN node.id; +---- 1 +1 +-STATEMENT CALL QUERY_FTS_INDEX('Doc', 'letters', 'adybug') RETURN node.id; +---- 0 +-STATEMENT CALL QUERY_FTS_INDEX('Doc', 'letters', 'Morning') RETURN node.id; +---- 1 +2 +-STATEMENT CALL QUERY_FTS_INDEX('Doc', 'words', 'graph') RETURN node.id; +---- 1 +1 +-STATEMENT CALL QUERY_FTS_INDEX('Doc', 'words', 'quiet') RETURN node.id; +---- 1 +2 +-RELOADDB +-LOAD_DYNAMIC_EXTENSION fts +-STATEMENT CALL QUERY_FTS_INDEX('Doc', 'letters', 'graph') RETURN node.id; +---- 1 +1