Commit e81e5741 authored by Tom Lane's avatar Tom Lane

Fix full text search to handle NOT above a phrase search correctly.

Queries such as '!(foo<->bar)' failed to find matching rows when
implemented as a GiST or GIN index search.  That's because of
failing to handle phrase searches as tri-valued when considering
a query without any position information for the target tsvector.
We can only say that the phrase operator might match, not that it
does match; and therefore its NOT also might match.  The previous
coding incorrectly inverted the approximate phrase result to
decide that there was certainly no match.

To fix, we need to make TS_phrase_execute return a real ternary result,
and then bubble that up accurately in TS_execute.  As long as we have
to do that anyway, we can simplify the baroque things TS_phrase_execute
was doing internally to manage tri-valued searching with only a bool
as explicit result.

For now, I left the externally-visible result of TS_execute as a plain
bool.  There do not appear to be any outside callers that need to
distinguish a three-way result, given that they passed in a flag
saying what to do in the absence of position data.  This might need
to change someday, but we wouldn't want to back-patch such a change.

Although tsginidx.c has its own TS_execute_ternary implementation for
use at upper index levels, that sadly managed to get this case wrong
as well :-(.  Fixing it is a lot easier fortunately.

Per bug #16388 from Charles Offenbacher.  Back-patch to 9.6 where
phrase search was introduced.

Discussion: https://postgr.es/m/16388-98cffba38d0b7e6e@postgresql.org
parent 5ac24755
......@@ -210,6 +210,11 @@ checkcondition_gin(void *checkval, QueryOperand *val, ExecPhraseData *data)
/*
* Evaluate tsquery boolean expression using ternary logic.
*
* Note: the reason we can't use TS_execute() for this is that its API
* for the checkcondition callback doesn't allow a MAYBE result to be
* returned, but we might have MAYBEs in the gcv->check array.
* Perhaps we should change that API.
*/
static GinTernaryValue
TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem, bool in_phrase)
......@@ -230,9 +235,19 @@ TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem, bool in_phrase)
switch (curitem->qoperator.oper)
{
case OP_NOT:
/* In phrase search, always return MAYBE since we lack positions */
/*
* Below a phrase search, force NOT's result to MAYBE. We cannot
* invert a TRUE result from the subexpression to FALSE, since
* TRUE only says that the subexpression matches somewhere, not
* that it matches everywhere, so there might be positions where
* the NOT will match. We could invert FALSE to TRUE, but there's
* little point in distinguishing TRUE from MAYBE, since a recheck
* will have been forced already.
*/
if (in_phrase)
return GIN_MAYBE;
result = TS_execute_ternary(gcv, curitem + 1, in_phrase);
if (result == GIN_MAYBE)
return result;
......@@ -242,7 +257,8 @@ TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem, bool in_phrase)
/*
* GIN doesn't contain any information about positions, so treat
* OP_PHRASE as OP_AND with recheck requirement
* OP_PHRASE as OP_AND with recheck requirement, and always
* reporting MAYBE not TRUE.
*/
*(gcv->need_recheck) = true;
/* Pass down in_phrase == true in case there's a NOT below */
......@@ -258,7 +274,8 @@ TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem, bool in_phrase)
val2 = TS_execute_ternary(gcv, curitem + 1, in_phrase);
if (val2 == GIN_FALSE)
return GIN_FALSE;
if (val1 == GIN_TRUE && val2 == GIN_TRUE)
if (val1 == GIN_TRUE && val2 == GIN_TRUE &&
curitem->qoperator.oper != OP_PHRASE)
return GIN_TRUE;
else
return GIN_MAYBE;
......
This diff is collapsed.
This diff is collapsed.
......@@ -116,6 +116,66 @@ SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
count
-------
0
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
count
-------
3
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
count
-------
432
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
count
-------
6
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
count
-------
507
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
count
-------
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
count
-------
507
(1 row)
create index wowidx on test_tsvector using gist (a);
SET enable_seqscan=OFF;
SET enable_indexscan=ON;
......@@ -188,6 +248,66 @@ SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
count
-------
0
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
count
-------
3
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
count
-------
432
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
count
-------
6
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
count
-------
507
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
count
-------
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
count
-------
507
(1 row)
SET enable_indexscan=OFF;
SET enable_bitmapscan=ON;
explain (costs off) SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh';
......@@ -260,6 +380,66 @@ SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
count
-------
0
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
count
-------
3
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
count
-------
432
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
count
-------
6
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
count
-------
507
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
count
-------
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
count
-------
507
(1 row)
-- Test siglen parameter of GiST tsvector_ops
CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(foo=1));
ERROR: unrecognized parameter "foo"
......@@ -355,6 +535,66 @@ SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
count
-------
0
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
count
-------
3
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
count
-------
432
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
count
-------
6
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
count
-------
507
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
count
-------
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
count
-------
507
(1 row)
DROP INDEX wowidx2;
CREATE INDEX wowidx ON test_tsvector USING gist (a tsvector_ops(siglen=484));
\d test_tsvector
......@@ -436,6 +676,66 @@ SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
count
-------
0
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
count
-------
3
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
count
-------
432
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
count
-------
6
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
count
-------
507
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
count
-------
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
count
-------
507
(1 row)
RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
......@@ -513,6 +813,66 @@ SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
count
-------
0
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
count
-------
3
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
count
-------
432
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
count
-------
1
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
count
-------
6
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
count
-------
507
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
count
-------
508
(1 row)
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
count
-------
507
(1 row)
-- Test optimization of non-empty GIN_SEARCH_MODE_ALL queries
EXPLAIN (COSTS OFF)
SELECT count(*) FROM test_tsvector WHERE a @@ '!qh';
......@@ -555,14 +915,14 @@ SELECT * FROM ts_stat('SELECT a FROM test_tsvector') ORDER BY ndoc DESC, nentry
------+------+--------
qq | 108 | 108
qt | 102 | 102
qe | 100 | 100
qh | 98 | 98
qe | 100 | 101
qh | 98 | 99
qw | 98 | 98
qa | 97 | 97
ql | 94 | 94
qs | 94 | 94
qr | 92 | 93
qi | 92 | 92
qr | 92 | 92
(10 rows)
SELECT * FROM ts_stat('SELECT a FROM test_tsvector', 'AB') ORDER BY ndoc DESC, nentry DESC, word;
......
......@@ -769,12 +769,90 @@ select to_tsvector('simple', 'z q') @@ '(!x | y <-> z) <-> q' AS "true";
t
(1 row)
select to_tsvector('simple', 'x y q') @@ '(!x | y) <-> y <-> q' AS "false";
false
-------
f
(1 row)
select to_tsvector('simple', 'x y q') @@ '(!x | !y) <-> y <-> q' AS "true";
true
------
t
(1 row)
select to_tsvector('simple', 'x y q') @@ '(x | !y) <-> y <-> q' AS "true";
true
------
t
(1 row)
select to_tsvector('simple', 'x y q') @@ '(x | !!z) <-> y <-> q' AS "true";
true
------
t
(1 row)
select to_tsvector('simple', 'x y q y') @@ '!x <-> y' AS "true";
true
------
t
(1 row)
select to_tsvector('simple', 'x y q y') @@ '!x <-> !y' AS "true";
true
------
t
(1 row)
select to_tsvector('simple', 'x y q y') @@ '!x <-> !!y' AS "true";
true
------
t
(1 row)
select to_tsvector('simple', 'x y q y') @@ '!(x <-> y)' AS "false";
false
-------
f
(1 row)
select to_tsvector('simple', 'x y q y') @@ '!(x <2> y)' AS "true";
true
------
t
(1 row)
select strip(to_tsvector('simple', 'x y q y')) @@ '!x <-> y' AS "false";
false
-------
f
(1 row)
select strip(to_tsvector('simple', 'x y q y')) @@ '!x <-> !y' AS "false";
false
-------
f
(1 row)
select strip(to_tsvector('simple', 'x y q y')) @@ '!x <-> !!y' AS "false";
false
-------
f
(1 row)
select strip(to_tsvector('simple', 'x y q y')) @@ '!(x <-> y)' AS "true";
true
------
t
(1 row)
select strip(to_tsvector('simple', 'x y q y')) @@ '!(x <2> y)' AS "true";
true
------
t
(1 row)
select to_tsvector('simple', 'x y q y') @@ '!foo' AS "true";
true
------
......
......@@ -51,6 +51,16 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*';
SELECT count(*) FROM test_tsvector WHERE a @@ any ('{wr,qh}');
SELECT count(*) FROM test_tsvector WHERE a @@ 'no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
create index wowidx on test_tsvector using gist (a);
......@@ -70,6 +80,16 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*';
SELECT count(*) FROM test_tsvector WHERE a @@ any ('{wr,qh}');
SELECT count(*) FROM test_tsvector WHERE a @@ 'no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
SET enable_indexscan=OFF;
SET enable_bitmapscan=ON;
......@@ -86,6 +106,16 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*';
SELECT count(*) FROM test_tsvector WHERE a @@ any ('{wr,qh}');
SELECT count(*) FROM test_tsvector WHERE a @@ 'no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
-- Test siglen parameter of GiST tsvector_ops
CREATE INDEX wowidx1 ON test_tsvector USING gist (a tsvector_ops(foo=1));
......@@ -112,6 +142,16 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*';
SELECT count(*) FROM test_tsvector WHERE a @@ any ('{wr,qh}');
SELECT count(*) FROM test_tsvector WHERE a @@ 'no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
DROP INDEX wowidx2;
......@@ -131,6 +171,16 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*';
SELECT count(*) FROM test_tsvector WHERE a @@ any ('{wr,qh}');
SELECT count(*) FROM test_tsvector WHERE a @@ 'no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
RESET enable_seqscan;
RESET enable_indexscan;
......@@ -155,6 +205,16 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*';
SELECT count(*) FROM test_tsvector WHERE a @@ any ('{wr,qh}');
SELECT count(*) FROM test_tsvector WHERE a @@ 'no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ '!no_such_lexeme';
SELECT count(*) FROM test_tsvector WHERE a @@ 'pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ 'yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ 'qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!pl <-> !yh';
SELECT count(*) FROM test_tsvector WHERE a @@ '!yh <-> pl';
SELECT count(*) FROM test_tsvector WHERE a @@ '!qe <2> qt';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(pl <-> yh)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(yh <-> pl)';
SELECT count(*) FROM test_tsvector WHERE a @@ '!(qe <2> qt)';
-- Test optimization of non-empty GIN_SEARCH_MODE_ALL queries
EXPLAIN (COSTS OFF)
......
......@@ -147,7 +147,20 @@ select to_tsvector('simple', 'y y q') @@ '(x | y <-> !z) <-> q' AS "true";
select to_tsvector('simple', 'x q') @@ '(x | y <-> !z) <-> q' AS "true";
select to_tsvector('simple', 'x q') @@ '(!x | y <-> z) <-> q' AS "false";
select to_tsvector('simple', 'z q') @@ '(!x | y <-> z) <-> q' AS "true";
select to_tsvector('simple', 'x y q') @@ '(!x | y) <-> y <-> q' AS "false";
select to_tsvector('simple', 'x y q') @@ '(!x | !y) <-> y <-> q' AS "true";
select to_tsvector('simple', 'x y q') @@ '(x | !y) <-> y <-> q' AS "true";
select to_tsvector('simple', 'x y q') @@ '(x | !!z) <-> y <-> q' AS "true";
select to_tsvector('simple', 'x y q y') @@ '!x <-> y' AS "true";
select to_tsvector('simple', 'x y q y') @@ '!x <-> !y' AS "true";
select to_tsvector('simple', 'x y q y') @@ '!x <-> !!y' AS "true";
select to_tsvector('simple', 'x y q y') @@ '!(x <-> y)' AS "false";
select to_tsvector('simple', 'x y q y') @@ '!(x <2> y)' AS "true";
select strip(to_tsvector('simple', 'x y q y')) @@ '!x <-> y' AS "false";
select strip(to_tsvector('simple', 'x y q y')) @@ '!x <-> !y' AS "false";
select strip(to_tsvector('simple', 'x y q y')) @@ '!x <-> !!y' AS "false";
select strip(to_tsvector('simple', 'x y q y')) @@ '!(x <-> y)' AS "true";
select strip(to_tsvector('simple', 'x y q y')) @@ '!(x <2> y)' AS "true";
select to_tsvector('simple', 'x y q y') @@ '!foo' AS "true";
select to_tsvector('simple', '') @@ '!foo' AS "true";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment