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

Commit92fe689

Browse files
committed
Fix assorted bugs by changing TS_execute's callback API to ternary logic.
Text search sometimes failed to find valid matches, for instance'!crew:A'::tsquery might fail to locate 'crew:1B'::tsvector duringan index search. The root of the issue is that TS_execute's callbackfunctions were not changed to use ternary (yes/no/maybe) reportingwhen we made the search logic itself do so. It's somewhat annoyingto break that API, but on the other hand we now see that any codeusing plain boolean logic is almost certainly broken since theaddition of phrase search. There seem to be very few outside callersof this code anyway, so we'll just break them intentionally to getthem to adapt.This allows removal of tsginidx.c's private re-implementation ofTS_execute, since that's now entirely duplicative. It's also nolonger necessary to avoid use of CALC_NOT in tsgistidx.c, sincethe underlying callbacks can now do something reasonable.Back-patch into v13. We can't change this in stable branches,but it seems not quite too late to fix it in v13.Tom Lane and Pavel BorisovDiscussion:https://postgr.es/m/CALT9ZEE-aLotzBg-pOp2GFTesGWVYzXA3=mZKzRDa_OKnLF7Mg@mail.gmail.com
1 parent7dab456 commit92fe689

File tree

10 files changed

+395
-189
lines changed

10 files changed

+395
-189
lines changed

‎src/backend/tsearch/wparser_def.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,7 +1969,7 @@ typedef struct
19691969
/*
19701970
* TS_execute callback for matching a tsquery operand to headline words
19711971
*/
1972-
staticbool
1972+
staticTSTernaryValue
19731973
checkcondition_HL(void*opaque,QueryOperand*val,ExecPhraseData*data)
19741974
{
19751975
hlCheck*checkval= (hlCheck*)opaque;
@@ -1982,7 +1982,7 @@ checkcondition_HL(void *opaque, QueryOperand *val, ExecPhraseData *data)
19821982
{
19831983
/* if data == NULL, don't need to report positions */
19841984
if (!data)
1985-
returntrue;
1985+
returnTS_YES;
19861986

19871987
if (!data->pos)
19881988
{
@@ -1999,9 +1999,9 @@ checkcondition_HL(void *opaque, QueryOperand *val, ExecPhraseData *data)
19991999
}
20002000

20012001
if (data&&data->npos>0)
2002-
returntrue;
2002+
returnTS_YES;
20032003

2004-
returnfalse;
2004+
returnTS_NO;
20052005
}
20062006

20072007
/*

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

Lines changed: 24 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,13 @@ typedef struct
178178
bool*need_recheck;
179179
}GinChkVal;
180180

181-
staticGinTernaryValue
182-
checkcondition_gin_internal(GinChkVal*gcv,QueryOperand*val,ExecPhraseData*data)
181+
/*
182+
* TS_execute callback for matching a tsquery operand to GIN index data
183+
*/
184+
staticTSTernaryValue
185+
checkcondition_gin(void*checkval,QueryOperand*val,ExecPhraseData*data)
183186
{
187+
GinChkVal*gcv= (GinChkVal*)checkval;
184188
intj;
185189

186190
/*
@@ -193,112 +197,22 @@ checkcondition_gin_internal(GinChkVal *gcv, QueryOperand *val, ExecPhraseData *d
193197
/* convert item's number to corresponding entry's (operand's) number */
194198
j=gcv->map_item_operand[((QueryItem*)val)-gcv->first_item];
195199

196-
/* return presence of current entry in indexed value */
197-
returngcv->check[j];
198-
}
199-
200-
/*
201-
* Wrapper of check condition function for TS_execute.
202-
*/
203-
staticbool
204-
checkcondition_gin(void*checkval,QueryOperand*val,ExecPhraseData*data)
205-
{
206-
returncheckcondition_gin_internal((GinChkVal*)checkval,
207-
val,
208-
data)!=GIN_FALSE;
209-
}
210-
211-
/*
212-
* Evaluate tsquery boolean expression using ternary logic.
213-
*
214-
* Note: the reason we can't use TS_execute() for this is that its API
215-
* for the checkcondition callback doesn't allow a MAYBE result to be
216-
* returned, but we might have MAYBEs in the gcv->check array.
217-
* Perhaps we should change that API.
218-
*/
219-
staticGinTernaryValue
220-
TS_execute_ternary(GinChkVal*gcv,QueryItem*curitem,boolin_phrase)
221-
{
222-
GinTernaryValueval1,
223-
val2,
224-
result;
225-
226-
/* since this function recurses, it could be driven to stack overflow */
227-
check_stack_depth();
228-
229-
if (curitem->type==QI_VAL)
230-
return
231-
checkcondition_gin_internal(gcv,
232-
(QueryOperand*)curitem,
233-
NULL/* don't have position info */ );
234-
235-
switch (curitem->qoperator.oper)
200+
/*
201+
* return presence of current entry in indexed value; but TRUE becomes
202+
* MAYBE in the presence of a query requiring recheck
203+
*/
204+
if (gcv->check[j]==GIN_TRUE)
236205
{
237-
caseOP_NOT:
238-
239-
/*
240-
* Below a phrase search, force NOT's result to MAYBE. We cannot
241-
* invert a TRUE result from the subexpression to FALSE, since
242-
* TRUE only says that the subexpression matches somewhere, not
243-
* that it matches everywhere, so there might be positions where
244-
* the NOT will match. We could invert FALSE to TRUE, but there's
245-
* little point in distinguishing TRUE from MAYBE, since a recheck
246-
* will have been forced already.
247-
*/
248-
if (in_phrase)
249-
returnGIN_MAYBE;
250-
251-
result=TS_execute_ternary(gcv,curitem+1,in_phrase);
252-
if (result==GIN_MAYBE)
253-
returnresult;
254-
return !result;
255-
256-
caseOP_PHRASE:
257-
258-
/*
259-
* GIN doesn't contain any information about positions, so treat
260-
* OP_PHRASE as OP_AND with recheck requirement, and always
261-
* reporting MAYBE not TRUE.
262-
*/
263-
*(gcv->need_recheck)= true;
264-
/* Pass down in_phrase == true in case there's a NOT below */
265-
in_phrase= true;
266-
267-
/* FALL THRU */
268-
269-
caseOP_AND:
270-
val1=TS_execute_ternary(gcv,curitem+curitem->qoperator.left,
271-
in_phrase);
272-
if (val1==GIN_FALSE)
273-
returnGIN_FALSE;
274-
val2=TS_execute_ternary(gcv,curitem+1,in_phrase);
275-
if (val2==GIN_FALSE)
276-
returnGIN_FALSE;
277-
if (val1==GIN_TRUE&&val2==GIN_TRUE&&
278-
curitem->qoperator.oper!=OP_PHRASE)
279-
returnGIN_TRUE;
280-
else
281-
returnGIN_MAYBE;
282-
283-
caseOP_OR:
284-
val1=TS_execute_ternary(gcv,curitem+curitem->qoperator.left,
285-
in_phrase);
286-
if (val1==GIN_TRUE)
287-
returnGIN_TRUE;
288-
val2=TS_execute_ternary(gcv,curitem+1,in_phrase);
289-
if (val2==GIN_TRUE)
290-
returnGIN_TRUE;
291-
if (val1==GIN_FALSE&&val2==GIN_FALSE)
292-
returnGIN_FALSE;
293-
else
294-
returnGIN_MAYBE;
295-
296-
default:
297-
elog(ERROR,"unrecognized operator: %d",curitem->qoperator.oper);
206+
if (val->weight!=0||data!=NULL)
207+
returnTS_MAYBE;
298208
}
299209

300-
/* not reachable, but keep compiler quiet */
301-
return false;
210+
/*
211+
* We rely on GinTernaryValue and TSTernaryValue using equivalent value
212+
* assignments. We could use a switch statement to map the values if that
213+
* ever stops being true, but it seems unlikely to happen.
214+
*/
215+
return (TSTernaryValue)gcv->check[j];
302216
}
303217

304218
Datum
@@ -370,10 +284,11 @@ gin_tsquery_triconsistent(PG_FUNCTION_ARGS)
370284
gcv.map_item_operand= (int*) (extra_data[0]);
371285
gcv.need_recheck=&recheck;
372286

373-
res=TS_execute_ternary(&gcv,GETQUERY(query), false);
374-
375-
if (res==GIN_TRUE&&recheck)
376-
res=GIN_MAYBE;
287+
if (TS_execute(GETQUERY(query),
288+
&gcv,
289+
TS_EXEC_CALC_NOT |TS_EXEC_PHRASE_NO_POS,
290+
checkcondition_gin))
291+
res=recheck ?GIN_MAYBE :GIN_TRUE;
377292
}
378293

379294
PG_RETURN_GIN_TERNARY_VALUE(res);

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,9 @@ typedef struct
273273
}CHKVAL;
274274

275275
/*
276-
*is there value 'val' in array or not ?
276+
*TS_execute callback for matching a tsquery operand to GIST leaf-page data
277277
*/
278-
staticbool
278+
staticTSTernaryValue
279279
checkcondition_arr(void*checkval,QueryOperand*val,ExecPhraseData*data)
280280
{
281281
int32*StopLow= ((CHKVAL*)checkval)->arrb;
@@ -288,23 +288,26 @@ checkcondition_arr(void *checkval, QueryOperand *val, ExecPhraseData *data)
288288
* we are not able to find a prefix by hash value
289289
*/
290290
if (val->prefix)
291-
returntrue;
291+
returnTS_MAYBE;
292292

293293
while (StopLow<StopHigh)
294294
{
295295
StopMiddle=StopLow+ (StopHigh-StopLow) /2;
296296
if (*StopMiddle==val->valcrc)
297-
returntrue;
297+
returnTS_MAYBE;
298298
elseif (*StopMiddle<val->valcrc)
299299
StopLow=StopMiddle+1;
300300
else
301301
StopHigh=StopMiddle;
302302
}
303303

304-
returnfalse;
304+
returnTS_NO;
305305
}
306306

307-
staticbool
307+
/*
308+
* TS_execute callback for matching a tsquery operand to GIST non-leaf data
309+
*/
310+
staticTSTernaryValue
308311
checkcondition_bit(void*checkval,QueryOperand*val,ExecPhraseData*data)
309312
{
310313
void*key= (SignTSVector*)checkval;
@@ -313,8 +316,12 @@ checkcondition_bit(void *checkval, QueryOperand *val, ExecPhraseData *data)
313316
* we are not able to find a prefix in signature tree
314317
*/
315318
if (val->prefix)
316-
return true;
317-
returnGETBIT(GETSIGN(key),HASHVAL(val->valcrc,GETSIGLEN(key)));
319+
returnTS_MAYBE;
320+
321+
if (GETBIT(GETSIGN(key),HASHVAL(val->valcrc,GETSIGLEN(key))))
322+
returnTS_MAYBE;
323+
else
324+
returnTS_NO;
318325
}
319326

320327
Datum
@@ -339,10 +346,9 @@ gtsvector_consistent(PG_FUNCTION_ARGS)
339346
if (ISALLTRUE(key))
340347
PG_RETURN_BOOL(true);
341348

342-
/* since signature is lossy, cannot specify CALC_NOT here */
343349
PG_RETURN_BOOL(TS_execute(GETQUERY(query),
344350
key,
345-
TS_EXEC_PHRASE_NO_POS,
351+
TS_EXEC_PHRASE_NO_POS |TS_EXEC_CALC_NOT,
346352
checkcondition_bit));
347353
}
348354
else

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,14 +556,18 @@ typedef struct
556556
#defineQR_GET_OPERAND_DATA(q,v) \
557557
( (q)->operandData + (((QueryItem*)(v)) - GETQUERY((q)->query)) )
558558

559-
staticbool
560-
checkcondition_QueryOperand(void*checkval,QueryOperand*val,ExecPhraseData*data)
559+
/*
560+
* TS_execute callback for matching a tsquery operand to QueryRepresentation
561+
*/
562+
staticTSTernaryValue
563+
checkcondition_QueryOperand(void*checkval,QueryOperand*val,
564+
ExecPhraseData*data)
561565
{
562566
QueryRepresentation*qr= (QueryRepresentation*)checkval;
563567
QueryRepresentationOperand*opData=QR_GET_OPERAND_DATA(qr,val);
564568

565569
if (!opData->operandexists)
566-
returnfalse;
570+
returnTS_NO;
567571

568572
if (data)
569573
{
@@ -573,7 +577,7 @@ checkcondition_QueryOperand(void *checkval, QueryOperand *val, ExecPhraseData *d
573577
data->pos+=MAXQROPOS-opData->npos;
574578
}
575579

576-
returntrue;
580+
returnTS_YES;
577581
}
578582

579583
typedefstruct

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp