Fix parsing of ignored operators in websearch_to_tsquery().
authorTom Lane <[email protected]>
Fri, 14 Jun 2024 00:34:43 +0000 (20:34 -0400)
committerTom Lane <[email protected]>
Fri, 14 Jun 2024 00:34:43 +0000 (20:34 -0400)
The manual says clearly that punctuation in the input of
websearch_to_tsquery() is ignored, except for the special cases
of dashes and quotes.  However, this failed for cases like
"(foo bar) or something", or in general an ISOPERATOR character
in front of the "or".  We'd switch back to WAITOPERAND state,
then ignore the operator character while remaining in that state,
and then reach the "or" in WAITOPERAND state which (intentionally)
makes us treat it as data.

The fix is simple enough: if we see an ISOPERATOR character while in
WAITOPERATOR state, we have to skip it while staying in that state.
(We don't need to worry about other punctuation characters: those will
be consumed as though they were words, but then rejected by lexizing.)

In v14 and up (since commit eb086056f) we can simplify the code a bit
more too, because there is no longer a reason for the WAITOPERAND
state to distinguish between quoted and unquoted operands.

Per bug #18479 from Manos Emmanouilidis.  Back-patch to all supported
branches.

Discussion: https://postgr.es/m/18479-d9b46e2fc242c33e@postgresql.org

src/backend/utils/adt/tsquery.c
src/test/regress/expected/tsearch.out
src/test/regress/sql/tsearch.sql

index ee98c3f02fc5061eb9e7d87f4573dc79676feab1..bf375116d48508e53ee224feff8673b20acf58e8 100644 (file)
@@ -433,7 +433,7 @@ gettoken_query_websearch(TSQueryParserState state, int8 *operator,
                }
                else if (ISOPERATOR(state->buf))
                {
-                   /* or else gettoken_tsvector() will raise an error */
+                   /* ignore, else gettoken_tsvector() will raise an error */
                    state->buf++;
                    state->state = WAITOPERAND;
                    continue;
@@ -492,6 +492,12 @@ gettoken_query_websearch(TSQueryParserState state, int8 *operator,
                    *operator = OP_OR;
                    return PT_OPR;
                }
+               else if (ISOPERATOR(state->buf))
+               {
+                   /* ignore other operators in this state too */
+                   state->buf++;
+                   continue;
+               }
                else if (*state->buf == '\0')
                {
                    return PT_END;
index 827321ac917d59b4fe82b6c11e7de6e44d7437b8..73f2d13297cc2d12709cd50fe1701d5c6c588dfe 100644 (file)
@@ -2539,12 +2539,19 @@ select websearch_to_tsquery('simple', 'abc <-> def');
  'abc' & 'def'
 (1 row)
 
+-- parens are ignored, too
 select websearch_to_tsquery('simple', 'abc (pg or class)');
   websearch_to_tsquery  
 ------------------------
  'abc' & 'pg' | 'class'
 (1 row)
 
+select websearch_to_tsquery('simple', '(foo bar) or (ding dong)');
+      websearch_to_tsquery       
+---------------------------------
+ 'foo' & 'bar' | 'ding' & 'dong'
+(1 row)
+
 -- NOT is ignored in quotes
 select websearch_to_tsquery('english', 'My brand new smartphone');
      websearch_to_tsquery      
index c958e4df0dbe94fa953bb1fde42cc6fe57ad7d7c..a6088288bc7dbdaf983dd27127ef5473f40650c8 100644 (file)
@@ -727,7 +727,10 @@ select websearch_to_tsquery('simple', ':');
 select websearch_to_tsquery('simple', 'abc & def');
 select websearch_to_tsquery('simple', 'abc | def');
 select websearch_to_tsquery('simple', 'abc <-> def');
+
+-- parens are ignored, too
 select websearch_to_tsquery('simple', 'abc (pg or class)');
+select websearch_to_tsquery('simple', '(foo bar) or (ding dong)');
 
 -- NOT is ignored in quotes
 select websearch_to_tsquery('english', 'My brand new smartphone');