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