LCOV - code coverage report
Current view: top level - contrib/ltree - ltree_io.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 290 322 90.1 %
Date: 2019-11-22 08:06:54 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * in/out function for ltree and lquery
       3             :  * Teodor Sigaev <teodor@stack.net>
       4             :  * contrib/ltree/ltree_io.c
       5             :  */
       6             : #include "postgres.h"
       7             : 
       8             : #include <ctype.h>
       9             : 
      10             : #include "crc32.h"
      11             : #include "ltree.h"
      12             : #include "utils/memutils.h"
      13             : 
      14           8 : PG_FUNCTION_INFO_V1(ltree_in);
      15           6 : PG_FUNCTION_INFO_V1(ltree_out);
      16           6 : PG_FUNCTION_INFO_V1(lquery_in);
      17           6 : PG_FUNCTION_INFO_V1(lquery_out);
      18             : 
      19             : 
      20             : #define UNCHAR ereport(ERROR, \
      21             :                        (errcode(ERRCODE_SYNTAX_ERROR), \
      22             :                         errmsg("syntax error at position %d", \
      23             :                         pos)));
      24             : 
      25             : 
      26             : typedef struct
      27             : {
      28             :     char       *start;
      29             :     int         len;            /* length in bytes */
      30             :     int         flag;
      31             :     int         wlen;           /* length in characters */
      32             : } nodeitem;
      33             : 
      34             : #define LTPRS_WAITNAME  0
      35             : #define LTPRS_WAITDELIM 1
      36             : 
      37             : Datum
      38        9618 : ltree_in(PG_FUNCTION_ARGS)
      39             : {
      40        9618 :     char       *buf = (char *) PG_GETARG_POINTER(0);
      41             :     char       *ptr;
      42             :     nodeitem   *list,
      43             :                *lptr;
      44        9618 :     int         num = 0,
      45        9618 :                 totallen = 0;
      46        9618 :     int         state = LTPRS_WAITNAME;
      47             :     ltree      *result;
      48             :     ltree_level *curlevel;
      49             :     int         charlen;
      50        9618 :     int         pos = 0;
      51             : 
      52        9618 :     ptr = buf;
      53      176804 :     while (*ptr)
      54             :     {
      55      157568 :         charlen = pg_mblen(ptr);
      56      157568 :         if (charlen == 1 && t_iseq(ptr, '.'))
      57       52138 :             num++;
      58      157568 :         ptr += charlen;
      59             :     }
      60             : 
      61        9618 :     if (num + 1 > MaxAllocSize / sizeof(nodeitem))
      62           0 :         ereport(ERROR,
      63             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
      64             :                  errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
      65             :                         num + 1, (int) (MaxAllocSize / sizeof(nodeitem)))));
      66        9618 :     list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
      67        9618 :     ptr = buf;
      68      176762 :     while (*ptr)
      69             :     {
      70      157528 :         charlen = pg_mblen(ptr);
      71             : 
      72      157528 :         if (state == LTPRS_WAITNAME)
      73             :         {
      74       61744 :             if (ISALNUM(ptr))
      75             :             {
      76       61742 :                 lptr->start = ptr;
      77       61742 :                 lptr->wlen = 0;
      78       61742 :                 state = LTPRS_WAITDELIM;
      79             :             }
      80             :             else
      81           2 :                 UNCHAR;
      82             :         }
      83       95784 :         else if (state == LTPRS_WAITDELIM)
      84             :         {
      85       95784 :             if (charlen == 1 && t_iseq(ptr, '.'))
      86             :             {
      87       52138 :                 lptr->len = ptr - lptr->start;
      88       52138 :                 if (lptr->wlen > 255)
      89           0 :                     ereport(ERROR,
      90             :                             (errcode(ERRCODE_NAME_TOO_LONG),
      91             :                              errmsg("name of level is too long"),
      92             :                              errdetail("Name length is %d, must "
      93             :                                        "be < 256, in position %d.",
      94             :                                        lptr->wlen, pos)));
      95             : 
      96       52138 :                 totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
      97       52138 :                 lptr++;
      98       52138 :                 state = LTPRS_WAITNAME;
      99             :             }
     100       43646 :             else if (!ISALNUM(ptr))
     101           0 :                 UNCHAR;
     102             :         }
     103             :         else
     104             :             /* internal error */
     105           0 :             elog(ERROR, "internal error in parser");
     106             : 
     107      157526 :         ptr += charlen;
     108      157526 :         lptr->wlen++;
     109      157526 :         pos++;
     110             :     }
     111             : 
     112        9616 :     if (state == LTPRS_WAITDELIM)
     113             :     {
     114        9604 :         lptr->len = ptr - lptr->start;
     115        9604 :         if (lptr->wlen > 255)
     116           0 :             ereport(ERROR,
     117             :                     (errcode(ERRCODE_NAME_TOO_LONG),
     118             :                      errmsg("name of level is too long"),
     119             :                      errdetail("Name length is %d, must "
     120             :                                "be < 256, in position %d.",
     121             :                                lptr->wlen, pos)));
     122             : 
     123        9604 :         totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
     124        9604 :         lptr++;
     125             :     }
     126          12 :     else if (!(state == LTPRS_WAITNAME && lptr == list))
     127           0 :         ereport(ERROR,
     128             :                 (errcode(ERRCODE_SYNTAX_ERROR),
     129             :                  errmsg("syntax error"),
     130             :                  errdetail("Unexpected end of line.")));
     131             : 
     132        9616 :     result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
     133        9616 :     SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
     134        9616 :     result->numlevel = lptr - list;
     135        9616 :     curlevel = LTREE_FIRST(result);
     136        9616 :     lptr = list;
     137       80974 :     while (lptr - list < result->numlevel)
     138             :     {
     139       61742 :         curlevel->len = (uint16) lptr->len;
     140       61742 :         memcpy(curlevel->name, lptr->start, lptr->len);
     141       61742 :         curlevel = LEVEL_NEXT(curlevel);
     142       61742 :         lptr++;
     143             :     }
     144             : 
     145        9616 :     pfree(list);
     146        9616 :     PG_RETURN_POINTER(result);
     147             : }
     148             : 
     149             : Datum
     150       12518 : ltree_out(PG_FUNCTION_ARGS)
     151             : {
     152       12518 :     ltree      *in = PG_GETARG_LTREE_P(0);
     153             :     char       *buf,
     154             :                *ptr;
     155             :     int         i;
     156             :     ltree_level *curlevel;
     157             : 
     158       12518 :     ptr = buf = (char *) palloc(VARSIZE(in));
     159       12518 :     curlevel = LTREE_FIRST(in);
     160       94496 :     for (i = 0; i < in->numlevel; i++)
     161             :     {
     162       81978 :         if (i != 0)
     163             :         {
     164       69488 :             *ptr = '.';
     165       69488 :             ptr++;
     166             :         }
     167       81978 :         memcpy(ptr, curlevel->name, curlevel->len);
     168       81978 :         ptr += curlevel->len;
     169       81978 :         curlevel = LEVEL_NEXT(curlevel);
     170             :     }
     171             : 
     172       12518 :     *ptr = '\0';
     173       12518 :     PG_FREE_IF_COPY(in, 0);
     174             : 
     175       12518 :     PG_RETURN_POINTER(buf);
     176             : }
     177             : 
     178             : #define LQPRS_WAITLEVEL 0
     179             : #define LQPRS_WAITDELIM 1
     180             : #define LQPRS_WAITOPEN  2
     181             : #define LQPRS_WAITFNUM  3
     182             : #define LQPRS_WAITSNUM  4
     183             : #define LQPRS_WAITND    5
     184             : #define LQPRS_WAITCLOSE 6
     185             : #define LQPRS_WAITEND   7
     186             : #define LQPRS_WAITVAR   8
     187             : 
     188             : 
     189             : #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
     190             : #define ITEMSIZE    MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
     191             : #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
     192             : 
     193             : Datum
     194         260 : lquery_in(PG_FUNCTION_ARGS)
     195             : {
     196         260 :     char       *buf = (char *) PG_GETARG_POINTER(0);
     197             :     char       *ptr;
     198         260 :     int         num = 0,
     199         260 :                 totallen = 0,
     200         260 :                 numOR = 0;
     201         260 :     int         state = LQPRS_WAITLEVEL;
     202             :     lquery     *result;
     203         260 :     nodeitem   *lptr = NULL;
     204             :     lquery_level *cur,
     205             :                *curqlevel,
     206             :                *tmpql;
     207         260 :     lquery_variant *lrptr = NULL;
     208         260 :     bool        hasnot = false;
     209         260 :     bool        wasbad = false;
     210             :     int         charlen;
     211         260 :     int         pos = 0;
     212             : 
     213         260 :     ptr = buf;
     214        2674 :     while (*ptr)
     215             :     {
     216        2154 :         charlen = pg_mblen(ptr);
     217             : 
     218        2154 :         if (charlen == 1)
     219             :         {
     220        2154 :             if (t_iseq(ptr, '.'))
     221         642 :                 num++;
     222        1512 :             else if (t_iseq(ptr, '|'))
     223          64 :                 numOR++;
     224             :         }
     225             : 
     226        2154 :         ptr += charlen;
     227             :     }
     228             : 
     229         260 :     num++;
     230         260 :     if (num > MaxAllocSize / ITEMSIZE)
     231           0 :         ereport(ERROR,
     232             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     233             :                  errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
     234             :                         num, (int) (MaxAllocSize / ITEMSIZE))));
     235         260 :     curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
     236         260 :     ptr = buf;
     237        2674 :     while (*ptr)
     238             :     {
     239        2154 :         charlen = pg_mblen(ptr);
     240             : 
     241        2154 :         if (state == LQPRS_WAITLEVEL)
     242             :         {
     243         902 :             if (ISALNUM(ptr))
     244             :             {
     245         474 :                 GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
     246         474 :                 lptr->start = ptr;
     247         474 :                 state = LQPRS_WAITDELIM;
     248         474 :                 curqlevel->numvar = 1;
     249             :             }
     250         428 :             else if (charlen == 1 && t_iseq(ptr, '!'))
     251             :             {
     252         116 :                 GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
     253         116 :                 lptr->start = ptr + 1;
     254         116 :                 state = LQPRS_WAITDELIM;
     255         116 :                 curqlevel->numvar = 1;
     256         116 :                 curqlevel->flag |= LQL_NOT;
     257         116 :                 hasnot = true;
     258             :             }
     259         312 :             else if (charlen == 1 && t_iseq(ptr, '*'))
     260         312 :                 state = LQPRS_WAITOPEN;
     261             :             else
     262           0 :                 UNCHAR;
     263             :         }
     264        1252 :         else if (state == LQPRS_WAITVAR)
     265             :         {
     266          64 :             if (ISALNUM(ptr))
     267             :             {
     268          64 :                 lptr++;
     269          64 :                 lptr->start = ptr;
     270          64 :                 state = LQPRS_WAITDELIM;
     271          64 :                 curqlevel->numvar++;
     272             :             }
     273             :             else
     274           0 :                 UNCHAR;
     275             :         }
     276        1188 :         else if (state == LQPRS_WAITDELIM)
     277             :         {
     278         718 :             if (charlen == 1 && t_iseq(ptr, '@'))
     279             :             {
     280          22 :                 if (lptr->start == ptr)
     281           0 :                     UNCHAR;
     282          22 :                 lptr->flag |= LVAR_INCASE;
     283          22 :                 curqlevel->flag |= LVAR_INCASE;
     284             :             }
     285         696 :             else if (charlen == 1 && t_iseq(ptr, '*'))
     286             :             {
     287          20 :                 if (lptr->start == ptr)
     288           0 :                     UNCHAR;
     289          20 :                 lptr->flag |= LVAR_ANYEND;
     290          20 :                 curqlevel->flag |= LVAR_ANYEND;
     291             :             }
     292         676 :             else if (charlen == 1 && t_iseq(ptr, '%'))
     293             :             {
     294           8 :                 if (lptr->start == ptr)
     295           0 :                     UNCHAR;
     296           8 :                 lptr->flag |= LVAR_SUBLEXEME;
     297           8 :                 curqlevel->flag |= LVAR_SUBLEXEME;
     298             :             }
     299         668 :             else if (charlen == 1 && t_iseq(ptr, '|'))
     300             :             {
     301         192 :                 lptr->len = ptr - lptr->start -
     302         128 :                     ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
     303         128 :                     ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
     304          64 :                     ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
     305          64 :                 if (lptr->wlen > 255)
     306           0 :                     ereport(ERROR,
     307             :                             (errcode(ERRCODE_NAME_TOO_LONG),
     308             :                              errmsg("name of level is too long"),
     309             :                              errdetail("Name length is %d, must "
     310             :                                        "be < 256, in position %d.",
     311             :                                        lptr->wlen, pos)));
     312             : 
     313          64 :                 state = LQPRS_WAITVAR;
     314             :             }
     315         604 :             else if (charlen == 1 && t_iseq(ptr, '.'))
     316             :             {
     317        1278 :                 lptr->len = ptr - lptr->start -
     318         852 :                     ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
     319         852 :                     ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
     320         426 :                     ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
     321         426 :                 if (lptr->wlen > 255)
     322           0 :                     ereport(ERROR,
     323             :                             (errcode(ERRCODE_NAME_TOO_LONG),
     324             :                              errmsg("name of level is too long"),
     325             :                              errdetail("Name length is %d, must "
     326             :                                        "be < 256, in position %d.",
     327             :                                        lptr->wlen, pos)));
     328             : 
     329         426 :                 state = LQPRS_WAITLEVEL;
     330         426 :                 curqlevel = NEXTLEV(curqlevel);
     331             :             }
     332         178 :             else if (ISALNUM(ptr))
     333             :             {
     334         356 :                 if (lptr->flag)
     335           0 :                     UNCHAR;
     336             :             }
     337             :             else
     338           0 :                 UNCHAR;
     339             :         }
     340         470 :         else if (state == LQPRS_WAITOPEN)
     341             :         {
     342         230 :             if (charlen == 1 && t_iseq(ptr, '{'))
     343          70 :                 state = LQPRS_WAITFNUM;
     344         160 :             else if (charlen == 1 && t_iseq(ptr, '.'))
     345             :             {
     346         160 :                 curqlevel->low = 0;
     347         160 :                 curqlevel->high = 0xffff;
     348         160 :                 curqlevel = NEXTLEV(curqlevel);
     349         160 :                 state = LQPRS_WAITLEVEL;
     350             :             }
     351             :             else
     352           0 :                 UNCHAR;
     353             :         }
     354         240 :         else if (state == LQPRS_WAITFNUM)
     355             :         {
     356          70 :             if (charlen == 1 && t_iseq(ptr, ','))
     357           4 :                 state = LQPRS_WAITSNUM;
     358          66 :             else if (t_isdigit(ptr))
     359             :             {
     360          66 :                 curqlevel->low = atoi(ptr);
     361          66 :                 state = LQPRS_WAITND;
     362             :             }
     363             :             else
     364           0 :                 UNCHAR;
     365             :         }
     366         170 :         else if (state == LQPRS_WAITSNUM)
     367             :         {
     368          26 :             if (t_isdigit(ptr))
     369             :             {
     370          22 :                 curqlevel->high = atoi(ptr);
     371          22 :                 state = LQPRS_WAITCLOSE;
     372             :             }
     373           4 :             else if (charlen == 1 && t_iseq(ptr, '}'))
     374             :             {
     375           4 :                 curqlevel->high = 0xffff;
     376           4 :                 state = LQPRS_WAITEND;
     377             :             }
     378             :             else
     379           0 :                 UNCHAR;
     380             :         }
     381         144 :         else if (state == LQPRS_WAITCLOSE)
     382             :         {
     383          22 :             if (charlen == 1 && t_iseq(ptr, '}'))
     384          22 :                 state = LQPRS_WAITEND;
     385           0 :             else if (!t_isdigit(ptr))
     386           0 :                 UNCHAR;
     387             :         }
     388         122 :         else if (state == LQPRS_WAITND)
     389             :         {
     390          66 :             if (charlen == 1 && t_iseq(ptr, '}'))
     391             :             {
     392          44 :                 curqlevel->high = curqlevel->low;
     393          44 :                 state = LQPRS_WAITEND;
     394             :             }
     395          22 :             else if (charlen == 1 && t_iseq(ptr, ','))
     396          22 :                 state = LQPRS_WAITSNUM;
     397           0 :             else if (!t_isdigit(ptr))
     398           0 :                 UNCHAR;
     399             :         }
     400          56 :         else if (state == LQPRS_WAITEND)
     401             :         {
     402          56 :             if (charlen == 1 && t_iseq(ptr, '.'))
     403             :             {
     404          56 :                 state = LQPRS_WAITLEVEL;
     405          56 :                 curqlevel = NEXTLEV(curqlevel);
     406             :             }
     407             :             else
     408           0 :                 UNCHAR;
     409             :         }
     410             :         else
     411             :             /* internal error */
     412           0 :             elog(ERROR, "internal error in parser");
     413             : 
     414        2154 :         ptr += charlen;
     415        2154 :         if (state == LQPRS_WAITDELIM)
     416         882 :             lptr->wlen++;
     417        2154 :         pos++;
     418             :     }
     419             : 
     420         260 :     if (state == LQPRS_WAITDELIM)
     421             :     {
     422         164 :         if (lptr->start == ptr)
     423           0 :             ereport(ERROR,
     424             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     425             :                      errmsg("syntax error"),
     426             :                      errdetail("Unexpected end of line.")));
     427             : 
     428         492 :         lptr->len = ptr - lptr->start -
     429         328 :             ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
     430         328 :             ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
     431         164 :             ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
     432         164 :         if (lptr->len == 0)
     433           0 :             ereport(ERROR,
     434             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     435             :                      errmsg("syntax error"),
     436             :                      errdetail("Unexpected end of line.")));
     437             : 
     438         164 :         if (lptr->wlen > 255)
     439           0 :             ereport(ERROR,
     440             :                     (errcode(ERRCODE_NAME_TOO_LONG),
     441             :                      errmsg("name of level is too long"),
     442             :                      errdetail("Name length is %d, must "
     443             :                                "be < 256, in position %d.",
     444             :                                lptr->wlen, pos)));
     445             :     }
     446          96 :     else if (state == LQPRS_WAITOPEN)
     447          82 :         curqlevel->high = 0xffff;
     448          14 :     else if (state != LQPRS_WAITEND)
     449           0 :         ereport(ERROR,
     450             :                 (errcode(ERRCODE_SYNTAX_ERROR),
     451             :                  errmsg("syntax error"),
     452             :                  errdetail("Unexpected end of line.")));
     453             : 
     454         260 :     curqlevel = tmpql;
     455         260 :     totallen = LQUERY_HDRSIZE;
     456        1422 :     while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
     457             :     {
     458         902 :         totallen += LQL_HDRSIZE;
     459         902 :         if (curqlevel->numvar)
     460             :         {
     461         590 :             lptr = GETVAR(curqlevel);
     462        1834 :             while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
     463             :             {
     464         654 :                 totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
     465         654 :                 lptr++;
     466             :             }
     467             :         }
     468         312 :         else if (curqlevel->low > curqlevel->high)
     469           0 :             ereport(ERROR,
     470             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     471             :                      errmsg("syntax error"),
     472             :                      errdetail("Low limit(%d) is greater than upper(%d).",
     473             :                                curqlevel->low, curqlevel->high)));
     474             : 
     475         902 :         curqlevel = NEXTLEV(curqlevel);
     476             :     }
     477             : 
     478         260 :     result = (lquery *) palloc0(totallen);
     479         260 :     SET_VARSIZE(result, totallen);
     480         260 :     result->numlevel = num;
     481         260 :     result->firstgood = 0;
     482         260 :     result->flag = 0;
     483         260 :     if (hasnot)
     484          80 :         result->flag |= LQUERY_HASNOT;
     485         260 :     cur = LQUERY_FIRST(result);
     486         260 :     curqlevel = tmpql;
     487        1422 :     while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
     488             :     {
     489         902 :         memcpy(cur, curqlevel, LQL_HDRSIZE);
     490         902 :         cur->totallen = LQL_HDRSIZE;
     491         902 :         if (curqlevel->numvar)
     492             :         {
     493         590 :             lrptr = LQL_FIRST(cur);
     494         590 :             lptr = GETVAR(curqlevel);
     495        1834 :             while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
     496             :             {
     497         654 :                 cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
     498         654 :                 lrptr->len = lptr->len;
     499         654 :                 lrptr->flag = lptr->flag;
     500         654 :                 lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
     501         654 :                 memcpy(lrptr->name, lptr->start, lptr->len);
     502         654 :                 lptr++;
     503         654 :                 lrptr = LVAR_NEXT(lrptr);
     504             :             }
     505         590 :             pfree(GETVAR(curqlevel));
     506         590 :             if (cur->numvar > 1 || cur->flag != 0)
     507         168 :                 wasbad = true;
     508         422 :             else if (wasbad == false)
     509         222 :                 (result->firstgood)++;
     510             :         }
     511             :         else
     512         312 :             wasbad = true;
     513         902 :         curqlevel = NEXTLEV(curqlevel);
     514         902 :         cur = LQL_NEXT(cur);
     515             :     }
     516             : 
     517         260 :     pfree(tmpql);
     518         260 :     PG_RETURN_POINTER(result);
     519             : }
     520             : 
     521             : Datum
     522          46 : lquery_out(PG_FUNCTION_ARGS)
     523             : {
     524          46 :     lquery     *in = PG_GETARG_LQUERY_P(0);
     525             :     char       *buf,
     526             :                *ptr;
     527             :     int         i,
     528             :                 j,
     529          46 :                 totallen = 1;
     530             :     lquery_level *curqlevel;
     531             :     lquery_variant *curtlevel;
     532             : 
     533          46 :     curqlevel = LQUERY_FIRST(in);
     534         176 :     for (i = 0; i < in->numlevel; i++)
     535             :     {
     536         130 :         totallen++;
     537         130 :         if (curqlevel->numvar)
     538          86 :             totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
     539             :         else
     540          44 :             totallen += 2 * 11 + 4;
     541         130 :         curqlevel = LQL_NEXT(curqlevel);
     542             :     }
     543             : 
     544          46 :     ptr = buf = (char *) palloc(totallen);
     545          46 :     curqlevel = LQUERY_FIRST(in);
     546         176 :     for (i = 0; i < in->numlevel; i++)
     547             :     {
     548         130 :         if (i != 0)
     549             :         {
     550          84 :             *ptr = '.';
     551          84 :             ptr++;
     552             :         }
     553         130 :         if (curqlevel->numvar)
     554             :         {
     555          86 :             if (curqlevel->flag & LQL_NOT)
     556             :             {
     557           0 :                 *ptr = '!';
     558           0 :                 ptr++;
     559             :             }
     560          86 :             curtlevel = LQL_FIRST(curqlevel);
     561         228 :             for (j = 0; j < curqlevel->numvar; j++)
     562             :             {
     563         142 :                 if (j != 0)
     564             :                 {
     565          56 :                     *ptr = '|';
     566          56 :                     ptr++;
     567             :                 }
     568         142 :                 memcpy(ptr, curtlevel->name, curtlevel->len);
     569         142 :                 ptr += curtlevel->len;
     570         142 :                 if ((curtlevel->flag & LVAR_SUBLEXEME))
     571             :                 {
     572           2 :                     *ptr = '%';
     573           2 :                     ptr++;
     574             :                 }
     575         142 :                 if ((curtlevel->flag & LVAR_INCASE))
     576             :                 {
     577           2 :                     *ptr = '@';
     578           2 :                     ptr++;
     579             :                 }
     580         142 :                 if ((curtlevel->flag & LVAR_ANYEND))
     581             :                 {
     582           2 :                     *ptr = '*';
     583           2 :                     ptr++;
     584             :                 }
     585         142 :                 curtlevel = LVAR_NEXT(curtlevel);
     586             :             }
     587             :         }
     588             :         else
     589             :         {
     590          44 :             if (curqlevel->low == curqlevel->high)
     591             :             {
     592           2 :                 sprintf(ptr, "*{%d}", curqlevel->low);
     593             :             }
     594          42 :             else if (curqlevel->low == 0)
     595             :             {
     596          38 :                 if (curqlevel->high == 0xffff)
     597             :                 {
     598          36 :                     *ptr = '*';
     599          36 :                     *(ptr + 1) = '\0';
     600             :                 }
     601             :                 else
     602           2 :                     sprintf(ptr, "*{,%d}", curqlevel->high);
     603             :             }
     604           4 :             else if (curqlevel->high == 0xffff)
     605             :             {
     606           2 :                 sprintf(ptr, "*{%d,}", curqlevel->low);
     607             :             }
     608             :             else
     609           2 :                 sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
     610          44 :             ptr = strchr(ptr, '\0');
     611             :         }
     612             : 
     613         130 :         curqlevel = LQL_NEXT(curqlevel);
     614             :     }
     615             : 
     616          46 :     *ptr = '\0';
     617          46 :     PG_FREE_IF_COPY(in, 0);
     618             : 
     619          46 :     PG_RETURN_POINTER(buf);
     620             : }

Generated by: LCOV version 1.13