PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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
45/*
46 * btree-comparison function.
47 */
48int
49ltree_compare(const ltree *a, const ltree *b)
50{
53 int an = a->numlevel;
54 int bn = b->numlevel;
55
56 while (an > 0 && bn > 0)
57 {
58 int res;
59
60 res = memcmp(al->name, bl->name, Min(al->len, bl->len));
61 if (res == 0)
62 {
63 if (al->len != bl->len)
64 return (int) al->len - (int) bl->len;
65 }
66 else
67 return res;
68
69 an--;
70 bn--;
71 al = LEVEL_NEXT(al);
72 bl = LEVEL_NEXT(bl);
73 }
74
75 return a->numlevel - b->numlevel;
76}
77
78/*
79 * Returns a "distance" between a and b. If a < b, the distance is negative,
80 * consistent with the ltree_compare() ordering.
81 */
82float
84{
87 int an = a->numlevel;
88 int bn = b->numlevel;
89
90 while (an > 0 && bn > 0)
91 {
92 int res;
93
94 res = memcmp(al->name, bl->name, Min(al->len, bl->len));
95 if (res == 0)
96 {
97 if (al->len != bl->len)
98 return (float) (al->len - bl->len) * 10.0 * (an + 1);
99 }
100 else
101 {
102 if (res < 0)
103 return -1.0 * 10.0 * (an + 1);
104 else
105 return 1.0 * 10.0 * (an + 1);
106 }
107
108 an--;
109 bn--;
110 al = LEVEL_NEXT(al);
111 bl = LEVEL_NEXT(bl);
112 }
113
114 return ((float) (a->numlevel - b->numlevel)) * 10.0 * (an + 1);
115}
116
117#define RUNCMP \
118ltree *a = PG_GETARG_LTREE_P(0); \
119ltree *b = PG_GETARG_LTREE_P(1); \
120int res = ltree_compare(a,b); \
121PG_FREE_IF_COPY(a,0); \
122PG_FREE_IF_COPY(b,1)
123
124Datum
130
131Datum
133{
134 RUNCMP;
135 PG_RETURN_BOOL(res < 0);
136}
137
138Datum
140{
141 RUNCMP;
142 PG_RETURN_BOOL(res <= 0);
143}
144
145Datum
147{
148 RUNCMP;
149 PG_RETURN_BOOL(res == 0);
150}
151
152Datum
154{
155 RUNCMP;
156 PG_RETURN_BOOL(res >= 0);
157}
158
159Datum
161{
162 RUNCMP;
163 PG_RETURN_BOOL(res > 0);
164}
165
166Datum
168{
169 RUNCMP;
170 PG_RETURN_BOOL(res != 0);
171}
172
173/* Compute a hash for the ltree */
174Datum
176{
178 uint32 result = 1;
179 int an = a->numlevel;
181
182 while (an > 0)
183 {
184 uint32 levelHash = DatumGetUInt32(hash_any((unsigned char *) al->name, al->len));
185
186 /*
187 * Combine hash values of successive elements by multiplying the
188 * current value by 31 and adding on the new element's hash value.
189 *
190 * This method is borrowed from hash_array(), which see for further
191 * commentary.
192 */
193 result = (result << 5) - result + levelHash;
194
195 an--;
196 al = LEVEL_NEXT(al);
197 }
198
199 PG_FREE_IF_COPY(a, 0);
201}
202
203/* Compute an extended hash for the ltree */
204Datum
206{
208 const uint64 seed = PG_GETARG_INT64(1);
209 uint64 result = 1;
210 int an = a->numlevel;
212
213 /*
214 * If the path has length zero, return 1 + seed to ensure that the low 32
215 * bits of the result match hash_ltree when the seed is 0, as required by
216 * the hash index support functions, but to also return a different value
217 * when there is a seed.
218 */
219 if (an == 0)
220 {
221 PG_FREE_IF_COPY(a, 0);
222 PG_RETURN_UINT64(result + seed);
223 }
224
225 while (an > 0)
226 {
227 uint64 levelHash = DatumGetUInt64(hash_any_extended((unsigned char *) al->name, al->len, seed));
228
229 result = (result << 5) - result + levelHash;
230
231 an--;
232 al = LEVEL_NEXT(al);
233 }
234
235 PG_FREE_IF_COPY(a, 0);
237}
238
239Datum
241{
243 int res = a->numlevel;
244
245 PG_FREE_IF_COPY(a, 0);
246 PG_RETURN_INT32(res);
247}
248
249bool
250inner_isparent(const ltree *c, const ltree *p)
251{
254 int pn = p->numlevel;
255
256 if (pn > c->numlevel)
257 return false;
258
259 while (pn > 0)
260 {
261 if (cl->len != pl->len)
262 return false;
263 if (memcmp(cl->name, pl->name, cl->len) != 0)
264 return false;
265
266 pn--;
267 cl = LEVEL_NEXT(cl);
268 pl = LEVEL_NEXT(pl);
269 }
270 return true;
271}
272
273Datum
275{
277 ltree *p = PG_GETARG_LTREE_P(0);
278 bool res = inner_isparent(c, p);
279
280 PG_FREE_IF_COPY(c, 1);
281 PG_FREE_IF_COPY(p, 0);
282 PG_RETURN_BOOL(res);
283}
284
285Datum
287{
289 ltree *p = PG_GETARG_LTREE_P(1);
290 bool res = inner_isparent(c, p);
291
292 PG_FREE_IF_COPY(c, 0);
293 PG_FREE_IF_COPY(p, 1);
294 PG_RETURN_BOOL(res);
295}
296
297
298static ltree *
300{
301 char *start = NULL,
302 *end = NULL;
303 ltree_level *ptr = LTREE_FIRST(t);
304 ltree *res;
305 int i;
306
310 errmsg("invalid positions")));
311
312 if (endpos > t->numlevel)
313 endpos = t->numlevel;
314
315 start = end = (char *) ptr;
316 for (i = 0; i < endpos; i++)
317 {
318 if (i == startpos)
319 start = (char *) ptr;
320 if (i == endpos - 1)
321 {
322 end = (char *) LEVEL_NEXT(ptr);
323 break;
324 }
325 ptr = LEVEL_NEXT(ptr);
326 }
327
328 res = (ltree *) palloc0(LTREE_HDRSIZE + (end - start));
329 SET_VARSIZE(res, LTREE_HDRSIZE + (end - start));
330 res->numlevel = endpos - startpos;
331
332 memcpy(LTREE_FIRST(res), start, end - start);
333
334 return res;
335}
336
337Datum
346
347Datum
349{
350 ltree *t = PG_GETARG_LTREE_P(0);
352 int32 len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
353 int32 end;
354 ltree *res;
355
356 if (start < 0)
357 start = t->numlevel + start;
358
359 if (len < 0)
360 end = t->numlevel + len;
361 else if (len == 0)
362 end = (fcinfo->nargs == 3) ? start : LTREE_MAX_LEVELS;
363 else
364 end = start + len;
365
366 res = inner_subltree(t, start, end);
367
368 PG_FREE_IF_COPY(t, 0);
370}
371
372static ltree *
374{
375 ltree *r;
376 int numlevel = (int) a->numlevel + b->numlevel;
377
378 if (numlevel > LTREE_MAX_LEVELS)
381 errmsg("number of ltree levels (%d) exceeds the maximum allowed (%d)",
382 numlevel, LTREE_MAX_LEVELS)));
383
386 r->numlevel = (uint16) numlevel;
387
389 memcpy(((char *) LTREE_FIRST(r)) + VARSIZE(a) - LTREE_HDRSIZE,
390 LTREE_FIRST(b),
392 return r;
393}
394
395Datum
397{
400 ltree *r;
401
402 r = ltree_concat(a, b);
403 PG_FREE_IF_COPY(a, 0);
404 PG_FREE_IF_COPY(b, 1);
406}
407
408Datum
410{
413 char *s;
414 ltree *r,
415 *tmp;
416
417 s = text_to_cstring(b);
418
420 PointerGetDatum(s)));
421
422 pfree(s);
423
424 r = ltree_concat(a, tmp);
425
426 pfree(tmp);
427
428 PG_FREE_IF_COPY(a, 0);
429 PG_FREE_IF_COPY(b, 1);
431}
432
433Datum
435{
438 int start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
439 int i,
440 j;
441 ltree_level *startptr,
442 *aptr,
443 *bptr;
444 bool found = false;
445
446 if (start < 0)
447 {
448 if (-start >= a->numlevel)
449 start = 0;
450 else
451 start = (int) (a->numlevel) + start;
452 }
453
454 if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0)
455 {
456 PG_FREE_IF_COPY(a, 0);
457 PG_FREE_IF_COPY(b, 1);
458 PG_RETURN_INT32(-1);
459 }
460
461 startptr = LTREE_FIRST(a);
462 for (i = 0; i <= a->numlevel - b->numlevel; i++)
463 {
464 if (i >= start)
465 {
466 aptr = startptr;
467 bptr = LTREE_FIRST(b);
468 for (j = 0; j < b->numlevel; j++)
469 {
470 if (!(aptr->len == bptr->len && memcmp(aptr->name, bptr->name, aptr->len) == 0))
471 break;
474 }
475
476 if (j == b->numlevel)
477 {
478 found = true;
479 break;
480 }
481 }
482 startptr = LEVEL_NEXT(startptr);
483 }
484
485 if (!found)
486 i = -1;
487
488 PG_FREE_IF_COPY(a, 0);
489 PG_FREE_IF_COPY(b, 1);
491}
492
493Datum
495{
498 char *s;
499 ltree *r,
500 *tmp;
501
502 s = text_to_cstring(b);
503
505 PointerGetDatum(s)));
506
507 pfree(s);
508
509 r = ltree_concat(tmp, a);
510
511 pfree(tmp);
512
513 PG_FREE_IF_COPY(a, 1);
514 PG_FREE_IF_COPY(b, 0);
516}
517
518/*
519 * Common code for variants of lca(), find longest common ancestor of inputs
520 *
521 * Returns NULL if there is no common ancestor, ie, the longest common
522 * prefix is empty.
523 */
524ltree *
526{
527 int tmp,
528 num,
529 i,
530 reslen;
531 ltree **ptr;
532 ltree_level *l1,
533 *l2;
534 ltree *res;
535
536 if (len <= 0)
537 return NULL; /* no inputs? */
538 if ((*a)->numlevel == 0)
539 return NULL; /* any empty input means NULL result */
540
541 /* num is the length of the longest common ancestor so far */
542 num = (*a)->numlevel - 1;
543
544 /* Compare each additional input to *a */
545 ptr = a + 1;
546 while (ptr - a < len)
547 {
548 if ((*ptr)->numlevel == 0)
549 return NULL;
550 else if ((*ptr)->numlevel == 1)
551 num = 0;
552 else
553 {
554 l1 = LTREE_FIRST(*a);
555 l2 = LTREE_FIRST(*ptr);
556 tmp = Min(num, (*ptr)->numlevel - 1);
557 num = 0;
558 for (i = 0; i < tmp; i++)
559 {
560 if (l1->len == l2->len &&
561 memcmp(l1->name, l2->name, l1->len) == 0)
562 num = i + 1;
563 else
564 break;
565 l1 = LEVEL_NEXT(l1);
566 l2 = LEVEL_NEXT(l2);
567 }
568 }
569 ptr++;
570 }
571
572 /* Now compute size of result ... */
573 reslen = LTREE_HDRSIZE;
574 l1 = LTREE_FIRST(*a);
575 for (i = 0; i < num; i++)
576 {
577 reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE);
578 l1 = LEVEL_NEXT(l1);
579 }
580
581 /* ... and construct it by copying from *a */
582 res = (ltree *) palloc0(reslen);
583 SET_VARSIZE(res, reslen);
584 res->numlevel = num;
585
586 l1 = LTREE_FIRST(*a);
587 l2 = LTREE_FIRST(res);
588
589 for (i = 0; i < num; i++)
590 {
591 memcpy(l2, l1, MAXALIGN(l1->len + LEVEL_HDRSIZE));
592 l1 = LEVEL_NEXT(l1);
593 l2 = LEVEL_NEXT(l2);
594 }
595
596 return res;
597}
598
599Datum
601{
602 int i;
603 ltree **a,
604 *res;
605
606 a = palloc_array(ltree *, fcinfo->nargs);
607 for (i = 0; i < fcinfo->nargs; i++)
609 res = lca_inner(a, (int) fcinfo->nargs);
610 for (i = 0; i < fcinfo->nargs; i++)
611 PG_FREE_IF_COPY(a[i], i);
612 pfree(a);
613
614 if (res)
616 else
618}
619
620Datum
622{
623 text *in = PG_GETARG_TEXT_PP(0);
624 char *s;
625 ltree *out;
626
627 s = text_to_cstring(in);
628
630 PointerGetDatum(s)));
631 pfree(s);
632 PG_FREE_IF_COPY(in, 0);
634}
635
636
637Datum
639{
640 ltree *in = PG_GETARG_LTREE_P(0);
641 char *ptr;
642 int i;
644 text *out;
645
646 out = (text *) palloc(VARSIZE(in) + VARHDRSZ);
647 ptr = VARDATA(out);
648 curlevel = LTREE_FIRST(in);
649 for (i = 0; i < in->numlevel; i++)
650 {
651 if (i != 0)
652 {
653 *ptr = '.';
654 ptr++;
655 }
656 memcpy(ptr, curlevel->name, curlevel->len);
657 ptr += curlevel->len;
659 }
660
661 SET_VARSIZE(out, ptr - ((char *) out));
662 PG_FREE_IF_COPY(in, 0);
663
665}
666
667
668/*
669 * ltreeparentsel - Selectivity of parent relationship for ltree data types.
670 *
671 * This function is not used anymore, if the ltree extension has been
672 * updated to 1.2 or later.
673 */
674Datum
676{
678 Oid operator = PG_GETARG_OID(1);
679 List *args = (List *) PG_GETARG_POINTER(2);
680 int varRelid = PG_GETARG_INT32(3);
681 double selec;
682
683 /* Use generic restriction selectivity logic, with default 0.001. */
685 args, varRelid,
686 0.001);
687
689}
#define Min(x, y)
Definition c.h:1091
#define MAXALIGN(LEN)
Definition c.h:896
#define VARHDRSZ
Definition c.h:781
double float8
Definition c.h:714
int32_t int32
Definition c.h:620
uint64_t uint64
Definition c.h:625
uint16_t uint16
Definition c.h:623
uint32_t uint32
Definition c.h:624
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_array(type, count)
Definition fe_memutils.h:91
#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:356
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define PG_RETURN_FLOAT8(x)
Definition fmgr.h:369
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:688
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_GETARG_INT64(n)
Definition fmgr.h:284
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_RETURN_UINT64(x)
Definition fmgr.h:371
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
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
#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:220
PGDLLEXPORT Datum ltree_in(PG_FUNCTION_ARGS)
Definition ltree_io.c:175
Datum lca(PG_FUNCTION_ARGS)
Definition ltree_op.c:600
bool inner_isparent(const ltree *c, const ltree *p)
Definition ltree_op.c:250
Datum hash_ltree_extended(PG_FUNCTION_ARGS)
Definition ltree_op.c:205
Datum ltree_index(PG_FUNCTION_ARGS)
Definition ltree_op.c:434
Datum ltree_cmp(PG_FUNCTION_ARGS)
Definition ltree_op.c:125
Datum subltree(PG_FUNCTION_ARGS)
Definition ltree_op.c:338
Datum ltree_gt(PG_FUNCTION_ARGS)
Definition ltree_op.c:160
static ltree * ltree_concat(ltree *a, ltree *b)
Definition ltree_op.c:373
ltree * lca_inner(ltree **a, int len)
Definition ltree_op.c:525
Datum nlevel(PG_FUNCTION_ARGS)
Definition ltree_op.c:240
Datum ltree_textadd(PG_FUNCTION_ARGS)
Definition ltree_op.c:494
float ltree_compare_distance(const ltree *a, const ltree *b)
Definition ltree_op.c:83
int ltree_compare(const ltree *a, const ltree *b)
Definition ltree_op.c:49
Datum ltreeparentsel(PG_FUNCTION_ARGS)
Definition ltree_op.c:675
Datum ltree_eq(PG_FUNCTION_ARGS)
Definition ltree_op.c:146
Datum ltree_ge(PG_FUNCTION_ARGS)
Definition ltree_op.c:153
Datum ltree_isparent(PG_FUNCTION_ARGS)
Definition ltree_op.c:274
static ltree * inner_subltree(ltree *t, int32 startpos, int32 endpos)
Definition ltree_op.c:299
Datum ltree_addtext(PG_FUNCTION_ARGS)
Definition ltree_op.c:409
Datum ltree_ne(PG_FUNCTION_ARGS)
Definition ltree_op.c:167
#define RUNCMP
Definition ltree_op.c:117
Datum text2ltree(PG_FUNCTION_ARGS)
Definition ltree_op.c:621
Datum ltree_risparent(PG_FUNCTION_ARGS)
Definition ltree_op.c:286
Datum ltree2text(PG_FUNCTION_ARGS)
Definition ltree_op.c:638
Datum hash_ltree(PG_FUNCTION_ARGS)
Definition ltree_op.c:175
Datum ltree_le(PG_FUNCTION_ARGS)
Definition ltree_op.c:139
Datum ltree_lt(PG_FUNCTION_ARGS)
Definition ltree_op.c:132
Datum ltree_addltree(PG_FUNCTION_ARGS)
Definition ltree_op.c:396
Datum subpath(PG_FUNCTION_ARGS)
Definition ltree_op.c:348
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
void * palloc(Size size)
Definition mcxt.c:1390
static char * errmsg
const void size_t len
static XLogRecPtr endpos
static XLogRecPtr startpos
static uint32 DatumGetUInt32(Datum X)
Definition postgres.h:222
static uint64 DatumGetUInt64(Datum X)
Definition postgres.h:436
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
char * c
static int fb(int x)
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:987
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:776
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:217
const char * name