Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit e9a4343

Browse files
authored
Drop support for Postgres 10 in full text search code. (#14397)
1 parent 21447c9 commit e9a4343

File tree

4 files changed

+41
-95
lines changed

4 files changed

+41
-95
lines changed

changelog.d/14397.removal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove support for PostgreSQL 10.

synapse/storage/databases/main/search.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -463,18 +463,17 @@ async def search_msgs(
463463

464464
if isinstance(self.database_engine, PostgresEngine):
465465
search_query = search_term
466-
tsquery_func = self.database_engine.tsquery_func
467-
sql = f"""
468-
SELECT ts_rank_cd(vector, {tsquery_func}('english', ?)) AS rank,
466+
sql = """
467+
SELECT ts_rank_cd(vector, websearch_to_tsquery('english', ?)) AS rank,
469468
room_id, event_id
470469
FROM event_search
471-
WHERE vector @@ {tsquery_func}('english', ?)
470+
WHERE vector @@ websearch_to_tsquery('english', ?)
472471
"""
473472
args = [search_query, search_query] + args
474473

475-
count_sql = f"""
474+
count_sql = """
476475
SELECT room_id, count(*) as count FROM event_search
477-
WHERE vector @@ {tsquery_func}('english', ?)
476+
WHERE vector @@ websearch_to_tsquery('english', ?)
478477
"""
479478
count_args = [search_query] + count_args
480479
elif isinstance(self.database_engine, Sqlite3Engine):
@@ -523,9 +522,7 @@ async def search_msgs(
523522

524523
highlights = None
525524
if isinstance(self.database_engine, PostgresEngine):
526-
highlights = await self._find_highlights_in_postgres(
527-
search_query, events, tsquery_func
528-
)
525+
highlights = await self._find_highlights_in_postgres(search_query, events)
529526

530527
count_sql += " GROUP BY room_id"
531528

@@ -604,18 +601,17 @@ async def search_rooms(
604601

605602
if isinstance(self.database_engine, PostgresEngine):
606603
search_query = search_term
607-
tsquery_func = self.database_engine.tsquery_func
608-
sql = f"""
609-
SELECT ts_rank_cd(vector, {tsquery_func}('english', ?)) as rank,
604+
sql = """
605+
SELECT ts_rank_cd(vector, websearch_to_tsquery('english', ?)) as rank,
610606
origin_server_ts, stream_ordering, room_id, event_id
611607
FROM event_search
612-
WHERE vector @@ {tsquery_func}('english', ?) AND
608+
WHERE vector @@ websearch_to_tsquery('english', ?) AND
613609
"""
614610
args = [search_query, search_query] + args
615611

616-
count_sql = f"""
612+
count_sql = """
617613
SELECT room_id, count(*) as count FROM event_search
618-
WHERE vector @@ {tsquery_func}('english', ?) AND
614+
WHERE vector @@ websearch_to_tsquery('english', ?) AND
619615
"""
620616
count_args = [search_query] + count_args
621617
elif isinstance(self.database_engine, Sqlite3Engine):
@@ -686,9 +682,7 @@ async def search_rooms(
686682

687683
highlights = None
688684
if isinstance(self.database_engine, PostgresEngine):
689-
highlights = await self._find_highlights_in_postgres(
690-
search_query, events, tsquery_func
691-
)
685+
highlights = await self._find_highlights_in_postgres(search_query, events)
692686

693687
count_sql += " GROUP BY room_id"
694688

@@ -714,7 +708,7 @@ async def search_rooms(
714708
}
715709

716710
async def _find_highlights_in_postgres(
717-
self, search_query: str, events: List[EventBase], tsquery_func: str
711+
self, search_query: str, events: List[EventBase]
718712
) -> Set[str]:
719713
"""Given a list of events and a search term, return a list of words
720714
that match from the content of the event.
@@ -725,7 +719,6 @@ async def _find_highlights_in_postgres(
725719
Args:
726720
search_query
727721
events: A list of events
728-
tsquery_func: The tsquery_* function to use when making queries
729722
730723
Returns:
731724
A set of strings.
@@ -758,13 +751,16 @@ def f(txn: LoggingTransaction) -> Set[str]:
758751
while stop_sel in value:
759752
stop_sel += ">"
760753

761-
query = f"SELECT ts_headline(?, {tsquery_func}('english', ?), %s)" % (
762-
_to_postgres_options(
763-
{
764-
"StartSel": start_sel,
765-
"StopSel": stop_sel,
766-
"MaxFragments": "50",
767-
}
754+
query = (
755+
"SELECT ts_headline(?, websearch_to_tsquery('english', ?), %s)"
756+
% (
757+
_to_postgres_options(
758+
{
759+
"StartSel": start_sel,
760+
"StopSel": stop_sel,
761+
"MaxFragments": "50",
762+
}
763+
)
768764
)
769765
)
770766
txn.execute(query, (value, search_query))

synapse/storage/engines/postgres.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -170,22 +170,6 @@ def supports_returning(self) -> bool:
170170
"""Do we support the `RETURNING` clause in insert/update/delete?"""
171171
return True
172172

173-
@property
174-
def tsquery_func(self) -> str:
175-
"""
176-
Selects a tsquery_* func to use.
177-
178-
Ref: https://www.postgresql.org/docs/current/textsearch-controls.html
179-
180-
Returns:
181-
The function name.
182-
"""
183-
# Postgres 11 added support for websearch_to_tsquery.
184-
assert self._version is not None
185-
if self._version >= 110000:
186-
return "websearch_to_tsquery"
187-
return "plainto_tsquery"
188-
189173
def is_deadlock(self, error: Exception) -> bool:
190174
if isinstance(error, psycopg2.DatabaseError):
191175
# https://www.postgresql.org/docs/current/static/errcodes-appendix.html

tests/storage/test_room_search.py

Lines changed: 17 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import List, Tuple, Union
15+
from typing import List, Tuple
1616
from unittest.case import SkipTest
17-
from unittest.mock import PropertyMock, patch
1817

1918
from twisted.test.proto_helpers import MemoryReactor
2019

@@ -220,24 +219,22 @@ class MessageSearchTest(HomeserverTestCase):
220219

221220
PHRASE = "the quick brown fox jumps over the lazy dog"
222221

223-
# Each entry is a search query, followed by either a boolean of whether it is
224-
# in the phrase OR a tuple of booleans: whether it matches using websearch
225-
# and using plain search.
226-
COMMON_CASES: List[Tuple[str, Union[bool, Tuple[bool, bool]]]] = [
222+
# Each entry is a search query, followed by a boolean of whether it is in the phrase.
223+
COMMON_CASES = [
227224
("nope", False),
228225
("brown", True),
229226
("quick brown", True),
230227
("brown quick", True),
231228
("quick \t brown", True),
232229
("jump", True),
233230
("brown nope", False),
234-
('"brown quick"', (False, True)),
231+
('"brown quick"', False),
235232
('"jumps over"', True),
236-
('"quick fox"', (False, True)),
233+
('"quick fox"', False),
237234
("nope OR doublenope", False),
238-
("furphy OR fox", (True, False)),
239-
("fox -nope", (True, False)),
240-
("fox -brown", (False, True)),
235+
("furphy OR fox", True),
236+
("fox -nope", True),
237+
("fox -brown", False),
241238
('"fox" quick', True),
242239
('"quick brown', True),
243240
('" quick "', True),
@@ -246,11 +243,11 @@ class MessageSearchTest(HomeserverTestCase):
246243
# TODO Test non-ASCII cases.
247244

248245
# Case that fail on SQLite.
249-
POSTGRES_CASES: List[Tuple[str, Union[bool, Tuple[bool, bool]]]] = [
246+
POSTGRES_CASES = [
250247
# SQLite treats NOT as a binary operator.
251-
("- fox", (False, True)),
252-
("- nope", (True, False)),
253-
('"-fox quick', (False, True)),
248+
("- fox", False),
249+
("- nope", True),
250+
('"-fox quick', False),
254251
# PostgreSQL skips stop words.
255252
('"the quick brown"', True),
256253
('"over lazy"', True),
@@ -275,7 +272,7 @@ def prepare(
275272
if isinstance(main_store.database_engine, PostgresEngine):
276273
assert main_store.database_engine._version is not None
277274
found = main_store.database_engine._version < 140000
278-
self.COMMON_CASES.append(('"fox quick', (found, True)))
275+
self.COMMON_CASES.append(('"fox quick', found))
279276

280277
def test_tokenize_query(self) -> None:
281278
"""Test the custom logic to tokenize a user's query."""
@@ -315,16 +312,10 @@ def test_tokenize_query(self) -> None:
315312
)
316313

317314
def _check_test_cases(
318-
self,
319-
store: DataStore,
320-
cases: List[Tuple[str, Union[bool, Tuple[bool, bool]]]],
321-
index=0,
315+
self, store: DataStore, cases: List[Tuple[str, bool]]
322316
) -> None:
323317
# Run all the test cases versus search_msgs
324318
for query, expect_to_contain in cases:
325-
if isinstance(expect_to_contain, tuple):
326-
expect_to_contain = expect_to_contain[index]
327-
328319
result = self.get_success(
329320
store.search_msgs([self.room_id], query, ["content.body"])
330321
)
@@ -343,9 +334,6 @@ def _check_test_cases(
343334

344335
# Run them again versus search_rooms
345336
for query, expect_to_contain in cases:
346-
if isinstance(expect_to_contain, tuple):
347-
expect_to_contain = expect_to_contain[index]
348-
349337
result = self.get_success(
350338
store.search_rooms([self.room_id], query, ["content.body"], 10)
351339
)
@@ -366,38 +354,15 @@ def test_postgres_web_search_for_phrase(self):
366354
"""
367355
Test searching for phrases using typical web search syntax, as per postgres' websearch_to_tsquery.
368356
This test is skipped unless the postgres instance supports websearch_to_tsquery.
369-
"""
370-
371-
store = self.hs.get_datastores().main
372-
if not isinstance(store.database_engine, PostgresEngine):
373-
raise SkipTest("Test only applies when postgres is used as the database")
374-
375-
if store.database_engine.tsquery_func != "websearch_to_tsquery":
376-
raise SkipTest(
377-
"Test only applies when postgres supporting websearch_to_tsquery is used as the database"
378-
)
379357
380-
self._check_test_cases(store, self.COMMON_CASES + self.POSTGRES_CASES, index=0)
381-
382-
def test_postgres_non_web_search_for_phrase(self):
383-
"""
384-
Test postgres searching for phrases without using web search, which is used when websearch_to_tsquery isn't
385-
supported by the current postgres version.
358+
See https://www.postgresql.org/docs/current/textsearch-controls.html
386359
"""
387360

388361
store = self.hs.get_datastores().main
389362
if not isinstance(store.database_engine, PostgresEngine):
390363
raise SkipTest("Test only applies when postgres is used as the database")
391364

392-
# Patch supports_websearch_to_tsquery to always return False to ensure we're testing the plainto_tsquery path.
393-
with patch(
394-
"synapse.storage.engines.postgres.PostgresEngine.tsquery_func",
395-
new_callable=PropertyMock,
396-
) as supports_websearch_to_tsquery:
397-
supports_websearch_to_tsquery.return_value = "plainto_tsquery"
398-
self._check_test_cases(
399-
store, self.COMMON_CASES + self.POSTGRES_CASES, index=1
400-
)
365+
self._check_test_cases(store, self.COMMON_CASES + self.POSTGRES_CASES)
401366

402367
def test_sqlite_search(self):
403368
"""
@@ -407,4 +372,4 @@ def test_sqlite_search(self):
407372
if not isinstance(store.database_engine, Sqlite3Engine):
408373
raise SkipTest("Test only applies when sqlite is used as the database")
409374

410-
self._check_test_cases(store, self.COMMON_CASES, index=0)
375+
self._check_test_cases(store, self.COMMON_CASES)

0 commit comments

Comments
 (0)