Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * op function for ltree
3 : : * Teodor Sigaev <teodor@stack.net>
4 : : * contrib/ltree/ltree_op.c
5 : : */
6 : : #include "postgres.h"
7 : :
8 : : #include <ctype.h>
9 : :
10 : : #include "access/htup_details.h"
11 : : #include "catalog/pg_statistic.h"
12 : : #include "common/hashfn.h"
13 : : #include "ltree.h"
14 : : #include "utils/builtins.h"
15 : : #include "utils/lsyscache.h"
16 : : #include "utils/selfuncs.h"
17 : :
6529 tgl@sss.pgh.pa.us 18 :CBC 3 : PG_MODULE_MAGIC;
19 : :
20 : : /* compare functions */
7929 bruce@momjian.us 21 : 3 : PG_FUNCTION_INFO_V1(ltree_cmp);
22 : 3 : PG_FUNCTION_INFO_V1(ltree_lt);
23 : 3 : PG_FUNCTION_INFO_V1(ltree_le);
24 : 3 : PG_FUNCTION_INFO_V1(ltree_eq);
25 : 2 : PG_FUNCTION_INFO_V1(ltree_ne);
26 : 3 : PG_FUNCTION_INFO_V1(ltree_ge);
27 : 3 : PG_FUNCTION_INFO_V1(ltree_gt);
24 tgl@sss.pgh.pa.us 28 :GNC 3 : PG_FUNCTION_INFO_V1(hash_ltree);
29 : 3 : PG_FUNCTION_INFO_V1(hash_ltree_extended);
7929 bruce@momjian.us 30 :CBC 3 : PG_FUNCTION_INFO_V1(nlevel);
31 : 3 : PG_FUNCTION_INFO_V1(ltree_isparent);
32 : 3 : PG_FUNCTION_INFO_V1(ltree_risparent);
33 : 3 : PG_FUNCTION_INFO_V1(subltree);
34 : 6 : PG_FUNCTION_INFO_V1(subpath);
7685 35 : 6 : PG_FUNCTION_INFO_V1(ltree_index);
7929 36 : 3 : PG_FUNCTION_INFO_V1(ltree_addltree);
37 : 3 : PG_FUNCTION_INFO_V1(ltree_addtext);
38 : 2 : PG_FUNCTION_INFO_V1(ltree_textadd);
7924 39 : 16 : PG_FUNCTION_INFO_V1(lca);
7685 40 : 3 : PG_FUNCTION_INFO_V1(ltree2text);
41 : 3 : PG_FUNCTION_INFO_V1(text2ltree);
6562 tgl@sss.pgh.pa.us 42 : 2 : PG_FUNCTION_INFO_V1(ltreeparentsel);
43 : :
44 : : int
5421 bruce@momjian.us 45 : 138953 : ltree_compare(const ltree *a, const ltree *b)
46 : : {
7929 47 : 138953 : ltree_level *al = LTREE_FIRST(a);
48 : 138953 : ltree_level *bl = LTREE_FIRST(b);
7893 49 : 138953 : int an = a->numlevel;
50 : 138953 : int bn = b->numlevel;
51 : :
52 [ + + + + ]: 235979 : while (an > 0 && bn > 0)
53 : : {
54 : : int res;
55 : :
4863 rhaas@postgresql.org 56 [ + + ]: 224334 : if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
57 : : {
7893 bruce@momjian.us 58 [ + + ]: 105726 : if (al->len != bl->len)
59 : 8700 : return (al->len - bl->len) * 10 * (an + 1);
60 : : }
61 : : else
62 : : {
2018 tgl@sss.pgh.pa.us 63 [ + + ]: 118608 : if (res < 0)
64 : 57231 : res = -1;
65 : : else
66 : 61377 : res = 1;
7893 bruce@momjian.us 67 : 118608 : return res * 10 * (an + 1);
68 : : }
69 : :
70 : 97026 : an--;
71 : 97026 : bn--;
72 : 97026 : al = LEVEL_NEXT(al);
73 : 97026 : bl = LEVEL_NEXT(bl);
74 : : }
75 : :
76 : 11645 : return (a->numlevel - b->numlevel) * 10 * (an + 1);
77 : : }
78 : :
79 : : #define RUNCMP \
80 : : ltree *a = PG_GETARG_LTREE_P(0); \
81 : : ltree *b = PG_GETARG_LTREE_P(1); \
82 : : int res = ltree_compare(a,b); \
83 : : PG_FREE_IF_COPY(a,0); \
84 : : PG_FREE_IF_COPY(b,1)
85 : :
86 : : Datum
87 : 71218 : ltree_cmp(PG_FUNCTION_ARGS)
88 : : {
2400 tgl@sss.pgh.pa.us 89 [ + - + + ]: 71218 : RUNCMP;
90 : 71218 : PG_RETURN_INT32(res);
91 : : }
92 : :
93 : : Datum
7893 bruce@momjian.us 94 : 2262 : ltree_lt(PG_FUNCTION_ARGS)
95 : : {
2400 tgl@sss.pgh.pa.us 96 [ + + - + ]: 2262 : RUNCMP;
916 michael@paquier.xyz 97 : 2262 : PG_RETURN_BOOL(res < 0);
98 : : }
99 : :
100 : : Datum
7893 bruce@momjian.us 101 : 2264 : ltree_le(PG_FUNCTION_ARGS)
102 : : {
2400 tgl@sss.pgh.pa.us 103 [ + + - + ]: 2264 : RUNCMP;
916 michael@paquier.xyz 104 : 2264 : PG_RETURN_BOOL(res <= 0);
105 : : }
106 : :
107 : : Datum
7893 bruce@momjian.us 108 : 2017 : ltree_eq(PG_FUNCTION_ARGS)
109 : : {
2400 tgl@sss.pgh.pa.us 110 [ + + + + ]: 2017 : RUNCMP;
916 michael@paquier.xyz 111 : 2017 : PG_RETURN_BOOL(res == 0);
112 : : }
113 : :
114 : : Datum
7893 bruce@momjian.us 115 : 2923 : ltree_ge(PG_FUNCTION_ARGS)
116 : : {
2400 tgl@sss.pgh.pa.us 117 [ + + - + ]: 2923 : RUNCMP;
916 michael@paquier.xyz 118 : 2923 : PG_RETURN_BOOL(res >= 0);
119 : : }
120 : :
121 : : Datum
7893 bruce@momjian.us 122 : 2922 : ltree_gt(PG_FUNCTION_ARGS)
123 : : {
2400 tgl@sss.pgh.pa.us 124 [ + + - + ]: 2922 : RUNCMP;
916 michael@paquier.xyz 125 : 2922 : PG_RETURN_BOOL(res > 0);
126 : : }
127 : :
128 : : Datum
7893 bruce@momjian.us 129 :UBC 0 : ltree_ne(PG_FUNCTION_ARGS)
130 : : {
2400 tgl@sss.pgh.pa.us 131 [ # # # # ]: 0 : RUNCMP;
916 michael@paquier.xyz 132 : 0 : PG_RETURN_BOOL(res != 0);
133 : : }
134 : :
135 : : /* Compute a hash for the ltree */
136 : : Datum
24 tgl@sss.pgh.pa.us 137 :GNC 3031 : hash_ltree(PG_FUNCTION_ARGS)
138 : : {
139 : 3031 : ltree *a = PG_GETARG_LTREE_P(0);
140 : 3031 : uint32 result = 1;
141 : 3031 : int an = a->numlevel;
142 : 3031 : ltree_level *al = LTREE_FIRST(a);
143 : :
144 [ + + ]: 22872 : while (an > 0)
145 : : {
146 : 19841 : uint32 levelHash = DatumGetUInt32(hash_any((unsigned char *) al->name, al->len));
147 : :
148 : : /*
149 : : * Combine hash values of successive elements by multiplying the
150 : : * current value by 31 and adding on the new element's hash value.
151 : : *
152 : : * This method is borrowed from hash_array(), which see for further
153 : : * commentary.
154 : : */
155 : 19841 : result = (result << 5) - result + levelHash;
156 : :
157 : 19841 : an--;
158 : 19841 : al = LEVEL_NEXT(al);
159 : : }
160 : :
161 [ + + ]: 3031 : PG_FREE_IF_COPY(a, 0);
162 : 3031 : PG_RETURN_UINT32(result);
163 : : }
164 : :
165 : : /* Compute an extended hash for the ltree */
166 : : Datum
167 : 12 : hash_ltree_extended(PG_FUNCTION_ARGS)
168 : : {
169 : 12 : ltree *a = PG_GETARG_LTREE_P(0);
170 : 12 : const uint64 seed = PG_GETARG_INT64(1);
171 : 12 : uint64 result = 1;
172 : 12 : int an = a->numlevel;
173 : 12 : ltree_level *al = LTREE_FIRST(a);
174 : :
175 : : /*
176 : : * If the path has length zero, return 1 + seed to ensure that the low 32
177 : : * bits of the result match hash_ltree when the seed is 0, as required by
178 : : * the hash index support functions, but to also return a different value
179 : : * when there is a seed.
180 : : */
181 [ + + ]: 12 : if (an == 0)
182 : : {
183 [ - + ]: 2 : PG_FREE_IF_COPY(a, 0);
184 : 2 : PG_RETURN_UINT64(result + seed);
185 : : }
186 : :
187 [ + + ]: 28 : while (an > 0)
188 : : {
189 : 18 : uint64 levelHash = DatumGetUInt64(hash_any_extended((unsigned char *) al->name, al->len, seed));
190 : :
191 : 18 : result = (result << 5) - result + levelHash;
192 : :
193 : 18 : an--;
194 : 18 : al = LEVEL_NEXT(al);
195 : : }
196 : :
197 [ - + ]: 10 : PG_FREE_IF_COPY(a, 0);
198 : 10 : PG_RETURN_UINT64(result);
199 : : }
200 : :
201 : : Datum
7893 bruce@momjian.us 202 :CBC 2 : nlevel(PG_FUNCTION_ARGS)
203 : : {
2400 tgl@sss.pgh.pa.us 204 : 2 : ltree *a = PG_GETARG_LTREE_P(0);
7893 bruce@momjian.us 205 : 2 : int res = a->numlevel;
206 : :
207 [ - + ]: 2 : PG_FREE_IF_COPY(a, 0);
7929 208 : 2 : PG_RETURN_INT32(res);
209 : : }
210 : :
211 : : bool
5421 212 : 21188 : inner_isparent(const ltree *c, const ltree *p)
213 : : {
7929 214 : 21188 : ltree_level *cl = LTREE_FIRST(c);
215 : 21188 : ltree_level *pl = LTREE_FIRST(p);
7893 216 : 21188 : int pn = p->numlevel;
217 : :
218 [ + + ]: 21188 : if (pn > c->numlevel)
7929 219 : 10166 : return false;
220 : :
7893 221 [ + + ]: 12019 : while (pn > 0)
222 : : {
223 [ + + ]: 11883 : if (cl->len != pl->len)
7929 224 : 7960 : return false;
2018 tgl@sss.pgh.pa.us 225 [ + + ]: 3923 : if (memcmp(cl->name, pl->name, cl->len) != 0)
7929 bruce@momjian.us 226 : 2926 : return false;
227 : :
228 : 997 : pn--;
7893 229 : 997 : cl = LEVEL_NEXT(cl);
230 : 997 : pl = LEVEL_NEXT(pl);
231 : : }
7929 232 : 136 : return true;
233 : : }
234 : :
235 : : Datum
7893 236 : 11538 : ltree_isparent(PG_FUNCTION_ARGS)
237 : : {
2400 tgl@sss.pgh.pa.us 238 : 11538 : ltree *c = PG_GETARG_LTREE_P(1);
239 : 11538 : ltree *p = PG_GETARG_LTREE_P(0);
7893 bruce@momjian.us 240 : 11538 : bool res = inner_isparent(c, p);
241 : :
242 [ - + ]: 11538 : PG_FREE_IF_COPY(c, 1);
243 [ + + ]: 11538 : PG_FREE_IF_COPY(p, 0);
244 : 11538 : PG_RETURN_BOOL(res);
245 : : }
246 : :
247 : : Datum
248 : 9320 : ltree_risparent(PG_FUNCTION_ARGS)
249 : : {
2400 tgl@sss.pgh.pa.us 250 : 9320 : ltree *c = PG_GETARG_LTREE_P(0);
251 : 9320 : ltree *p = PG_GETARG_LTREE_P(1);
7893 bruce@momjian.us 252 : 9320 : bool res = inner_isparent(c, p);
253 : :
254 [ + + ]: 9320 : PG_FREE_IF_COPY(c, 0);
255 [ - + ]: 9320 : PG_FREE_IF_COPY(p, 1);
256 : 9320 : PG_RETURN_BOOL(res);
257 : : }
258 : :
259 : :
260 : : static ltree *
4311 peter_e@gmx.net 261 : 9 : inner_subltree(ltree *t, int32 startpos, int32 endpos)
262 : : {
7893 bruce@momjian.us 263 : 9 : char *start = NULL,
264 : 9 : *end = NULL;
7929 265 : 9 : ltree_level *ptr = LTREE_FIRST(t);
266 : : ltree *res;
267 : : int i;
268 : :
7576 teodor@sigaev.ru 269 [ + - + - : 9 : if (startpos < 0 || endpos < 0 || startpos >= t->numlevel || startpos > endpos)
+ - - + ]
7570 tgl@sss.pgh.pa.us 270 [ # # ]:UBC 0 : ereport(ERROR,
271 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
272 : : errmsg("invalid positions")));
273 : :
7893 bruce@momjian.us 274 [ + + ]:CBC 9 : if (endpos > t->numlevel)
7929 275 : 2 : endpos = t->numlevel;
276 : :
7576 teodor@sigaev.ru 277 : 9 : start = end = (char *) ptr;
7893 bruce@momjian.us 278 [ + + ]: 19 : for (i = 0; i < endpos; i++)
279 : : {
280 [ + + ]: 18 : if (i == startpos)
281 : 7 : start = (char *) ptr;
282 [ + + ]: 18 : if (i == endpos - 1)
283 : : {
284 : 8 : end = (char *) LEVEL_NEXT(ptr);
7929 285 : 8 : break;
286 : : }
7893 287 : 10 : ptr = LEVEL_NEXT(ptr);
288 : : }
289 : :
2959 andres@anarazel.de 290 : 9 : res = (ltree *) palloc0(LTREE_HDRSIZE + (end - start));
6255 tgl@sss.pgh.pa.us 291 : 9 : SET_VARSIZE(res, LTREE_HDRSIZE + (end - start));
7893 bruce@momjian.us 292 : 9 : res->numlevel = endpos - startpos;
293 : :
294 : 9 : memcpy(LTREE_FIRST(res), start, end - start);
295 : :
7929 296 : 9 : return res;
297 : : }
298 : :
299 : : Datum
7893 300 : 1 : subltree(PG_FUNCTION_ARGS)
301 : : {
2400 tgl@sss.pgh.pa.us 302 : 1 : ltree *t = PG_GETARG_LTREE_P(0);
7893 bruce@momjian.us 303 : 1 : ltree *res = inner_subltree(t, PG_GETARG_INT32(1), PG_GETARG_INT32(2));
304 : :
305 [ - + ]: 1 : PG_FREE_IF_COPY(t, 0);
7929 306 : 1 : PG_RETURN_POINTER(res);
307 : : }
308 : :
309 : : Datum
7893 310 : 8 : subpath(PG_FUNCTION_ARGS)
311 : : {
2400 tgl@sss.pgh.pa.us 312 : 8 : ltree *t = PG_GETARG_LTREE_P(0);
4311 peter_e@gmx.net 313 : 8 : int32 start = PG_GETARG_INT32(1);
314 [ + + ]: 8 : int32 len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
315 : : int32 end;
316 : : ltree *res;
317 : :
7893 bruce@momjian.us 318 : 8 : end = start + len;
319 : :
320 [ + + ]: 8 : if (start < 0)
321 : : {
7929 322 : 1 : start = t->numlevel + start;
7893 323 : 1 : end = start + len;
324 : : }
325 [ - + ]: 8 : if (start < 0)
326 : : { /* start > t->numlevel */
7929 bruce@momjian.us 327 :UBC 0 : start = t->numlevel + start;
7893 328 : 0 : end = start + len;
329 : : }
330 : :
7893 bruce@momjian.us 331 [ + + ]:CBC 8 : if (len < 0)
7929 332 : 2 : end = t->numlevel + len;
7893 333 [ + + ]: 6 : else if (len == 0)
7576 teodor@sigaev.ru 334 [ + + ]: 4 : end = (fcinfo->nargs == 3) ? start : 0xffff;
335 : :
7893 bruce@momjian.us 336 : 8 : res = inner_subltree(t, start, end);
337 : :
338 [ - + ]: 8 : PG_FREE_IF_COPY(t, 0);
7929 339 : 8 : PG_RETURN_POINTER(res);
340 : : }
341 : :
342 : : static ltree *
5421 343 : 6 : ltree_concat(ltree *a, ltree *b)
344 : : {
345 : : ltree *r;
1478 tgl@sss.pgh.pa.us 346 : 6 : int numlevel = (int) a->numlevel + b->numlevel;
347 : :
348 [ + + ]: 6 : if (numlevel > LTREE_MAX_LEVELS)
349 [ + - ]: 1 : ereport(ERROR,
350 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
351 : : errmsg("number of ltree levels (%d) exceeds the maximum allowed (%d)",
352 : : numlevel, LTREE_MAX_LEVELS)));
353 : :
2959 andres@anarazel.de 354 : 5 : r = (ltree *) palloc0(VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
6255 tgl@sss.pgh.pa.us 355 : 5 : SET_VARSIZE(r, VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
1478 356 : 5 : r->numlevel = (uint16) numlevel;
357 : :
6255 358 : 5 : memcpy(LTREE_FIRST(r), LTREE_FIRST(a), VARSIZE(a) - LTREE_HDRSIZE);
359 : 5 : memcpy(((char *) LTREE_FIRST(r)) + VARSIZE(a) - LTREE_HDRSIZE,
360 : : LTREE_FIRST(b),
361 : 5 : VARSIZE(b) - LTREE_HDRSIZE);
7893 bruce@momjian.us 362 : 5 : return r;
363 : : }
364 : :
365 : : Datum
366 : 5 : ltree_addltree(PG_FUNCTION_ARGS)
367 : : {
2400 tgl@sss.pgh.pa.us 368 : 5 : ltree *a = PG_GETARG_LTREE_P(0);
369 : 5 : ltree *b = PG_GETARG_LTREE_P(1);
370 : : ltree *r;
371 : :
7929 bruce@momjian.us 372 : 5 : r = ltree_concat(a, b);
7893 373 [ - + ]: 4 : PG_FREE_IF_COPY(a, 0);
374 [ - + ]: 4 : PG_FREE_IF_COPY(b, 1);
7929 375 : 4 : PG_RETURN_POINTER(r);
376 : : }
377 : :
378 : : Datum
7893 379 : 1 : ltree_addtext(PG_FUNCTION_ARGS)
380 : : {
2400 tgl@sss.pgh.pa.us 381 : 1 : ltree *a = PG_GETARG_LTREE_P(0);
5864 382 : 1 : text *b = PG_GETARG_TEXT_PP(1);
383 : : char *s;
384 : : ltree *r,
385 : : *tmp;
386 : :
387 : 1 : s = text_to_cstring(b);
388 : :
389 : 1 : tmp = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
390 : : PointerGetDatum(s)));
391 : :
7929 bruce@momjian.us 392 : 1 : pfree(s);
393 : :
7893 394 : 1 : r = ltree_concat(a, tmp);
395 : :
396 : 1 : pfree(tmp);
397 : :
398 [ - + ]: 1 : PG_FREE_IF_COPY(a, 0);
399 [ - + ]: 1 : PG_FREE_IF_COPY(b, 1);
7929 400 : 1 : PG_RETURN_POINTER(r);
401 : : }
402 : :
403 : : Datum
7685 404 : 18 : ltree_index(PG_FUNCTION_ARGS)
405 : : {
2400 tgl@sss.pgh.pa.us 406 : 18 : ltree *a = PG_GETARG_LTREE_P(0);
407 : 18 : ltree *b = PG_GETARG_LTREE_P(1);
7559 bruce@momjian.us 408 [ + + ]: 18 : int start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
409 : : int i,
410 : : j;
411 : : ltree_level *startptr,
412 : : *aptr,
413 : : *bptr;
414 : 18 : bool found = false;
415 : :
416 [ + + ]: 18 : if (start < 0)
417 : : {
418 [ + + ]: 5 : if (-start >= a->numlevel)
419 : 1 : start = 0;
420 : : else
421 : 4 : start = (int) (a->numlevel) + start;
422 : : }
423 : :
424 [ + + + - : 18 : if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0)
- + ]
425 : : {
7685 426 [ - + ]: 1 : PG_FREE_IF_COPY(a, 0);
427 [ - + ]: 1 : PG_FREE_IF_COPY(b, 1);
428 : 1 : PG_RETURN_INT32(-1);
429 : : }
430 : :
7559 431 : 17 : startptr = LTREE_FIRST(a);
432 [ + + ]: 109 : for (i = 0; i <= a->numlevel - b->numlevel; i++)
433 : : {
434 [ + + ]: 106 : if (i >= start)
435 : : {
436 : 58 : aptr = startptr;
437 : 58 : bptr = LTREE_FIRST(b);
438 [ + + ]: 93 : for (j = 0; j < b->numlevel; j++)
439 : : {
4863 rhaas@postgresql.org 440 [ + - + + ]: 79 : if (!(aptr->len == bptr->len && memcmp(aptr->name, bptr->name, aptr->len) == 0))
441 : : break;
7559 bruce@momjian.us 442 : 35 : aptr = LEVEL_NEXT(aptr);
443 : 35 : bptr = LEVEL_NEXT(bptr);
444 : : }
445 : :
446 [ + + ]: 58 : if (j == b->numlevel)
447 : : {
448 : 14 : found = true;
7685 449 : 14 : break;
450 : : }
451 : : }
7559 452 : 92 : startptr = LEVEL_NEXT(startptr);
453 : : }
454 : :
455 [ + + ]: 17 : if (!found)
456 : 3 : i = -1;
457 : :
7685 458 [ - + ]: 17 : PG_FREE_IF_COPY(a, 0);
459 [ - + ]: 17 : PG_FREE_IF_COPY(b, 1);
460 : 17 : PG_RETURN_INT32(i);
461 : : }
462 : :
463 : : Datum
7893 bruce@momjian.us 464 :UBC 0 : ltree_textadd(PG_FUNCTION_ARGS)
465 : : {
2400 tgl@sss.pgh.pa.us 466 : 0 : ltree *a = PG_GETARG_LTREE_P(1);
5864 467 : 0 : text *b = PG_GETARG_TEXT_PP(0);
468 : : char *s;
469 : : ltree *r,
470 : : *tmp;
471 : :
472 : 0 : s = text_to_cstring(b);
473 : :
474 : 0 : tmp = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
475 : : PointerGetDatum(s)));
476 : :
7893 bruce@momjian.us 477 : 0 : pfree(s);
478 : :
479 : 0 : r = ltree_concat(tmp, a);
480 : :
481 : 0 : pfree(tmp);
482 : :
483 [ # # ]: 0 : PG_FREE_IF_COPY(a, 1);
484 [ # # ]: 0 : PG_FREE_IF_COPY(b, 0);
485 : 0 : PG_RETURN_POINTER(r);
486 : : }
487 : :
488 : : /*
489 : : * Common code for variants of lca(), find longest common ancestor of inputs
490 : : *
491 : : * Returns NULL if there is no common ancestor, ie, the longest common
492 : : * prefix is empty.
493 : : */
494 : : ltree *
5421 bruce@momjian.us 495 :CBC 14 : lca_inner(ltree **a, int len)
496 : : {
497 : : int tmp,
498 : : num,
499 : : i,
500 : : reslen;
501 : : ltree **ptr;
502 : : ltree_level *l1,
503 : : *l2;
504 : : ltree *res;
505 : :
2102 tgl@sss.pgh.pa.us 506 [ + + ]: 14 : if (len <= 0)
507 : 1 : return NULL; /* no inputs? */
7893 bruce@momjian.us 508 [ + + ]: 13 : if ((*a)->numlevel == 0)
2102 tgl@sss.pgh.pa.us 509 : 1 : return NULL; /* any empty input means NULL result */
510 : :
511 : : /* num is the length of the longest common ancestor so far */
512 : 12 : num = (*a)->numlevel - 1;
513 : :
514 : : /* Compare each additional input to *a */
515 : 12 : ptr = a + 1;
7893 bruce@momjian.us 516 [ + + ]: 23 : while (ptr - a < len)
517 : : {
518 [ + + ]: 12 : if ((*ptr)->numlevel == 0)
7924 519 : 1 : return NULL;
7893 520 [ + + ]: 11 : else if ((*ptr)->numlevel == 1)
521 : 2 : num = 0;
522 : : else
523 : : {
7924 524 : 9 : l1 = LTREE_FIRST(*a);
525 : 9 : l2 = LTREE_FIRST(*ptr);
2102 tgl@sss.pgh.pa.us 526 : 9 : tmp = Min(num, (*ptr)->numlevel - 1);
7893 bruce@momjian.us 527 : 9 : num = 0;
2102 tgl@sss.pgh.pa.us 528 [ + + ]: 23 : for (i = 0; i < tmp; i++)
529 : : {
530 [ + + ]: 21 : if (l1->len == l2->len &&
531 [ + + ]: 18 : memcmp(l1->name, l2->name, l1->len) == 0)
7893 bruce@momjian.us 532 : 14 : num = i + 1;
533 : : else
534 : : break;
535 : 14 : l1 = LEVEL_NEXT(l1);
536 : 14 : l2 = LEVEL_NEXT(l2);
537 : : }
538 : : }
7924 539 : 11 : ptr++;
540 : : }
541 : :
542 : : /* Now compute size of result ... */
2102 tgl@sss.pgh.pa.us 543 : 11 : reslen = LTREE_HDRSIZE;
7924 bruce@momjian.us 544 : 11 : l1 = LTREE_FIRST(*a);
7893 545 [ + + ]: 21 : for (i = 0; i < num; i++)
546 : : {
7924 547 : 10 : reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE);
7893 548 : 10 : l1 = LEVEL_NEXT(l1);
549 : : }
550 : :
551 : : /* ... and construct it by copying from *a */
2959 andres@anarazel.de 552 : 11 : res = (ltree *) palloc0(reslen);
6255 tgl@sss.pgh.pa.us 553 : 11 : SET_VARSIZE(res, reslen);
7924 bruce@momjian.us 554 : 11 : res->numlevel = num;
555 : :
556 : 11 : l1 = LTREE_FIRST(*a);
557 : 11 : l2 = LTREE_FIRST(res);
558 : :
7893 559 [ + + ]: 21 : for (i = 0; i < num; i++)
560 : : {
561 : 10 : memcpy(l2, l1, MAXALIGN(l1->len + LEVEL_HDRSIZE));
562 : 10 : l1 = LEVEL_NEXT(l1);
563 : 10 : l2 = LEVEL_NEXT(l2);
564 : : }
565 : :
7924 566 : 11 : return res;
567 : : }
568 : :
569 : : Datum
7893 570 : 6 : lca(PG_FUNCTION_ARGS)
571 : : {
572 : : int i;
573 : : ltree **a,
574 : : *res;
575 : :
576 : 6 : a = (ltree **) palloc(sizeof(ltree *) * fcinfo->nargs);
577 [ + + ]: 21 : for (i = 0; i < fcinfo->nargs; i++)
2400 tgl@sss.pgh.pa.us 578 : 15 : a[i] = PG_GETARG_LTREE_P(i);
7893 bruce@momjian.us 579 : 6 : res = lca_inner(a, (int) fcinfo->nargs);
580 [ + + ]: 21 : for (i = 0; i < fcinfo->nargs; i++)
581 [ - + ]: 15 : PG_FREE_IF_COPY(a[i], i);
7924 582 : 6 : pfree(a);
583 : :
7893 584 [ + + ]: 6 : if (res)
7924 585 : 5 : PG_RETURN_POINTER(res);
586 : : else
587 : 1 : PG_RETURN_NULL();
588 : : }
589 : :
590 : : Datum
7685 591 : 1 : text2ltree(PG_FUNCTION_ARGS)
592 : : {
5864 tgl@sss.pgh.pa.us 593 : 1 : text *in = PG_GETARG_TEXT_PP(0);
594 : : char *s;
595 : : ltree *out;
596 : :
597 : 1 : s = text_to_cstring(in);
598 : :
599 : 1 : out = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
600 : : PointerGetDatum(s)));
7685 bruce@momjian.us 601 : 1 : pfree(s);
7559 602 [ - + ]: 1 : PG_FREE_IF_COPY(in, 0);
7685 603 : 1 : PG_RETURN_POINTER(out);
604 : : }
605 : :
606 : :
607 : : Datum
608 : 1 : ltree2text(PG_FUNCTION_ARGS)
609 : : {
2400 tgl@sss.pgh.pa.us 610 : 1 : ltree *in = PG_GETARG_LTREE_P(0);
611 : : char *ptr;
612 : : int i;
613 : : ltree_level *curlevel;
614 : : text *out;
615 : :
6255 616 : 1 : out = (text *) palloc(VARSIZE(in) + VARHDRSZ);
7559 bruce@momjian.us 617 : 1 : ptr = VARDATA(out);
7685 618 : 1 : curlevel = LTREE_FIRST(in);
7559 619 [ + + ]: 6 : for (i = 0; i < in->numlevel; i++)
620 : : {
621 [ + + ]: 5 : if (i != 0)
622 : : {
7685 623 : 4 : *ptr = '.';
624 : 4 : ptr++;
625 : : }
626 : 5 : memcpy(ptr, curlevel->name, curlevel->len);
627 : 5 : ptr += curlevel->len;
628 : 5 : curlevel = LEVEL_NEXT(curlevel);
629 : : }
630 : :
6256 tgl@sss.pgh.pa.us 631 : 1 : SET_VARSIZE(out, ptr - ((char *) out));
7685 bruce@momjian.us 632 [ - + ]: 1 : PG_FREE_IF_COPY(in, 0);
633 : :
634 : 1 : PG_RETURN_POINTER(out);
635 : : }
636 : :
637 : :
638 : : /*
639 : : * ltreeparentsel - Selectivity of parent relationship for ltree data types.
640 : : *
641 : : * This function is not used anymore, if the ltree extension has been
642 : : * updated to 1.2 or later.
643 : : */
644 : : Datum
6563 bruce@momjian.us 645 :UBC 0 : ltreeparentsel(PG_FUNCTION_ARGS)
646 : : {
647 : 0 : PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
648 : 0 : Oid operator = PG_GETARG_OID(1);
649 : 0 : List *args = (List *) PG_GETARG_POINTER(2);
650 : 0 : int varRelid = PG_GETARG_INT32(3);
651 : : double selec;
652 : :
653 : : /* Use generic restriction selectivity logic, with default 0.001. */
1409 tgl@sss.pgh.pa.us 654 : 0 : selec = generic_restriction_selectivity(root, operator, InvalidOid,
655 : : args, varRelid,
656 : : 0.001);
657 : :
6563 bruce@momjian.us 658 : 0 : PG_RETURN_FLOAT8((float8) selec);
659 : : }
|