diff --git a/src/backend/utils/adt/tsquery.c b/src/backend/utils/adt/tsquery.c index 257b5d3345..eea6e0eae1 100644 --- a/src/backend/utils/adt/tsquery.c +++ b/src/backend/utils/adt/tsquery.c @@ -16,12 +16,21 @@ #include "libpq/pqformat.h" #include "miscadmin.h" +#include "tsearch/ts_type.h" #include "tsearch/ts_locale.h" #include "tsearch/ts_utils.h" #include "utils/builtins.h" #include "utils/memutils.h" #include "utils/pg_crc.h" +/* FTS operator priorities, see ts_type.h */ +const int tsearch_op_priority[OP_COUNT] = +{ + 3, /* OP_NOT */ + 2, /* OP_AND */ + 1, /* OP_OR */ + 4 /* OP_PHRASE */ +}; struct TSQueryParserStateData { @@ -736,9 +745,6 @@ while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \ (inf)->cur = (inf)->buf + len; \ } -#define PRINT_PRIORITY(x) \ - ( (QO_PRIORITY(x) == OP_NOT) ? OP_NOT_PHRASE : QO_PRIORITY(x) ) - /* * recursively traverse the tree and * print it in infix (human-readable) form diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h index ff3fef1f47..8d24b32fac 100644 --- a/src/include/tsearch/ts_type.h +++ b/src/include/tsearch/ts_type.h @@ -222,11 +222,15 @@ typedef struct * for query transformation! That's need to simplify * algorithm of query transformation. */ -#define OP_OR 1 +#define OP_NOT 1 #define OP_AND 2 -#define OP_NOT 3 +#define OP_OR 3 #define OP_PHRASE 4 -#define OP_NOT_PHRASE 5 /* +#define OP_COUNT 4 + +extern const int tsearch_op_priority[OP_COUNT]; + +#define NOT_PHRASE_P 5 /* * OP_PHRASE negation operations must have greater * priority in order to force infix() to surround * the whole OP_PHRASE expression with parentheses. @@ -234,8 +238,13 @@ typedef struct #define TOP_PRIORITY 6 /* highest priority for val nodes */ -#define OP_PRIORITY(x) (x) +/* get operation priority by its code*/ +#define OP_PRIORITY(x) ( tsearch_op_priority[(x) - 1] ) +/* get QueryOperator priority */ #define QO_PRIORITY(x) OP_PRIORITY(((QueryOperator *) (x))->oper) +/* special case: get QueryOperator priority for correct printing !(a <-> b>) */ +#define PRINT_PRIORITY(x) \ + ( (((QueryOperator *) (x))->oper == OP_NOT) ? NOT_PHRASE_P : QO_PRIORITY(x) ) typedef struct { diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out index a4c61e20cb..2c3aa1a293 100644 --- a/src/test/regress/expected/tsearch.out +++ b/src/test/regress/expected/tsearch.out @@ -1169,7 +1169,7 @@ RESET enable_seqscan; SELECT ts_rewrite('foo & bar & qq & new & york', 'new & york'::tsquery, 'big & apple | nyc | new & york & city'); ts_rewrite ------------------------------------------------------------------------------ - 'foo' & 'bar' & 'qq' & ( 'nyc' | 'big' & 'apple' | 'city' & 'new' & 'york' ) + 'foo' & 'bar' & 'qq' & ( 'city' & 'new' & 'york' | 'nyc' | 'big' & 'apple' ) (1 row) SELECT ts_rewrite('moscow', 'SELECT keyword, sample FROM test_tsquery'::text ); @@ -1187,7 +1187,7 @@ SELECT ts_rewrite('moscow & hotel', 'SELECT keyword, sample FROM test_tsquery':: SELECT ts_rewrite('bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery'::text ); ts_rewrite --------------------------------------------------------------------------------- - ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' ) + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) (1 row) SELECT ts_rewrite( 'moscow', 'SELECT keyword, sample FROM test_tsquery'); @@ -1205,7 +1205,7 @@ SELECT ts_rewrite( 'moscow & hotel', 'SELECT keyword, sample FROM test_tsquery') SELECT ts_rewrite( 'bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery'); ts_rewrite --------------------------------------------------------------------------------- - ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' ) + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) (1 row) SELECT ts_rewrite('1 & (2 <-> 3)', 'SELECT keyword, sample FROM test_tsquery'::text ); @@ -1270,7 +1270,7 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; ts_rewrite --------------------------------------------------------------------------------- - ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' ) + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) (1 row) SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; @@ -1288,7 +1288,7 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; ts_rewrite --------------------------------------------------------------------------------- - ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' ) + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) (1 row) CREATE INDEX qq ON test_tsquery USING gist (keyword tsquery_ops); @@ -1331,7 +1331,7 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; ts_rewrite --------------------------------------------------------------------------------- - ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' ) + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) (1 row) SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query; @@ -1349,7 +1349,7 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query; ts_rewrite --------------------------------------------------------------------------------- - ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' ) + 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) (1 row) RESET enable_seqscan; diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out index c904c1c705..c8ca0624d4 100644 --- a/src/test/regress/expected/tstypes.out +++ b/src/test/regress/expected/tstypes.out @@ -473,7 +473,7 @@ SELECT 'a' > 'b & c'::tsquery as "false"; SELECT 'a | f' < 'b & c'::tsquery as "false"; false ------- - f + t (1 row) SELECT 'a | ff' < 'b & c'::tsquery as "false";