Line data Source code
1 : /*
2 : * GiST support for ltree
3 : * Teodor Sigaev <teodor@stack.net>
4 : * contrib/ltree/ltree_gist.c
5 : */
6 : #include "postgres.h"
7 :
8 : #include "access/gist.h"
9 : #include "access/reloptions.h"
10 : #include "access/stratnum.h"
11 : #include "crc32.h"
12 : #include "ltree.h"
13 : #include "utils/array.h"
14 :
15 : #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
16 : #define ISEQ(a,b) ( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 )
17 :
18 4 : PG_FUNCTION_INFO_V1(ltree_gist_in);
19 4 : PG_FUNCTION_INFO_V1(ltree_gist_out);
20 :
21 : Datum
22 0 : ltree_gist_in(PG_FUNCTION_ARGS)
23 : {
24 0 : ereport(ERROR,
25 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
26 : errmsg("cannot accept a value of type %s", "ltree_gist")));
27 :
28 : PG_RETURN_VOID(); /* keep compiler quiet */
29 : }
30 :
31 : Datum
32 0 : ltree_gist_out(PG_FUNCTION_ARGS)
33 : {
34 0 : ereport(ERROR,
35 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
36 : errmsg("cannot display a value of type %s", "ltree_gist")));
37 :
38 : PG_RETURN_VOID(); /* keep compiler quiet */
39 : }
40 :
41 : ltree_gist *
42 33922 : ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen,
43 : ltree *left, ltree *right)
44 : {
45 44476 : int32 size = LTG_HDRSIZE + (isalltrue ? 0 : siglen) +
46 10554 : (left ? VARSIZE(left) + (right ? VARSIZE(right) : 0) : 0);
47 33922 : ltree_gist *result = palloc(size);
48 :
49 33922 : SET_VARSIZE(result, size);
50 :
51 33922 : if (siglen)
52 : {
53 29898 : result->flag = 0;
54 :
55 29898 : if (isalltrue)
56 0 : result->flag |= LTG_ALLTRUE;
57 29898 : else if (sign)
58 10106 : memcpy(LTG_SIGN(result), sign, siglen);
59 : else
60 19792 : memset(LTG_SIGN(result), 0, siglen);
61 :
62 29898 : if (left)
63 : {
64 6530 : memcpy(LTG_LNODE(result, siglen), left, VARSIZE(left));
65 :
66 6530 : if (!right || left == right || ISEQ(left, right))
67 0 : result->flag |= LTG_NORIGHT;
68 : else
69 6530 : memcpy(LTG_RNODE(result, siglen), right, VARSIZE(right));
70 : }
71 : }
72 : else
73 : {
74 : Assert(left);
75 4024 : result->flag = LTG_ONENODE;
76 4024 : memcpy(LTG_NODE(result), left, VARSIZE(left));
77 : }
78 :
79 33922 : return result;
80 : }
81 :
82 6 : PG_FUNCTION_INFO_V1(ltree_compress);
83 6 : PG_FUNCTION_INFO_V1(ltree_decompress);
84 6 : PG_FUNCTION_INFO_V1(ltree_same);
85 6 : PG_FUNCTION_INFO_V1(ltree_union);
86 6 : PG_FUNCTION_INFO_V1(ltree_penalty);
87 6 : PG_FUNCTION_INFO_V1(ltree_picksplit);
88 6 : PG_FUNCTION_INFO_V1(ltree_consistent);
89 6 : PG_FUNCTION_INFO_V1(ltree_gist_options);
90 :
91 : #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key))
92 :
93 : Datum
94 4206 : ltree_compress(PG_FUNCTION_ARGS)
95 : {
96 4206 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
97 4206 : GISTENTRY *retval = entry;
98 :
99 4206 : if (entry->leafkey)
100 : { /* ltree */
101 4024 : ltree *val = DatumGetLtreeP(entry->key);
102 4024 : ltree_gist *key = ltree_gist_alloc(false, NULL, 0, val, 0);
103 :
104 4024 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
105 4024 : gistentryinit(*retval, PointerGetDatum(key),
106 : entry->rel, entry->page,
107 : entry->offset, false);
108 : }
109 4206 : PG_RETURN_POINTER(retval);
110 : }
111 :
112 : Datum
113 197578 : ltree_decompress(PG_FUNCTION_ARGS)
114 : {
115 197578 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
116 197578 : ltree_gist *key = (ltree_gist *) PG_DETOAST_DATUM(entry->key);
117 :
118 197578 : if (PointerGetDatum(key) != entry->key)
119 : {
120 0 : GISTENTRY *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
121 :
122 0 : gistentryinit(*retval, PointerGetDatum(key),
123 : entry->rel, entry->page,
124 : entry->offset, false);
125 0 : PG_RETURN_POINTER(retval);
126 : }
127 197578 : PG_RETURN_POINTER(entry);
128 : }
129 :
130 : Datum
131 6398 : ltree_same(PG_FUNCTION_ARGS)
132 : {
133 6398 : ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0);
134 6398 : ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1);
135 6398 : bool *result = (bool *) PG_GETARG_POINTER(2);
136 6398 : int siglen = LTREE_GET_SIGLEN();
137 :
138 6398 : *result = false;
139 6398 : if (LTG_ISONENODE(a) != LTG_ISONENODE(b))
140 0 : PG_RETURN_POINTER(result);
141 :
142 6398 : if (LTG_ISONENODE(a))
143 0 : *result = ISEQ(LTG_NODE(a), LTG_NODE(b));
144 : else
145 : {
146 : int32 i;
147 6398 : BITVECP sa = LTG_SIGN(a),
148 6398 : sb = LTG_SIGN(b);
149 :
150 6398 : if (LTG_ISALLTRUE(a) != LTG_ISALLTRUE(b))
151 0 : PG_RETURN_POINTER(result);
152 :
153 6398 : if (!ISEQ(LTG_LNODE(a, siglen), LTG_LNODE(b, siglen)))
154 18 : PG_RETURN_POINTER(result);
155 6380 : if (!ISEQ(LTG_RNODE(a, siglen), LTG_RNODE(b, siglen)))
156 28 : PG_RETURN_POINTER(result);
157 :
158 6352 : *result = true;
159 6352 : if (!LTG_ISALLTRUE(a))
160 : {
161 9213464 : LOOPBYTE(siglen)
162 : {
163 9207116 : if (sa[i] != sb[i])
164 : {
165 4 : *result = false;
166 4 : break;
167 : }
168 : }
169 : }
170 : }
171 :
172 6352 : PG_RETURN_POINTER(result);
173 : }
174 :
175 : static void
176 11350 : hashing(BITVECP sign, ltree *t, int siglen)
177 : {
178 11350 : int tlen = t->numlevel;
179 11350 : ltree_level *cur = LTREE_FIRST(t);
180 : int hash;
181 :
182 85940 : while (tlen > 0)
183 : {
184 74590 : hash = ltree_crc32_sz(cur->name, cur->len);
185 74590 : HASH(sign, hash, siglen);
186 74590 : cur = LEVEL_NEXT(cur);
187 74590 : tlen--;
188 : }
189 11350 : }
190 :
191 : Datum
192 6398 : ltree_union(PG_FUNCTION_ARGS)
193 : {
194 6398 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
195 6398 : int *size = (int *) PG_GETARG_POINTER(1);
196 6398 : int siglen = LTREE_GET_SIGLEN();
197 6398 : BITVECP base = palloc0(siglen);
198 : int32 i,
199 : j;
200 : ltree_gist *result,
201 : *cur;
202 6398 : ltree *left = NULL,
203 6398 : *right = NULL,
204 : *curtree;
205 6398 : bool isalltrue = false;
206 :
207 19194 : for (j = 0; j < entryvec->n; j++)
208 : {
209 12796 : cur = GETENTRY(entryvec, j);
210 12796 : if (LTG_ISONENODE(cur))
211 : {
212 6398 : curtree = LTG_NODE(cur);
213 6398 : hashing(base, curtree, siglen);
214 6398 : if (!left || ltree_compare(left, curtree) > 0)
215 18 : left = curtree;
216 6398 : if (!right || ltree_compare(right, curtree) < 0)
217 28 : right = curtree;
218 : }
219 : else
220 : {
221 6398 : if (isalltrue || LTG_ISALLTRUE(cur))
222 0 : isalltrue = true;
223 : else
224 : {
225 6398 : BITVECP sc = LTG_SIGN(cur);
226 :
227 9282798 : LOOPBYTE(siglen)
228 9276400 : ((unsigned char *) base)[i] |= sc[i];
229 : }
230 :
231 6398 : curtree = LTG_LNODE(cur, siglen);
232 6398 : if (!left || ltree_compare(left, curtree) > 0)
233 6398 : left = curtree;
234 6398 : curtree = LTG_RNODE(cur, siglen);
235 6398 : if (!right || ltree_compare(right, curtree) < 0)
236 6398 : right = curtree;
237 : }
238 : }
239 :
240 6398 : if (isalltrue == false)
241 : {
242 6398 : isalltrue = true;
243 6398 : LOOPBYTE(siglen)
244 : {
245 6398 : if (((unsigned char *) base)[i] != 0xff)
246 : {
247 6398 : isalltrue = false;
248 6398 : break;
249 : }
250 : }
251 : }
252 :
253 6398 : result = ltree_gist_alloc(isalltrue, base, siglen, left, right);
254 :
255 6398 : *size = VARSIZE(result);
256 :
257 6398 : PG_RETURN_POINTER(result);
258 : }
259 :
260 : Datum
261 19302 : ltree_penalty(PG_FUNCTION_ARGS)
262 : {
263 19302 : ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
264 19302 : ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
265 19302 : float *penalty = (float *) PG_GETARG_POINTER(2);
266 19302 : int siglen = LTREE_GET_SIGLEN();
267 : int32 cmpr,
268 : cmpl;
269 :
270 19302 : cmpl = ltree_compare(LTG_GETLNODE(origval, siglen), LTG_GETLNODE(newval, siglen));
271 19302 : cmpr = ltree_compare(LTG_GETRNODE(newval, siglen), LTG_GETRNODE(origval, siglen));
272 :
273 19302 : *penalty = Max(cmpl, 0) + Max(cmpr, 0);
274 :
275 19302 : PG_RETURN_POINTER(penalty);
276 : }
277 :
278 : /* used for sorting */
279 : typedef struct rix
280 : {
281 : int index;
282 : ltree *r;
283 : } RIX;
284 :
285 : static int
286 35092 : treekey_cmp(const void *a, const void *b)
287 : {
288 70184 : return ltree_compare(((const RIX *) a)->r,
289 35092 : ((const RIX *) b)->r);
290 : }
291 :
292 :
293 : Datum
294 66 : ltree_picksplit(PG_FUNCTION_ARGS)
295 : {
296 66 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
297 66 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
298 66 : int siglen = LTREE_GET_SIGLEN();
299 : OffsetNumber j;
300 : int32 i;
301 : RIX *array;
302 : OffsetNumber maxoff;
303 : int nbytes;
304 : ltree *lu_l,
305 : *lu_r,
306 : *ru_l,
307 : *ru_r;
308 : ltree_gist *lu,
309 : *ru;
310 66 : BITVECP ls = palloc0(siglen),
311 66 : rs = palloc0(siglen);
312 66 : bool lisat = false,
313 66 : risat = false;
314 :
315 66 : maxoff = entryvec->n - 1;
316 66 : nbytes = (maxoff + 2) * sizeof(OffsetNumber);
317 66 : v->spl_left = (OffsetNumber *) palloc(nbytes);
318 66 : v->spl_right = (OffsetNumber *) palloc(nbytes);
319 66 : v->spl_nleft = 0;
320 66 : v->spl_nright = 0;
321 66 : array = (RIX *) palloc(sizeof(RIX) * (maxoff + 1));
322 :
323 : /* copy the data into RIXes, and sort the RIXes */
324 5066 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
325 : {
326 5000 : array[j].index = j;
327 5000 : lu = GETENTRY(entryvec, j); /* use as tmp val */
328 5000 : array[j].r = LTG_GETLNODE(lu, siglen);
329 : }
330 :
331 66 : qsort(&array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1,
332 : sizeof(RIX), treekey_cmp);
333 :
334 66 : lu_l = lu_r = ru_l = ru_r = NULL;
335 5066 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
336 : {
337 5000 : lu = GETENTRY(entryvec, array[j].index); /* use as tmp val */
338 5000 : if (j <= (maxoff - FirstOffsetNumber + 1) / 2)
339 : {
340 2490 : v->spl_left[v->spl_nleft] = array[j].index;
341 2490 : v->spl_nleft++;
342 2490 : if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), lu_r) > 0)
343 2488 : lu_r = LTG_GETRNODE(lu, siglen);
344 2490 : if (LTG_ISONENODE(lu))
345 2466 : hashing(ls, LTG_NODE(lu), siglen);
346 : else
347 : {
348 24 : if (lisat || LTG_ISALLTRUE(lu))
349 0 : lisat = true;
350 : else
351 : {
352 24 : BITVECP sc = LTG_SIGN(lu);
353 :
354 48600 : LOOPBYTE(siglen)
355 48576 : ((unsigned char *) ls)[i] |= sc[i];
356 : }
357 : }
358 : }
359 : else
360 : {
361 2510 : v->spl_right[v->spl_nright] = array[j].index;
362 2510 : v->spl_nright++;
363 2510 : if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), ru_r) > 0)
364 2508 : ru_r = LTG_GETRNODE(lu, siglen);
365 2510 : if (LTG_ISONENODE(lu))
366 2486 : hashing(rs, LTG_NODE(lu), siglen);
367 : else
368 : {
369 24 : if (risat || LTG_ISALLTRUE(lu))
370 0 : risat = true;
371 : else
372 : {
373 24 : BITVECP sc = LTG_SIGN(lu);
374 :
375 48600 : LOOPBYTE(siglen)
376 48576 : ((unsigned char *) rs)[i] |= sc[i];
377 : }
378 : }
379 : }
380 : }
381 :
382 66 : if (lisat == false)
383 : {
384 66 : lisat = true;
385 66 : LOOPBYTE(siglen)
386 : {
387 66 : if (((unsigned char *) ls)[i] != 0xff)
388 : {
389 66 : lisat = false;
390 66 : break;
391 : }
392 : }
393 : }
394 :
395 66 : if (risat == false)
396 : {
397 66 : risat = true;
398 66 : LOOPBYTE(siglen)
399 : {
400 66 : if (((unsigned char *) rs)[i] != 0xff)
401 : {
402 66 : risat = false;
403 66 : break;
404 : }
405 : }
406 : }
407 :
408 66 : lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index), siglen);
409 66 : lu = ltree_gist_alloc(lisat, ls, siglen, lu_l, lu_r);
410 :
411 66 : ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index), siglen);
412 66 : ru = ltree_gist_alloc(risat, rs, siglen, ru_l, ru_r);
413 :
414 66 : pfree(ls);
415 66 : pfree(rs);
416 :
417 66 : v->spl_ldatum = PointerGetDatum(lu);
418 66 : v->spl_rdatum = PointerGetDatum(ru);
419 :
420 66 : PG_RETURN_POINTER(v);
421 : }
422 :
423 : static bool
424 44 : gist_isparent(ltree_gist *key, ltree *query, int siglen)
425 : {
426 44 : int32 numlevel = query->numlevel;
427 : int i;
428 :
429 188 : for (i = query->numlevel; i >= 0; i--)
430 : {
431 152 : query->numlevel = i;
432 160 : if (ltree_compare(query, LTG_GETLNODE(key, siglen)) >= 0 &&
433 8 : ltree_compare(query, LTG_GETRNODE(key, siglen)) <= 0)
434 : {
435 8 : query->numlevel = numlevel;
436 8 : return true;
437 : }
438 : }
439 :
440 36 : query->numlevel = numlevel;
441 36 : return false;
442 : }
443 :
444 : static ltree *
445 88 : copy_ltree(ltree *src)
446 : {
447 88 : ltree *dst = (ltree *) palloc0(VARSIZE(src));
448 :
449 88 : memcpy(dst, src, VARSIZE(src));
450 88 : return dst;
451 : }
452 :
453 : static bool
454 44 : gist_ischild(ltree_gist *key, ltree *query, int siglen)
455 : {
456 44 : ltree *left = copy_ltree(LTG_GETLNODE(key, siglen));
457 44 : ltree *right = copy_ltree(LTG_GETRNODE(key, siglen));
458 44 : bool res = true;
459 :
460 44 : if (left->numlevel > query->numlevel)
461 32 : left->numlevel = query->numlevel;
462 :
463 44 : if (ltree_compare(query, left) < 0)
464 36 : res = false;
465 :
466 44 : if (right->numlevel > query->numlevel)
467 38 : right->numlevel = query->numlevel;
468 :
469 44 : if (res && ltree_compare(query, right) > 0)
470 0 : res = false;
471 :
472 44 : pfree(left);
473 44 : pfree(right);
474 :
475 44 : return res;
476 : }
477 :
478 : static bool
479 392 : gist_qe(ltree_gist *key, lquery *query, int siglen)
480 : {
481 392 : lquery_level *curq = LQUERY_FIRST(query);
482 392 : BITVECP sign = LTG_SIGN(key);
483 392 : int qlen = query->numlevel;
484 :
485 392 : if (LTG_ISALLTRUE(key))
486 0 : return true;
487 :
488 1538 : while (qlen > 0)
489 : {
490 1146 : if (curq->numvar && LQL_CANLOOKSIGN(curq))
491 : {
492 754 : bool isexist = false;
493 754 : int vlen = curq->numvar;
494 754 : lquery_variant *curv = LQL_FIRST(curq);
495 :
496 754 : while (vlen > 0)
497 : {
498 754 : if (GETBIT(sign, HASHVAL(curv->val, siglen)))
499 : {
500 754 : isexist = true;
501 754 : break;
502 : }
503 0 : curv = LVAR_NEXT(curv);
504 0 : vlen--;
505 : }
506 754 : if (!isexist)
507 0 : return false;
508 : }
509 :
510 1146 : curq = LQL_NEXT(curq);
511 1146 : qlen--;
512 : }
513 :
514 392 : return true;
515 : }
516 :
517 : static int
518 520 : gist_tqcmp(ltree *t, lquery *q)
519 : {
520 520 : ltree_level *al = LTREE_FIRST(t);
521 520 : lquery_level *ql = LQUERY_FIRST(q);
522 : lquery_variant *bl;
523 520 : int an = t->numlevel;
524 520 : int bn = q->firstgood;
525 520 : int res = 0;
526 :
527 616 : while (an > 0 && bn > 0)
528 : {
529 484 : bl = LQL_FIRST(ql);
530 484 : if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
531 : {
532 164 : if (al->len != bl->len)
533 68 : return al->len - bl->len;
534 : }
535 : else
536 320 : return res;
537 96 : an--;
538 96 : bn--;
539 96 : al = LEVEL_NEXT(al);
540 96 : ql = LQL_NEXT(ql);
541 : }
542 :
543 132 : return Min(t->numlevel, q->firstgood) - q->firstgood;
544 : }
545 :
546 : static bool
547 392 : gist_between(ltree_gist *key, lquery *query, int siglen)
548 : {
549 392 : if (query->firstgood == 0)
550 74 : return true;
551 :
552 318 : if (gist_tqcmp(LTG_GETLNODE(key, siglen), query) > 0)
553 116 : return false;
554 :
555 202 : if (gist_tqcmp(LTG_GETRNODE(key, siglen), query) < 0)
556 90 : return false;
557 :
558 112 : return true;
559 : }
560 :
561 : typedef struct LtreeSignature
562 : {
563 : BITVECP sign;
564 : int siglen;
565 : } LtreeSignature;
566 :
567 : static bool
568 148 : checkcondition_bit(void *cxt, ITEM *val)
569 : {
570 148 : LtreeSignature *sig = cxt;
571 :
572 148 : return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, HASHVAL(val->val, sig->siglen)) : true;
573 : }
574 :
575 : static bool
576 74 : gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen)
577 : {
578 : LtreeSignature sig;
579 :
580 74 : if (LTG_ISALLTRUE(key))
581 0 : return true;
582 :
583 74 : sig.sign = LTG_SIGN(key);
584 74 : sig.siglen = siglen;
585 :
586 74 : return ltree_execute(GETQUERY(query),
587 : &sig, false,
588 : checkcondition_bit);
589 : }
590 :
591 : static bool
592 60 : arrq_cons(ltree_gist *key, ArrayType *_query, int siglen)
593 : {
594 60 : lquery *query = (lquery *) ARR_DATA_PTR(_query);
595 60 : int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
596 :
597 60 : if (ARR_NDIM(_query) > 1)
598 0 : ereport(ERROR,
599 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
600 : errmsg("array must be one-dimensional")));
601 60 : if (array_contains_nulls(_query))
602 0 : ereport(ERROR,
603 : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
604 : errmsg("array must not contain nulls")));
605 :
606 128 : while (num > 0)
607 : {
608 94 : if (gist_qe(key, query, siglen) && gist_between(key, query, siglen))
609 26 : return true;
610 68 : num--;
611 68 : query = NEXTVAL(query);
612 : }
613 34 : return false;
614 : }
615 :
616 : Datum
617 19688 : ltree_consistent(PG_FUNCTION_ARGS)
618 : {
619 19688 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
620 19688 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
621 :
622 : /* Oid subtype = PG_GETARG_OID(3); */
623 19688 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
624 19688 : int siglen = LTREE_GET_SIGLEN();
625 19688 : ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
626 19688 : void *query = NULL;
627 19688 : bool res = false;
628 :
629 : /* All cases served by this function are exact */
630 19688 : *recheck = false;
631 :
632 19688 : switch (strategy)
633 : {
634 616 : case BTLessStrategyNumber:
635 616 : query = PG_GETARG_LTREE_P(1);
636 616 : res = (GIST_LEAF(entry)) ?
637 588 : (ltree_compare((ltree *) query, LTG_NODE(key)) > 0)
638 1232 : :
639 28 : (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
640 616 : break;
641 616 : case BTLessEqualStrategyNumber:
642 616 : query = PG_GETARG_LTREE_P(1);
643 616 : res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
644 616 : break;
645 578 : case BTEqualStrategyNumber:
646 578 : query = PG_GETARG_LTREE_P(1);
647 578 : if (GIST_LEAF(entry))
648 534 : res = (ltree_compare((ltree *) query, LTG_NODE(key)) == 0);
649 : else
650 88 : res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0
651 60 : &&
652 16 : ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
653 578 : break;
654 1876 : case BTGreaterEqualStrategyNumber:
655 1876 : query = PG_GETARG_LTREE_P(1);
656 1876 : res = (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
657 1876 : break;
658 1876 : case BTGreaterStrategyNumber:
659 1876 : query = PG_GETARG_LTREE_P(1);
660 1876 : res = (GIST_LEAF(entry)) ?
661 1848 : (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) < 0)
662 3752 : :
663 28 : (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
664 1876 : break;
665 374 : case 10:
666 374 : query = PG_GETARG_LTREE_P_COPY(1);
667 374 : res = (GIST_LEAF(entry)) ?
668 330 : inner_isparent((ltree *) query, LTG_NODE(key))
669 704 : :
670 44 : gist_isparent(key, (ltree *) query, siglen);
671 374 : break;
672 374 : case 11:
673 374 : query = PG_GETARG_LTREE_P(1);
674 374 : res = (GIST_LEAF(entry)) ?
675 330 : inner_isparent(LTG_NODE(key), (ltree *) query)
676 704 : :
677 44 : gist_ischild(key, (ltree *) query, siglen);
678 374 : break;
679 8078 : case 12:
680 : case 13:
681 8078 : query = PG_GETARG_LQUERY_P(1);
682 8078 : if (GIST_LEAF(entry))
683 7780 : res = DatumGetBool(DirectFunctionCall2(ltq_regex,
684 : PointerGetDatum(LTG_NODE(key)),
685 : PointerGetDatum((lquery *) query)
686 : ));
687 : else
688 596 : res = (gist_qe(key, (lquery *) query, siglen) &&
689 298 : gist_between(key, (lquery *) query, siglen));
690 8078 : break;
691 4098 : case 14:
692 : case 15:
693 4098 : query = PG_GETARG_LTXTQUERY_P(1);
694 4098 : if (GIST_LEAF(entry))
695 4024 : res = DatumGetBool(DirectFunctionCall2(ltxtq_exec,
696 : PointerGetDatum(LTG_NODE(key)),
697 : PointerGetDatum((ltxtquery *) query)
698 : ));
699 : else
700 74 : res = gist_qtxt(key, (ltxtquery *) query, siglen);
701 4098 : break;
702 1202 : case 16:
703 : case 17:
704 1202 : query = PG_GETARG_ARRAYTYPE_P(1);
705 1202 : if (GIST_LEAF(entry))
706 1142 : res = DatumGetBool(DirectFunctionCall2(lt_q_regex,
707 : PointerGetDatum(LTG_NODE(key)),
708 : PointerGetDatum((ArrayType *) query)
709 : ));
710 : else
711 60 : res = arrq_cons(key, (ArrayType *) query, siglen);
712 1202 : break;
713 0 : default:
714 : /* internal error */
715 0 : elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
716 : }
717 :
718 19688 : PG_FREE_IF_COPY(query, 1);
719 19688 : PG_RETURN_BOOL(res);
720 : }
721 :
722 : static void
723 6 : ltree_gist_relopts_validator(void *parsed_options, relopt_value *vals,
724 : int nvals)
725 : {
726 6 : LtreeGistOptions *options = (LtreeGistOptions *) parsed_options;
727 :
728 6 : if (options->siglen != INTALIGN(options->siglen))
729 2 : ereport(ERROR,
730 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
731 : errmsg("siglen value must be a multiple of %d", ALIGNOF_INT)));
732 4 : }
733 :
734 : Datum
735 28 : ltree_gist_options(PG_FUNCTION_ARGS)
736 : {
737 28 : local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
738 :
739 28 : init_local_reloptions(relopts, sizeof(LtreeGistOptions));
740 28 : add_local_int_reloption(relopts, "siglen",
741 : "signature length in bytes",
742 : LTREE_SIGLEN_DEFAULT,
743 : INTALIGN(1),
744 : LTREE_SIGLEN_MAX,
745 : offsetof(LtreeGistOptions, siglen));
746 28 : register_reloptions_validator(relopts, ltree_gist_relopts_validator);
747 :
748 28 : PG_RETURN_VOID();
749 : }
|