Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0eaaaf0

Browse files
committed
Prevent crash when ts_rewrite() replaces a non-top-level subtree with null.
When ts_rewrite()'s replacement argument is an empty tsquery, it's supposedto simplify any operator nodes whose operand(s) become NULL; but it failedto do that reliably, because dropvoidsubtree() only examined the top levelof the result tree. Rather than make a second recursive pass, let's justgive the responsibility to dofindsubquery() to simplify while it's doingthe main replacement pass. Per report from Andreas Seltenreich.Artur Zakirov, with some cosmetic changes by me. Back-patch to allsupported branches.Discussion:https://postgr.es/m/8737i01dew.fsf@credativ.de
1 parent9cda81f commit0eaaaf0

File tree

3 files changed

+47
-29
lines changed

3 files changed

+47
-29
lines changed

‎src/backend/utils/adt/tsquery_rewrite.c

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ findeq(QTNode *node, QTNode *ex, QTNode *subs, bool *isfind)
140140

141141
node->nchild=j;
142142

143+
/*
144+
* At this point we might have a node with zero or one child,
145+
* which should be simplified. But we leave it to our caller
146+
* (dofindsubquery) to take care of that.
147+
*/
148+
143149
/*
144150
* Re-sort the node to put new child in the right place. This
145151
* is a bit bogus, because it won't matter for findsubquery's
@@ -186,6 +192,15 @@ findeq(QTNode *node, QTNode *ex, QTNode *subs, bool *isfind)
186192
* Recursive guts of findsubquery(): attempt to replace "ex" with "subs"
187193
* at the root node, and if we failed to do so, recursively match against
188194
* child nodes.
195+
*
196+
* Delete any void subtrees resulting from the replacement.
197+
* In the following example '5' is replaced by empty operand:
198+
*
199+
* AND-> 6
200+
* / \
201+
*5 OR
202+
*/ \
203+
* 65
189204
*/
190205
staticQTNode*
191206
dofindsubquery(QTNode*root,QTNode*ex,QTNode*subs,bool*isfind)
@@ -196,45 +211,33 @@ dofindsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind)
196211
/* also, since it's a bit expensive, let's check for query cancel. */
197212
CHECK_FOR_INTERRUPTS();
198213

214+
/* match at the node itself */
199215
root=findeq(root,ex,subs,isfind);
200216

201-
if (root&& (root->flags&QTN_NOCHANGE)==0&&root->valnode->type==QI_OPR)
202-
{
203-
inti;
204-
205-
for (i=0;i<root->nchild;i++)
206-
root->child[i]=dofindsubquery(root->child[i],ex,subs,isfind);
207-
}
208-
209-
returnroot;
210-
}
211-
212-
/*
213-
* Delete any void subtrees that may have been inserted when the replacement
214-
* subtree is void.
215-
*/
216-
staticQTNode*
217-
dropvoidsubtree(QTNode*root)
218-
{
219-
if (!root)
220-
returnNULL;
221-
222-
if (root->valnode->type==QI_OPR)
217+
/* unless we matched here, consider matches at child nodes */
218+
if (root&& (root->flags&QTN_NOCHANGE)==0&&
219+
root->valnode->type==QI_OPR)
223220
{
224221
inti,
225222
j=0;
226223

224+
/*
225+
* Any subtrees that are replaced by NULL must be dropped from the
226+
* tree.
227+
*/
227228
for (i=0;i<root->nchild;i++)
228229
{
229-
if (root->child[i])
230-
{
231-
root->child[j]=root->child[i];
230+
root->child[j]=dofindsubquery(root->child[i],ex,subs,isfind);
231+
if (root->child[j])
232232
j++;
233-
}
234233
}
235234

236235
root->nchild=j;
237236

237+
/*
238+
* If we have just zero or one remaining child node, simplify out this
239+
* operator node.
240+
*/
238241
if (root->nchild==0)
239242
{
240243
QTNFree(root);
@@ -267,9 +270,6 @@ findsubquery(QTNode *root, QTNode *ex, QTNode *subs, bool *isfind)
267270

268271
root=dofindsubquery(root,ex,subs,&DidFind);
269272

270-
if (!subs&&DidFind)
271-
root=dropvoidsubtree(root);
272-
273273
if (isfind)
274274
*isfind=DidFind;
275275

‎src/test/regress/expected/tsearch.out

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,21 @@ SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::t
12511251
'5' <-> '7' | '5' <-> '8'
12521252
(1 row)
12531253

1254+
-- Check empty substitution
1255+
SELECT ts_rewrite(to_tsquery('5 & (6 | 5)'), to_tsquery('5'), to_tsquery(''));
1256+
NOTICE: text-search query doesn't contain lexemes: ""
1257+
ts_rewrite
1258+
------------
1259+
'6'
1260+
(1 row)
1261+
1262+
SELECT ts_rewrite(to_tsquery('!5'), to_tsquery('5'), to_tsquery(''));
1263+
NOTICE: text-search query doesn't contain lexemes: ""
1264+
ts_rewrite
1265+
------------
1266+
1267+
(1 row)
1268+
12541269
SELECT keyword FROM test_tsquery WHERE keyword @> 'new';
12551270
keyword
12561271
----------------

‎src/test/regress/sql/tsearch.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,9 @@ SELECT ts_rewrite('1 & (2 <2> 3)', 'SELECT keyword, sample FROM test_tsquery'::t
418418
SELECT ts_rewrite('5 <-> (1 & (2 <-> 3))','SELECT keyword, sample FROM test_tsquery'::text );
419419
SELECT ts_rewrite('5 <-> (6 | 8)','SELECT keyword, sample FROM test_tsquery'::text );
420420

421+
-- Check empty substitution
422+
SELECT ts_rewrite(to_tsquery('5 & (6 | 5)'), to_tsquery('5'), to_tsquery(''));
423+
SELECT ts_rewrite(to_tsquery('!5'), to_tsquery('5'), to_tsquery(''));
421424

422425
SELECT keywordFROM test_tsqueryWHERE keyword @>'new';
423426
SELECT keywordFROM test_tsqueryWHERE keyword @>'moscow';

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp