From 28c03e5e8147d94775248493a2dfc68a67a98ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Wed, 18 Mar 2026 17:23:14 +0100 Subject: [PATCH] Consider empty string and None as incompatible with full text searches Closes #14691 --- trytond/trytond/tests/test_field_char.py | 34 ++++++++++++++++++++++++ trytond/trytond/tools/misc.py | 2 ++ 2 files changed, 36 insertions(+) diff --git a/trytond/trytond/tests/test_field_char.py b/trytond/trytond/tests/test_field_char.py index b95bea33ca..ea9b8abfb4 100644 --- a/trytond/trytond/tests/test_field_char.py +++ b/trytond/trytond/tests/test_field_char.py @@ -820,6 +820,40 @@ class FieldCharSimilarityTestCase(ExtensionTestCase): pool = Pool() self._test_search(pool.get('test.char_translate')) + @with_transaction() + def test_search_empty(self): + "Test a full text search with an empty string" + pool = Pool() + Char = pool.get('test.char') + + record1, record2 = Char.create([{ + 'char': "word", + }, { + 'char': "", + }]) + + with Transaction().set_context(search_similarity=0.3): + self.assertEqual( + Char.search([('char', 'ilike', '')]), + [record2]) + + @with_transaction() + def test_search_null(self): + "Test a full text search with NULL" + pool = Pool() + Char = pool.get('test.char') + + record1, record2 = Char.create([{ + 'char': "word", + }, { + 'char': None, + }]) + + with Transaction().set_context(search_similarity=0.3): + self.assertEqual( + Char.search([('char', 'ilike', None)]), + [record2]) + def _test_order(self, Model): record1, record2 = Model.create([{ 'char': "word", diff --git a/trytond/trytond/tools/misc.py b/trytond/trytond/tools/misc.py index f9c6fda536..35a5f4084f 100644 --- a/trytond/trytond/tools/misc.py +++ b/trytond/trytond/tools/misc.py @@ -223,6 +223,8 @@ def unescape_wildcard(string, wildcards='%_', escape='\\'): def is_full_text(value, escape='\\'): + if not value: + return False escaped = strip_wildcard(value, escape=escape) escaped = escaped.replace(escape + '%', '').replace(escape + '_', '') if '%' in escaped or '_' in escaped: