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