0001-dofindsubquery-with-drop.diff

text/plain

Filename: 0001-dofindsubquery-with-drop.diff
Type: text/plain
Part: 0
Message: Re: [sqlsmith] Crash in tsquery_rewrite/QTNBinary

Patch

Format: unified
Series: patch 0001
File+
src/backend/utils/adt/tsquery_rewrite.c 15 28
src/test/regress/expected/tsearch.out 8 0
src/test/regress/sql/tsearch.sql 2 0
diff --git a/src/backend/utils/adt/tsquery_rewrite.c b/src/backend/utils/adt/tsquery_rewrite.c
index e5bed6e..00174bd 100644
--- a/src/backend/utils/adt/tsquery_rewrite.c
+++ b/src/backend/utils/adt/tsquery_rewrite.c
@@ -186,6 +186,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. In the following example '5' is replaced by empty
+ * operand:
+ *
+ *    AND       ->    6
+ *   /   \
+ *  5    PHRASE
+ *       /     \
+ *      6      5
  */
 static QTNode *
 dofindsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind)
@@ -200,39 +209,20 @@ dofindsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *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)
-	{
 		int			i,
 					j = 0;
 
 		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++;
-			}
 		}
 
+		/*
+		 * Delete any void subtrees that may have been inserted when the replacement
+		 * subtree is void.
+		 */
 		root->nchild = j;
 
 		if (root->nchild == 0)
@@ -267,9 +257,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 55d6a85..9c20aaf 100644
--- a/src/test/regress/expected/tsearch.out
+++ b/src/test/regress/expected/tsearch.out
@@ -1251,6 +1251,14 @@ SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::t
  '5' <-> '7' | '5' <-> '8'
 (1 row)
 
+-- Check empty substitute
+SELECT ts_rewrite(to_tsquery('5 & 6 <-> 5'), to_tsquery('5'), to_tsquery('I'));
+NOTICE:  text-search query contains only stop words or doesn't contain lexemes, ignored
+ ts_rewrite 
+------------
+ '6'
+(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 afd990e..8752344 100644
--- a/src/test/regress/sql/tsearch.sql
+++ b/src/test/regress/sql/tsearch.sql
@@ -418,6 +418,8 @@ 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 substitute
+SELECT ts_rewrite(to_tsquery('5 & 6 <-> 5'), to_tsquery('5'), to_tsquery('I'));
 
 SELECT keyword FROM test_tsquery WHERE keyword @> 'new';
 SELECT keyword FROM test_tsquery WHERE keyword @> 'moscow';