Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * contrib/ltree/_ltree_gist.c
3 : : *
4 : : *
5 : : * GiST support for ltree[]
6 : : * Teodor Sigaev <teodor@stack.net>
7 : : */
8 : : #include "postgres.h"
9 : :
10 : : #include <math.h>
11 : :
12 : : #include "access/gist.h"
13 : : #include "access/reloptions.h"
14 : : #include "access/stratnum.h"
15 : : #include "crc32.h"
16 : : #include "ltree.h"
17 : : #include "port/pg_bitutils.h"
18 : : #include "utils/array.h"
19 : :
8403 bruce@momjian.us 20 :CBC 3 : PG_FUNCTION_INFO_V1(_ltree_compress);
21 : 3 : PG_FUNCTION_INFO_V1(_ltree_same);
22 : 3 : PG_FUNCTION_INFO_V1(_ltree_union);
23 : 3 : PG_FUNCTION_INFO_V1(_ltree_penalty);
24 : 3 : PG_FUNCTION_INFO_V1(_ltree_picksplit);
25 : 3 : PG_FUNCTION_INFO_V1(_ltree_consistent);
1986 akorotkov@postgresql 26 : 3 : PG_FUNCTION_INFO_V1(_ltree_gist_options);
27 : :
28 : : #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key))
29 : : #define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
30 : :
31 : : #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
32 : :
33 : :
34 : : static void
35 : 7058 : hashing(BITVECP sign, ltree *t, int siglen)
36 : : {
8403 bruce@momjian.us 37 : 7058 : int tlen = t->numlevel;
8439 38 : 7058 : ltree_level *cur = LTREE_FIRST(t);
39 : : int hash;
40 : :
8403 41 [ + + ]: 53466 : while (tlen > 0)
42 : : {
43 : 46408 : hash = ltree_crc32_sz(cur->name, cur->len);
1986 akorotkov@postgresql 44 : 46408 : AHASH(sign, hash, siglen);
8439 bruce@momjian.us 45 : 46408 : cur = LEVEL_NEXT(cur);
46 : 46408 : tlen--;
47 : : }
48 : 7058 : }
49 : :
50 : : Datum
8403 51 : 5873 : _ltree_compress(PG_FUNCTION_ARGS)
52 : : {
53 : 5873 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
8439 54 : 5873 : GISTENTRY *retval = entry;
1986 akorotkov@postgresql 55 [ + - ]: 5873 : int siglen = LTREE_GET_ASIGLEN();
56 : :
8403 bruce@momjian.us 57 [ + + ]: 5873 : if (entry->leafkey)
58 : : { /* ltree */
59 : : ltree_gist *key;
60 : 2000 : ArrayType *val = DatumGetArrayTypeP(entry->key);
61 : 2000 : int num = ArrayGetNItems(ARR_NDIM(val), ARR_DIMS(val));
62 [ - + ]: 2000 : ltree *item = (ltree *) ARR_DATA_PTR(val);
63 : :
5673 tgl@sss.pgh.pa.us 64 [ - + ]: 2000 : if (ARR_NDIM(val) > 1)
8080 tgl@sss.pgh.pa.us 65 [ # # ]:UBC 0 : ereport(ERROR,
66 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
67 : : errmsg("array must be one-dimensional")));
5354 tgl@sss.pgh.pa.us 68 [ - + ]:CBC 2000 : if (array_contains_nulls(val))
7231 tgl@sss.pgh.pa.us 69 [ # # ]:UBC 0 : ereport(ERROR,
70 : : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
71 : : errmsg("array must not contain nulls")));
72 : :
1986 akorotkov@postgresql 73 :CBC 2000 : key = ltree_gist_alloc(false, NULL, siglen, NULL, NULL);
74 : :
8403 bruce@momjian.us 75 [ + + ]: 9058 : while (num > 0)
76 : : {
1986 akorotkov@postgresql 77 : 7058 : hashing(LTG_SIGN(key), item, siglen);
8439 bruce@momjian.us 78 : 7058 : num--;
79 : 7058 : item = NEXTVAL(item);
80 : : }
81 : :
8403 82 : 2000 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
8439 83 : 2000 : gistentryinit(*retval, PointerGetDatum(key),
84 : : entry->rel, entry->page,
85 : : entry->offset, false);
86 : : }
29 tgl@sss.pgh.pa.us 87 [ + - ]:GNC 3873 : else if (!LTG_ISALLTRUE(DatumGetPointer(entry->key)))
88 : : {
89 : : int32 i;
90 : : ltree_gist *key;
8403 bruce@momjian.us 91 :CBC 3873 : BITVECP sign = LTG_SIGN(DatumGetPointer(entry->key));
92 : :
1986 akorotkov@postgresql 93 [ + - ]: 3873 : ALOOPBYTE(siglen)
94 : : {
6504 bruce@momjian.us 95 [ + - ]: 3873 : if ((sign[i] & 0xff) != 0xff)
96 : 3873 : PG_RETURN_POINTER(retval);
97 : : }
98 : :
1986 akorotkov@postgresql 99 :UBC 0 : key = ltree_gist_alloc(true, sign, siglen, NULL, NULL);
8403 bruce@momjian.us 100 : 0 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
8439 101 : 0 : gistentryinit(*retval, PointerGetDatum(key),
102 : : entry->rel, entry->page,
103 : : entry->offset, false);
104 : : }
8439 bruce@momjian.us 105 :CBC 2000 : PG_RETURN_POINTER(retval);
106 : : }
107 : :
108 : : Datum
8403 109 : 7887 : _ltree_same(PG_FUNCTION_ARGS)
110 : : {
111 : 7887 : ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0);
112 : 7887 : ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1);
113 : 7887 : bool *result = (bool *) PG_GETARG_POINTER(2);
1986 akorotkov@postgresql 114 [ + - ]: 7887 : int siglen = LTREE_GET_ASIGLEN();
115 : :
8403 bruce@momjian.us 116 [ - + - - ]: 7887 : if (LTG_ISALLTRUE(a) && LTG_ISALLTRUE(b))
8439 bruce@momjian.us 117 :UBC 0 : *result = true;
8403 bruce@momjian.us 118 [ - + ]:CBC 7887 : else if (LTG_ISALLTRUE(a))
8439 bruce@momjian.us 119 :UBC 0 : *result = false;
8403 bruce@momjian.us 120 [ - + ]:CBC 7887 : else if (LTG_ISALLTRUE(b))
8439 bruce@momjian.us 121 :UBC 0 : *result = false;
122 : : else
123 : : {
124 : : int32 i;
8403 bruce@momjian.us 125 :CBC 7887 : BITVECP sa = LTG_SIGN(a),
126 : 7887 : sb = LTG_SIGN(b);
127 : :
8439 128 : 7887 : *result = true;
1986 akorotkov@postgresql 129 [ + + ]: 11315959 : ALOOPBYTE(siglen)
130 : : {
6504 bruce@momjian.us 131 [ + + ]: 11310147 : if (sa[i] != sb[i])
132 : : {
133 : 2075 : *result = false;
134 : 2075 : break;
135 : : }
136 : : }
137 : : }
8403 138 : 7887 : PG_RETURN_POINTER(result);
139 : : }
140 : :
141 : : static int32
1986 akorotkov@postgresql 142 : 15774 : unionkey(BITVECP sbase, ltree_gist *add, int siglen)
143 : : {
144 : : int32 i;
8403 bruce@momjian.us 145 : 15774 : BITVECP sadd = LTG_SIGN(add);
146 : :
147 [ - + ]: 15774 : if (LTG_ISALLTRUE(add))
8439 bruce@momjian.us 148 :UBC 0 : return 1;
149 : :
1986 akorotkov@postgresql 150 [ + + ]:CBC 28513222 : ALOOPBYTE(siglen)
6504 bruce@momjian.us 151 : 28497448 : sbase[i] |= sadd[i];
8439 152 : 15774 : return 0;
153 : : }
154 : :
155 : : Datum
8403 156 : 7887 : _ltree_union(PG_FUNCTION_ARGS)
157 : : {
7678 158 : 7887 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
8403 159 : 7887 : int *size = (int *) PG_GETARG_POINTER(1);
1986 akorotkov@postgresql 160 [ + - ]: 7887 : int siglen = LTREE_GET_ASIGLEN();
161 : : int32 i;
162 : 7887 : ltree_gist *result = ltree_gist_alloc(false, NULL, siglen, NULL, NULL);
163 : 7887 : BITVECP base = LTG_SIGN(result);
164 : :
7830 teodor@sigaev.ru 165 [ + + ]: 23661 : for (i = 0; i < entryvec->n; i++)
166 : : {
1986 akorotkov@postgresql 167 [ - + ]: 15774 : if (unionkey(base, GETENTRY(entryvec, i), siglen))
168 : : {
1986 akorotkov@postgresql 169 :UBC 0 : result->flag |= LTG_ALLTRUE;
170 : 0 : SET_VARSIZE(result, LTG_HDRSIZE);
8439 bruce@momjian.us 171 : 0 : break;
172 : : }
173 : : }
174 : :
1986 akorotkov@postgresql 175 :CBC 7887 : *size = VARSIZE(result);
176 : :
8403 bruce@momjian.us 177 : 7887 : PG_RETURN_POINTER(result);
178 : : }
179 : :
180 : : static int32
1986 akorotkov@postgresql 181 :UBC 0 : sizebitvec(BITVECP sign, int siglen)
182 : : {
183 : 0 : return pg_popcount((const char *) sign, siglen);
184 : : }
185 : :
186 : : static int
1986 akorotkov@postgresql 187 :CBC 125258 : hemdistsign(BITVECP a, BITVECP b, int siglen)
188 : : {
189 : : int i,
190 : : diff,
7678 bruce@momjian.us 191 : 125258 : dist = 0;
192 : :
1986 akorotkov@postgresql 193 [ + + ]: 59199126 : ALOOPBYTE(siglen)
194 : : {
6504 bruce@momjian.us 195 : 59073868 : diff = (unsigned char) (a[i] ^ b[i]);
196 : : /* Using the popcount functions here isn't likely to win */
2395 tgl@sss.pgh.pa.us 197 : 59073868 : dist += pg_number_of_ones[diff];
198 : : }
8123 bruce@momjian.us 199 : 125258 : return dist;
200 : : }
201 : :
202 : : static int
1986 akorotkov@postgresql 203 : 125258 : hemdist(ltree_gist *a, ltree_gist *b, int siglen)
204 : : {
7678 bruce@momjian.us 205 [ - + ]: 125258 : if (LTG_ISALLTRUE(a))
206 : : {
7678 bruce@momjian.us 207 [ # # ]:UBC 0 : if (LTG_ISALLTRUE(b))
208 : 0 : return 0;
209 : : else
1986 akorotkov@postgresql 210 : 0 : return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(b), siglen);
211 : : }
7678 bruce@momjian.us 212 [ - + ]:CBC 125258 : else if (LTG_ISALLTRUE(b))
1986 akorotkov@postgresql 213 :UBC 0 : return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(a), siglen);
214 : :
1986 akorotkov@postgresql 215 :CBC 125258 : return hemdistsign(LTG_SIGN(a), LTG_SIGN(b), siglen);
216 : : }
217 : :
218 : :
219 : : Datum
8403 bruce@momjian.us 220 : 19298 : _ltree_penalty(PG_FUNCTION_ARGS)
221 : : {
222 : 19298 : ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
223 : 19298 : ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
224 : 19298 : float *penalty = (float *) PG_GETARG_POINTER(2);
1986 akorotkov@postgresql 225 [ + - ]: 19298 : int siglen = LTREE_GET_ASIGLEN();
226 : :
227 : 19298 : *penalty = hemdist(origval, newval, siglen);
8403 bruce@momjian.us 228 : 19298 : PG_RETURN_POINTER(penalty);
229 : : }
230 : :
231 : : typedef struct
232 : : {
233 : : OffsetNumber pos;
234 : : int32 cost;
235 : : } SPLITCOST;
236 : :
237 : : static int
238 : 8033 : comparecost(const void *a, const void *b)
239 : : {
5109 peter_e@gmx.net 240 : 8033 : return ((const SPLITCOST *) a)->cost - ((const SPLITCOST *) b)->cost;
241 : : }
242 : :
243 : : Datum
8403 bruce@momjian.us 244 : 899 : _ltree_picksplit(PG_FUNCTION_ARGS)
245 : : {
7678 246 : 899 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
8403 247 : 899 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1986 akorotkov@postgresql 248 [ + - ]: 899 : int siglen = LTREE_GET_ASIGLEN();
249 : : OffsetNumber k,
250 : : j;
251 : : ltree_gist *datum_l,
252 : : *datum_r;
253 : : BITVECP union_l,
254 : : union_r;
255 : : int32 size_alpha,
256 : : size_beta;
257 : : int32 size_waste,
8123 bruce@momjian.us 258 : 899 : waste = -1;
259 : : int32 nbytes;
8403 260 : 899 : OffsetNumber seed_1 = 0,
261 : 899 : seed_2 = 0;
262 : : OffsetNumber *left,
263 : : *right;
264 : : OffsetNumber maxoff;
265 : : BITVECP ptr;
266 : : int i;
267 : : SPLITCOST *costvector;
268 : : ltree_gist *_k,
269 : : *_j;
270 : :
7830 teodor@sigaev.ru 271 : 899 : maxoff = entryvec->n - 2;
8439 bruce@momjian.us 272 : 899 : nbytes = (maxoff + 2) * sizeof(OffsetNumber);
273 : 899 : v->spl_left = (OffsetNumber *) palloc(nbytes);
274 : 899 : v->spl_right = (OffsetNumber *) palloc(nbytes);
275 : :
7678 276 [ + + ]: 3930 : for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
277 : : {
8403 278 : 3031 : _k = GETENTRY(entryvec, k);
7678 279 [ + + ]: 93271 : for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
280 : : {
1986 akorotkov@postgresql 281 : 90240 : size_waste = hemdist(_k, GETENTRY(entryvec, j), siglen);
7678 bruce@momjian.us 282 [ + + ]: 90240 : if (size_waste > waste)
283 : : {
8439 284 : 1649 : waste = size_waste;
285 : 1649 : seed_1 = k;
286 : 1649 : seed_2 = j;
287 : : }
288 : : }
289 : : }
290 : :
291 : 899 : left = v->spl_left;
292 : 899 : v->spl_nleft = 0;
293 : 899 : right = v->spl_right;
294 : 899 : v->spl_nright = 0;
295 : :
8403 296 [ + - - + ]: 899 : if (seed_1 == 0 || seed_2 == 0)
297 : : {
8439 bruce@momjian.us 298 :UBC 0 : seed_1 = 1;
299 : 0 : seed_2 = 2;
300 : : }
301 : :
302 : : /* form initial .. */
1986 akorotkov@postgresql 303 :CBC 899 : datum_l = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_1)),
304 : 899 : LTG_SIGN(GETENTRY(entryvec, seed_1)),
305 : : siglen, NULL, NULL);
306 : :
307 : 899 : datum_r = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_2)),
308 : 899 : LTG_SIGN(GETENTRY(entryvec, seed_2)),
309 : : siglen, NULL, NULL);
310 : :
8439 bruce@momjian.us 311 : 899 : maxoff = OffsetNumberNext(maxoff);
312 : : /* sort before ... */
8403 313 : 899 : costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
314 [ + + ]: 5728 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
315 : : {
316 : 4829 : costvector[j - 1].pos = j;
317 : 4829 : _j = GETENTRY(entryvec, j);
1986 akorotkov@postgresql 318 : 4829 : size_alpha = hemdist(datum_l, _j, siglen);
319 : 4829 : size_beta = hemdist(datum_r, _j, siglen);
1065 peter@eisentraut.org 320 : 4829 : costvector[j - 1].cost = abs(size_alpha - size_beta);
321 : : }
942 322 : 899 : qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
323 : :
7678 bruce@momjian.us 324 : 899 : union_l = LTG_SIGN(datum_l);
325 : 899 : union_r = LTG_SIGN(datum_r);
326 : :
8403 327 [ + + ]: 5728 : for (k = 0; k < maxoff; k++)
328 : : {
8439 329 : 4829 : j = costvector[k].pos;
8403 330 [ + + ]: 4829 : if (j == seed_1)
331 : : {
8439 332 : 899 : *left++ = j;
333 : 899 : v->spl_nleft++;
334 : 899 : continue;
335 : : }
8403 336 [ + + ]: 3930 : else if (j == seed_2)
337 : : {
8439 338 : 899 : *right++ = j;
339 : 899 : v->spl_nright++;
340 : 899 : continue;
341 : : }
8123 342 : 3031 : _j = GETENTRY(entryvec, j);
1986 akorotkov@postgresql 343 : 3031 : size_alpha = hemdist(datum_l, _j, siglen);
344 : 3031 : size_beta = hemdist(datum_r, _j, siglen);
345 : :
7678 bruce@momjian.us 346 [ + + ]: 3031 : if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
347 : : {
348 [ + - - + ]: 1463 : if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j))
349 : : {
8123 bruce@momjian.us 350 [ # # ]:UBC 0 : if (!LTG_ISALLTRUE(datum_l))
942 peter@eisentraut.org 351 : 0 : memset(union_l, 0xff, siglen);
352 : : }
353 : : else
354 : : {
7678 bruce@momjian.us 355 :CBC 1463 : ptr = LTG_SIGN(_j);
1986 akorotkov@postgresql 356 [ + + ]: 1695115 : ALOOPBYTE(siglen)
6504 bruce@momjian.us 357 : 1693652 : union_l[i] |= ptr[i];
358 : : }
8439 359 : 1463 : *left++ = j;
360 : 1463 : v->spl_nleft++;
361 : : }
362 : : else
363 : : {
7678 364 [ + - - + ]: 1568 : if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j))
365 : : {
8123 bruce@momjian.us 366 [ # # ]:UBC 0 : if (!LTG_ISALLTRUE(datum_r))
942 peter@eisentraut.org 367 : 0 : memset(union_r, 0xff, siglen);
368 : : }
369 : : else
370 : : {
7678 bruce@momjian.us 371 :CBC 1568 : ptr = LTG_SIGN(_j);
1986 akorotkov@postgresql 372 [ + + ]: 1945664 : ALOOPBYTE(siglen)
6504 bruce@momjian.us 373 : 1944096 : union_r[i] |= ptr[i];
374 : : }
8439 375 : 1568 : *right++ = j;
376 : 1568 : v->spl_nright++;
377 : : }
378 : : }
379 : :
380 : 899 : *right = *left = FirstOffsetNumber;
381 : :
382 : 899 : v->spl_ldatum = PointerGetDatum(datum_l);
383 : 899 : v->spl_rdatum = PointerGetDatum(datum_r);
384 : :
8403 385 : 899 : PG_RETURN_POINTER(v);
386 : : }
387 : :
388 : : static bool
1986 akorotkov@postgresql 389 : 2555 : gist_te(ltree_gist *key, ltree *query, int siglen)
390 : : {
8403 bruce@momjian.us 391 : 2555 : ltree_level *curq = LTREE_FIRST(query);
392 : 2555 : BITVECP sign = LTG_SIGN(key);
393 : 2555 : int qlen = query->numlevel;
394 : : unsigned int hv;
395 : :
396 [ - + ]: 2555 : if (LTG_ISALLTRUE(key))
8439 bruce@momjian.us 397 :UBC 0 : return true;
398 : :
8403 bruce@momjian.us 399 [ + + ]:CBC 8627 : while (qlen > 0)
400 : : {
401 : 6603 : hv = ltree_crc32_sz(curq->name, curq->len);
1986 akorotkov@postgresql 402 [ + + ]: 6603 : if (!GETBIT(sign, AHASHVAL(hv, siglen)))
8403 bruce@momjian.us 403 : 531 : return false;
8439 404 : 6072 : curq = LEVEL_NEXT(curq);
405 : 6072 : qlen--;
406 : : }
407 : :
408 : 2024 : return true;
409 : : }
410 : :
411 : : typedef struct LtreeSignature
412 : : {
413 : : BITVECP sign;
414 : : int siglen;
415 : : } LtreeSignature;
416 : :
417 : : static bool
1986 akorotkov@postgresql 418 : 3698 : checkcondition_bit(void *cxt, ITEM *val)
419 : : {
420 : 3698 : LtreeSignature *sig = cxt;
421 : :
422 [ + - + + ]: 3698 : return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, AHASHVAL(val->val, sig->siglen)) : true;
423 : : }
424 : :
425 : : static bool
426 : 2151 : gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen)
427 : : {
428 : : LtreeSignature sig;
429 : :
8403 bruce@momjian.us 430 [ - + ]: 2151 : if (LTG_ISALLTRUE(key))
8439 bruce@momjian.us 431 :UBC 0 : return true;
432 : :
1986 akorotkov@postgresql 433 :CBC 2151 : sig.sign = LTG_SIGN(key);
434 : 2151 : sig.siglen = siglen;
435 : :
2046 alvherre@alvh.no-ip. 436 : 2151 : return ltree_execute(GETQUERY(query),
437 : : &sig, false,
438 : : checkcondition_bit);
439 : : }
440 : :
441 : : static bool
1986 akorotkov@postgresql 442 : 14850 : gist_qe(ltree_gist *key, lquery *query, int siglen)
443 : : {
8403 bruce@momjian.us 444 : 14850 : lquery_level *curq = LQUERY_FIRST(query);
445 : 14850 : BITVECP sign = LTG_SIGN(key);
446 : 14850 : int qlen = query->numlevel;
447 : :
448 [ - + ]: 14850 : if (LTG_ISALLTRUE(key))
8439 bruce@momjian.us 449 :UBC 0 : return true;
450 : :
8403 bruce@momjian.us 451 [ + + ]:CBC 46019 : while (qlen > 0)
452 : : {
453 [ + + + - ]: 36767 : if (curq->numvar && LQL_CANLOOKSIGN(curq))
454 : : {
455 : 25543 : bool isexist = false;
456 : 25543 : int vlen = curq->numvar;
8439 457 : 25543 : lquery_variant *curv = LQL_FIRST(curq);
458 : :
8403 459 [ + + ]: 31141 : while (vlen > 0)
460 : : {
1986 akorotkov@postgresql 461 [ + + ]: 25543 : if (GETBIT(sign, AHASHVAL(curv->val, siglen)))
462 : : {
8403 bruce@momjian.us 463 : 19945 : isexist = true;
8439 464 : 19945 : break;
465 : : }
466 : 5598 : curv = LVAR_NEXT(curv);
467 : 5598 : vlen--;
468 : : }
8403 469 [ + + ]: 25543 : if (!isexist)
8439 470 : 5598 : return false;
471 : : }
472 : :
473 : 31169 : curq = LQL_NEXT(curq);
474 : 31169 : qlen--;
475 : : }
476 : :
477 : 9252 : return true;
478 : : }
479 : :
480 : : static bool
1986 akorotkov@postgresql 481 : 2328 : _arrq_cons(ltree_gist *key, ArrayType *_query, int siglen)
482 : : {
7678 bruce@momjian.us 483 [ - + ]: 2328 : lquery *query = (lquery *) ARR_DATA_PTR(_query);
484 : 2328 : int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
485 : :
5673 tgl@sss.pgh.pa.us 486 [ - + ]: 2328 : if (ARR_NDIM(_query) > 1)
7678 bruce@momjian.us 487 [ # # ]:UBC 0 : ereport(ERROR,
488 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
489 : : errmsg("array must be one-dimensional")));
5354 tgl@sss.pgh.pa.us 490 [ - + ]:CBC 2328 : if (array_contains_nulls(_query))
7231 tgl@sss.pgh.pa.us 491 [ # # ]:UBC 0 : ereport(ERROR,
492 : : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
493 : : errmsg("array must not contain nulls")));
494 : :
7678 bruce@momjian.us 495 [ + + ]:CBC 4146 : while (num > 0)
496 : : {
1986 akorotkov@postgresql 497 [ + + ]: 3355 : if (gist_qe(key, query, siglen))
7678 bruce@momjian.us 498 : 1537 : return true;
499 : 1818 : num--;
500 : 1818 : query = (lquery *) NEXTVAL(query);
501 : : }
502 : 791 : return false;
503 : : }
504 : :
505 : : Datum
8403 506 : 18529 : _ltree_consistent(PG_FUNCTION_ARGS)
507 : : {
508 : 18529 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
282 peter@eisentraut.org 509 : 18529 : void *query = PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
8439 bruce@momjian.us 510 : 18529 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
511 : :
512 : : /* Oid subtype = PG_GETARG_OID(3); */
6354 tgl@sss.pgh.pa.us 513 : 18529 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1986 akorotkov@postgresql 514 [ + - ]: 18529 : int siglen = LTREE_GET_ASIGLEN();
6354 tgl@sss.pgh.pa.us 515 : 18529 : ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
8403 bruce@momjian.us 516 : 18529 : bool res = false;
517 : :
518 : : /* All cases served by this function are inexact */
6354 tgl@sss.pgh.pa.us 519 : 18529 : *recheck = true;
520 : :
8403 bruce@momjian.us 521 [ + + + + : 18529 : switch (strategy)
- ]
522 : : {
8439 523 : 2555 : case 10:
524 : : case 11:
1986 akorotkov@postgresql 525 : 2555 : res = gist_te(key, (ltree *) query, siglen);
8439 bruce@momjian.us 526 : 2555 : break;
527 : 11495 : case 12:
528 : : case 13:
1986 akorotkov@postgresql 529 : 11495 : res = gist_qe(key, (lquery *) query, siglen);
8403 bruce@momjian.us 530 : 11495 : break;
8439 531 : 2151 : case 14:
532 : : case 15:
1986 akorotkov@postgresql 533 : 2151 : res = gist_qtxt(key, (ltxtquery *) query, siglen);
8403 bruce@momjian.us 534 : 2151 : break;
8235 535 : 2328 : case 16:
536 : : case 17:
1986 akorotkov@postgresql 537 : 2328 : res = _arrq_cons(key, (ArrayType *) query, siglen);
8235 bruce@momjian.us 538 : 2328 : break;
8439 bruce@momjian.us 539 :UBC 0 : default:
540 : : /* internal error */
8080 tgl@sss.pgh.pa.us 541 [ # # ]: 0 : elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
542 : : }
6912 bruce@momjian.us 543 [ - + ]:CBC 18529 : PG_FREE_IF_COPY(query, 1);
8439 544 : 18529 : PG_RETURN_BOOL(res);
545 : : }
546 : :
547 : : Datum
1986 akorotkov@postgresql 548 : 10 : _ltree_gist_options(PG_FUNCTION_ARGS)
549 : : {
550 : 10 : local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
551 : :
552 : 10 : init_local_reloptions(relopts, sizeof(LtreeGistOptions));
553 : 10 : add_local_int_reloption(relopts, "siglen", "signature length",
554 : : LTREE_ASIGLEN_DEFAULT, 1, LTREE_ASIGLEN_MAX,
555 : : offsetof(LtreeGistOptions, siglen));
556 : :
557 : 10 : PG_RETURN_VOID();
558 : : }
|