From 19d290155d084754eeb5ebb2569654da06073ee8 Mon Sep 17 00:00:00 2001 From: Teodor Sigaev <teodor@sigaev.ru> Date: Fri, 15 Jul 2016 19:22:18 +0300 Subject: [PATCH] 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. --- src/backend/utils/adt/tsquery_cleanup.c | 8 +++++++- src/test/regress/expected/tsearch.out | 12 ++++++++++++ src/test/regress/sql/tsearch.sql | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) 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'); -- GitLab