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 : :
7893 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);
1476 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 : : {
7893 bruce@momjian.us 37 : 7058 : int tlen = t->numlevel;
7929 38 : 7058 : ltree_level *cur = LTREE_FIRST(t);
39 : : int hash;
40 : :
7893 41 [ + + ]: 53466 : while (tlen > 0)
42 : : {
43 : 46408 : hash = ltree_crc32_sz(cur->name, cur->len);
1476 akorotkov@postgresql 44 : 46408 : AHASH(sign, hash, siglen);
7929 bruce@momjian.us 45 : 46408 : cur = LEVEL_NEXT(cur);
46 : 46408 : tlen--;
47 : : }
48 : 7058 : }
49 : :
50 : : Datum
7893 51 : 5879 : _ltree_compress(PG_FUNCTION_ARGS)
52 : : {
53 : 5879 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
7929 54 : 5879 : GISTENTRY *retval = entry;
1476 akorotkov@postgresql 55 [ + - ]: 5879 : int siglen = LTREE_GET_ASIGLEN();
56 : :
7893 bruce@momjian.us 57 [ + + ]: 5879 : 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 : :
5163 tgl@sss.pgh.pa.us 64 [ - + ]: 2000 : if (ARR_NDIM(val) > 1)
7570 tgl@sss.pgh.pa.us 65 [ # # ]:UBC 0 : ereport(ERROR,
66 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
67 : : errmsg("array must be one-dimensional")));
4844 tgl@sss.pgh.pa.us 68 [ - + ]:CBC 2000 : if (array_contains_nulls(val))
6721 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 : :
1476 akorotkov@postgresql 73 :CBC 2000 : key = ltree_gist_alloc(false, NULL, siglen, NULL, NULL);
74 : :
7893 bruce@momjian.us 75 [ + + ]: 9058 : while (num > 0)
76 : : {
1476 akorotkov@postgresql 77 : 7058 : hashing(LTG_SIGN(key), item, siglen);
7929 bruce@momjian.us 78 : 7058 : num--;
79 : 7058 : item = NEXTVAL(item);
80 : : }
81 : :
7893 82 : 2000 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
7929 83 : 2000 : gistentryinit(*retval, PointerGetDatum(key),
84 : : entry->rel, entry->page,
85 : : entry->offset, false);
86 : : }
7168 87 [ + - ]: 3879 : else if (!LTG_ISALLTRUE(entry->key))
88 : : {
89 : : int32 i;
90 : : ltree_gist *key;
7893 91 : 3879 : BITVECP sign = LTG_SIGN(DatumGetPointer(entry->key));
92 : :
1476 akorotkov@postgresql 93 [ + - ]: 3879 : ALOOPBYTE(siglen)
94 : : {
5994 bruce@momjian.us 95 [ + - ]: 3879 : if ((sign[i] & 0xff) != 0xff)
96 : 3879 : PG_RETURN_POINTER(retval);
97 : : }
98 : :
1476 akorotkov@postgresql 99 :UBC 0 : key = ltree_gist_alloc(true, sign, siglen, NULL, NULL);
7893 bruce@momjian.us 100 : 0 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
7929 101 : 0 : gistentryinit(*retval, PointerGetDatum(key),
102 : : entry->rel, entry->page,
103 : : entry->offset, false);
104 : : }
7929 bruce@momjian.us 105 :CBC 2000 : PG_RETURN_POINTER(retval);
106 : : }
107 : :
108 : : Datum
7893 109 : 7851 : _ltree_same(PG_FUNCTION_ARGS)
110 : : {
111 : 7851 : ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0);
112 : 7851 : ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1);
113 : 7851 : bool *result = (bool *) PG_GETARG_POINTER(2);
1476 akorotkov@postgresql 114 [ + - ]: 7851 : int siglen = LTREE_GET_ASIGLEN();
115 : :
7893 bruce@momjian.us 116 [ - + - - ]: 7851 : if (LTG_ISALLTRUE(a) && LTG_ISALLTRUE(b))
7929 bruce@momjian.us 117 :UBC 0 : *result = true;
7893 bruce@momjian.us 118 [ - + ]:CBC 7851 : else if (LTG_ISALLTRUE(a))
7929 bruce@momjian.us 119 :UBC 0 : *result = false;
7893 bruce@momjian.us 120 [ - + ]:CBC 7851 : else if (LTG_ISALLTRUE(b))
7929 bruce@momjian.us 121 :UBC 0 : *result = false;
122 : : else
123 : : {
124 : : int32 i;
7893 bruce@momjian.us 125 :CBC 7851 : BITVECP sa = LTG_SIGN(a),
126 : 7851 : sb = LTG_SIGN(b);
127 : :
7929 128 : 7851 : *result = true;
1476 akorotkov@postgresql 129 [ + + ]: 11225194 : ALOOPBYTE(siglen)
130 : : {
5994 bruce@momjian.us 131 [ + + ]: 11219462 : if (sa[i] != sb[i])
132 : : {
133 : 2119 : *result = false;
134 : 2119 : break;
135 : : }
136 : : }
137 : : }
7893 138 : 7851 : PG_RETURN_POINTER(result);
139 : : }
140 : :
141 : : static int32
1476 akorotkov@postgresql 142 : 15702 : unionkey(BITVECP sbase, ltree_gist *add, int siglen)
143 : : {
144 : : int32 i;
7893 bruce@momjian.us 145 : 15702 : BITVECP sadd = LTG_SIGN(add);
146 : :
147 [ - + ]: 15702 : if (LTG_ISALLTRUE(add))
7929 bruce@momjian.us 148 :UBC 0 : return 1;
149 : :
1476 akorotkov@postgresql 150 [ + + ]:CBC 28367422 : ALOOPBYTE(siglen)
5994 bruce@momjian.us 151 : 28351720 : sbase[i] |= sadd[i];
7929 152 : 15702 : return 0;
153 : : }
154 : :
155 : : Datum
7893 156 : 7851 : _ltree_union(PG_FUNCTION_ARGS)
157 : : {
7168 158 : 7851 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
7893 159 : 7851 : int *size = (int *) PG_GETARG_POINTER(1);
1476 akorotkov@postgresql 160 [ + - ]: 7851 : int siglen = LTREE_GET_ASIGLEN();
161 : : int32 i;
162 : 7851 : ltree_gist *result = ltree_gist_alloc(false, NULL, siglen, NULL, NULL);
163 : 7851 : BITVECP base = LTG_SIGN(result);
164 : :
7320 teodor@sigaev.ru 165 [ + + ]: 23553 : for (i = 0; i < entryvec->n; i++)
166 : : {
1476 akorotkov@postgresql 167 [ - + ]: 15702 : if (unionkey(base, GETENTRY(entryvec, i), siglen))
168 : : {
1476 akorotkov@postgresql 169 :UBC 0 : result->flag |= LTG_ALLTRUE;
170 : 0 : SET_VARSIZE(result, LTG_HDRSIZE);
7929 bruce@momjian.us 171 : 0 : break;
172 : : }
173 : : }
174 : :
1476 akorotkov@postgresql 175 :CBC 7851 : *size = VARSIZE(result);
176 : :
7893 bruce@momjian.us 177 : 7851 : PG_RETURN_POINTER(result);
178 : : }
179 : :
180 : : static int32
1476 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
1476 akorotkov@postgresql 187 :CBC 114662 : hemdistsign(BITVECP a, BITVECP b, int siglen)
188 : : {
189 : : int i,
190 : : diff,
7168 bruce@momjian.us 191 : 114662 : dist = 0;
192 : :
1476 akorotkov@postgresql 193 [ + + ]: 58297034 : ALOOPBYTE(siglen)
194 : : {
5994 bruce@momjian.us 195 : 58182372 : diff = (unsigned char) (a[i] ^ b[i]);
196 : : /* Using the popcount functions here isn't likely to win */
1885 tgl@sss.pgh.pa.us 197 : 58182372 : dist += pg_number_of_ones[diff];
198 : : }
7613 bruce@momjian.us 199 : 114662 : return dist;
200 : : }
201 : :
202 : : static int
1476 akorotkov@postgresql 203 : 114662 : hemdist(ltree_gist *a, ltree_gist *b, int siglen)
204 : : {
7168 bruce@momjian.us 205 [ - + ]: 114662 : if (LTG_ISALLTRUE(a))
206 : : {
7168 bruce@momjian.us 207 [ # # ]:UBC 0 : if (LTG_ISALLTRUE(b))
208 : 0 : return 0;
209 : : else
1476 akorotkov@postgresql 210 : 0 : return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(b), siglen);
211 : : }
7168 bruce@momjian.us 212 [ - + ]:CBC 114662 : else if (LTG_ISALLTRUE(b))
1476 akorotkov@postgresql 213 :UBC 0 : return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(a), siglen);
214 : :
1476 akorotkov@postgresql 215 :CBC 114662 : return hemdistsign(LTG_SIGN(a), LTG_SIGN(b), siglen);
216 : : }
217 : :
218 : :
219 : : Datum
7893 bruce@momjian.us 220 : 19262 : _ltree_penalty(PG_FUNCTION_ARGS)
221 : : {
222 : 19262 : ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
223 : 19262 : ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
224 : 19262 : float *penalty = (float *) PG_GETARG_POINTER(2);
1476 akorotkov@postgresql 225 [ + - ]: 19262 : int siglen = LTREE_GET_ASIGLEN();
226 : :
227 : 19262 : *penalty = hemdist(origval, newval, siglen);
7893 bruce@momjian.us 228 : 19262 : PG_RETURN_POINTER(penalty);
229 : : }
230 : :
231 : : typedef struct
232 : : {
233 : : OffsetNumber pos;
234 : : int32 cost;
235 : : } SPLITCOST;
236 : :
237 : : static int
238 : 7630 : comparecost(const void *a, const void *b)
239 : : {
4599 peter_e@gmx.net 240 : 7630 : return ((const SPLITCOST *) a)->cost - ((const SPLITCOST *) b)->cost;
241 : : }
242 : :
243 : : Datum
7893 bruce@momjian.us 244 : 880 : _ltree_picksplit(PG_FUNCTION_ARGS)
245 : : {
7168 246 : 880 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
7893 247 : 880 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1476 akorotkov@postgresql 248 [ + - ]: 880 : 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,
7613 bruce@momjian.us 258 : 880 : waste = -1;
259 : : int32 nbytes;
7893 260 : 880 : OffsetNumber seed_1 = 0,
261 : 880 : 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 : :
7320 teodor@sigaev.ru 271 : 880 : maxoff = entryvec->n - 2;
7929 bruce@momjian.us 272 : 880 : nbytes = (maxoff + 2) * sizeof(OffsetNumber);
273 : 880 : v->spl_left = (OffsetNumber *) palloc(nbytes);
274 : 880 : v->spl_right = (OffsetNumber *) palloc(nbytes);
275 : :
7168 276 [ + + ]: 3736 : for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
277 : : {
7893 278 : 2856 : _k = GETENTRY(entryvec, k);
7168 279 [ + + ]: 83312 : for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
280 : : {
1476 akorotkov@postgresql 281 : 80456 : size_waste = hemdist(_k, GETENTRY(entryvec, j), siglen);
7168 bruce@momjian.us 282 [ + + ]: 80456 : if (size_waste > waste)
283 : : {
7929 284 : 1596 : waste = size_waste;
285 : 1596 : seed_1 = k;
286 : 1596 : seed_2 = j;
287 : : }
288 : : }
289 : : }
290 : :
291 : 880 : left = v->spl_left;
292 : 880 : v->spl_nleft = 0;
293 : 880 : right = v->spl_right;
294 : 880 : v->spl_nright = 0;
295 : :
7893 296 [ + - - + ]: 880 : if (seed_1 == 0 || seed_2 == 0)
297 : : {
7929 bruce@momjian.us 298 :UBC 0 : seed_1 = 1;
299 : 0 : seed_2 = 2;
300 : : }
301 : :
302 : : /* form initial .. */
1476 akorotkov@postgresql 303 :CBC 880 : datum_l = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_1)),
304 : 880 : LTG_SIGN(GETENTRY(entryvec, seed_1)),
305 : : siglen, NULL, NULL);
306 : :
307 : 880 : datum_r = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_2)),
308 : 880 : LTG_SIGN(GETENTRY(entryvec, seed_2)),
309 : : siglen, NULL, NULL);
310 : :
7929 bruce@momjian.us 311 : 880 : maxoff = OffsetNumberNext(maxoff);
312 : : /* sort before ... */
7893 313 : 880 : costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
314 [ + + ]: 5496 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
315 : : {
316 : 4616 : costvector[j - 1].pos = j;
317 : 4616 : _j = GETENTRY(entryvec, j);
1476 akorotkov@postgresql 318 : 4616 : size_alpha = hemdist(datum_l, _j, siglen);
319 : 4616 : size_beta = hemdist(datum_r, _j, siglen);
555 peter@eisentraut.org 320 : 4616 : costvector[j - 1].cost = abs(size_alpha - size_beta);
321 : : }
432 322 : 880 : qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
323 : :
7168 bruce@momjian.us 324 : 880 : union_l = LTG_SIGN(datum_l);
325 : 880 : union_r = LTG_SIGN(datum_r);
326 : :
7893 327 [ + + ]: 5496 : for (k = 0; k < maxoff; k++)
328 : : {
7929 329 : 4616 : j = costvector[k].pos;
7893 330 [ + + ]: 4616 : if (j == seed_1)
331 : : {
7929 332 : 880 : *left++ = j;
333 : 880 : v->spl_nleft++;
334 : 880 : continue;
335 : : }
7893 336 [ + + ]: 3736 : else if (j == seed_2)
337 : : {
7929 338 : 880 : *right++ = j;
339 : 880 : v->spl_nright++;
340 : 880 : continue;
341 : : }
7613 342 : 2856 : _j = GETENTRY(entryvec, j);
1476 akorotkov@postgresql 343 : 2856 : size_alpha = hemdist(datum_l, _j, siglen);
344 : 2856 : size_beta = hemdist(datum_r, _j, siglen);
345 : :
7168 bruce@momjian.us 346 [ + + ]: 2856 : if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
347 : : {
348 [ + - - + ]: 1306 : if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j))
349 : : {
7613 bruce@momjian.us 350 [ # # ]:UBC 0 : if (!LTG_ISALLTRUE(datum_l))
432 peter@eisentraut.org 351 : 0 : memset(union_l, 0xff, siglen);
352 : : }
353 : : else
354 : : {
7168 bruce@momjian.us 355 :CBC 1306 : ptr = LTG_SIGN(_j);
1476 akorotkov@postgresql 356 [ + + ]: 1588766 : ALOOPBYTE(siglen)
5994 bruce@momjian.us 357 : 1587460 : union_l[i] |= ptr[i];
358 : : }
7929 359 : 1306 : *left++ = j;
360 : 1306 : v->spl_nleft++;
361 : : }
362 : : else
363 : : {
7168 364 [ + - - + ]: 1550 : if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j))
365 : : {
7613 bruce@momjian.us 366 [ # # ]:UBC 0 : if (!LTG_ISALLTRUE(datum_r))
432 peter@eisentraut.org 367 : 0 : memset(union_r, 0xff, siglen);
368 : : }
369 : : else
370 : : {
7168 bruce@momjian.us 371 :CBC 1550 : ptr = LTG_SIGN(_j);
1476 akorotkov@postgresql 372 [ + + ]: 1975082 : ALOOPBYTE(siglen)
5994 bruce@momjian.us 373 : 1973532 : union_r[i] |= ptr[i];
374 : : }
7929 375 : 1550 : *right++ = j;
376 : 1550 : v->spl_nright++;
377 : : }
378 : : }
379 : :
380 : 880 : *right = *left = FirstOffsetNumber;
381 : :
382 : 880 : v->spl_ldatum = PointerGetDatum(datum_l);
383 : 880 : v->spl_rdatum = PointerGetDatum(datum_r);
384 : :
7893 385 : 880 : PG_RETURN_POINTER(v);
386 : : }
387 : :
388 : : static bool
1476 akorotkov@postgresql 389 : 2589 : gist_te(ltree_gist *key, ltree *query, int siglen)
390 : : {
7893 bruce@momjian.us 391 : 2589 : ltree_level *curq = LTREE_FIRST(query);
392 : 2589 : BITVECP sign = LTG_SIGN(key);
393 : 2589 : int qlen = query->numlevel;
394 : : unsigned int hv;
395 : :
396 [ - + ]: 2589 : if (LTG_ISALLTRUE(key))
7929 bruce@momjian.us 397 :UBC 0 : return true;
398 : :
7893 bruce@momjian.us 399 [ + + ]:CBC 8676 : while (qlen > 0)
400 : : {
401 : 6647 : hv = ltree_crc32_sz(curq->name, curq->len);
1476 akorotkov@postgresql 402 [ + + ]: 6647 : if (!GETBIT(sign, AHASHVAL(hv, siglen)))
7893 bruce@momjian.us 403 : 560 : return false;
7929 404 : 6087 : curq = LEVEL_NEXT(curq);
405 : 6087 : qlen--;
406 : : }
407 : :
408 : 2029 : return true;
409 : : }
410 : :
411 : : typedef struct LtreeSignature
412 : : {
413 : : BITVECP sign;
414 : : int siglen;
415 : : } LtreeSignature;
416 : :
417 : : static bool
1476 akorotkov@postgresql 418 : 3716 : checkcondition_bit(void *cxt, ITEM *val)
419 : : {
420 : 3716 : LtreeSignature *sig = cxt;
421 : :
422 [ + - + + ]: 3716 : return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, AHASHVAL(val->val, sig->siglen)) : true;
423 : : }
424 : :
425 : : static bool
426 : 2163 : gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen)
427 : : {
428 : : LtreeSignature sig;
429 : :
7893 bruce@momjian.us 430 [ - + ]: 2163 : if (LTG_ISALLTRUE(key))
7929 bruce@momjian.us 431 :UBC 0 : return true;
432 : :
1476 akorotkov@postgresql 433 :CBC 2163 : sig.sign = LTG_SIGN(key);
434 : 2163 : sig.siglen = siglen;
435 : :
1536 alvherre@alvh.no-ip. 436 : 2163 : return ltree_execute(GETQUERY(query),
437 : : &sig, false,
438 : : checkcondition_bit);
439 : : }
440 : :
441 : : static bool
1476 akorotkov@postgresql 442 : 14730 : gist_qe(ltree_gist *key, lquery *query, int siglen)
443 : : {
7893 bruce@momjian.us 444 : 14730 : lquery_level *curq = LQUERY_FIRST(query);
445 : 14730 : BITVECP sign = LTG_SIGN(key);
446 : 14730 : int qlen = query->numlevel;
447 : :
448 [ - + ]: 14730 : if (LTG_ISALLTRUE(key))
7929 bruce@momjian.us 449 :UBC 0 : return true;
450 : :
7893 bruce@momjian.us 451 [ + + ]:CBC 45622 : while (qlen > 0)
452 : : {
453 [ + + + - ]: 36442 : if (curq->numvar && LQL_CANLOOKSIGN(curq))
454 : : {
455 : 25306 : bool isexist = false;
456 : 25306 : int vlen = curq->numvar;
7929 457 : 25306 : lquery_variant *curv = LQL_FIRST(curq);
458 : :
7893 459 [ + + ]: 30856 : while (vlen > 0)
460 : : {
1476 akorotkov@postgresql 461 [ + + ]: 25306 : if (GETBIT(sign, AHASHVAL(curv->val, siglen)))
462 : : {
7893 bruce@momjian.us 463 : 19756 : isexist = true;
7929 464 : 19756 : break;
465 : : }
466 : 5550 : curv = LVAR_NEXT(curv);
467 : 5550 : vlen--;
468 : : }
7893 469 [ + + ]: 25306 : if (!isexist)
7929 470 : 5550 : return false;
471 : : }
472 : :
473 : 30892 : curq = LQL_NEXT(curq);
474 : 30892 : qlen--;
475 : : }
476 : :
477 : 9180 : return true;
478 : : }
479 : :
480 : : static bool
1476 akorotkov@postgresql 481 : 2276 : _arrq_cons(ltree_gist *key, ArrayType *_query, int siglen)
482 : : {
7168 bruce@momjian.us 483 [ - + ]: 2276 : lquery *query = (lquery *) ARR_DATA_PTR(_query);
484 : 2276 : int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
485 : :
5163 tgl@sss.pgh.pa.us 486 [ - + ]: 2276 : if (ARR_NDIM(_query) > 1)
7168 bruce@momjian.us 487 [ # # ]:UBC 0 : ereport(ERROR,
488 : : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
489 : : errmsg("array must be one-dimensional")));
4844 tgl@sss.pgh.pa.us 490 [ - + ]:CBC 2276 : if (array_contains_nulls(_query))
6721 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 : :
7168 bruce@momjian.us 495 [ + + ]:CBC 4043 : while (num > 0)
496 : : {
1476 akorotkov@postgresql 497 [ + + ]: 3262 : if (gist_qe(key, query, siglen))
7168 bruce@momjian.us 498 : 1495 : return true;
499 : 1767 : num--;
500 : 1767 : query = (lquery *) NEXTVAL(query);
501 : : }
502 : 781 : return false;
503 : : }
504 : :
505 : : Datum
7893 506 : 18496 : _ltree_consistent(PG_FUNCTION_ARGS)
507 : : {
508 : 18496 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
2400 tgl@sss.pgh.pa.us 509 : 18496 : void *query = (void *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
7929 bruce@momjian.us 510 : 18496 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
511 : :
512 : : /* Oid subtype = PG_GETARG_OID(3); */
5844 tgl@sss.pgh.pa.us 513 : 18496 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
1476 akorotkov@postgresql 514 [ + - ]: 18496 : int siglen = LTREE_GET_ASIGLEN();
5844 tgl@sss.pgh.pa.us 515 : 18496 : ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
7893 bruce@momjian.us 516 : 18496 : bool res = false;
517 : :
518 : : /* All cases served by this function are inexact */
5844 tgl@sss.pgh.pa.us 519 : 18496 : *recheck = true;
520 : :
7893 bruce@momjian.us 521 [ + + + + : 18496 : switch (strategy)
- ]
522 : : {
7929 523 : 2589 : case 10:
524 : : case 11:
1476 akorotkov@postgresql 525 : 2589 : res = gist_te(key, (ltree *) query, siglen);
7929 bruce@momjian.us 526 : 2589 : break;
527 : 11468 : case 12:
528 : : case 13:
1476 akorotkov@postgresql 529 : 11468 : res = gist_qe(key, (lquery *) query, siglen);
7893 bruce@momjian.us 530 : 11468 : break;
7929 531 : 2163 : case 14:
532 : : case 15:
1476 akorotkov@postgresql 533 : 2163 : res = gist_qtxt(key, (ltxtquery *) query, siglen);
7893 bruce@momjian.us 534 : 2163 : break;
7725 535 : 2276 : case 16:
536 : : case 17:
1476 akorotkov@postgresql 537 : 2276 : res = _arrq_cons(key, (ArrayType *) query, siglen);
7725 bruce@momjian.us 538 : 2276 : break;
7929 bruce@momjian.us 539 :UBC 0 : default:
540 : : /* internal error */
7570 tgl@sss.pgh.pa.us 541 [ # # ]: 0 : elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
542 : : }
6402 bruce@momjian.us 543 [ - + ]:CBC 18496 : PG_FREE_IF_COPY(query, 1);
7929 544 : 18496 : PG_RETURN_BOOL(res);
545 : : }
546 : :
547 : : Datum
1476 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 : : }
|