aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-04-06 15:52:37 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-04-06 15:52:37 -0400
commita1fb4bd8562e0a7f162ff8a08c3c2ecdeb792f80 (patch)
tree6c583557c7f51c476360e77b142da5ae551228a0 /src/backend
parent790be6f31e6ae0484890afe77b1080b8299f6b92 (diff)
downloadpostgresql-a1fb4bd8562e0a7f162ff8a08c3c2ecdeb792f80.tar.gz
postgresql-a1fb4bd8562e0a7f162ff8a08c3c2ecdeb792f80.zip
Fix ts_headline() edge cases for empty query and empty search text.
tsquery's GETQUERY() macro is only safe to apply to a tsquery that is known non-empty; otherwise it gives a pointer to garbage. Before commit 5a617d75d, ts_headline() avoided this pitfall, but only in a very indirect, nonobvious way. (hlCover could not reach its TS_execute call, because if the query contains no lexemes then hlFirstIndex would surely return -1.) After that commit, it fell into the trap, resulting in weird errors such as "unrecognized operator" and/or valgrind complaints. In HEAD, fix this by not calling TS_execute_locations() at all for an empty query. In the back branches, add a defensive check to hlCover() --- that's not fixing any live bug, but I judge the code a bit too fragile as-is. Also, both mark_hl_fragments() and mark_hl_words() were careless about the possibility of empty search text: in the cases where no match has been found, they'd end up telling mark_fragment() to mark from word indexes 0 to 0 inclusive, even when there is no word 0. This is harmless since we over-allocated the prs->words array, but it does annoy valgrind. Fix so that the end index is -1 and thus mark_fragment() will do nothing in such cases. Bottom line is that this fixes a live bug in HEAD, but in the back branches it's only getting rid of a valgrind nitpick. Back-patch anyway. Per report from Alexander Lakhin. Discussion: https://postgr.es/m/c27f642d-020b-01ff-ae61-086af287c4fd@gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/tsearch/wparser_def.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/src/backend/tsearch/wparser_def.c b/src/backend/tsearch/wparser_def.c
index 53a545863aa..7fd3a20400e 100644
--- a/src/backend/tsearch/wparser_def.c
+++ b/src/backend/tsearch/wparser_def.c
@@ -2046,6 +2046,9 @@ hlCover(HeadlineParsedText *prs, TSQuery query, int max_cover,
nextpmax;
hlCheck ch;
+ if (query->size <= 0)
+ return false; /* empty query matches nothing */
+
/*
* We look for the earliest, shortest substring of prs->words that
* satisfies the query. Both the pmin and pmax indices must be words
@@ -2350,7 +2353,8 @@ mark_hl_fragments(HeadlineParsedText *prs, TSQuery query, bool highlightall,
/* show the first min_words words if we have not marked anything */
if (num_f <= 0)
{
- startpos = endpos = curlen = 0;
+ startpos = curlen = 0;
+ endpos = -1;
for (i = 0; i < prs->curwords && curlen < min_words; i++)
{
if (!NONWORDTOKEN(prs->words[i].type))
@@ -2505,7 +2509,7 @@ mark_hl_words(HeadlineParsedText *prs, TSQuery query, bool highlightall,
if (bestlen < 0)
{
curlen = 0;
- pose = 0;
+ pose = -1;
for (i = 0; i < prs->curwords && curlen < min_words; i++)
{
if (!NONWORDTOKEN(prs->words[i].type))