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