LCOV - code coverage report
Current view: top level - contrib/ltree - ltree_op.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 293 317 92.4 %
Date: 2025-04-02 00:15:10 Functions: 47 50 94.0 %
Legend: Lines: hit not hit

          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             : 
      16           6 : PG_MODULE_MAGIC_EXT(
      17             :                     .name = "ltree",
      18             :                     .version = PG_VERSION
      19             : );
      20             : 
      21             : /* compare functions */
      22           6 : PG_FUNCTION_INFO_V1(ltree_cmp);
      23           6 : PG_FUNCTION_INFO_V1(ltree_lt);
      24           6 : PG_FUNCTION_INFO_V1(ltree_le);
      25           6 : PG_FUNCTION_INFO_V1(ltree_eq);
      26           4 : PG_FUNCTION_INFO_V1(ltree_ne);
      27           6 : PG_FUNCTION_INFO_V1(ltree_ge);
      28           6 : PG_FUNCTION_INFO_V1(ltree_gt);
      29           6 : PG_FUNCTION_INFO_V1(hash_ltree);
      30           6 : PG_FUNCTION_INFO_V1(hash_ltree_extended);
      31           6 : PG_FUNCTION_INFO_V1(nlevel);
      32           6 : PG_FUNCTION_INFO_V1(ltree_isparent);
      33           6 : PG_FUNCTION_INFO_V1(ltree_risparent);
      34           6 : PG_FUNCTION_INFO_V1(subltree);
      35          12 : PG_FUNCTION_INFO_V1(subpath);
      36          12 : PG_FUNCTION_INFO_V1(ltree_index);
      37           6 : PG_FUNCTION_INFO_V1(ltree_addltree);
      38           6 : PG_FUNCTION_INFO_V1(ltree_addtext);
      39           4 : PG_FUNCTION_INFO_V1(ltree_textadd);
      40          32 : PG_FUNCTION_INFO_V1(lca);
      41           6 : PG_FUNCTION_INFO_V1(ltree2text);
      42           6 : PG_FUNCTION_INFO_V1(text2ltree);
      43           4 : PG_FUNCTION_INFO_V1(ltreeparentsel);
      44             : 
      45             : int
      46      277218 : ltree_compare(const ltree *a, const ltree *b)
      47             : {
      48      277218 :     ltree_level *al = LTREE_FIRST(a);
      49      277218 :     ltree_level *bl = LTREE_FIRST(b);
      50      277218 :     int         an = a->numlevel;
      51      277218 :     int         bn = b->numlevel;
      52             : 
      53      473406 :     while (an > 0 && bn > 0)
      54             :     {
      55             :         int         res;
      56             : 
      57      450076 :         if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
      58             :         {
      59      213832 :             if (al->len != bl->len)
      60       17644 :                 return (al->len - bl->len) * 10 * (an + 1);
      61             :         }
      62             :         else
      63             :         {
      64      236244 :             if (res < 0)
      65      115366 :                 res = -1;
      66             :             else
      67      120878 :                 res = 1;
      68      236244 :             return res * 10 * (an + 1);
      69             :         }
      70             : 
      71      196188 :         an--;
      72      196188 :         bn--;
      73      196188 :         al = LEVEL_NEXT(al);
      74      196188 :         bl = LEVEL_NEXT(bl);
      75             :     }
      76             : 
      77       23330 :     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      142436 : ltree_cmp(PG_FUNCTION_ARGS)
      89             : {
      90      142436 :     RUNCMP;
      91      142436 :     PG_RETURN_INT32(res);
      92             : }
      93             : 
      94             : Datum
      95        4278 : ltree_lt(PG_FUNCTION_ARGS)
      96             : {
      97        4278 :     RUNCMP;
      98        4278 :     PG_RETURN_BOOL(res < 0);
      99             : }
     100             : 
     101             : Datum
     102        4280 : ltree_le(PG_FUNCTION_ARGS)
     103             : {
     104        4280 :     RUNCMP;
     105        4280 :     PG_RETURN_BOOL(res <= 0);
     106             : }
     107             : 
     108             : Datum
     109        4032 : ltree_eq(PG_FUNCTION_ARGS)
     110             : {
     111        4032 :     RUNCMP;
     112        4032 :     PG_RETURN_BOOL(res == 0);
     113             : }
     114             : 
     115             : Datum
     116        4064 : ltree_ge(PG_FUNCTION_ARGS)
     117             : {
     118        4064 :     RUNCMP;
     119        4064 :     PG_RETURN_BOOL(res >= 0);
     120             : }
     121             : 
     122             : Datum
     123        4064 : ltree_gt(PG_FUNCTION_ARGS)
     124             : {
     125        4064 :     RUNCMP;
     126        4064 :     PG_RETURN_BOOL(res > 0);
     127             : }
     128             : 
     129             : Datum
     130           0 : ltree_ne(PG_FUNCTION_ARGS)
     131             : {
     132           0 :     RUNCMP;
     133           0 :     PG_RETURN_BOOL(res != 0);
     134             : }
     135             : 
     136             : /* Compute a hash for the ltree */
     137             : Datum
     138        6062 : hash_ltree(PG_FUNCTION_ARGS)
     139             : {
     140        6062 :     ltree      *a = PG_GETARG_LTREE_P(0);
     141        6062 :     uint32      result = 1;
     142        6062 :     int         an = a->numlevel;
     143        6062 :     ltree_level *al = LTREE_FIRST(a);
     144             : 
     145       45744 :     while (an > 0)
     146             :     {
     147       39682 :         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       39682 :         result = (result << 5) - result + levelHash;
     157             : 
     158       39682 :         an--;
     159       39682 :         al = LEVEL_NEXT(al);
     160             :     }
     161             : 
     162        6062 :     PG_FREE_IF_COPY(a, 0);
     163        6062 :     PG_RETURN_UINT32(result);
     164             : }
     165             : 
     166             : /* Compute an extended hash for the ltree */
     167             : Datum
     168          24 : hash_ltree_extended(PG_FUNCTION_ARGS)
     169             : {
     170          24 :     ltree      *a = PG_GETARG_LTREE_P(0);
     171          24 :     const uint64 seed = PG_GETARG_INT64(1);
     172          24 :     uint64      result = 1;
     173          24 :     int         an = a->numlevel;
     174          24 :     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          24 :     if (an == 0)
     183             :     {
     184           4 :         PG_FREE_IF_COPY(a, 0);
     185           4 :         PG_RETURN_UINT64(result + seed);
     186             :     }
     187             : 
     188          56 :     while (an > 0)
     189             :     {
     190          36 :         uint64      levelHash = DatumGetUInt64(hash_any_extended((unsigned char *) al->name, al->len, seed));
     191             : 
     192          36 :         result = (result << 5) - result + levelHash;
     193             : 
     194          36 :         an--;
     195          36 :         al = LEVEL_NEXT(al);
     196             :     }
     197             : 
     198          20 :     PG_FREE_IF_COPY(a, 0);
     199          20 :     PG_RETURN_UINT64(result);
     200             : }
     201             : 
     202             : Datum
     203           4 : nlevel(PG_FUNCTION_ARGS)
     204             : {
     205           4 :     ltree      *a = PG_GETARG_LTREE_P(0);
     206           4 :     int         res = a->numlevel;
     207             : 
     208           4 :     PG_FREE_IF_COPY(a, 0);
     209           4 :     PG_RETURN_INT32(res);
     210             : }
     211             : 
     212             : bool
     213       42376 : inner_isparent(const ltree *c, const ltree *p)
     214             : {
     215       42376 :     ltree_level *cl = LTREE_FIRST(c);
     216       42376 :     ltree_level *pl = LTREE_FIRST(p);
     217       42376 :     int         pn = p->numlevel;
     218             : 
     219       42376 :     if (pn > c->numlevel)
     220       20332 :         return false;
     221             : 
     222       24038 :     while (pn > 0)
     223             :     {
     224       23766 :         if (cl->len != pl->len)
     225       15920 :             return false;
     226        7846 :         if (memcmp(cl->name, pl->name, cl->len) != 0)
     227        5852 :             return false;
     228             : 
     229        1994 :         pn--;
     230        1994 :         cl = LEVEL_NEXT(cl);
     231        1994 :         pl = LEVEL_NEXT(pl);
     232             :     }
     233         272 :     return true;
     234             : }
     235             : 
     236             : Datum
     237       23076 : ltree_isparent(PG_FUNCTION_ARGS)
     238             : {
     239       23076 :     ltree      *c = PG_GETARG_LTREE_P(1);
     240       23076 :     ltree      *p = PG_GETARG_LTREE_P(0);
     241       23076 :     bool        res = inner_isparent(c, p);
     242             : 
     243       23076 :     PG_FREE_IF_COPY(c, 1);
     244       23076 :     PG_FREE_IF_COPY(p, 0);
     245       23076 :     PG_RETURN_BOOL(res);
     246             : }
     247             : 
     248             : Datum
     249       18640 : ltree_risparent(PG_FUNCTION_ARGS)
     250             : {
     251       18640 :     ltree      *c = PG_GETARG_LTREE_P(0);
     252       18640 :     ltree      *p = PG_GETARG_LTREE_P(1);
     253       18640 :     bool        res = inner_isparent(c, p);
     254             : 
     255       18640 :     PG_FREE_IF_COPY(c, 0);
     256       18640 :     PG_FREE_IF_COPY(p, 1);
     257       18640 :     PG_RETURN_BOOL(res);
     258             : }
     259             : 
     260             : 
     261             : static ltree *
     262          18 : inner_subltree(ltree *t, int32 startpos, int32 endpos)
     263             : {
     264          18 :     char       *start = NULL,
     265          18 :                *end = NULL;
     266          18 :     ltree_level *ptr = LTREE_FIRST(t);
     267             :     ltree      *res;
     268             :     int         i;
     269             : 
     270          18 :     if (startpos < 0 || endpos < 0 || startpos >= t->numlevel || startpos > endpos)
     271           0 :         ereport(ERROR,
     272             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     273             :                  errmsg("invalid positions")));
     274             : 
     275          18 :     if (endpos > t->numlevel)
     276           4 :         endpos = t->numlevel;
     277             : 
     278          18 :     start = end = (char *) ptr;
     279          38 :     for (i = 0; i < endpos; i++)
     280             :     {
     281          36 :         if (i == startpos)
     282          14 :             start = (char *) ptr;
     283          36 :         if (i == endpos - 1)
     284             :         {
     285          16 :             end = (char *) LEVEL_NEXT(ptr);
     286          16 :             break;
     287             :         }
     288          20 :         ptr = LEVEL_NEXT(ptr);
     289             :     }
     290             : 
     291          18 :     res = (ltree *) palloc0(LTREE_HDRSIZE + (end - start));
     292          18 :     SET_VARSIZE(res, LTREE_HDRSIZE + (end - start));
     293          18 :     res->numlevel = endpos - startpos;
     294             : 
     295          18 :     memcpy(LTREE_FIRST(res), start, end - start);
     296             : 
     297          18 :     return res;
     298             : }
     299             : 
     300             : Datum
     301           2 : subltree(PG_FUNCTION_ARGS)
     302             : {
     303           2 :     ltree      *t = PG_GETARG_LTREE_P(0);
     304           2 :     ltree      *res = inner_subltree(t, PG_GETARG_INT32(1), PG_GETARG_INT32(2));
     305             : 
     306           2 :     PG_FREE_IF_COPY(t, 0);
     307           2 :     PG_RETURN_POINTER(res);
     308             : }
     309             : 
     310             : Datum
     311          16 : subpath(PG_FUNCTION_ARGS)
     312             : {
     313          16 :     ltree      *t = PG_GETARG_LTREE_P(0);
     314          16 :     int32       start = PG_GETARG_INT32(1);
     315          16 :     int32       len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
     316             :     int32       end;
     317             :     ltree      *res;
     318             : 
     319          16 :     end = start + len;
     320             : 
     321          16 :     if (start < 0)
     322             :     {
     323           2 :         start = t->numlevel + start;
     324           2 :         end = start + len;
     325             :     }
     326          16 :     if (start < 0)
     327             :     {                           /* start > t->numlevel */
     328           0 :         start = t->numlevel + start;
     329           0 :         end = start + len;
     330             :     }
     331             : 
     332          16 :     if (len < 0)
     333           4 :         end = t->numlevel + len;
     334          12 :     else if (len == 0)
     335           8 :         end = (fcinfo->nargs == 3) ? start : 0xffff;
     336             : 
     337          16 :     res = inner_subltree(t, start, end);
     338             : 
     339          16 :     PG_FREE_IF_COPY(t, 0);
     340          16 :     PG_RETURN_POINTER(res);
     341             : }
     342             : 
     343             : static ltree *
     344          12 : ltree_concat(ltree *a, ltree *b)
     345             : {
     346             :     ltree      *r;
     347          12 :     int         numlevel = (int) a->numlevel + b->numlevel;
     348             : 
     349          12 :     if (numlevel > LTREE_MAX_LEVELS)
     350           2 :         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             : 
     355          10 :     r = (ltree *) palloc0(VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
     356          10 :     SET_VARSIZE(r, VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
     357          10 :     r->numlevel = (uint16) numlevel;
     358             : 
     359          10 :     memcpy(LTREE_FIRST(r), LTREE_FIRST(a), VARSIZE(a) - LTREE_HDRSIZE);
     360          10 :     memcpy(((char *) LTREE_FIRST(r)) + VARSIZE(a) - LTREE_HDRSIZE,
     361             :            LTREE_FIRST(b),
     362          10 :            VARSIZE(b) - LTREE_HDRSIZE);
     363          10 :     return r;
     364             : }
     365             : 
     366             : Datum
     367          10 : ltree_addltree(PG_FUNCTION_ARGS)
     368             : {
     369          10 :     ltree      *a = PG_GETARG_LTREE_P(0);
     370          10 :     ltree      *b = PG_GETARG_LTREE_P(1);
     371             :     ltree      *r;
     372             : 
     373          10 :     r = ltree_concat(a, b);
     374           8 :     PG_FREE_IF_COPY(a, 0);
     375           8 :     PG_FREE_IF_COPY(b, 1);
     376           8 :     PG_RETURN_POINTER(r);
     377             : }
     378             : 
     379             : Datum
     380           2 : ltree_addtext(PG_FUNCTION_ARGS)
     381             : {
     382           2 :     ltree      *a = PG_GETARG_LTREE_P(0);
     383           2 :     text       *b = PG_GETARG_TEXT_PP(1);
     384             :     char       *s;
     385             :     ltree      *r,
     386             :                *tmp;
     387             : 
     388           2 :     s = text_to_cstring(b);
     389             : 
     390           2 :     tmp = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     391             :                                                         PointerGetDatum(s)));
     392             : 
     393           2 :     pfree(s);
     394             : 
     395           2 :     r = ltree_concat(a, tmp);
     396             : 
     397           2 :     pfree(tmp);
     398             : 
     399           2 :     PG_FREE_IF_COPY(a, 0);
     400           2 :     PG_FREE_IF_COPY(b, 1);
     401           2 :     PG_RETURN_POINTER(r);
     402             : }
     403             : 
     404             : Datum
     405          36 : ltree_index(PG_FUNCTION_ARGS)
     406             : {
     407          36 :     ltree      *a = PG_GETARG_LTREE_P(0);
     408          36 :     ltree      *b = PG_GETARG_LTREE_P(1);
     409          36 :     int         start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
     410             :     int         i,
     411             :                 j;
     412             :     ltree_level *startptr,
     413             :                *aptr,
     414             :                *bptr;
     415          36 :     bool        found = false;
     416             : 
     417          36 :     if (start < 0)
     418             :     {
     419          10 :         if (-start >= a->numlevel)
     420           2 :             start = 0;
     421             :         else
     422           8 :             start = (int) (a->numlevel) + start;
     423             :     }
     424             : 
     425          36 :     if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0)
     426             :     {
     427           2 :         PG_FREE_IF_COPY(a, 0);
     428           2 :         PG_FREE_IF_COPY(b, 1);
     429           2 :         PG_RETURN_INT32(-1);
     430             :     }
     431             : 
     432          34 :     startptr = LTREE_FIRST(a);
     433         218 :     for (i = 0; i <= a->numlevel - b->numlevel; i++)
     434             :     {
     435         212 :         if (i >= start)
     436             :         {
     437         116 :             aptr = startptr;
     438         116 :             bptr = LTREE_FIRST(b);
     439         186 :             for (j = 0; j < b->numlevel; j++)
     440             :             {
     441         158 :                 if (!(aptr->len == bptr->len && memcmp(aptr->name, bptr->name, aptr->len) == 0))
     442             :                     break;
     443          70 :                 aptr = LEVEL_NEXT(aptr);
     444          70 :                 bptr = LEVEL_NEXT(bptr);
     445             :             }
     446             : 
     447         116 :             if (j == b->numlevel)
     448             :             {
     449          28 :                 found = true;
     450          28 :                 break;
     451             :             }
     452             :         }
     453         184 :         startptr = LEVEL_NEXT(startptr);
     454             :     }
     455             : 
     456          34 :     if (!found)
     457           6 :         i = -1;
     458             : 
     459          34 :     PG_FREE_IF_COPY(a, 0);
     460          34 :     PG_FREE_IF_COPY(b, 1);
     461          34 :     PG_RETURN_INT32(i);
     462             : }
     463             : 
     464             : Datum
     465           0 : ltree_textadd(PG_FUNCTION_ARGS)
     466             : {
     467           0 :     ltree      *a = PG_GETARG_LTREE_P(1);
     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             : 
     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 *
     496          28 : 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             : 
     507          28 :     if (len <= 0)
     508           2 :         return NULL;            /* no inputs? */
     509          26 :     if ((*a)->numlevel == 0)
     510           2 :         return NULL;            /* any empty input means NULL result */
     511             : 
     512             :     /* num is the length of the longest common ancestor so far */
     513          24 :     num = (*a)->numlevel - 1;
     514             : 
     515             :     /* Compare each additional input to *a */
     516          24 :     ptr = a + 1;
     517          46 :     while (ptr - a < len)
     518             :     {
     519          24 :         if ((*ptr)->numlevel == 0)
     520           2 :             return NULL;
     521          22 :         else if ((*ptr)->numlevel == 1)
     522           4 :             num = 0;
     523             :         else
     524             :         {
     525          18 :             l1 = LTREE_FIRST(*a);
     526          18 :             l2 = LTREE_FIRST(*ptr);
     527          18 :             tmp = Min(num, (*ptr)->numlevel - 1);
     528          18 :             num = 0;
     529          46 :             for (i = 0; i < tmp; i++)
     530             :             {
     531          42 :                 if (l1->len == l2->len &&
     532          36 :                     memcmp(l1->name, l2->name, l1->len) == 0)
     533          28 :                     num = i + 1;
     534             :                 else
     535             :                     break;
     536          28 :                 l1 = LEVEL_NEXT(l1);
     537          28 :                 l2 = LEVEL_NEXT(l2);
     538             :             }
     539             :         }
     540          22 :         ptr++;
     541             :     }
     542             : 
     543             :     /* Now compute size of result ... */
     544          22 :     reslen = LTREE_HDRSIZE;
     545          22 :     l1 = LTREE_FIRST(*a);
     546          42 :     for (i = 0; i < num; i++)
     547             :     {
     548          20 :         reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE);
     549          20 :         l1 = LEVEL_NEXT(l1);
     550             :     }
     551             : 
     552             :     /* ... and construct it by copying from *a */
     553          22 :     res = (ltree *) palloc0(reslen);
     554          22 :     SET_VARSIZE(res, reslen);
     555          22 :     res->numlevel = num;
     556             : 
     557          22 :     l1 = LTREE_FIRST(*a);
     558          22 :     l2 = LTREE_FIRST(res);
     559             : 
     560          42 :     for (i = 0; i < num; i++)
     561             :     {
     562          20 :         memcpy(l2, l1, MAXALIGN(l1->len + LEVEL_HDRSIZE));
     563          20 :         l1 = LEVEL_NEXT(l1);
     564          20 :         l2 = LEVEL_NEXT(l2);
     565             :     }
     566             : 
     567          22 :     return res;
     568             : }
     569             : 
     570             : Datum
     571          12 : lca(PG_FUNCTION_ARGS)
     572             : {
     573             :     int         i;
     574             :     ltree     **a,
     575             :                *res;
     576             : 
     577          12 :     a = (ltree **) palloc(sizeof(ltree *) * fcinfo->nargs);
     578          42 :     for (i = 0; i < fcinfo->nargs; i++)
     579          30 :         a[i] = PG_GETARG_LTREE_P(i);
     580          12 :     res = lca_inner(a, (int) fcinfo->nargs);
     581          42 :     for (i = 0; i < fcinfo->nargs; i++)
     582          30 :         PG_FREE_IF_COPY(a[i], i);
     583          12 :     pfree(a);
     584             : 
     585          12 :     if (res)
     586          10 :         PG_RETURN_POINTER(res);
     587             :     else
     588           2 :         PG_RETURN_NULL();
     589             : }
     590             : 
     591             : Datum
     592           2 : text2ltree(PG_FUNCTION_ARGS)
     593             : {
     594           2 :     text       *in = PG_GETARG_TEXT_PP(0);
     595             :     char       *s;
     596             :     ltree      *out;
     597             : 
     598           2 :     s = text_to_cstring(in);
     599             : 
     600           2 :     out = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     601             :                                                         PointerGetDatum(s)));
     602           2 :     pfree(s);
     603           2 :     PG_FREE_IF_COPY(in, 0);
     604           2 :     PG_RETURN_POINTER(out);
     605             : }
     606             : 
     607             : 
     608             : Datum
     609           2 : ltree2text(PG_FUNCTION_ARGS)
     610             : {
     611           2 :     ltree      *in = PG_GETARG_LTREE_P(0);
     612             :     char       *ptr;
     613             :     int         i;
     614             :     ltree_level *curlevel;
     615             :     text       *out;
     616             : 
     617           2 :     out = (text *) palloc(VARSIZE(in) + VARHDRSZ);
     618           2 :     ptr = VARDATA(out);
     619           2 :     curlevel = LTREE_FIRST(in);
     620          12 :     for (i = 0; i < in->numlevel; i++)
     621             :     {
     622          10 :         if (i != 0)
     623             :         {
     624           8 :             *ptr = '.';
     625           8 :             ptr++;
     626             :         }
     627          10 :         memcpy(ptr, curlevel->name, curlevel->len);
     628          10 :         ptr += curlevel->len;
     629          10 :         curlevel = LEVEL_NEXT(curlevel);
     630             :     }
     631             : 
     632           2 :     SET_VARSIZE(out, ptr - ((char *) out));
     633           2 :     PG_FREE_IF_COPY(in, 0);
     634             : 
     635           2 :     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
     646           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. */
     655           0 :     selec = generic_restriction_selectivity(root, operator, InvalidOid,
     656             :                                             args, varRelid,
     657             :                                             0.001);
     658             : 
     659           0 :     PG_RETURN_FLOAT8((float8) selec);
     660             : }

Generated by: LCOV version 1.14