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

Generated by: LCOV version 1.14