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