LCOV - differential code coverage report
Current view: top level - contrib/ltree - ltree_io.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 86.0 % 392 337 8 13 26 8 6 144 30 157 39 154 2 13
Current Date: 2023-04-08 17:13:01 Functions: 81.0 % 21 17 4 14 3 4 17
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 78.9 % 38 30 8 30 1
Legend: Lines: hit not hit (240..) days: 86.7 % 354 307 13 26 8 6 144 157 30 152
Function coverage date bins:
(60,120] days: 100.0 % 3 3 3
(240..) days: 37.8 % 37 14 4 14 3 16

 Age         Owner                  TLA  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 "libpq/pqformat.h"
                                 12                 : #include "ltree.h"
                                 13                 : #include "utils/memutils.h"
                                 14                 : #include "varatt.h"
                                 15                 : 
                                 16                 : 
                                 17                 : typedef struct
                                 18                 : {
                                 19                 :     const char *start;
                                 20                 :     int         len;            /* length in bytes */
                                 21                 :     int         flag;
                                 22                 :     int         wlen;           /* length in characters */
                                 23                 : } nodeitem;
                                 24                 : 
                                 25                 : #define LTPRS_WAITNAME  0
                                 26                 : #define LTPRS_WAITDELIM 1
                                 27                 : 
                                 28                 : static bool finish_nodeitem(nodeitem *lptr, const char *ptr,
                                 29                 :                             bool is_lquery, int pos, struct Node *escontext);
                                 30                 : 
                                 31                 : 
                                 32                 : /*
                                 33                 :  * expects a null terminated string
                                 34                 :  * returns an ltree
                                 35                 :  */
                                 36                 : static ltree *
  102 andrew                     37 GNC        4851 : parse_ltree(const char *buf, struct Node *escontext)
 7522 bruce                      38 ECB             : {
                                 39                 :     const char *ptr;
                                 40                 :     nodeitem   *list,
                                 41                 :                *lptr;
 7522 bruce                      42 GIC        4851 :     int         num = 0,
 7522 bruce                      43 CBC        4851 :                 totallen = 0;
                                 44            4851 :     int         state = LTPRS_WAITNAME;
 7522 bruce                      45 ECB             :     ltree      *result;
                                 46                 :     ltree_level *curlevel;
                                 47                 :     int         charlen;
 1104 tgl                        48 GIC        4851 :     int         pos = 1;        /* character position for error messages */
 1104 tgl                        49 ECB             : 
                                 50                 : #define UNCHAR ereturn(escontext, NULL,\
                                 51                 :                        errcode(ERRCODE_SYNTAX_ERROR), \
                                 52                 :                        errmsg("ltree syntax error at character %d", \
                                 53                 :                               pos))
                                 54                 : 
 7522 bruce                      55 GIC        4851 :     ptr = buf;
 7522 bruce                      56 CBC      479073 :     while (*ptr)
 7522 bruce                      57 ECB             :     {
 5396 teodor                     58 GIC      474222 :         charlen = pg_mblen(ptr);
 1103 tgl                        59 CBC      474222 :         if (t_iseq(ptr, '.'))
 7558 bruce                      60          222765 :             num++;
 5050                            61          474222 :         ptr += charlen;
 7558 bruce                      62 ECB             :     }
                                 63                 : 
 1107 tgl                        64 GIC        4851 :     if (num + 1 > LTREE_MAX_LEVELS)
  102 andrew                     65 GNC           1 :         ereturn(escontext, NULL,
 3338 noah                       66 ECB             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                 67                 :                  errmsg("number of ltree labels (%d) exceeds the maximum allowed (%d)",
                                 68                 :                         num + 1, LTREE_MAX_LEVELS)));
 7522 bruce                      69 GIC        4850 :     list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
 7522 bruce                      70 CBC        4850 :     ptr = buf;
                                 71          347966 :     while (*ptr)
 7522 bruce                      72 ECB             :     {
 5396 teodor                     73 GIC      343121 :         charlen = pg_mblen(ptr);
 5396 teodor                     74 ECB             : 
 1103 tgl                        75 GIC      343121 :         switch (state)
 7522 bruce                      76 ECB             :         {
 1103 tgl                        77 GIC      162064 :             case LTPRS_WAITNAME:
   93 andrew                     78 GNC      162064 :                 if (ISLABEL(ptr))
 1103 tgl                        79 ECB             :                 {
 1103 tgl                        80 GIC      162059 :                     lptr->start = ptr;
 1103 tgl                        81 CBC      162059 :                     lptr->wlen = 0;
                                 82          162059 :                     state = LTPRS_WAITDELIM;
 1103 tgl                        83 ECB             :                 }
                                 84                 :                 else
 1103 tgl                        85 GIC           5 :                     UNCHAR;
 1103 tgl                        86 CBC      162059 :                 break;
                                 87          181057 :             case LTPRS_WAITDELIM:
                                 88          181057 :                 if (t_iseq(ptr, '.'))
 1103 tgl                        89 ECB             :                 {
  102 andrew                     90 GNC      157223 :                     if (!finish_nodeitem(lptr, ptr, false, pos, escontext))
  102 andrew                     91 UNC           0 :                         return NULL;
 1103 tgl                        92 CBC      157223 :                     totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
 1103 tgl                        93 GBC      157223 :                     lptr++;
 1103 tgl                        94 CBC      157223 :                     state = LTPRS_WAITNAME;
 1103 tgl                        95 ECB             :                 }
   93 andrew                     96 GNC       23834 :                 else if (!ISLABEL(ptr))
 1103 tgl                        97 UIC           0 :                     UNCHAR;
 1103 tgl                        98 CBC      181057 :                 break;
 1103 tgl                        99 UBC           0 :             default:
 1103 tgl                       100 LBC           0 :                 elog(ERROR, "internal error in ltree parser");
 7522 bruce                     101 EUB             :         }
 5396 teodor                    102                 : 
 5050 bruce                     103 GIC      343116 :         ptr += charlen;
 5396 teodor                    104          343116 :         lptr->wlen++;
 5396 teodor                    105 CBC      343116 :         pos++;
 7558 bruce                     106 ECB             :     }
                                107                 : 
 7522 bruce                     108 GIC        4845 :     if (state == LTPRS_WAITDELIM)
                                109                 :     {
  102 andrew                    110 GNC        4836 :         if (!finish_nodeitem(lptr, ptr, false, pos, escontext))
  102 andrew                    111 UNC           0 :             return NULL;
 7553 bruce                     112 GIC        4835 :         totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
 7558 bruce                     113 CBC        4835 :         lptr++;
 7522 bruce                     114 EUB             :     }
 7522 bruce                     115 CBC           9 :     else if (!(state == LTPRS_WAITNAME && lptr == list))
  102 andrew                    116 GNC           3 :         ereturn(escontext, NULL,
                                117                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
 1104 tgl                       118 ECB             :                  errmsg("ltree syntax error"),
                                119                 :                  errdetail("Unexpected end of input.")));
                                120                 : 
 5476 tgl                       121 GIC        4841 :     result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
 5884                           122            4841 :     SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
 7522 bruce                     123            4841 :     result->numlevel = lptr - list;
 7558 bruce                     124 CBC        4841 :     curlevel = LTREE_FIRST(result);
 7522                           125            4841 :     lptr = list;
                                126          166892 :     while (lptr - list < result->numlevel)
 7522 bruce                     127 ECB             :     {
 5396 teodor                    128 CBC      162051 :         curlevel->len = (uint16) lptr->len;
 7522 bruce                     129          162051 :         memcpy(curlevel->name, lptr->start, lptr->len);
 7522 bruce                     130 GIC      162051 :         curlevel = LEVEL_NEXT(curlevel);
 7558 bruce                     131 CBC      162051 :         lptr++;
 7558 bruce                     132 ECB             :     }
                                133                 : 
 7558 bruce                     134 CBC        4841 :     pfree(list);
 1103 tgl                       135 GIC        4841 :     return result;
                                136                 : 
 1104 tgl                       137 ECB             : #undef UNCHAR
 7558 bruce                     138                 : }
                                139                 : 
                                140                 : /*
                                141                 :  * expects an ltree
                                142                 :  * returns a null terminated string
                                143                 :  */
                                144                 : static char *
 1103 tgl                       145 GIC        6261 : deparse_ltree(const ltree *in)
                                146                 : {
                                147                 :     char       *buf,
 7522 bruce                     148 ECB             :                *ptr;
                                149                 :     int         i;
                                150                 :     ltree_level *curlevel;
                                151                 : 
 5884 tgl                       152 GIC        6261 :     ptr = buf = (char *) palloc(VARSIZE(in));
 7558 bruce                     153            6261 :     curlevel = LTREE_FIRST(in);
 7522                           154           47254 :     for (i = 0; i < in->numlevel; i++)
 7522 bruce                     155 ECB             :     {
 7522 bruce                     156 CBC       40993 :         if (i != 0)
 7522 bruce                     157 ECB             :         {
 7558 bruce                     158 GIC       34746 :             *ptr = '.';
 7558 bruce                     159 CBC       34746 :             ptr++;
                                160                 :         }
 7522                           161           40993 :         memcpy(ptr, curlevel->name, curlevel->len);
                                162           40993 :         ptr += curlevel->len;
 7558 bruce                     163 GIC       40993 :         curlevel = LEVEL_NEXT(curlevel);
 7558 bruce                     164 ECB             :     }
                                165                 : 
 7522 bruce                     166 CBC        6261 :     *ptr = '\0';
 1103 tgl                       167 GIC        6261 :     return buf;
                                168                 : }
 1103 tgl                       169 ECB             : 
                                170                 : /*
                                171                 :  * Basic ltree I/O functions
                                172                 :  */
 1103 tgl                       173 GIC           4 : PG_FUNCTION_INFO_V1(ltree_in);
                                174                 : Datum
                                175            4851 : ltree_in(PG_FUNCTION_ARGS)
 1103 tgl                       176 ECB             : {
 1103 tgl                       177 GIC        4851 :     char       *buf = (char *) PG_GETARG_POINTER(0);
                                178                 :     ltree      *res;
 1103 tgl                       179 ECB             : 
  102 andrew                    180 GNC        4851 :     if ((res = parse_ltree(buf, fcinfo->context)) == NULL)
                                181               4 :         PG_RETURN_NULL();
                                182                 : 
                                183            4841 :     PG_RETURN_POINTER(res);
 1103 tgl                       184 ECB             : }
                                185                 : 
 1103 tgl                       186 GIC           3 : PG_FUNCTION_INFO_V1(ltree_out);
 1103 tgl                       187 ECB             : Datum
 1103 tgl                       188 CBC        6261 : ltree_out(PG_FUNCTION_ARGS)
                                189                 : {
                                190            6261 :     ltree      *in = PG_GETARG_LTREE_P(0);
                                191                 : 
 1103 tgl                       192 GIC        6261 :     PG_RETURN_POINTER(deparse_ltree(in));
 1103 tgl                       193 ECB             : }
                                194                 : 
                                195                 : /*
                                196                 :  * ltree type send function
                                197                 :  *
                                198                 :  * The type is sent as text in binary mode, so this is almost the same
                                199                 :  * as the output function, but it's prefixed with a version number so we
                                200                 :  * can change the binary format sent in future if necessary. For now,
                                201                 :  * only version 1 is supported.
                                202                 :  */
 1103 tgl                       203 GIC           2 : PG_FUNCTION_INFO_V1(ltree_send);
                                204                 : Datum
 1103 tgl                       205 UIC           0 : ltree_send(PG_FUNCTION_ARGS)
                                206                 : {
                                207               0 :     ltree      *in = PG_GETARG_LTREE_P(0);
                                208                 :     StringInfoData buf;
                                209               0 :     int         version = 1;
 1103 tgl                       210 LBC           0 :     char       *res = deparse_ltree(in);
                                211                 : 
 1103 tgl                       212 UBC           0 :     pq_begintypsend(&buf);
 1103 tgl                       213 UIC           0 :     pq_sendint8(&buf, version);
 1103 tgl                       214 UBC           0 :     pq_sendtext(&buf, res, strlen(res));
 1103 tgl                       215 UIC           0 :     pfree(res);
 1103 tgl                       216 EUB             : 
 1103 tgl                       217 UBC           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                                218                 : }
 1103 tgl                       219 EUB             : 
                                220                 : /*
                                221                 :  * ltree type recv function
                                222                 :  *
                                223                 :  * The type is sent as text in binary mode, so this is almost the same
                                224                 :  * as the input function, but it's prefixed with a version number so we
                                225                 :  * can change the binary format sent in future if necessary. For now,
                                226                 :  * only version 1 is supported.
                                227                 :  */
 1103 tgl                       228 GIC           2 : PG_FUNCTION_INFO_V1(ltree_recv);
                                229                 : Datum
 1103 tgl                       230 UIC           0 : ltree_recv(PG_FUNCTION_ARGS)
                                231                 : {
                                232               0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                233               0 :     int         version = pq_getmsgint(buf, 1);
                                234                 :     char       *str;
 1103 tgl                       235 ECB             :     int         nbytes;
                                236                 :     ltree      *res;
 7558 bruce                     237 EUB             : 
 1103 tgl                       238 UIC           0 :     if (version != 1)
 1103 tgl                       239 UBC           0 :         elog(ERROR, "unsupported ltree version number %d", version);
 1103 tgl                       240 EUB             : 
 1103 tgl                       241 UIC           0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
  102 andrew                    242 UNC           0 :     res = parse_ltree(str, NULL);
 1103 tgl                       243 UIC           0 :     pfree(str);
                                244                 : 
 1103 tgl                       245 UBC           0 :     PG_RETURN_POINTER(res);
 7558 bruce                     246 EUB             : }
                                247                 : 
 1103 tgl                       248                 : 
 7522 bruce                     249                 : #define LQPRS_WAITLEVEL 0
                                250                 : #define LQPRS_WAITDELIM 1
                                251                 : #define LQPRS_WAITOPEN  2
                                252                 : #define LQPRS_WAITFNUM  3
                                253                 : #define LQPRS_WAITSNUM  4
                                254                 : #define LQPRS_WAITND    5
                                255                 : #define LQPRS_WAITCLOSE 6
                                256                 : #define LQPRS_WAITEND   7
                                257                 : #define LQPRS_WAITVAR   8
                                258                 : 
                                259                 : 
                                260                 : #define GETVAR(x) ( *((nodeitem**)LQL_FIRST(x)) )
                                261                 : #define ITEMSIZE    MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
                                262                 : #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
                                263                 : 
                                264                 : /*
                                265                 :  * expects a null terminated string
                                266                 :  * returns an lquery
                                267                 :  */
                                268                 : static lquery *
  102 andrew                    269 GNC         191 : parse_lquery(const char *buf, struct Node *escontext)
                                270                 : {
                                271                 :     const char *ptr;
 7522 bruce                     272 GIC         191 :     int         num = 0,
                                273             191 :                 totallen = 0,
                                274             191 :                 numOR = 0;
                                275             191 :     int         state = LQPRS_WAITLEVEL;
 7522 bruce                     276 ECB             :     lquery     *result;
 7522 bruce                     277 GIC         191 :     nodeitem   *lptr = NULL;
                                278                 :     lquery_level *cur,
 7522 bruce                     279 ECB             :                *curqlevel,
                                280                 :                *tmpql;
 7522 bruce                     281 CBC         191 :     lquery_variant *lrptr = NULL;
                                282             191 :     bool        hasnot = false;
 7522 bruce                     283 GIC         191 :     bool        wasbad = false;
 5396 teodor                    284 ECB             :     int         charlen;
 1104 tgl                       285 GIC         191 :     int         pos = 1;        /* character position for error messages */
                                286                 : 
                                287                 : #define UNCHAR ereturn(escontext, NULL,\
 1104 tgl                       288 ECB             :                        errcode(ERRCODE_SYNTAX_ERROR), \
                                289                 :                        errmsg("lquery syntax error at character %d", \
                                290                 :                               pos))
                                291                 : 
 7522 bruce                     292 CBC         191 :     ptr = buf;
 7522 bruce                     293 GIC      267834 :     while (*ptr)
                                294                 :     {
 5396 teodor                    295          267643 :         charlen = pg_mblen(ptr);
                                296                 : 
 1103 tgl                       297          267643 :         if (t_iseq(ptr, '.'))
                                298          131474 :             num++;
 1103 tgl                       299 CBC      136169 :         else if (t_iseq(ptr, '|'))
                                300              34 :             numOR++;
                                301                 : 
 5050 bruce                     302          267643 :         ptr += charlen;
                                303                 :     }
 7522 bruce                     304 ECB             : 
 7558 bruce                     305 CBC         191 :     num++;
 1107 tgl                       306             191 :     if (num > LQUERY_MAX_LEVELS)
  102 andrew                    307 GNC           1 :         ereturn(escontext, NULL,
                                308                 :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 1104 tgl                       309 ECB             :                  errmsg("number of lquery items (%d) exceeds the maximum allowed (%d)",
                                310                 :                         num, LQUERY_MAX_LEVELS)));
 5476 tgl                       311 GIC         190 :     curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
 7522 bruce                     312 CBC         190 :     ptr = buf;
                                313          136706 :     while (*ptr)
 7522 bruce                     314 ECB             :     {
 5396 teodor                    315 GIC      136531 :         charlen = pg_mblen(ptr);
                                316                 : 
 1103 tgl                       317          136531 :         switch (state)
 7522 bruce                     318 ECB             :         {
 1103 tgl                       319 CBC       66112 :             case LQPRS_WAITLEVEL:
   93 andrew                    320 GNC       66112 :                 if (ISLABEL(ptr))
                                321                 :                 {
 1103 tgl                       322 CBC       65839 :                     GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
 1103 tgl                       323 GIC       65839 :                     lptr->start = ptr;
 1103 tgl                       324 CBC       65839 :                     state = LQPRS_WAITDELIM;
 1103 tgl                       325 GIC       65839 :                     curqlevel->numvar = 1;
 1103 tgl                       326 ECB             :                 }
 1103 tgl                       327 CBC         273 :                 else if (t_iseq(ptr, '!'))
                                328                 :                 {
                                329              78 :                     GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
                                330              78 :                     lptr->start = ptr + 1;
                                331              78 :                     lptr->wlen = -1; /* compensate for counting ! below */
                                332              78 :                     state = LQPRS_WAITDELIM;
 1103 tgl                       333 GIC          78 :                     curqlevel->numvar = 1;
 1103 tgl                       334 CBC          78 :                     curqlevel->flag |= LQL_NOT;
 1103 tgl                       335 GIC          78 :                     hasnot = true;
 1103 tgl                       336 ECB             :                 }
 1103 tgl                       337 CBC         195 :                 else if (t_iseq(ptr, '*'))
                                338             186 :                     state = LQPRS_WAITOPEN;
 1103 tgl                       339 ECB             :                 else
 7558 bruce                     340 CBC           9 :                     UNCHAR;
 1103 tgl                       341           66103 :                 break;
                                342              34 :             case LQPRS_WAITVAR:
   93 andrew                    343 GNC          34 :                 if (ISLABEL(ptr))
 1103 tgl                       344 ECB             :                 {
 1103 tgl                       345 CBC          33 :                     lptr++;
 1103 tgl                       346 GIC          33 :                     lptr->start = ptr;
 1103 tgl                       347 CBC          33 :                     state = LQPRS_WAITDELIM;
                                348              33 :                     curqlevel->numvar++;
 1103 tgl                       349 ECB             :                 }
                                350                 :                 else
 7558 bruce                     351 GIC           1 :                     UNCHAR;
 1103 tgl                       352 CBC          33 :                 break;
                                353           70007 :             case LQPRS_WAITDELIM:
                                354           70007 :                 if (t_iseq(ptr, '@'))
 1103 tgl                       355 ECB             :                 {
 1103 tgl                       356 GIC          19 :                     lptr->flag |= LVAR_INCASE;
                                357              19 :                     curqlevel->flag |= LVAR_INCASE;
 1103 tgl                       358 ECB             :                 }
 1103 tgl                       359 CBC       69988 :                 else if (t_iseq(ptr, '*'))
 1103 tgl                       360 ECB             :                 {
 1103 tgl                       361 CBC          19 :                     lptr->flag |= LVAR_ANYEND;
 1103 tgl                       362 GIC          19 :                     curqlevel->flag |= LVAR_ANYEND;
 1103 tgl                       363 ECB             :                 }
 1103 tgl                       364 CBC       69969 :                 else if (t_iseq(ptr, '%'))
                                365                 :                 {
                                366               6 :                     lptr->flag |= LVAR_SUBLEXEME;
 1103 tgl                       367 GIC           6 :                     curqlevel->flag |= LVAR_SUBLEXEME;
 1103 tgl                       368 ECB             :                 }
 1103 tgl                       369 CBC       69963 :                 else if (t_iseq(ptr, '|'))
                                370                 :                 {
  102 andrew                    371 GNC          34 :                     if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
  102 andrew                    372 UNC           0 :                         return NULL;
 1103 tgl                       373 GIC          34 :                     state = LQPRS_WAITVAR;
 1103 tgl                       374 ECB             :                 }
 1103 tgl                       375 CBC       69929 :                 else if (t_iseq(ptr, '{'))
                                376                 :                 {
  102 andrew                    377 GNC          20 :                     if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
  102 andrew                    378 UNC           0 :                         return NULL;
 1103 tgl                       379 GIC          20 :                     curqlevel->flag |= LQL_COUNT;
 1103 tgl                       380 CBC          20 :                     state = LQPRS_WAITFNUM;
 1103 tgl                       381 EUB             :                 }
 1103 tgl                       382 CBC       69909 :                 else if (t_iseq(ptr, '.'))
                                383                 :                 {
  102 andrew                    384 GNC       65789 :                     if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
  102 andrew                    385 UNC           0 :                         return NULL;
 1103 tgl                       386 GIC       65787 :                     state = LQPRS_WAITLEVEL;
 1103 tgl                       387 CBC       65787 :                     curqlevel = NEXTLEV(curqlevel);
 1103 tgl                       388 EUB             :                 }
   93 andrew                    389 GNC        4120 :                 else if (ISLABEL(ptr))
 1103 tgl                       390 ECB             :                 {
                                391                 :                     /* disallow more chars after a flag */
 1103 tgl                       392 CBC        4120 :                     if (lptr->flag)
 1103 tgl                       393 UIC           0 :                         UNCHAR;
 1103 tgl                       394 ECB             :                 }
 1103 tgl                       395 EUB             :                 else
 7558 bruce                     396 LBC           0 :                     UNCHAR;
 1103 tgl                       397 CBC       70005 :                 break;
 1103 tgl                       398 GIC         140 :             case LQPRS_WAITOPEN:
 1103 tgl                       399 CBC         140 :                 if (t_iseq(ptr, '{'))
 1103 tgl                       400 GIC          50 :                     state = LQPRS_WAITFNUM;
                                401              90 :                 else if (t_iseq(ptr, '.'))
 1103 tgl                       402 ECB             :                 {
 1103 tgl                       403 EUB             :                     /* We only get here for '*', so these are correct defaults */
 1103 tgl                       404 GIC          90 :                     curqlevel->low = 0;
                                405              90 :                     curqlevel->high = LTREE_MAX_LEVELS;
 1103 tgl                       406 GBC          90 :                     curqlevel = NEXTLEV(curqlevel);
 1103 tgl                       407 CBC          90 :                     state = LQPRS_WAITLEVEL;
 1103 tgl                       408 ECB             :                 }
                                409                 :                 else
 7558 bruce                     410 LBC           0 :                     UNCHAR;
 1103 tgl                       411 CBC         140 :                 break;
 1103 tgl                       412 GIC          70 :             case LQPRS_WAITFNUM:
                                413              70 :                 if (t_iseq(ptr, ','))
 1103 tgl                       414 CBC          16 :                     state = LQPRS_WAITSNUM;
                                415              54 :                 else if (t_isdigit(ptr))
 1103 tgl                       416 ECB             :                 {
 1103 tgl                       417 CBC          54 :                     int         low = atoi(ptr);
                                418                 : 
 1103 tgl                       419 GIC          54 :                     if (low < 0 || low > LTREE_MAX_LEVELS)
  102 andrew                    420 GNC           1 :                         ereturn(escontext, NULL,
 1103 tgl                       421 ECB             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                422                 :                                  errmsg("lquery syntax error"),
                                423                 :                                  errdetail("Low limit (%d) exceeds the maximum allowed (%d), at character %d.",
                                424                 :                                            low, LTREE_MAX_LEVELS, pos)));
                                425                 : 
 1103 tgl                       426 GIC          53 :                     curqlevel->low = (uint16) low;
 1103 tgl                       427 CBC          53 :                     state = LQPRS_WAITND;
                                428                 :                 }
 1103 tgl                       429 ECB             :                 else
 1103 tgl                       430 LBC           0 :                     UNCHAR;
 1103 tgl                       431 GIC          69 :                 break;
                                432              37 :             case LQPRS_WAITSNUM:
                                433              37 :                 if (t_isdigit(ptr))
                                434                 :                 {
                                435              21 :                     int         high = atoi(ptr);
 1103 tgl                       436 ECB             : 
 1103 tgl                       437 CBC          21 :                     if (high < 0 || high > LTREE_MAX_LEVELS)
  102 andrew                    438 GNC           1 :                         ereturn(escontext, NULL,
                                439                 :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
 1103 tgl                       440 EUB             :                                  errmsg("lquery syntax error"),
 1103 tgl                       441 ECB             :                                  errdetail("High limit (%d) exceeds the maximum allowed (%d), at character %d.",
                                442                 :                                            high, LTREE_MAX_LEVELS, pos)));
 1103 tgl                       443 CBC          20 :                     else if (curqlevel->low > high)
  102 andrew                    444 GNC           1 :                         ereturn(escontext, NULL,
 1103 tgl                       445 ECB             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
                                446                 :                                  errmsg("lquery syntax error"),
                                447                 :                                  errdetail("Low limit (%d) is greater than high limit (%d), at character %d.",
                                448                 :                                            curqlevel->low, high, pos)));
                                449                 : 
 1103 tgl                       450 GIC          19 :                     curqlevel->high = (uint16) high;
                                451              19 :                     state = LQPRS_WAITCLOSE;
                                452                 :                 }
 1103 tgl                       453 CBC          16 :                 else if (t_iseq(ptr, '}'))
 1103 tgl                       454 ECB             :                 {
 1103 tgl                       455 GIC          16 :                     curqlevel->high = LTREE_MAX_LEVELS;
                                456              16 :                     state = LQPRS_WAITEND;
                                457                 :                 }
                                458                 :                 else
 1103 tgl                       459 UIC           0 :                     UNCHAR;
 1103 tgl                       460 CBC          35 :                 break;
                                461              28 :             case LQPRS_WAITCLOSE:
 1103 tgl                       462 GIC          28 :                 if (t_iseq(ptr, '}'))
 1103 tgl                       463 CBC          19 :                     state = LQPRS_WAITEND;
 1103 tgl                       464 GIC           9 :                 else if (!t_isdigit(ptr))
 1103 tgl                       465 LBC           0 :                     UNCHAR;
 1103 tgl                       466 CBC          28 :                 break;
 1103 tgl                       467 GIC          57 :             case LQPRS_WAITND:
                                468              57 :                 if (t_iseq(ptr, '}'))
 1103 tgl                       469 EUB             :                 {
 1103 tgl                       470 CBC          32 :                     curqlevel->high = curqlevel->low;
                                471              32 :                     state = LQPRS_WAITEND;
 1103 tgl                       472 ECB             :                 }
 1103 tgl                       473 CBC          25 :                 else if (t_iseq(ptr, ','))
                                474              21 :                     state = LQPRS_WAITSNUM;
 1103 tgl                       475 GBC           4 :                 else if (!t_isdigit(ptr))
 1103 tgl                       476 LBC           0 :                     UNCHAR;
 1103 tgl                       477 CBC          57 :                 break;
                                478              46 :             case LQPRS_WAITEND:
 1103 tgl                       479 GIC          46 :                 if (t_iseq(ptr, '.'))
 1103 tgl                       480 ECB             :                 {
 1103 tgl                       481 CBC          46 :                     state = LQPRS_WAITLEVEL;
 1103 tgl                       482 GIC          46 :                     curqlevel = NEXTLEV(curqlevel);
 1103 tgl                       483 ECB             :                 }
                                484                 :                 else
 1103 tgl                       485 LBC           0 :                     UNCHAR;
 1103 tgl                       486 GBC          46 :                 break;
 1103 tgl                       487 LBC           0 :             default:
                                488               0 :                 elog(ERROR, "internal error in lquery parser");
 7522 bruce                     489 ECB             :         }
                                490                 : 
 5050 bruce                     491 CBC      136516 :         ptr += charlen;
                                492          136516 :         if (state == LQPRS_WAITDELIM)
 5396 teodor                    493 GIC       70114 :             lptr->wlen++;
                                494          136516 :         pos++;
 7558 bruce                     495 EUB             :     }
 7522 bruce                     496 ECB             : 
 7522 bruce                     497 GBC         175 :     if (state == LQPRS_WAITDELIM)
                                498                 :     {
  102 andrew                    499 GNC         107 :         if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
  101 andrew                    500 UNC           0 :             return NULL;
                                501                 :     }
 7522 bruce                     502 GIC          68 :     else if (state == LQPRS_WAITOPEN)
 1107 tgl                       503              46 :         curqlevel->high = LTREE_MAX_LEVELS;
 7522 bruce                     504 CBC          22 :     else if (state != LQPRS_WAITEND)
  102 andrew                    505 GNC           1 :         ereturn(escontext, NULL,
 7199 tgl                       506 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
 1107                           507                 :                  errmsg("lquery syntax error"),
                                508                 :                  errdetail("Unexpected end of input.")));
                                509                 : 
 7558 bruce                     510 CBC         171 :     curqlevel = tmpql;
 7522 bruce                     511 GIC         171 :     totallen = LQUERY_HDRSIZE;
 7522 bruce                     512 CBC       66254 :     while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
 7522 bruce                     513 EUB             :     {
 7522 bruce                     514 GIC       66083 :         totallen += LQL_HDRSIZE;
 7522 bruce                     515 CBC       66083 :         if (curqlevel->numvar)
 7522 bruce                     516 ECB             :         {
 7558 bruce                     517 CBC       65900 :             lptr = GETVAR(curqlevel);
 7522                           518          131833 :             while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
                                519                 :             {
 7553 bruce                     520 GIC       65933 :                 totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
 7558                           521           65933 :                 lptr++;
                                522                 :             }
 7522 bruce                     523 ECB             :         }
 7553 bruce                     524 CBC       66083 :         curqlevel = NEXTLEV(curqlevel);
 7558 bruce                     525 ECB             :     }
                                526                 : 
 5476 tgl                       527 CBC         171 :     result = (lquery *) palloc0(totallen);
 5884                           528             171 :     SET_VARSIZE(result, totallen);
 7558 bruce                     529 GIC         171 :     result->numlevel = num;
 7558 bruce                     530 CBC         171 :     result->firstgood = 0;
 7522                           531             171 :     result->flag = 0;
 7522 bruce                     532 GIC         171 :     if (hasnot)
 7558 bruce                     533 CBC          52 :         result->flag |= LQUERY_HASNOT;
                                534             171 :     cur = LQUERY_FIRST(result);
 7558 bruce                     535 GIC         171 :     curqlevel = tmpql;
 7522                           536           66254 :     while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
 7522 bruce                     537 ECB             :     {
 7522 bruce                     538 GIC       66083 :         memcpy(cur, curqlevel, LQL_HDRSIZE);
                                539           66083 :         cur->totallen = LQL_HDRSIZE;
 7522 bruce                     540 CBC       66083 :         if (curqlevel->numvar)
 7522 bruce                     541 ECB             :         {
 7558 bruce                     542 CBC       65900 :             lrptr = LQL_FIRST(cur);
                                543           65900 :             lptr = GETVAR(curqlevel);
 7522                           544          131833 :             while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
 7522 bruce                     545 ECB             :             {
 7553 bruce                     546 CBC       65933 :                 cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
 7522                           547           65933 :                 lrptr->len = lptr->len;
 7558                           548           65933 :                 lrptr->flag = lptr->flag;
 6406 tgl                       549           65933 :                 lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
 7522 bruce                     550 GIC       65933 :                 memcpy(lrptr->name, lptr->start, lptr->len);
 7558 bruce                     551 CBC       65933 :                 lptr++;
 7522                           552           65933 :                 lrptr = LVAR_NEXT(lrptr);
 7558 bruce                     553 ECB             :             }
 7522 bruce                     554 GIC       65900 :             pfree(GETVAR(curqlevel));
 7522 bruce                     555 CBC       65900 :             if (cur->numvar > 1 || cur->flag != 0)
 1106 tgl                       556 ECB             :             {
                                557                 :                 /* Not a simple match */
 7522 bruce                     558 GIC         112 :                 wasbad = true;
 1106 tgl                       559 ECB             :             }
 7522 bruce                     560 CBC       65788 :             else if (wasbad == false)
 1106 tgl                       561 ECB             :             {
                                562                 :                 /* count leading simple matches */
 7522 bruce                     563 CBC       65674 :                 (result->firstgood)++;
 1106 tgl                       564 ECB             :             }
 7522 bruce                     565                 :         }
                                566                 :         else
 1106 tgl                       567                 :         {
                                568                 :             /* '*', so this isn't a simple match */
 7522 bruce                     569 GIC         183 :             wasbad = true;
                                570                 :         }
 7553 bruce                     571 CBC       66083 :         curqlevel = NEXTLEV(curqlevel);
 7558 bruce                     572 GIC       66083 :         cur = LQL_NEXT(cur);
 7558 bruce                     573 ECB             :     }
                                574                 : 
 7558 bruce                     575 GIC         171 :     pfree(tmpql);
 1103 tgl                       576 CBC         171 :     return result;
                                577                 : 
                                578                 : #undef UNCHAR
                                579                 : }
                                580                 : 
                                581                 : /*
 1103 tgl                       582 ECB             :  * Close out parsing an ltree or lquery nodeitem:
                                583                 :  * compute the correct length, and complain if it's not OK
                                584                 :  */
                                585                 : static bool
  102 andrew                    586 GNC      228009 : finish_nodeitem(nodeitem *lptr, const char *ptr, bool is_lquery, int pos,
                                587                 :     struct Node *escontext)
                                588                 : {
 1103 tgl                       589 CBC      228009 :     if (is_lquery)
 1103 tgl                       590 ECB             :     {
                                591                 :         /*
                                592                 :          * Back up over any flag characters, and discount them from length and
                                593                 :          * position.
                                594                 :          */
 1103 tgl                       595 GIC       65994 :         while (ptr > lptr->start && strchr("@*%", ptr[-1]) != NULL)
                                596                 :         {
                                597              44 :             ptr--;
                                598              44 :             lptr->wlen--;
                                599              44 :             pos--;
 1103 tgl                       600 ECB             :         }
                                601                 :     }
                                602                 : 
                                603                 :     /* Now compute the byte length, which we weren't tracking before. */
 1103 tgl                       604 GIC      228009 :     lptr->len = ptr - lptr->start;
                                605                 : 
                                606                 :     /* Complain if it's empty or too long */
                                607          228009 :     if (lptr->len == 0)
  102 andrew                    608 GNC           3 :         ereturn(escontext, false,
 1103 tgl                       609 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                610                 :                  is_lquery ?
                                611                 :                  errmsg("lquery syntax error at character %d", pos) :
                                612                 :                  errmsg("ltree syntax error at character %d", pos),
                                613                 :                  errdetail("Empty labels are not allowed.")));
 1103 tgl                       614 GIC      228006 :     if (lptr->wlen > LTREE_LABEL_MAX_CHARS)
  102 andrew                    615 GNC           3 :         ereturn(escontext, false,
                                616                 :                 (errcode(ERRCODE_NAME_TOO_LONG),
                                617                 :                  errmsg("label string is too long"),
 1103 tgl                       618 ECB             :                  errdetail("Label length is %d, must be at most %d, at character %d.",
                                619                 :                            lptr->wlen, LTREE_LABEL_MAX_CHARS, pos)));
  102 andrew                    620 GNC      228003 :     return true;
                                621                 : }
 1103 tgl                       622 ECB             : 
                                623                 : /*
                                624                 :  * expects an lquery
                                625                 :  * returns a null terminated string
                                626                 :  */
                                627                 : static char *
 1103 tgl                       628 GIC          30 : deparse_lquery(const lquery *in)
 7522 bruce                     629 ECB             : {
                                630                 :     char       *buf,
                                631                 :                *ptr;
                                632                 :     int         i,
                                633                 :                 j,
 7053 tgl                       634 GIC          30 :                 totallen = 1;
 7522 bruce                     635 ECB             :     lquery_level *curqlevel;
                                636                 :     lquery_variant *curtlevel;
                                637                 : 
 7558 bruce                     638 GIC          30 :     curqlevel = LQUERY_FIRST(in);
 7522                           639             106 :     for (i = 0; i < in->numlevel; i++)
                                640                 :     {
 7053 tgl                       641              76 :         totallen++;
 7522 bruce                     642              76 :         if (curqlevel->numvar)
 1104 tgl                       643 ECB             :         {
 7053 tgl                       644 GIC          51 :             totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
 1104                           645              51 :             if (curqlevel->flag & LQL_COUNT)
                                646               4 :                 totallen += 2 * 11 + 3;
                                647                 :         }
                                648                 :         else
 7053 tgl                       649 CBC          25 :             totallen += 2 * 11 + 4;
 7558 bruce                     650 GIC          76 :         curqlevel = LQL_NEXT(curqlevel);
                                651                 :     }
                                652                 : 
 7522 bruce                     653 CBC          30 :     ptr = buf = (char *) palloc(totallen);
 7558                           654              30 :     curqlevel = LQUERY_FIRST(in);
 7522 bruce                     655 GIC         106 :     for (i = 0; i < in->numlevel; i++)
 7522 bruce                     656 ECB             :     {
 7522 bruce                     657 CBC          76 :         if (i != 0)
                                658                 :         {
 7558                           659              46 :             *ptr = '.';
                                660              46 :             ptr++;
 7558 bruce                     661 ECB             :         }
 7522 bruce                     662 GIC          76 :         if (curqlevel->numvar)
                                663                 :         {
 7522 bruce                     664 CBC          51 :             if (curqlevel->flag & LQL_NOT)
 7522 bruce                     665 ECB             :             {
 7558 bruce                     666 GIC           2 :                 *ptr = '!';
                                667               2 :                 ptr++;
 7558 bruce                     668 ECB             :             }
 7558 bruce                     669 CBC          51 :             curtlevel = LQL_FIRST(curqlevel);
 7522                           670             131 :             for (j = 0; j < curqlevel->numvar; j++)
                                671                 :             {
                                672              80 :                 if (j != 0)
                                673                 :                 {
 7558                           674              29 :                     *ptr = '|';
                                675              29 :                     ptr++;
                                676                 :                 }
 7522                           677              80 :                 memcpy(ptr, curtlevel->name, curtlevel->len);
 7522 bruce                     678 GIC          80 :                 ptr += curtlevel->len;
 6248 neilc                     679 CBC          80 :                 if ((curtlevel->flag & LVAR_SUBLEXEME))
                                680                 :                 {
 7558 bruce                     681               1 :                     *ptr = '%';
                                682               1 :                     ptr++;
                                683                 :                 }
 7522                           684              80 :                 if ((curtlevel->flag & LVAR_INCASE))
 7522 bruce                     685 ECB             :                 {
 7558 bruce                     686 GIC           3 :                     *ptr = '@';
 7558 bruce                     687 CBC           3 :                     ptr++;
                                688                 :                 }
 7522                           689              80 :                 if ((curtlevel->flag & LVAR_ANYEND))
 7522 bruce                     690 ECB             :                 {
 7558 bruce                     691 GIC           4 :                     *ptr = '*';
 7558 bruce                     692 CBC           4 :                     ptr++;
 7558 bruce                     693 ECB             :                 }
 7558 bruce                     694 CBC          80 :                 curtlevel = LVAR_NEXT(curtlevel);
                                695                 :             }
 7522 bruce                     696 ECB             :         }
                                697                 :         else
                                698                 :         {
 1104 tgl                       699 CBC          25 :             *ptr = '*';
 1104 tgl                       700 GIC          25 :             ptr++;
 1104 tgl                       701 ECB             :         }
                                702                 : 
 1104 tgl                       703 GIC          76 :         if ((curqlevel->flag & LQL_COUNT) || curqlevel->numvar == 0)
 7522 bruce                     704 ECB             :         {
 7522 bruce                     705 GIC          29 :             if (curqlevel->low == curqlevel->high)
 7522 bruce                     706 ECB             :             {
 1104 tgl                       707 CBC           2 :                 sprintf(ptr, "{%d}", curqlevel->low);
                                708                 :             }
 7522 bruce                     709              27 :             else if (curqlevel->low == 0)
                                710                 :             {
 1107 tgl                       711 GIC          23 :                 if (curqlevel->high == LTREE_MAX_LEVELS)
                                712                 :                 {
 1104                           713              20 :                     if (curqlevel->numvar == 0)
 1104 tgl                       714 ECB             :                     {
                                715                 :                         /* This is default for '*', so print nothing */
 1104 tgl                       716 GIC          19 :                         *ptr = '\0';
                                717                 :                     }
 1104 tgl                       718 ECB             :                     else
 1104 tgl                       719 GIC           1 :                         sprintf(ptr, "{,}");
 7522 bruce                     720 ECB             :                 }
                                721                 :                 else
 1104 tgl                       722 CBC           3 :                     sprintf(ptr, "{,%d}", curqlevel->high);
                                723                 :             }
 1107                           724               4 :             else if (curqlevel->high == LTREE_MAX_LEVELS)
                                725                 :             {
 1104                           726               2 :                 sprintf(ptr, "{%d,}", curqlevel->low);
                                727                 :             }
 7522 bruce                     728 ECB             :             else
 1104 tgl                       729 GIC           2 :                 sprintf(ptr, "{%d,%d}", curqlevel->low, curqlevel->high);
 7522 bruce                     730              29 :             ptr = strchr(ptr, '\0');
 7558 bruce                     731 ECB             :         }
                                732                 : 
 7558 bruce                     733 GIC          76 :         curqlevel = LQL_NEXT(curqlevel);
 7558 bruce                     734 ECB             :     }
                                735                 : 
 7522 bruce                     736 GIC          30 :     *ptr = '\0';
 1103 tgl                       737 CBC          30 :     return buf;
                                738                 : }
 1103 tgl                       739 ECB             : 
                                740                 : /*
                                741                 :  * Basic lquery I/O functions
                                742                 :  */
 1103 tgl                       743 GIC           3 : PG_FUNCTION_INFO_V1(lquery_in);
 1103 tgl                       744 ECB             : Datum
 1103 tgl                       745 CBC         191 : lquery_in(PG_FUNCTION_ARGS)
                                746                 : {
 1103 tgl                       747 GIC         191 :     char       *buf = (char *) PG_GETARG_POINTER(0);
                                748                 :     lquery     *res;
  102 andrew                    749 ECB             : 
  102 andrew                    750 GNC         191 :     if ((res = parse_lquery(buf, fcinfo->context)) == NULL)
                                751               4 :         PG_RETURN_NULL();
                                752                 : 
                                753             171 :     PG_RETURN_POINTER(res);
                                754                 : }
 1103 tgl                       755 ECB             : 
 1103 tgl                       756 CBC           3 : PG_FUNCTION_INFO_V1(lquery_out);
                                757                 : Datum
 1103 tgl                       758 GIC          30 : lquery_out(PG_FUNCTION_ARGS)
                                759                 : {
                                760              30 :     lquery     *in = PG_GETARG_LQUERY_P(0);
                                761                 : 
 1103 tgl                       762 CBC          30 :     PG_RETURN_POINTER(deparse_lquery(in));
                                763                 : }
 1103 tgl                       764 ECB             : 
                                765                 : /*
                                766                 :  * lquery type send function
                                767                 :  *
                                768                 :  * The type is sent as text in binary mode, so this is almost the same
                                769                 :  * as the output function, but it's prefixed with a version number so we
                                770                 :  * can change the binary format sent in future if necessary. For now,
                                771                 :  * only version 1 is supported.
                                772                 :  */
 1103 tgl                       773 GIC           2 : PG_FUNCTION_INFO_V1(lquery_send);
                                774                 : Datum
 1103 tgl                       775 LBC           0 : lquery_send(PG_FUNCTION_ARGS)
                                776                 : {
                                777               0 :     lquery     *in = PG_GETARG_LQUERY_P(0);
                                778                 :     StringInfoData buf;
                                779               0 :     int         version = 1;
 1103 tgl                       780 UIC           0 :     char       *res = deparse_lquery(in);
 1103 tgl                       781 ECB             : 
 1103 tgl                       782 UIC           0 :     pq_begintypsend(&buf);
                                783               0 :     pq_sendint8(&buf, version);
                                784               0 :     pq_sendtext(&buf, res, strlen(res));
                                785               0 :     pfree(res);
                                786                 : 
                                787               0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                                788                 : }
                                789                 : 
                                790                 : /*
                                791                 :  * lquery type recv function
 1103 tgl                       792 ECB             :  *
                                793                 :  * The type is sent as text in binary mode, so this is almost the same
 1103 tgl                       794 EUB             :  * as the input function, but it's prefixed with a version number so we
                                795                 :  * can change the binary format sent in future if necessary. For now,
                                796                 :  * only version 1 is supported.
                                797                 :  */
 1103 tgl                       798 GBC           2 : PG_FUNCTION_INFO_V1(lquery_recv);
 1103 tgl                       799 EUB             : Datum
 1103 tgl                       800 UIC           0 : lquery_recv(PG_FUNCTION_ARGS)
 1103 tgl                       801 EUB             : {
 1103 tgl                       802 UBC           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                803               0 :     int         version = pq_getmsgint(buf, 1);
 1103 tgl                       804 EUB             :     char       *str;
                                805                 :     int         nbytes;
                                806                 :     lquery     *res;
                                807                 : 
 1103 tgl                       808 UIC           0 :     if (version != 1)
                                809               0 :         elog(ERROR, "unsupported lquery version number %d", version);
                                810                 : 
                                811               0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
  102 andrew                    812 UNC           0 :     res = parse_lquery(str, NULL);
 1103 tgl                       813 UIC           0 :     pfree(str);
                                814                 : 
                                815               0 :     PG_RETURN_POINTER(res);
                                816                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a