summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTeodor Sigaev <teodor@sigaev.ru>2016-07-15 19:22:18 +0300
committerTeodor Sigaev <teodor@sigaev.ru>2016-07-15 19:22:18 +0300
commit19d290155d084754eeb5ebb2569654da06073ee8 (patch)
tree5d732d9e5d88087605083878100f5eaafd101e72 /src
parentce150e7e0fc1a127fee7933d71f4204a79ecce04 (diff)
Fix nested NOT operation cleanup in tsquery.
During normalization of tsquery tree it tries to simplify nested NOT operations but there it's obvioulsy missed that subsequent node could be a leaf node (value node) Bug #14245: Segfault on weird to_tsquery Reported by David Kellum.
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/tsquery_cleanup.c8
-rw-r--r--src/test/regress/expected/tsearch.out12
-rw-r--r--src/test/regress/sql/tsearch.sql3
3 files changed, 22 insertions, 1 deletions
diff --git a/src/backend/utils/adt/tsquery_cleanup.c b/src/backend/utils/adt/tsquery_cleanup.c
index 1a90964ce79..8c2df73ea6b 100644
--- a/src/backend/utils/adt/tsquery_cleanup.c
+++ b/src/backend/utils/adt/tsquery_cleanup.c
@@ -406,6 +406,8 @@ normalize_phrase_tree(NODE *node)
if (node->valnode->qoperator.oper == OP_NOT)
{
+ NODE *orignode = node;
+
/* eliminate NOT sequence */
while (node->valnode->type == QI_OPR &&
node->valnode->qoperator.oper == node->right->valnode->qoperator.oper)
@@ -413,7 +415,11 @@ normalize_phrase_tree(NODE *node)
node = node->right->right;
}
- node->right = normalize_phrase_tree(node->right);
+ if (orignode != node)
+ /* current node isn't checked yet */
+ node = normalize_phrase_tree(node);
+ else
+ node->right = normalize_phrase_tree(node->right);
}
else if (node->valnode->qoperator.oper == OP_PHRASE)
{
diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out
index 2ec3d1b6ab9..129d06ef07e 100644
--- a/src/test/regress/expected/tsearch.out
+++ b/src/test/regress/expected/tsearch.out
@@ -555,6 +555,18 @@ SELECT plainto_tsquery('english', 'foo bar') && 'asd | fg';
(1 row)
-- Check stop word deletion, a and s are stop-words
+SELECT to_tsquery('english', '!(a & !b) & c');
+ to_tsquery
+------------
+ 'b' & 'c'
+(1 row)
+
+SELECT to_tsquery('english', '!(a & !b)');
+ to_tsquery
+------------
+ 'b'
+(1 row)
+
SELECT to_tsquery('english', '(1 <-> 2) <-> a');
to_tsquery
-------------
diff --git a/src/test/regress/sql/tsearch.sql b/src/test/regress/sql/tsearch.sql
index 5f3d335fc39..65eb9438d49 100644
--- a/src/test/regress/sql/tsearch.sql
+++ b/src/test/regress/sql/tsearch.sql
@@ -130,6 +130,9 @@ SELECT plainto_tsquery('english', 'foo bar') || !!plainto_tsquery('english', 'as
SELECT plainto_tsquery('english', 'foo bar') && 'asd | fg';
-- Check stop word deletion, a and s are stop-words
+SELECT to_tsquery('english', '!(a & !b) & c');
+SELECT to_tsquery('english', '!(a & !b)');
+
SELECT to_tsquery('english', '(1 <-> 2) <-> a');
SELECT to_tsquery('english', '(1 <-> a) <-> 2');
SELECT to_tsquery('english', '(a <-> 1) <-> 2');