LCOV - code coverage report
Current view: top level - contrib/ltree - ltree_op.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19beta1 Lines: 93.6 % 329 308
Test Date: 2026-06-28 23:16:35 Functions: 94.1 % 51 48
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            3 : PG_MODULE_MAGIC_EXT(
      17              :                     .name = "ltree",
      18              :                     .version = PG_VERSION
      19              : );
      20              : 
      21              : /* compare functions */
      22            3 : PG_FUNCTION_INFO_V1(ltree_cmp);
      23            3 : PG_FUNCTION_INFO_V1(ltree_lt);
      24            3 : PG_FUNCTION_INFO_V1(ltree_le);
      25            3 : PG_FUNCTION_INFO_V1(ltree_eq);
      26            2 : PG_FUNCTION_INFO_V1(ltree_ne);
      27            3 : PG_FUNCTION_INFO_V1(ltree_ge);
      28            3 : PG_FUNCTION_INFO_V1(ltree_gt);
      29            3 : PG_FUNCTION_INFO_V1(hash_ltree);
      30            3 : PG_FUNCTION_INFO_V1(hash_ltree_extended);
      31            3 : PG_FUNCTION_INFO_V1(nlevel);
      32            3 : PG_FUNCTION_INFO_V1(ltree_isparent);
      33            3 : PG_FUNCTION_INFO_V1(ltree_risparent);
      34            3 : PG_FUNCTION_INFO_V1(subltree);
      35            6 : PG_FUNCTION_INFO_V1(subpath);
      36            6 : PG_FUNCTION_INFO_V1(ltree_index);
      37            3 : PG_FUNCTION_INFO_V1(ltree_addltree);
      38            3 : PG_FUNCTION_INFO_V1(ltree_addtext);
      39            2 : PG_FUNCTION_INFO_V1(ltree_textadd);
      40           16 : PG_FUNCTION_INFO_V1(lca);
      41            3 : PG_FUNCTION_INFO_V1(ltree2text);
      42            3 : PG_FUNCTION_INFO_V1(text2ltree);
      43            2 : PG_FUNCTION_INFO_V1(ltreeparentsel);
      44              : 
      45              : /*
      46              :  * btree-comparison function.
      47              :  */
      48              : int
      49        98260 : ltree_compare(const ltree *a, const ltree *b)
      50              : {
      51        98260 :     ltree_level *al = LTREE_FIRST(a);
      52        98260 :     ltree_level *bl = LTREE_FIRST(b);
      53        98260 :     int         an = a->numlevel;
      54        98260 :     int         bn = b->numlevel;
      55              : 
      56       185826 :     while (an > 0 && bn > 0)
      57              :     {
      58              :         int         res;
      59              : 
      60       176600 :         res = memcmp(al->name, bl->name, Min(al->len, bl->len));
      61       176600 :         if (res == 0)
      62              :         {
      63        93842 :             if (al->len != bl->len)
      64         6276 :                 return (int) al->len - (int) bl->len;
      65              :         }
      66              :         else
      67        82758 :             return res;
      68              : 
      69        87566 :         an--;
      70        87566 :         bn--;
      71        87566 :         al = LEVEL_NEXT(al);
      72        87566 :         bl = LEVEL_NEXT(bl);
      73              :     }
      74              : 
      75         9226 :     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              :  */
      82              : float
      83        19512 : ltree_compare_distance(const ltree *a, const ltree *b)
      84              : {
      85        19512 :     ltree_level *al = LTREE_FIRST(a);
      86        19512 :     ltree_level *bl = LTREE_FIRST(b);
      87        19512 :     int         an = a->numlevel;
      88        19512 :     int         bn = b->numlevel;
      89              : 
      90        20298 :     while (an > 0 && bn > 0)
      91              :     {
      92              :         int         res;
      93              : 
      94        18133 :         res = memcmp(al->name, bl->name, Min(al->len, bl->len));
      95        18133 :         if (res == 0)
      96              :         {
      97         1817 :             if (al->len != bl->len)
      98         1031 :                 return (float) (al->len - bl->len) * 10.0 * (an + 1);
      99              :         }
     100              :         else
     101              :         {
     102        16316 :             if (res < 0)
     103        10543 :                 return -1.0 * 10.0 * (an + 1);
     104              :             else
     105         5773 :                 return 1.0 * 10.0 * (an + 1);
     106              :         }
     107              : 
     108          786 :         an--;
     109          786 :         bn--;
     110          786 :         al = LEVEL_NEXT(al);
     111          786 :         bl = LEVEL_NEXT(bl);
     112              :     }
     113              : 
     114         2165 :     return ((float) (a->numlevel - b->numlevel)) * 10.0 * (an + 1);
     115              : }
     116              : 
     117              : #define RUNCMP                      \
     118              : ltree *a = PG_GETARG_LTREE_P(0);    \
     119              : ltree *b = PG_GETARG_LTREE_P(1);    \
     120              : int res = ltree_compare(a,b);       \
     121              : PG_FREE_IF_COPY(a,0);               \
     122              : PG_FREE_IF_COPY(b,1)
     123              : 
     124              : Datum
     125        51231 : ltree_cmp(PG_FUNCTION_ARGS)
     126              : {
     127        51231 :     RUNCMP;
     128        51231 :     PG_RETURN_INT32(res);
     129              : }
     130              : 
     131              : Datum
     132         2141 : ltree_lt(PG_FUNCTION_ARGS)
     133              : {
     134         2141 :     RUNCMP;
     135         2141 :     PG_RETURN_BOOL(res < 0);
     136              : }
     137              : 
     138              : Datum
     139         2141 : ltree_le(PG_FUNCTION_ARGS)
     140              : {
     141         2141 :     RUNCMP;
     142         2141 :     PG_RETURN_BOOL(res <= 0);
     143              : }
     144              : 
     145              : Datum
     146         2017 : ltree_eq(PG_FUNCTION_ARGS)
     147              : {
     148         2017 :     RUNCMP;
     149         2017 :     PG_RETURN_BOOL(res == 0);
     150              : }
     151              : 
     152              : Datum
     153         2118 : ltree_ge(PG_FUNCTION_ARGS)
     154              : {
     155         2118 :     RUNCMP;
     156         2118 :     PG_RETURN_BOOL(res >= 0);
     157              : }
     158              : 
     159              : Datum
     160         2118 : ltree_gt(PG_FUNCTION_ARGS)
     161              : {
     162         2118 :     RUNCMP;
     163         2118 :     PG_RETURN_BOOL(res > 0);
     164              : }
     165              : 
     166              : Datum
     167            0 : ltree_ne(PG_FUNCTION_ARGS)
     168              : {
     169            0 :     RUNCMP;
     170            0 :     PG_RETURN_BOOL(res != 0);
     171              : }
     172              : 
     173              : /* Compute a hash for the ltree */
     174              : Datum
     175         3031 : hash_ltree(PG_FUNCTION_ARGS)
     176              : {
     177         3031 :     ltree      *a = PG_GETARG_LTREE_P(0);
     178         3031 :     uint32      result = 1;
     179         3031 :     int         an = a->numlevel;
     180         3031 :     ltree_level *al = LTREE_FIRST(a);
     181              : 
     182        22872 :     while (an > 0)
     183              :     {
     184        19841 :         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        19841 :         result = (result << 5) - result + levelHash;
     194              : 
     195        19841 :         an--;
     196        19841 :         al = LEVEL_NEXT(al);
     197              :     }
     198              : 
     199         3031 :     PG_FREE_IF_COPY(a, 0);
     200         3031 :     PG_RETURN_UINT32(result);
     201              : }
     202              : 
     203              : /* Compute an extended hash for the ltree */
     204              : Datum
     205           12 : hash_ltree_extended(PG_FUNCTION_ARGS)
     206              : {
     207           12 :     ltree      *a = PG_GETARG_LTREE_P(0);
     208           12 :     const uint64 seed = PG_GETARG_INT64(1);
     209           12 :     uint64      result = 1;
     210           12 :     int         an = a->numlevel;
     211           12 :     ltree_level *al = LTREE_FIRST(a);
     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           12 :     if (an == 0)
     220              :     {
     221            2 :         PG_FREE_IF_COPY(a, 0);
     222            2 :         PG_RETURN_UINT64(result + seed);
     223              :     }
     224              : 
     225           28 :     while (an > 0)
     226              :     {
     227           18 :         uint64      levelHash = DatumGetUInt64(hash_any_extended((unsigned char *) al->name, al->len, seed));
     228              : 
     229           18 :         result = (result << 5) - result + levelHash;
     230              : 
     231           18 :         an--;
     232           18 :         al = LEVEL_NEXT(al);
     233              :     }
     234              : 
     235           10 :     PG_FREE_IF_COPY(a, 0);
     236           10 :     PG_RETURN_UINT64(result);
     237              : }
     238              : 
     239              : Datum
     240            2 : nlevel(PG_FUNCTION_ARGS)
     241              : {
     242            2 :     ltree      *a = PG_GETARG_LTREE_P(0);
     243            2 :     int         res = a->numlevel;
     244              : 
     245            2 :     PG_FREE_IF_COPY(a, 0);
     246            2 :     PG_RETURN_INT32(res);
     247              : }
     248              : 
     249              : bool
     250        21188 : inner_isparent(const ltree *c, const ltree *p)
     251              : {
     252        21188 :     ltree_level *cl = LTREE_FIRST(c);
     253        21188 :     ltree_level *pl = LTREE_FIRST(p);
     254        21188 :     int         pn = p->numlevel;
     255              : 
     256        21188 :     if (pn > c->numlevel)
     257        10166 :         return false;
     258              : 
     259        12019 :     while (pn > 0)
     260              :     {
     261        11883 :         if (cl->len != pl->len)
     262         7960 :             return false;
     263         3923 :         if (memcmp(cl->name, pl->name, cl->len) != 0)
     264         2926 :             return false;
     265              : 
     266          997 :         pn--;
     267          997 :         cl = LEVEL_NEXT(cl);
     268          997 :         pl = LEVEL_NEXT(pl);
     269              :     }
     270          136 :     return true;
     271              : }
     272              : 
     273              : Datum
     274        11538 : ltree_isparent(PG_FUNCTION_ARGS)
     275              : {
     276        11538 :     ltree      *c = PG_GETARG_LTREE_P(1);
     277        11538 :     ltree      *p = PG_GETARG_LTREE_P(0);
     278        11538 :     bool        res = inner_isparent(c, p);
     279              : 
     280        11538 :     PG_FREE_IF_COPY(c, 1);
     281        11538 :     PG_FREE_IF_COPY(p, 0);
     282        11538 :     PG_RETURN_BOOL(res);
     283              : }
     284              : 
     285              : Datum
     286         9320 : ltree_risparent(PG_FUNCTION_ARGS)
     287              : {
     288         9320 :     ltree      *c = PG_GETARG_LTREE_P(0);
     289         9320 :     ltree      *p = PG_GETARG_LTREE_P(1);
     290         9320 :     bool        res = inner_isparent(c, p);
     291              : 
     292         9320 :     PG_FREE_IF_COPY(c, 0);
     293         9320 :     PG_FREE_IF_COPY(p, 1);
     294         9320 :     PG_RETURN_BOOL(res);
     295              : }
     296              : 
     297              : 
     298              : static ltree *
     299           10 : inner_subltree(ltree *t, int32 startpos, int32 endpos)
     300              : {
     301           10 :     char       *start = NULL,
     302           10 :                *end = NULL;
     303           10 :     ltree_level *ptr = LTREE_FIRST(t);
     304              :     ltree      *res;
     305              :     int         i;
     306              : 
     307           10 :     if (startpos < 0 || endpos < 0 || startpos >= t->numlevel || startpos > endpos)
     308            1 :         ereport(ERROR,
     309              :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     310              :                  errmsg("invalid positions")));
     311              : 
     312            9 :     if (endpos > t->numlevel)
     313            2 :         endpos = t->numlevel;
     314              : 
     315            9 :     start = end = (char *) ptr;
     316           19 :     for (i = 0; i < endpos; i++)
     317              :     {
     318           18 :         if (i == startpos)
     319            7 :             start = (char *) ptr;
     320           18 :         if (i == endpos - 1)
     321              :         {
     322            8 :             end = (char *) LEVEL_NEXT(ptr);
     323            8 :             break;
     324              :         }
     325           10 :         ptr = LEVEL_NEXT(ptr);
     326              :     }
     327              : 
     328            9 :     res = (ltree *) palloc0(LTREE_HDRSIZE + (end - start));
     329            9 :     SET_VARSIZE(res, LTREE_HDRSIZE + (end - start));
     330            9 :     res->numlevel = endpos - startpos;
     331              : 
     332            9 :     memcpy(LTREE_FIRST(res), start, end - start);
     333              : 
     334            9 :     return res;
     335              : }
     336              : 
     337              : Datum
     338            1 : subltree(PG_FUNCTION_ARGS)
     339              : {
     340            1 :     ltree      *t = PG_GETARG_LTREE_P(0);
     341            1 :     ltree      *res = inner_subltree(t, PG_GETARG_INT32(1), PG_GETARG_INT32(2));
     342              : 
     343            1 :     PG_FREE_IF_COPY(t, 0);
     344            1 :     PG_RETURN_POINTER(res);
     345              : }
     346              : 
     347              : Datum
     348            9 : subpath(PG_FUNCTION_ARGS)
     349              : {
     350            9 :     ltree      *t = PG_GETARG_LTREE_P(0);
     351            9 :     int32       start = PG_GETARG_INT32(1);
     352            9 :     int32       len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
     353              :     int32       end;
     354              :     ltree      *res;
     355              : 
     356            9 :     if (start < 0)
     357            2 :         start = t->numlevel + start;
     358              : 
     359            9 :     if (len < 0)
     360            2 :         end = t->numlevel + len;
     361            7 :     else if (len == 0)
     362            5 :         end = (fcinfo->nargs == 3) ? start : LTREE_MAX_LEVELS;
     363              :     else
     364            2 :         end = start + len;
     365              : 
     366            9 :     res = inner_subltree(t, start, end);
     367              : 
     368            8 :     PG_FREE_IF_COPY(t, 0);
     369            8 :     PG_RETURN_POINTER(res);
     370              : }
     371              : 
     372              : static ltree *
     373            6 : ltree_concat(ltree *a, ltree *b)
     374              : {
     375              :     ltree      *r;
     376            6 :     int         numlevel = (int) a->numlevel + b->numlevel;
     377              : 
     378            6 :     if (numlevel > LTREE_MAX_LEVELS)
     379            1 :         ereport(ERROR,
     380              :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     381              :                  errmsg("number of ltree levels (%d) exceeds the maximum allowed (%d)",
     382              :                         numlevel, LTREE_MAX_LEVELS)));
     383              : 
     384            5 :     r = (ltree *) palloc0(VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
     385            5 :     SET_VARSIZE(r, VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
     386            5 :     r->numlevel = (uint16) numlevel;
     387              : 
     388            5 :     memcpy(LTREE_FIRST(r), LTREE_FIRST(a), VARSIZE(a) - LTREE_HDRSIZE);
     389            5 :     memcpy(((char *) LTREE_FIRST(r)) + VARSIZE(a) - LTREE_HDRSIZE,
     390              :            LTREE_FIRST(b),
     391            5 :            VARSIZE(b) - LTREE_HDRSIZE);
     392            5 :     return r;
     393              : }
     394              : 
     395              : Datum
     396            5 : ltree_addltree(PG_FUNCTION_ARGS)
     397              : {
     398            5 :     ltree      *a = PG_GETARG_LTREE_P(0);
     399            5 :     ltree      *b = PG_GETARG_LTREE_P(1);
     400              :     ltree      *r;
     401              : 
     402            5 :     r = ltree_concat(a, b);
     403            4 :     PG_FREE_IF_COPY(a, 0);
     404            4 :     PG_FREE_IF_COPY(b, 1);
     405            4 :     PG_RETURN_POINTER(r);
     406              : }
     407              : 
     408              : Datum
     409            1 : ltree_addtext(PG_FUNCTION_ARGS)
     410              : {
     411            1 :     ltree      *a = PG_GETARG_LTREE_P(0);
     412            1 :     text       *b = PG_GETARG_TEXT_PP(1);
     413              :     char       *s;
     414              :     ltree      *r,
     415              :                *tmp;
     416              : 
     417            1 :     s = text_to_cstring(b);
     418              : 
     419            1 :     tmp = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     420              :                                                         PointerGetDatum(s)));
     421              : 
     422            1 :     pfree(s);
     423              : 
     424            1 :     r = ltree_concat(a, tmp);
     425              : 
     426            1 :     pfree(tmp);
     427              : 
     428            1 :     PG_FREE_IF_COPY(a, 0);
     429            1 :     PG_FREE_IF_COPY(b, 1);
     430            1 :     PG_RETURN_POINTER(r);
     431              : }
     432              : 
     433              : Datum
     434           18 : ltree_index(PG_FUNCTION_ARGS)
     435              : {
     436           18 :     ltree      *a = PG_GETARG_LTREE_P(0);
     437           18 :     ltree      *b = PG_GETARG_LTREE_P(1);
     438           18 :     int         start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
     439              :     int         i,
     440              :                 j;
     441              :     ltree_level *startptr,
     442              :                *aptr,
     443              :                *bptr;
     444           18 :     bool        found = false;
     445              : 
     446           18 :     if (start < 0)
     447              :     {
     448            5 :         if (-start >= a->numlevel)
     449            1 :             start = 0;
     450              :         else
     451            4 :             start = (int) (a->numlevel) + start;
     452              :     }
     453              : 
     454           18 :     if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0)
     455              :     {
     456            1 :         PG_FREE_IF_COPY(a, 0);
     457            1 :         PG_FREE_IF_COPY(b, 1);
     458            1 :         PG_RETURN_INT32(-1);
     459              :     }
     460              : 
     461           17 :     startptr = LTREE_FIRST(a);
     462          109 :     for (i = 0; i <= a->numlevel - b->numlevel; i++)
     463              :     {
     464          106 :         if (i >= start)
     465              :         {
     466           58 :             aptr = startptr;
     467           58 :             bptr = LTREE_FIRST(b);
     468           93 :             for (j = 0; j < b->numlevel; j++)
     469              :             {
     470           79 :                 if (!(aptr->len == bptr->len && memcmp(aptr->name, bptr->name, aptr->len) == 0))
     471              :                     break;
     472           35 :                 aptr = LEVEL_NEXT(aptr);
     473           35 :                 bptr = LEVEL_NEXT(bptr);
     474              :             }
     475              : 
     476           58 :             if (j == b->numlevel)
     477              :             {
     478           14 :                 found = true;
     479           14 :                 break;
     480              :             }
     481              :         }
     482           92 :         startptr = LEVEL_NEXT(startptr);
     483              :     }
     484              : 
     485           17 :     if (!found)
     486            3 :         i = -1;
     487              : 
     488           17 :     PG_FREE_IF_COPY(a, 0);
     489           17 :     PG_FREE_IF_COPY(b, 1);
     490           17 :     PG_RETURN_INT32(i);
     491              : }
     492              : 
     493              : Datum
     494            0 : ltree_textadd(PG_FUNCTION_ARGS)
     495              : {
     496            0 :     ltree      *a = PG_GETARG_LTREE_P(1);
     497            0 :     text       *b = PG_GETARG_TEXT_PP(0);
     498              :     char       *s;
     499              :     ltree      *r,
     500              :                *tmp;
     501              : 
     502            0 :     s = text_to_cstring(b);
     503              : 
     504            0 :     tmp = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     505              :                                                         PointerGetDatum(s)));
     506              : 
     507            0 :     pfree(s);
     508              : 
     509            0 :     r = ltree_concat(tmp, a);
     510              : 
     511            0 :     pfree(tmp);
     512              : 
     513            0 :     PG_FREE_IF_COPY(a, 1);
     514            0 :     PG_FREE_IF_COPY(b, 0);
     515            0 :     PG_RETURN_POINTER(r);
     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              :  */
     524              : ltree *
     525           14 : lca_inner(ltree **a, int len)
     526              : {
     527              :     int         tmp,
     528              :                 num,
     529              :                 i,
     530              :                 reslen;
     531              :     ltree     **ptr;
     532              :     ltree_level *l1,
     533              :                *l2;
     534              :     ltree      *res;
     535              : 
     536           14 :     if (len <= 0)
     537            1 :         return NULL;            /* no inputs? */
     538           13 :     if ((*a)->numlevel == 0)
     539            1 :         return NULL;            /* any empty input means NULL result */
     540              : 
     541              :     /* num is the length of the longest common ancestor so far */
     542           12 :     num = (*a)->numlevel - 1;
     543              : 
     544              :     /* Compare each additional input to *a */
     545           12 :     ptr = a + 1;
     546           23 :     while (ptr - a < len)
     547              :     {
     548           12 :         if ((*ptr)->numlevel == 0)
     549            1 :             return NULL;
     550           11 :         else if ((*ptr)->numlevel == 1)
     551            2 :             num = 0;
     552              :         else
     553              :         {
     554            9 :             l1 = LTREE_FIRST(*a);
     555            9 :             l2 = LTREE_FIRST(*ptr);
     556            9 :             tmp = Min(num, (*ptr)->numlevel - 1);
     557            9 :             num = 0;
     558           23 :             for (i = 0; i < tmp; i++)
     559              :             {
     560           21 :                 if (l1->len == l2->len &&
     561           18 :                     memcmp(l1->name, l2->name, l1->len) == 0)
     562           14 :                     num = i + 1;
     563              :                 else
     564              :                     break;
     565           14 :                 l1 = LEVEL_NEXT(l1);
     566           14 :                 l2 = LEVEL_NEXT(l2);
     567              :             }
     568              :         }
     569           11 :         ptr++;
     570              :     }
     571              : 
     572              :     /* Now compute size of result ... */
     573           11 :     reslen = LTREE_HDRSIZE;
     574           11 :     l1 = LTREE_FIRST(*a);
     575           21 :     for (i = 0; i < num; i++)
     576              :     {
     577           10 :         reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE);
     578           10 :         l1 = LEVEL_NEXT(l1);
     579              :     }
     580              : 
     581              :     /* ... and construct it by copying from *a */
     582           11 :     res = (ltree *) palloc0(reslen);
     583           11 :     SET_VARSIZE(res, reslen);
     584           11 :     res->numlevel = num;
     585              : 
     586           11 :     l1 = LTREE_FIRST(*a);
     587           11 :     l2 = LTREE_FIRST(res);
     588              : 
     589           21 :     for (i = 0; i < num; i++)
     590              :     {
     591           10 :         memcpy(l2, l1, MAXALIGN(l1->len + LEVEL_HDRSIZE));
     592           10 :         l1 = LEVEL_NEXT(l1);
     593           10 :         l2 = LEVEL_NEXT(l2);
     594              :     }
     595              : 
     596           11 :     return res;
     597              : }
     598              : 
     599              : Datum
     600            6 : lca(PG_FUNCTION_ARGS)
     601              : {
     602              :     int         i;
     603              :     ltree     **a,
     604              :                *res;
     605              : 
     606            6 :     a = palloc_array(ltree *, fcinfo->nargs);
     607           21 :     for (i = 0; i < fcinfo->nargs; i++)
     608           15 :         a[i] = PG_GETARG_LTREE_P(i);
     609            6 :     res = lca_inner(a, (int) fcinfo->nargs);
     610           21 :     for (i = 0; i < fcinfo->nargs; i++)
     611           15 :         PG_FREE_IF_COPY(a[i], i);
     612            6 :     pfree(a);
     613              : 
     614            6 :     if (res)
     615            5 :         PG_RETURN_POINTER(res);
     616              :     else
     617            1 :         PG_RETURN_NULL();
     618              : }
     619              : 
     620              : Datum
     621            1 : text2ltree(PG_FUNCTION_ARGS)
     622              : {
     623            1 :     text       *in = PG_GETARG_TEXT_PP(0);
     624              :     char       *s;
     625              :     ltree      *out;
     626              : 
     627            1 :     s = text_to_cstring(in);
     628              : 
     629            1 :     out = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     630              :                                                         PointerGetDatum(s)));
     631            1 :     pfree(s);
     632            1 :     PG_FREE_IF_COPY(in, 0);
     633            1 :     PG_RETURN_POINTER(out);
     634              : }
     635              : 
     636              : 
     637              : Datum
     638            1 : ltree2text(PG_FUNCTION_ARGS)
     639              : {
     640            1 :     ltree      *in = PG_GETARG_LTREE_P(0);
     641              :     char       *ptr;
     642              :     int         i;
     643              :     ltree_level *curlevel;
     644              :     text       *out;
     645              : 
     646            1 :     out = (text *) palloc(VARSIZE(in) + VARHDRSZ);
     647            1 :     ptr = VARDATA(out);
     648            1 :     curlevel = LTREE_FIRST(in);
     649            6 :     for (i = 0; i < in->numlevel; i++)
     650              :     {
     651            5 :         if (i != 0)
     652              :         {
     653            4 :             *ptr = '.';
     654            4 :             ptr++;
     655              :         }
     656            5 :         memcpy(ptr, curlevel->name, curlevel->len);
     657            5 :         ptr += curlevel->len;
     658            5 :         curlevel = LEVEL_NEXT(curlevel);
     659              :     }
     660              : 
     661            1 :     SET_VARSIZE(out, ptr - ((char *) out));
     662            1 :     PG_FREE_IF_COPY(in, 0);
     663              : 
     664            1 :     PG_RETURN_POINTER(out);
     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              :  */
     674              : Datum
     675            0 : ltreeparentsel(PG_FUNCTION_ARGS)
     676              : {
     677            0 :     PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
     678            0 :     Oid         operator = PG_GETARG_OID(1);
     679            0 :     List       *args = (List *) PG_GETARG_POINTER(2);
     680            0 :     int         varRelid = PG_GETARG_INT32(3);
     681              :     double      selec;
     682              : 
     683              :     /* Use generic restriction selectivity logic, with default 0.001. */
     684            0 :     selec = generic_restriction_selectivity(root, operator, InvalidOid,
     685              :                                             args, varRelid,
     686              :                                             0.001);
     687              : 
     688            0 :     PG_RETURN_FLOAT8((float8) selec);
     689              : }
        

Generated by: LCOV version 2.0-1