aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/tsquery_rewrite.c58
-rw-r--r--src/test/regress/expected/tsearch.out15
-rw-r--r--src/test/regress/sql/tsearch.sql3
3 files changed, 47 insertions, 29 deletions
diff --git a/src/backend/utils/adt/tsquery_rewrite.c b/src/backend/utils/adt/tsquery_rewrite.c
index e5bed6efb38..1e09f590056 100644
--- a/src/backend/utils/adt/tsquery_rewrite.c
+++ b/src/backend/utils/adt/tsquery_rewrite.c
@@ -141,6 +141,12 @@ findeq(QTNode *node, QTNode *ex, QTNode *subs, bool *isfind)
node->nchild = j;
/*
+ * At this point we might have a node with zero or one child,
+ * which should be simplified. But we leave it to our caller
+ * (dofindsubquery) to take care of that.
+ */
+
+ /*
* Re-sort the node to put new child in the right place. This
* is a bit bogus, because it won't matter for findsubquery's
* remaining processing, and it's insufficient to prepare the
@@ -186,6 +192,15 @@ findeq(QTNode *node, QTNode *ex, QTNode *subs, bool *isfind)
* Recursive guts of findsubquery(): attempt to replace "ex" with "subs"
* at the root node, and if we failed to do so, recursively match against
* child nodes.
+ *
+ * Delete any void subtrees resulting from the replacement.
+ * In the following example '5' is replaced by empty operand:
+ *
+ * AND -> 6
+ * / \
+ * 5 OR
+ * / \
+ * 6 5
*/
static QTNode *
dofindsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind)
@@ -196,45 +211,33 @@ dofindsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind)
/* also, since it's a bit expensive, let's check for query cancel. */
CHECK_FOR_INTERRUPTS();
+ /* match at the node itself */
root = findeq(root, ex, subs, isfind);
- if (root && (root->flags & QTN_NOCHANGE) == 0 && root->valnode->type == QI_OPR)
- {
- int i;
-
- for (i = 0; i < root->nchild; i++)
- root->child[i] = dofindsubquery(root->child[i], ex, subs, isfind);
- }
-
- return root;
-}
-
-/*
- * Delete any void subtrees that may have been inserted when the replacement
- * subtree is void.
- */
-static QTNode *
-dropvoidsubtree(QTNode *root)
-{
- if (!root)
- return NULL;
-
- if (root->valnode->type == QI_OPR)
+ /* unless we matched here, consider matches at child nodes */
+ if (root && (root->flags & QTN_NOCHANGE) == 0 &&
+ root->valnode->type == QI_OPR)
{
int i,
j = 0;
+ /*
+ * Any subtrees that are replaced by NULL must be dropped from the
+ * tree.
+ */
for (i = 0; i < root->nchild; i++)
{
- if (root->child[i])
- {
- root->child[j] = root->child[i];
+ root->child[j] = dofindsubquery(root->child[i], ex, subs, isfind);
+ if (root->child[j])
j++;
- }
}
root->nchild = j;
+ /*
+ * If we have just zero or one remaining child node, simplify out this
+ * operator node.
+ */
if (root->nchild == 0)
{
QTNFree(root);
@@ -267,9 +270,6 @@ findsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind)
root = dofindsubquery(root, ex, subs, &DidFind);
- if (!subs && DidFind)
- root = dropvoidsubtree(root);
-
if (isfind)
*isfind = DidFind;
diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out
index 55d6a857387..be4bdf21f10 100644
--- a/src/test/regress/expected/tsearch.out
+++ b/src/test/regress/expected/tsearch.out
@@ -1251,6 +1251,21 @@ SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::t
'5' <-> '7' | '5' <-> '8'
(1 row)
+-- Check empty substitution
+SELECT ts_rewrite(to_tsquery('5 & (6 | 5)'), to_tsquery('5'), to_tsquery(''));
+NOTICE: text-search query doesn't contain lexemes: ""
+ ts_rewrite
+------------
+ '6'
+(1 row)
+
+SELECT ts_rewrite(to_tsquery('!5'), to_tsquery('5'), to_tsquery(''));
+NOTICE: text-search query doesn't contain lexemes: ""
+ ts_rewrite
+------------
+
+(1 row)
+
SELECT keyword FROM test_tsquery WHERE keyword @> 'new';
keyword
----------------
diff --git a/src/test/regress/sql/tsearch.sql b/src/test/regress/sql/tsearch.sql
index afd990e6969..de43860c704 100644
--- a/src/test/regress/sql/tsearch.sql
+++ b/src/test/regress/sql/tsearch.sql
@@ -418,6 +418,9 @@ SELECT ts_rewrite('1 & (2 <2> 3)', 'SELECT keyword, sample FROM test_tsquery'::t
SELECT ts_rewrite('5 <-> (1 & (2 <-> 3))', 'SELECT keyword, sample FROM test_tsquery'::text );
SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::text );
+-- Check empty substitution
+SELECT ts_rewrite(to_tsquery('5 & (6 | 5)'), to_tsquery('5'), to_tsquery(''));
+SELECT ts_rewrite(to_tsquery('!5'), to_tsquery('5'), to_tsquery(''));
SELECT keyword FROM test_tsquery WHERE keyword @> 'new';
SELECT keyword FROM test_tsquery WHERE keyword @> 'moscow';