Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * tsquery_op.c
4 : : * Various operations with tsquery
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : *
8 : : *
9 : : * IDENTIFICATION
10 : : * src/backend/utils/adt/tsquery_op.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include "lib/qunique.h"
18 : : #include "tsearch/ts_utils.h"
19 : : #include "utils/fmgrprotos.h"
20 : : #include "varatt.h"
21 : :
22 : : Datum
6081 tgl@sss.pgh.pa.us 23 :CBC 9 : tsquery_numnode(PG_FUNCTION_ARGS)
24 : : {
25 : 9 : TSQuery query = PG_GETARG_TSQUERY(0);
26 : 9 : int nnode = query->size;
27 : :
28 [ - + ]: 9 : PG_FREE_IF_COPY(query, 0);
29 : 9 : PG_RETURN_INT32(nnode);
30 : : }
31 : :
32 : : static QTNode *
2929 teodor@sigaev.ru 33 : 54 : join_tsqueries(TSQuery a, TSQuery b, int8 operator, uint16 distance)
34 : : {
6081 tgl@sss.pgh.pa.us 35 : 54 : QTNode *res = (QTNode *) palloc0(sizeof(QTNode));
36 : :
37 : 54 : res->flags |= QTN_NEEDFREE;
38 : :
39 : 54 : res->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
6064 teodor@sigaev.ru 40 : 54 : res->valnode->type = QI_OPR;
5386 peter_e@gmx.net 41 : 54 : res->valnode->qoperator.oper = operator;
2929 teodor@sigaev.ru 42 [ + + ]: 54 : if (operator == OP_PHRASE)
43 : 24 : res->valnode->qoperator.distance = distance;
44 : :
6081 tgl@sss.pgh.pa.us 45 : 54 : res->child = (QTNode **) palloc0(sizeof(QTNode *) * 2);
46 : 54 : res->child[0] = QT2QTN(GETQUERY(b), GETOPERAND(b));
47 : 54 : res->child[1] = QT2QTN(GETQUERY(a), GETOPERAND(a));
48 : 54 : res->nchild = 2;
49 : :
50 : 54 : return res;
51 : : }
52 : :
53 : : Datum
54 : 18 : tsquery_and(PG_FUNCTION_ARGS)
55 : : {
56 : 18 : TSQuery a = PG_GETARG_TSQUERY_COPY(0);
57 : 18 : TSQuery b = PG_GETARG_TSQUERY_COPY(1);
58 : : QTNode *res;
59 : : TSQuery query;
60 : :
61 [ - + ]: 18 : if (a->size == 0)
62 : : {
6081 tgl@sss.pgh.pa.us 63 [ # # ]:UBC 0 : PG_FREE_IF_COPY(a, 1);
64 : 0 : PG_RETURN_POINTER(b);
65 : : }
6081 tgl@sss.pgh.pa.us 66 [ - + ]:CBC 18 : else if (b->size == 0)
67 : : {
6081 tgl@sss.pgh.pa.us 68 [ # # ]:UBC 0 : PG_FREE_IF_COPY(b, 1);
69 : 0 : PG_RETURN_POINTER(a);
70 : : }
71 : :
2929 teodor@sigaev.ru 72 :CBC 18 : res = join_tsqueries(a, b, OP_AND, 0);
73 : :
6081 tgl@sss.pgh.pa.us 74 : 18 : query = QTN2QT(res);
75 : :
76 : 18 : QTNFree(res);
77 [ + - ]: 18 : PG_FREE_IF_COPY(a, 0);
78 [ + - ]: 18 : PG_FREE_IF_COPY(b, 1);
79 : :
80 : 18 : PG_RETURN_TSQUERY(query);
81 : : }
82 : :
83 : : Datum
84 : 12 : tsquery_or(PG_FUNCTION_ARGS)
85 : : {
86 : 12 : TSQuery a = PG_GETARG_TSQUERY_COPY(0);
87 : 12 : TSQuery b = PG_GETARG_TSQUERY_COPY(1);
88 : : QTNode *res;
89 : : TSQuery query;
90 : :
91 [ - + ]: 12 : if (a->size == 0)
92 : : {
6081 tgl@sss.pgh.pa.us 93 [ # # ]:UBC 0 : PG_FREE_IF_COPY(a, 1);
94 : 0 : PG_RETURN_POINTER(b);
95 : : }
6081 tgl@sss.pgh.pa.us 96 [ - + ]:CBC 12 : else if (b->size == 0)
97 : : {
6081 tgl@sss.pgh.pa.us 98 [ # # ]:UBC 0 : PG_FREE_IF_COPY(b, 1);
99 : 0 : PG_RETURN_POINTER(a);
100 : : }
101 : :
2929 teodor@sigaev.ru 102 :CBC 12 : res = join_tsqueries(a, b, OP_OR, 0);
103 : :
6081 tgl@sss.pgh.pa.us 104 : 12 : query = QTN2QT(res);
105 : :
106 : 12 : QTNFree(res);
107 [ + - ]: 12 : PG_FREE_IF_COPY(a, 0);
108 [ + - ]: 12 : PG_FREE_IF_COPY(b, 1);
109 : :
2671 110 : 12 : PG_RETURN_TSQUERY(query);
111 : : }
112 : :
113 : : Datum
2929 teodor@sigaev.ru 114 : 24 : tsquery_phrase_distance(PG_FUNCTION_ARGS)
115 : : {
116 : 24 : TSQuery a = PG_GETARG_TSQUERY_COPY(0);
117 : 24 : TSQuery b = PG_GETARG_TSQUERY_COPY(1);
118 : : QTNode *res;
119 : : TSQuery query;
2925 peter_e@gmx.net 120 : 24 : int32 distance = PG_GETARG_INT32(2);
121 : :
2929 teodor@sigaev.ru 122 [ + - - + ]: 24 : if (distance < 0 || distance > MAXENTRYPOS)
2929 teodor@sigaev.ru 123 [ # # ]:UBC 0 : ereport(ERROR,
124 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
125 : : errmsg("distance in phrase operator must be an integer value between zero and %d inclusive",
126 : : MAXENTRYPOS)));
2929 teodor@sigaev.ru 127 [ - + ]:CBC 24 : if (a->size == 0)
128 : : {
2929 teodor@sigaev.ru 129 [ # # ]:UBC 0 : PG_FREE_IF_COPY(a, 1);
130 : 0 : PG_RETURN_POINTER(b);
131 : : }
2929 teodor@sigaev.ru 132 [ - + ]:CBC 24 : else if (b->size == 0)
133 : : {
2929 teodor@sigaev.ru 134 [ # # ]:UBC 0 : PG_FREE_IF_COPY(b, 1);
135 : 0 : PG_RETURN_POINTER(a);
136 : : }
137 : :
2929 teodor@sigaev.ru 138 :CBC 24 : res = join_tsqueries(a, b, OP_PHRASE, (uint16) distance);
139 : :
140 : 24 : query = QTN2QT(res);
141 : :
142 : 24 : QTNFree(res);
143 [ + - ]: 24 : PG_FREE_IF_COPY(a, 0);
144 [ + - ]: 24 : PG_FREE_IF_COPY(b, 1);
145 : :
2671 tgl@sss.pgh.pa.us 146 : 24 : PG_RETURN_TSQUERY(query);
147 : : }
148 : :
149 : : Datum
2929 teodor@sigaev.ru 150 : 21 : tsquery_phrase(PG_FUNCTION_ARGS)
151 : : {
595 peter@eisentraut.org 152 : 21 : PG_RETURN_DATUM(DirectFunctionCall3(tsquery_phrase_distance,
153 : : PG_GETARG_DATUM(0),
154 : : PG_GETARG_DATUM(1),
155 : : Int32GetDatum(1)));
156 : : }
157 : :
158 : : Datum
6081 tgl@sss.pgh.pa.us 159 : 6 : tsquery_not(PG_FUNCTION_ARGS)
160 : : {
161 : 6 : TSQuery a = PG_GETARG_TSQUERY_COPY(0);
162 : : QTNode *res;
163 : : TSQuery query;
164 : :
165 [ - + ]: 6 : if (a->size == 0)
6081 tgl@sss.pgh.pa.us 166 :UBC 0 : PG_RETURN_POINTER(a);
167 : :
6081 tgl@sss.pgh.pa.us 168 :CBC 6 : res = (QTNode *) palloc0(sizeof(QTNode));
169 : :
170 : 6 : res->flags |= QTN_NEEDFREE;
171 : :
172 : 6 : res->valnode = (QueryItem *) palloc0(sizeof(QueryItem));
6064 teodor@sigaev.ru 173 : 6 : res->valnode->type = QI_OPR;
5386 peter_e@gmx.net 174 : 6 : res->valnode->qoperator.oper = OP_NOT;
175 : :
6081 tgl@sss.pgh.pa.us 176 : 6 : res->child = (QTNode **) palloc0(sizeof(QTNode *));
177 : 6 : res->child[0] = QT2QTN(GETQUERY(a), GETOPERAND(a));
178 : 6 : res->nchild = 1;
179 : :
180 : 6 : query = QTN2QT(res);
181 : :
182 : 6 : QTNFree(res);
183 [ + - ]: 6 : PG_FREE_IF_COPY(a, 0);
184 : :
185 : 6 : PG_RETURN_POINTER(query);
186 : : }
187 : :
188 : : static int
189 : 226 : CompareTSQ(TSQuery a, TSQuery b)
190 : : {
191 [ + + ]: 226 : if (a->size != b->size)
192 : : {
193 [ + + ]: 117 : return (a->size < b->size) ? -1 : 1;
194 : : }
195 [ + + ]: 109 : else if (VARSIZE(a) != VARSIZE(b))
196 : : {
197 [ + + ]: 75 : return (VARSIZE(a) < VARSIZE(b)) ? -1 : 1;
198 : : }
5003 199 [ + - ]: 34 : else if (a->size != 0)
200 : : {
6081 201 : 34 : QTNode *an = QT2QTN(GETQUERY(a), GETOPERAND(a));
202 : 34 : QTNode *bn = QT2QTN(GETQUERY(b), GETOPERAND(b));
203 : 34 : int res = QTNodeCompare(an, bn);
204 : :
205 : 34 : QTNFree(an);
206 : 34 : QTNFree(bn);
207 : :
208 : 34 : return res;
209 : : }
210 : :
6081 tgl@sss.pgh.pa.us 211 :UBC 0 : return 0;
212 : : }
213 : :
214 : : Datum
6081 tgl@sss.pgh.pa.us 215 :CBC 30 : tsquery_cmp(PG_FUNCTION_ARGS)
216 : : {
217 : 30 : TSQuery a = PG_GETARG_TSQUERY_COPY(0);
218 : 30 : TSQuery b = PG_GETARG_TSQUERY_COPY(1);
219 : 30 : int res = CompareTSQ(a, b);
220 : :
221 [ + - ]: 30 : PG_FREE_IF_COPY(a, 0);
222 [ + - ]: 30 : PG_FREE_IF_COPY(b, 1);
223 : :
224 : 30 : PG_RETURN_INT32(res);
225 : : }
226 : :
227 : : #define CMPFUNC( NAME, CONDITION ) \
228 : : Datum \
229 : : NAME(PG_FUNCTION_ARGS) { \
230 : : TSQuery a = PG_GETARG_TSQUERY_COPY(0); \
231 : : TSQuery b = PG_GETARG_TSQUERY_COPY(1); \
232 : : int res = CompareTSQ(a,b); \
233 : : \
234 : : PG_FREE_IF_COPY(a,0); \
235 : : PG_FREE_IF_COPY(b,1); \
236 : : \
237 : : PG_RETURN_BOOL( CONDITION ); \
238 : : } \
239 : : /* keep compiler quiet - no extra ; */ \
240 : : extern int no_such_variable
241 : :
242 [ + - + - ]: 48 : CMPFUNC(tsquery_lt, res < 0);
243 [ + - + - ]: 36 : CMPFUNC(tsquery_le, res <= 0);
244 [ + - + - ]: 37 : CMPFUNC(tsquery_eq, res == 0);
245 [ + - + - ]: 36 : CMPFUNC(tsquery_ge, res >= 0);
246 [ + - + - ]: 39 : CMPFUNC(tsquery_gt, res > 0);
6081 tgl@sss.pgh.pa.us 247 [ # # # # ]:UBC 0 : CMPFUNC(tsquery_ne, res != 0);
248 : :
249 : : TSQuerySign
6081 tgl@sss.pgh.pa.us 250 :CBC 18 : makeTSQuerySign(TSQuery a)
251 : : {
252 : : int i;
253 : 18 : QueryItem *ptr = GETQUERY(a);
254 : 18 : TSQuerySign sign = 0;
255 : :
256 [ + + ]: 78 : for (i = 0; i < a->size; i++)
257 : : {
6064 teodor@sigaev.ru 258 [ + + ]: 60 : if (ptr->type == QI_VAL)
5003 tgl@sss.pgh.pa.us 259 : 39 : sign |= ((TSQuerySign) 1) << (((unsigned int) ptr->qoperand.valcrc) % TSQS_SIGLEN);
6081 260 : 60 : ptr++;
261 : : }
262 : :
263 : 18 : return sign;
264 : : }
265 : :
266 : : static char **
3457 heikki.linnakangas@i 267 : 288 : collectTSQueryValues(TSQuery a, int *nvalues_p)
268 : : {
269 : 288 : QueryItem *ptr = GETQUERY(a);
270 : 288 : char *operand = GETOPERAND(a);
271 : : char **values;
272 : 288 : int nvalues = 0;
273 : : int i;
274 : :
275 : 288 : values = (char **) palloc(sizeof(char *) * a->size);
276 : :
277 [ + + ]: 912 : for (i = 0; i < a->size; i++)
278 : : {
279 [ + + ]: 624 : if (ptr->type == QI_VAL)
280 : : {
281 : 456 : int len = ptr->qoperand.length;
282 : : char *val;
283 : :
284 : 456 : val = palloc(len + 1);
285 : 456 : memcpy(val, operand + ptr->qoperand.distance, len);
286 : 456 : val[len] = '\0';
287 : :
288 : 456 : values[nvalues++] = val;
289 : : }
290 : 624 : ptr++;
291 : : }
292 : :
293 : 288 : *nvalues_p = nvalues;
294 : 288 : return values;
295 : : }
296 : :
297 : : static int
298 : 384 : cmp_string(const void *a, const void *b)
299 : : {
1846 peter@eisentraut.org 300 : 384 : const char *sa = *((char *const *) a);
301 : 384 : const char *sb = *((char *const *) b);
302 : :
3457 heikki.linnakangas@i 303 : 384 : return strcmp(sa, sb);
304 : : }
305 : :
306 : : Datum
307 : 144 : tsq_mcontains(PG_FUNCTION_ARGS)
308 : : {
309 : 144 : TSQuery query = PG_GETARG_TSQUERY(0);
310 : 144 : TSQuery ex = PG_GETARG_TSQUERY(1);
311 : : char **query_values;
312 : : int query_nvalues;
313 : : char **ex_values;
314 : : int ex_nvalues;
315 : 144 : bool result = true;
316 : :
317 : : /* Extract the query terms into arrays */
318 : 144 : query_values = collectTSQueryValues(query, &query_nvalues);
319 : 144 : ex_values = collectTSQueryValues(ex, &ex_nvalues);
320 : :
321 : : /* Sort and remove duplicates from both arrays */
322 : 144 : qsort(query_values, query_nvalues, sizeof(char *), cmp_string);
1620 tmunro@postgresql.or 323 : 144 : query_nvalues = qunique(query_values, query_nvalues, sizeof(char *),
324 : : cmp_string);
3457 heikki.linnakangas@i 325 : 144 : qsort(ex_values, ex_nvalues, sizeof(char *), cmp_string);
1620 tmunro@postgresql.or 326 : 144 : ex_nvalues = qunique(ex_values, ex_nvalues, sizeof(char *), cmp_string);
327 : :
3457 heikki.linnakangas@i 328 [ + + ]: 144 : if (ex_nvalues > query_nvalues)
329 : 60 : result = false;
330 : : else
331 : : {
332 : : int i;
3249 bruce@momjian.us 333 : 84 : int j = 0;
334 : :
3457 heikki.linnakangas@i 335 [ + + ]: 102 : for (i = 0; i < ex_nvalues; i++)
336 : : {
337 [ + + ]: 228 : for (; j < query_nvalues; j++)
338 : : {
339 [ + + ]: 162 : if (strcmp(ex_values[i], query_values[j]) == 0)
340 : 18 : break;
341 : : }
342 [ + + ]: 84 : if (j == query_nvalues)
343 : : {
344 : 66 : result = false;
6081 tgl@sss.pgh.pa.us 345 : 66 : break;
346 : : }
347 : : }
348 : : }
349 : :
3457 heikki.linnakangas@i 350 : 144 : PG_RETURN_BOOL(result);
351 : : }
352 : :
353 : : Datum
6081 tgl@sss.pgh.pa.us 354 : 72 : tsq_mcontained(PG_FUNCTION_ARGS)
355 : : {
1536 alvherre@alvh.no-ip. 356 : 72 : PG_RETURN_DATUM(DirectFunctionCall2(tsq_mcontains,
357 : : PG_GETARG_DATUM(1),
358 : : PG_GETARG_DATUM(0)));
359 : : }
|