8000 Fix two bugs in tsquery @> operator. · leelingco/postgres@4d1c738 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4d1c738

Browse files
committed
Fix two bugs in tsquery @> operator.
1. The comparison for matching terms used only the CRC to decide if there's a match. Two different terms with the same CRC gave a match. 2. It assumed that if the second operand has more terms than the first, it's never a match. That assumption is bogus, because there can be duplicate terms in either operand. Rewrite the implementation in a way that doesn't have those bugs. Backpatch to all supported versions.
1 parent 94de3a6 commit 4d1c738

File tree

1 file changed

+90
-41
lines changed

1 file changed

+90
-41
lines changed

src/backend/utils/adt/tsquery_op.c

Lines changed: 90 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -216,63 +216,112 @@ makeTSQuerySign(TSQuery a)
216216
return sign;
217217
}
218218

219-
Datum
220-
tsq_mcontains(PG_FUNCTION_ARGS)
219+
static char **
220+
collectTSQueryValues(TSQuery a, int *nvalues_p)
221221
{
222-
TSQuery query = PG_GETARG_TSQUERY(0);
223-
TSQuery ex = PG_GETARG_TSQUERY(1);
224-
TSQuerySign sq,
225-
se;
226-
int i,
227-
j;
228-
QueryItem *iq,
229-
*ie;
230-
231-
if (query->size < ex->size)
222+
QueryItem *ptr = GETQUERY(a);
223+
char *operand = GETOPERAND(a);
224+
char **values;
225+
int nvalues = 0;
226+
int i;
227+
228+
values = (char **) palloc(sizeof(char *) * a->size);
229+
230+
for (i = 0; i < a->size; i++)
232231
{
233-
PG_FREE_IF_COPY(query, 0);
234-
PG_FREE_IF_COPY(ex, 1);
232+
if (ptr->type == QI_VAL)
233+
{
234+
int len = ptr->qoperand.length;
235+
char *val;
236+
237+
val = palloc(len + 1);
238+
memcpy(val, operand + ptr->qoperand.distance, len);
239+
val[len] = '\0';
235240

236-
PG_RETURN_BOOL(false);
241+
values[nvalues++] = val;
242+
}
243+
ptr++;
237244
}
238245

239-
sq = makeTSQuerySign(query);
240-
se = makeTSQuerySign(ex);
246+
*nvalues_p = nvalues;
247+
return values;
248+
}
249+
250+
static int
251+
cmp_string(const void *a, const void *b)
252+
{
253+
const char *sa = *((const char **) a);
254+
const char *sb = *((const char **) b);
255+
return strcmp(sa, sb);
256+
}
241257

242-
if ((sq & se) != se)
258+
static int
259+
remove_duplicates(char **strings, int n)
260+
{
261+
if (n <= 1)
262+
return n;
263+
else
243264
{
244-
PG_FREE_IF_COPY(query, 0);
245-
PG_FREE_IF_COPY(ex, 1);
265+
int i;
266+
char *prev = strings[0];
267+
int new_n = 1;
246268

247-
PG_RETURN_BOOL(false);
269+
for (i = 1; i < n; i++)
270+
{
271+
if (strcmp(strings[i], prev) != 0)
272+
{
273+
strings[new_n++] = strings[i];
274+
prev = strings[i];
275+
}
276+
}
277+
return new_n;
248278
}
279+
}
249280

250-
iq = GETQUERY(query);
251-
ie = GETQUERY(ex);
252-
253-
for (i = 0; i < ex->size; i++)
281+
Datum
282+
tsq_mcontains(PG_FUNCTION_ARGS)
283+
{
284+
TSQuery query = PG_GETARG_TSQUERY(0);
285+
TSQuery ex = PG_GETARG_TSQUERY(1);
286+
char **query_values;
287+
int query_nvalues;
288+
char **ex_values;
289+
int ex_nvalues;
290+
bool result = true;
291+
292+
/* Extract the query terms into arrays */
293+
query_values = collectTSQueryValues(query, &query_nvalues);
294+
ex_values = collectTSQueryValues(ex, &ex_nvalues);
295+
296+
/* Sort and remove duplicates from both arrays */
297+
qsort(query_values, query_nvalues, sizeof(char *), cmp_string);
298+
query_nvalues = remove_duplicates(query_values, query_nvalues);
299+
qsort(ex_values, ex_nvalues, sizeof(char *), cmp_string);
300+
ex_nvalues = remove_duplicates(ex_values, ex_nvalues);
301+
302+
if (ex_nvalues > query_nvalues)
303+
result = false;
304+
else
254305
{
255-
if (ie[i].type != QI_VAL)
256-
continue;
257-
for (j = 0; j < query->size; j++)
306+
int i;
307+
int j = 0;
308+
309+
for (i = 0; i < ex_nvalues; i++)
258310
{
259-
if (iq[j].type == QI_VAL &&
260-
ie[i].qoperand.valcrc == iq[j].qoperand.valcrc)
311+
for (; j < query_nvalues; j++)
312+
{
313+
if (strcmp(ex_values[i], query_values[j]) == 0)
314+
break;
315+
}
316+
if (j == query_nvalues)
317+
{
318+
result = false;
261319
break;
262-
}
263-
if (j >= query->size)
264-
{
265-
PG_FREE_IF_COPY(query, 0);
266-
PG_FREE_IF_COPY(ex, 1);
267-
268-
PG_RETURN_BOOL(false);
320+
}
269321
}
270322
}
271323

272-
PG_FREE_IF_COPY(query, 0);
273-
PG_FREE_IF_COPY(ex, 1);
274-
275-
PG_RETURN_BOOL(true);
324+
PG_RETURN_BOOL(result);
276325
}
277326

278327
Datum

0 commit comments

Comments
 (0)
0