PostgreSQL Source Code git master
ltree_op.c
Go to the documentation of this file.
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
17 .name = "ltree",
18 .version = PG_VERSION
19);
20
21/* compare functions */
44
45int
46ltree_compare(const ltree *a, const ltree *b)
47{
50 int an = a->numlevel;
51 int bn = b->numlevel;
52
53 while (an > 0 && bn > 0)
54 {
55 int res;
56
57 if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
58 {
59 if (al->len != bl->len)
60 return (al->len - bl->len) * 10 * (an + 1);
61 }
62 else
63 {
64 if (res < 0)
65 res = -1;
66 else
67 res = 1;
68 return res * 10 * (an + 1);
69 }
70
71 an--;
72 bn--;
73 al = LEVEL_NEXT(al);
74 bl = LEVEL_NEXT(bl);
75 }
76
77 return (a->numlevel - b->numlevel) * 10 * (an + 1);
78}
79
80#define RUNCMP \
81ltree *a = PG_GETARG_LTREE_P(0); \
82ltree *b = PG_GETARG_LTREE_P(1); \
83int res = ltree_compare(a,b); \
84PG_FREE_IF_COPY(a,0); \
85PG_FREE_IF_COPY(b,1)
86
89{
90 RUNCMP;
91 PG_RETURN_INT32(res);
92}
93
96{
97 RUNCMP;
98 PG_RETURN_BOOL(res < 0);
99}
100
101Datum
103{
104 RUNCMP;
105 PG_RETURN_BOOL(res <= 0);
106}
107
108Datum
110{
111 RUNCMP;
112 PG_RETURN_BOOL(res == 0);
113}
114
115Datum
117{
118 RUNCMP;
119 PG_RETURN_BOOL(res >= 0);
120}
121
122Datum
124{
125 RUNCMP;
126 PG_RETURN_BOOL(res > 0);
127}
128
129Datum
131{
132 RUNCMP;
133 PG_RETURN_BOOL(res != 0);
134}
135
136/* Compute a hash for the ltree */
137Datum
139{
141 uint32 result = 1;
142 int an = a->numlevel;
144
145 while (an > 0)
146 {
147 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 result = (result << 5) - result + levelHash;
157
158 an--;
159 al = LEVEL_NEXT(al);
160 }
161
162 PG_FREE_IF_COPY(a, 0);
163 PG_RETURN_UINT32(result);
164}
165
166/* Compute an extended hash for the ltree */
167Datum
169{
171 const uint64 seed = PG_GETARG_INT64(1);
172 uint64 result = 1;
173 int an = a->numlevel;
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 if (an == 0)
183 {
184 PG_FREE_IF_COPY(a, 0);
185 PG_RETURN_UINT64(result + seed);
186 }
187
188 while (an > 0)
189 {
190 uint64 levelHash = DatumGetUInt64(hash_any_extended((unsigned char *) al->name, al->len, seed));
191
192 result = (result << 5) - result + levelHash;
193
194 an--;
195 al = LEVEL_NEXT(al);
196 }
197
198 PG_FREE_IF_COPY(a, 0);
199 PG_RETURN_UINT64(result);
200}
201
202Datum
204{
206 int res = a->numlevel;
207
208 PG_FREE_IF_COPY(a, 0);
209 PG_RETURN_INT32(res);
210}
211
212bool
213inner_isparent(const ltree *c, const ltree *p)
214{
216 ltree_level *pl = LTREE_FIRST(p);
217 int pn = p->numlevel;
218
219 if (pn > c->numlevel)
220 return false;
221
222 while (pn > 0)
223 {
224 if (cl->len != pl->len)
225 return false;
226 if (memcmp(cl->name, pl->name, cl->len) != 0)
227 return false;
228
229 pn--;
230 cl = LEVEL_NEXT(cl);
231 pl = LEVEL_NEXT(pl);
232 }
233 return true;
234}
235
236Datum
238{
240 ltree *p = PG_GETARG_LTREE_P(0);
241 bool res = inner_isparent(c, p);
242
243 PG_FREE_IF_COPY(c, 1);
244 PG_FREE_IF_COPY(p, 0);
245 PG_RETURN_BOOL(res);
246}
247
248Datum
250{
252 ltree *p = PG_GETARG_LTREE_P(1);
253 bool res = inner_isparent(c, p);
254
255 PG_FREE_IF_COPY(c, 0);
256 PG_FREE_IF_COPY(p, 1);
257 PG_RETURN_BOOL(res);
258}
259
260
261static ltree *
263{
264 char *start = NULL,
265 *end = NULL;
266 ltree_level *ptr = LTREE_FIRST(t);
267 ltree *res;
268 int i;
269
270 if (startpos < 0 || endpos < 0 || startpos >= t->numlevel || startpos > endpos)
272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
273 errmsg("invalid positions")));
274
275 if (endpos > t->numlevel)
276 endpos = t->numlevel;
277
278 start = end = (char *) ptr;
279 for (i = 0; i < endpos; i++)
280 {
281 if (i == startpos)
282 start = (char *) ptr;
283 if (i == endpos - 1)
284 {
285 end = (char *) LEVEL_NEXT(ptr);
286 break;
287 }
288 ptr = LEVEL_NEXT(ptr);
289 }
290
291 res = (ltree *) palloc0(LTREE_HDRSIZE + (end - start));
292 SET_VARSIZE(res, LTREE_HDRSIZE + (end - start));
293 res->numlevel = endpos - startpos;
294
295 memcpy(LTREE_FIRST(res), start, end - start);
296
297 return res;
298}
299
300Datum
302{
303 ltree *t = PG_GETARG_LTREE_P(0);
305
306 PG_FREE_IF_COPY(t, 0);
308}
309
310Datum
312{
313 ltree *t = PG_GETARG_LTREE_P(0);
315 int32 len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
316 int32 end;
317 ltree *res;
318
319 if (start < 0)
320 start = t->numlevel + start;
321
322 if (len < 0)
323 end = t->numlevel + len;
324 else if (len == 0)
325 end = (fcinfo->nargs == 3) ? start : LTREE_MAX_LEVELS;
326 else
327 end = start + len;
328
329 res = inner_subltree(t, start, end);
330
331 PG_FREE_IF_COPY(t, 0);
333}
334
335static ltree *
337{
338 ltree *r;
339 int numlevel = (int) a->numlevel + b->numlevel;
340
341 if (numlevel > LTREE_MAX_LEVELS)
343 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
344 errmsg("number of ltree levels (%d) exceeds the maximum allowed (%d)",
345 numlevel, LTREE_MAX_LEVELS)));
346
349 r->numlevel = (uint16) numlevel;
350
352 memcpy(((char *) LTREE_FIRST(r)) + VARSIZE(a) - LTREE_HDRSIZE,
353 LTREE_FIRST(b),
355 return r;
356}
357
358Datum
360{
363 ltree *r;
364
365 r = ltree_concat(a, b);
366 PG_FREE_IF_COPY(a, 0);
367 PG_FREE_IF_COPY(b, 1);
369}
370
371Datum
373{
376 char *s;
377 ltree *r,
378 *tmp;
379
380 s = text_to_cstring(b);
381
383 PointerGetDatum(s)));
384
385 pfree(s);
386
387 r = ltree_concat(a, tmp);
388
389 pfree(tmp);
390
391 PG_FREE_IF_COPY(a, 0);
392 PG_FREE_IF_COPY(b, 1);
394}
395
396Datum
398{
401 int start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
402 int i,
403 j;
404 ltree_level *startptr,
405 *aptr,
406 *bptr;
407 bool found = false;
408
409 if (start < 0)
410 {
411 if (-start >= a->numlevel)
412 start = 0;
413 else
414 start = (int) (a->numlevel) + start;
415 }
416
417 if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0)
418 {
419 PG_FREE_IF_COPY(a, 0);
420 PG_FREE_IF_COPY(b, 1);
421 PG_RETURN_INT32(-1);
422 }
423
424 startptr = LTREE_FIRST(a);
425 for (i = 0; i <= a->numlevel - b->numlevel; i++)
426 {
427 if (i >= start)
428 {
429 aptr = startptr;
430 bptr = LTREE_FIRST(b);
431 for (j = 0; j < b->numlevel; j++)
432 {
433 if (!(aptr->len == bptr->len && memcmp(aptr->name, bptr->name, aptr->len) == 0))
434 break;
435 aptr = LEVEL_NEXT(aptr);
436 bptr = LEVEL_NEXT(bptr);
437 }
438
439 if (j == b->numlevel)
440 {
441 found = true;
442 break;
443 }
444 }
445 startptr = LEVEL_NEXT(startptr);
446 }
447
448 if (!found)
449 i = -1;
450
451 PG_FREE_IF_COPY(a, 0);
452 PG_FREE_IF_COPY(b, 1);
454}
455
456Datum
458{
461 char *s;
462 ltree *r,
463 *tmp;
464
465 s = text_to_cstring(b);
466
468 PointerGetDatum(s)));
469
470 pfree(s);
471
472 r = ltree_concat(tmp, a);
473
474 pfree(tmp);
475
476 PG_FREE_IF_COPY(a, 1);
477 PG_FREE_IF_COPY(b, 0);
479}
480
481/*
482 * Common code for variants of lca(), find longest common ancestor of inputs
483 *
484 * Returns NULL if there is no common ancestor, ie, the longest common
485 * prefix is empty.
486 */
487ltree *
489{
490 int tmp,
491 num,
492 i,
493 reslen;
494 ltree **ptr;
495 ltree_level *l1,
496 *l2;
497 ltree *res;
498
499 if (len <= 0)
500 return NULL; /* no inputs? */
501 if ((*a)->numlevel == 0)
502 return NULL; /* any empty input means NULL result */
503
504 /* num is the length of the longest common ancestor so far */
505 num = (*a)->numlevel - 1;
506
507 /* Compare each additional input to *a */
508 ptr = a + 1;
509 while (ptr - a < len)
510 {
511 if ((*ptr)->numlevel == 0)
512 return NULL;
513 else if ((*ptr)->numlevel == 1)
514 num = 0;
515 else
516 {
517 l1 = LTREE_FIRST(*a);
518 l2 = LTREE_FIRST(*ptr);
519 tmp = Min(num, (*ptr)->numlevel - 1);
520 num = 0;
521 for (i = 0; i < tmp; i++)
522 {
523 if (l1->len == l2->len &&
524 memcmp(l1->name, l2->name, l1->len) == 0)
525 num = i + 1;
526 else
527 break;
528 l1 = LEVEL_NEXT(l1);
529 l2 = LEVEL_NEXT(l2);
530 }
531 }
532 ptr++;
533 }
534
535 /* Now compute size of result ... */
536 reslen = LTREE_HDRSIZE;
537 l1 = LTREE_FIRST(*a);
538 for (i = 0; i < num; i++)
539 {
540 reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE);
541 l1 = LEVEL_NEXT(l1);
542 }
543
544 /* ... and construct it by copying from *a */
545 res = (ltree *) palloc0(reslen);
546 SET_VARSIZE(res, reslen);
547 res->numlevel = num;
548
549 l1 = LTREE_FIRST(*a);
550 l2 = LTREE_FIRST(res);
551
552 for (i = 0; i < num; i++)
553 {
554 memcpy(l2, l1, MAXALIGN(l1->len + LEVEL_HDRSIZE));
555 l1 = LEVEL_NEXT(l1);
556 l2 = LEVEL_NEXT(l2);
557 }
558
559 return res;
560}
561
562Datum
564{
565 int i;
566 ltree **a,
567 *res;
568
569 a = (ltree **) palloc(sizeof(ltree *) * fcinfo->nargs);
570 for (i = 0; i < fcinfo->nargs; i++)
572 res = lca_inner(a, (int) fcinfo->nargs);
573 for (i = 0; i < fcinfo->nargs; i++)
574 PG_FREE_IF_COPY(a[i], i);
575 pfree(a);
576
577 if (res)
579 else
581}
582
583Datum
585{
586 text *in = PG_GETARG_TEXT_PP(0);
587 char *s;
588 ltree *out;
589
590 s = text_to_cstring(in);
591
593 PointerGetDatum(s)));
594 pfree(s);
595 PG_FREE_IF_COPY(in, 0);
597}
598
599
600Datum
602{
603 ltree *in = PG_GETARG_LTREE_P(0);
604 char *ptr;
605 int i;
606 ltree_level *curlevel;
607 text *out;
608
609 out = (text *) palloc(VARSIZE(in) + VARHDRSZ);
610 ptr = VARDATA(out);
611 curlevel = LTREE_FIRST(in);
612 for (i = 0; i < in->numlevel; i++)
613 {
614 if (i != 0)
615 {
616 *ptr = '.';
617 ptr++;
618 }
619 memcpy(ptr, curlevel->name, curlevel->len);
620 ptr += curlevel->len;
621 curlevel = LEVEL_NEXT(curlevel);
622 }
623
624 SET_VARSIZE(out, ptr - ((char *) out));
625 PG_FREE_IF_COPY(in, 0);
626
628}
629
630
631/*
632 * ltreeparentsel - Selectivity of parent relationship for ltree data types.
633 *
634 * This function is not used anymore, if the ltree extension has been
635 * updated to 1.2 or later.
636 */
637Datum
639{
641 Oid operator = PG_GETARG_OID(1);
643 int varRelid = PG_GETARG_INT32(3);
644 double selec;
645
646 /* Use generic restriction selectivity logic, with default 0.001. */
648 args, varRelid,
649 0.001);
650
651 PG_RETURN_FLOAT8((float8) selec);
652}
#define Min(x, y)
Definition: c.h:1008
#define MAXALIGN(LEN)
Definition: c.h:815
#define VARHDRSZ
Definition: c.h:702
double float8
Definition: c.h:640
int32_t int32
Definition: c.h:539
uint64_t uint64
Definition: c.h:544
uint16_t uint16
Definition: c.h:542
uint32_t uint32
Definition: c.h:543
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_UINT32(x)
Definition: fmgr.h:355
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_FLOAT8(x)
Definition: fmgr.h:367
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_UINT64(x)
Definition: fmgr.h:369
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.h:37
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
return str start
int b
Definition: isn.c:74
int a
Definition: isn.c:73
int j
Definition: isn.c:78
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
#define LEVEL_HDRSIZE
Definition: ltree.h:39
#define LTREE_MAX_LEVELS
Definition: ltree.h:52
#define LTREE_FIRST(x)
Definition: ltree.h:51
#define LEVEL_NEXT(x)
Definition: ltree.h:40
#define LTREE_HDRSIZE
Definition: ltree.h:50
#define PG_GETARG_LTREE_P(n)
Definition: ltree.h:218
PGDLLEXPORT Datum ltree_in(PG_FUNCTION_ARGS)
Definition: ltree_io.c:174
Datum lca(PG_FUNCTION_ARGS)
Definition: ltree_op.c:563
bool inner_isparent(const ltree *c, const ltree *p)
Definition: ltree_op.c:213
Datum hash_ltree_extended(PG_FUNCTION_ARGS)
Definition: ltree_op.c:168
Datum ltree_index(PG_FUNCTION_ARGS)
Definition: ltree_op.c:397
Datum ltree_cmp(PG_FUNCTION_ARGS)
Definition: ltree_op.c:88
Datum subltree(PG_FUNCTION_ARGS)
Definition: ltree_op.c:301
PG_FUNCTION_INFO_V1(ltree_cmp)
Datum ltree_gt(PG_FUNCTION_ARGS)
Definition: ltree_op.c:123
static ltree * ltree_concat(ltree *a, ltree *b)
Definition: ltree_op.c:336
ltree * lca_inner(ltree **a, int len)
Definition: ltree_op.c:488
PG_MODULE_MAGIC_EXT(.name="ltree",.version=PG_VERSION)
Datum nlevel(PG_FUNCTION_ARGS)
Definition: ltree_op.c:203
Datum ltree_textadd(PG_FUNCTION_ARGS)
Definition: ltree_op.c:457
int ltree_compare(const ltree *a, const ltree *b)
Definition: ltree_op.c:46
Datum ltreeparentsel(PG_FUNCTION_ARGS)
Definition: ltree_op.c:638
Datum ltree_eq(PG_FUNCTION_ARGS)
Definition: ltree_op.c:109
Datum ltree_ge(PG_FUNCTION_ARGS)
Definition: ltree_op.c:116
Datum ltree_isparent(PG_FUNCTION_ARGS)
Definition: ltree_op.c:237
static ltree * inner_subltree(ltree *t, int32 startpos, int32 endpos)
Definition: ltree_op.c:262
Datum ltree_addtext(PG_FUNCTION_ARGS)
Definition: ltree_op.c:372
Datum ltree_ne(PG_FUNCTION_ARGS)
Definition: ltree_op.c:130
#define RUNCMP
Definition: ltree_op.c:80
Datum text2ltree(PG_FUNCTION_ARGS)
Definition: ltree_op.c:584
Datum ltree_risparent(PG_FUNCTION_ARGS)
Definition: ltree_op.c:249
Datum ltree2text(PG_FUNCTION_ARGS)
Definition: ltree_op.c:601
Datum hash_ltree(PG_FUNCTION_ARGS)
Definition: ltree_op.c:138
Datum ltree_le(PG_FUNCTION_ARGS)
Definition: ltree_op.c:102
Datum ltree_lt(PG_FUNCTION_ARGS)
Definition: ltree_op.c:95
Datum ltree_addltree(PG_FUNCTION_ARGS)
Definition: ltree_op.c:359
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:311
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
void * palloc(Size size)
Definition: mcxt.c:1365
const void size_t len
static XLogRecPtr endpos
Definition: pg_receivewal.c:56
static XLogRecPtr startpos
static uint32 DatumGetUInt32(Datum X)
Definition: postgres.h:232
static uint64 DatumGetUInt64(Datum X)
Definition: postgres.h:413
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
char * c
tree ctl root
Definition: radixtree.h:1857
double generic_restriction_selectivity(PlannerInfo *root, Oid oproid, Oid collation, List *args, int varRelid, double default_selectivity)
Definition: selfuncs.c:984
Definition: pg_list.h:54
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:36
uint16 len
Definition: ltree.h:35
Definition: ltree.h:43
uint16 numlevel
Definition: ltree.h:45
Definition: c.h:697
static Size VARSIZE(const void *PTR)
Definition: varatt.h:298
static char * VARDATA(const void *PTR)
Definition: varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition: varatt.h:432
char * text_to_cstring(const text *t)
Definition: varlena.c:214
const char * name