LCOV - differential code coverage report
Current view: top level - contrib/ltree - ltxtquery_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: 72.2 % 291 210 19 28 31 3 15 95 29 71 56 102 7 9
Current Date: 2023-04-08 15:15:32 Functions: 86.7 % 15 13 2 12 1 2 13
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  * txtquery io
       3                 :  * Teodor Sigaev <teodor@stack.net>
       4                 :  * contrib/ltree/ltxtquery_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 "miscadmin.h"
      14                 : #include "nodes/miscnodes.h"
      15                 : #include "varatt.h"
      16                 : 
      17                 : 
      18                 : /* parser's states */
      19                 : #define WAITOPERAND 1
      20                 : #define INOPERAND 2
      21                 : #define WAITOPERATOR    3
      22                 : 
      23                 : /*
      24                 :  * node of query tree, also used
      25                 :  * for storing polish notation in parser
      26                 :  */
      27                 : typedef struct NODE
      28                 : {
      29                 :     int32       type;
      30                 :     int32       val;
      31                 :     int16       distance;
      32                 :     int16       length;
      33                 :     uint16      flag;
      34                 :     struct NODE *next;
      35                 : } NODE;
      36                 : 
      37                 : typedef struct
      38                 : {
      39                 :     char       *buf;
      40                 :     int32       state;
      41                 :     int32       count;
      42                 :     struct Node *escontext;
      43                 :     /* reverse polish notation in list (for temporary usage) */
      44                 :     NODE       *str;
      45                 :     /* number in str */
      46                 :     int32       num;
      47                 : 
      48                 :     /* user-friendly operand */
      49                 :     int32       lenop;
      50                 :     int32       sumlen;
      51                 :     char       *op;
      52                 :     char       *curop;
      53                 : } QPRS_STATE;
      54                 : 
      55                 : /*
      56                 :  * get token from query string
      57                 :  *
      58                 :  * caller needs to check if a soft-error was set if the result is ERR.
      59                 :  */
      60                 : static int32
      61 GIC         108 : gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint16 *flag)
      62                 : {
      63                 :     int         charlen;
      64                 : 
      65                 :     for (;;)
      66 ECB             :     {
      67 GIC         365 :         charlen = pg_mblen(state->buf);
      68                 : 
      69             365 :         switch (state->state)
      70                 :         {
      71              83 :             case WAITOPERAND:
      72 GNC          83 :                 if (t_iseq(state->buf, '!'))
      73                 :                 {
      74 CBC           6 :                     (state->buf)++;
      75 GIC           6 :                     *val = (int32) '!';
      76 CBC           6 :                     return OPR;
      77 ECB             :                 }
      78 GNC          77 :                 else if (t_iseq(state->buf, '('))
      79 ECB             :                 {
      80 LBC           0 :                     state->count++;
      81               0 :                     (state->buf)++;
      82 UIC           0 :                     return OPEN;
      83 ECB             :                 }
      84 GNC          77 :                 else if (ISLABEL(state->buf))
      85 EUB             :                 {
      86 GBC          50 :                     state->state = INOPERAND;
      87              50 :                     *strval = state->buf;
      88 GIC          50 :                     *lenval = charlen;
      89 CBC          50 :                     *flag = 0;
      90                 :                 }
      91              27 :                 else if (!t_isspace(state->buf))
      92 GNC           2 :                     ereturn(state->escontext, ERR,
      93 ECB             :                             (errcode(ERRCODE_SYNTAX_ERROR),
      94                 :                              errmsg("operand syntax error")));
      95 GIC          75 :                 break;
      96 CBC         207 :             case INOPERAND:
      97 GNC         207 :                 if (ISLABEL(state->buf))
      98                 :                 {
      99 GIC         127 :                     if (*flag)
     100 UNC           0 :                         ereturn(state->escontext, ERR,
     101 ECB             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
     102                 :                                  errmsg("modifiers syntax error")));
     103 GIC         127 :                     *lenval += charlen;
     104 ECB             :                 }
     105 GNC          80 :                 else if (t_iseq(state->buf, '%'))
     106 GIC           4 :                     *flag |= LVAR_SUBLEXEME;
     107 GNC          76 :                 else if (t_iseq(state->buf, '@'))
     108 CBC          12 :                     *flag |= LVAR_INCASE;
     109 GNC          64 :                 else if (t_iseq(state->buf, '*'))
     110 CBC          14 :                     *flag |= LVAR_ANYEND;
     111 ECB             :                 else
     112                 :                 {
     113 CBC          50 :                     state->state = WAITOPERATOR;
     114              50 :                     return VAL;
     115 ECB             :                 }
     116 GIC         157 :                 break;
     117              75 :             case WAITOPERATOR:
     118 GNC          75 :                 if (t_iseq(state->buf, '&') || t_iseq(state->buf, '|'))
     119 ECB             :                 {
     120 GIC          25 :                     state->state = WAITOPERAND;
     121 CBC          25 :                     *val = (int32) *(state->buf);
     122              25 :                     (state->buf)++;
     123              25 :                     return OPR;
     124                 :                 }
     125 GNC          50 :                 else if (t_iseq(state->buf, ')'))
     126 ECB             :                 {
     127 LBC           0 :                     (state->buf)++;
     128               0 :                     state->count--;
     129 UIC           0 :                     return (state->count < 0) ? ERR : CLOSE;
     130 ECB             :                 }
     131 GIC          50 :                 else if (*(state->buf) == '\0')
     132                 :                 {
     133 GBC          25 :                     return (state->count) ? ERR : END;
     134                 :                 }
     135 GNC          25 :                 else if (!t_iseq(state->buf, ' '))
     136                 :                 {
     137 UBC           0 :                     return ERR;
     138                 :                 }
     139 GIC          25 :                 break;
     140 LBC           0 :             default:
     141 UIC           0 :                 return ERR;
     142 ECB             :                 break;
     143                 :         }
     144                 : 
     145 GIC         257 :         state->buf += charlen;
     146 EUB             :     }
     147                 : 
     148                 :     /* should not get here */
     149                 : }
     150 ECB             : 
     151 EUB             : /*
     152                 :  * push new one in polish notation reverse view
     153                 :  */
     154                 : static bool
     155 GIC          81 : pushquery(QPRS_STATE *state, int32 type, int32 val, int32 distance, int32 lenval, uint16 flag)
     156 ECB             : {
     157 GIC          81 :     NODE       *tmp = (NODE *) palloc(sizeof(NODE));
     158                 : 
     159              81 :     tmp->type = type;
     160              81 :     tmp->val = val;
     161              81 :     tmp->flag = flag;
     162              81 :     if (distance > 0xffff)
     163 UNC           0 :         ereturn(state->escontext, false,
     164                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     165                 :                  errmsg("value is too big")));
     166 CBC          81 :     if (lenval > 0xff)
     167 UNC           0 :         ereturn(state->escontext, false,
     168 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     169                 :                  errmsg("operand is too long")));
     170 CBC          81 :     tmp->distance = distance;
     171              81 :     tmp->length = lenval;
     172              81 :     tmp->next = state->str;
     173              81 :     state->str = tmp;
     174 GBC          81 :     state->num++;
     175 GNC          81 :     return true;
     176                 : }
     177                 : 
     178 ECB             : /*
     179 EUB             :  * This function is used for query text parsing
     180                 :  */
     181                 : static bool
     182 CBC          50 : pushval_asis(QPRS_STATE *state, int type, char *strval, int lenval, uint16 flag)
     183 ECB             : {
     184 CBC          50 :     if (lenval > 0xffff)
     185 UNC           0 :         ereturn(state->escontext, false,
     186 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     187                 :                  errmsg("word is too long")));
     188                 : 
     189 GNC          50 :     if (! pushquery(state, type, ltree_crc32_sz(strval, lenval),
     190              50 :                     state->curop - state->op, lenval, flag))
     191 UNC           0 :         return false;
     192                 : 
     193 GIC          50 :     while (state->curop - state->op + lenval + 1 >= state->lenop)
     194                 :     {
     195 LBC           0 :         int32       tmp = state->curop - state->op;
     196                 : 
     197               0 :         state->lenop *= 2;
     198 UNC           0 :         state->op = (char *) repalloc(state->op, state->lenop);
     199 UIC           0 :         state->curop = state->op + tmp;
     200                 :     }
     201 GNC          50 :     memcpy(state->curop, strval, lenval);
     202 CBC          50 :     state->curop += lenval;
     203              50 :     *(state->curop) = '\0';
     204 GBC          50 :     state->curop++;
     205 GIC          50 :     state->sumlen += lenval + 1;
     206 GNC          50 :     return true;
     207 ECB             : }
     208                 : 
     209 EUB             : #define STACKDEPTH      32
     210                 : /*
     211                 :  * make polish notation of query
     212                 :  */
     213                 : static int32
     214 GIC          27 : makepol(QPRS_STATE *state)
     215 ECB             : {
     216 CBC          27 :     int32       val = 0,
     217 ECB             :                 type;
     218 CBC          27 :     int32       lenval = 0;
     219              27 :     char       *strval = NULL;
     220 ECB             :     int32       stack[STACKDEPTH];
     221 GIC          27 :     int32       lenstack = 0;
     222              27 :     uint16      flag = 0;
     223                 : 
     224                 :     /* since this function recurses, it could be driven to stack overflow */
     225              27 :     check_stack_depth();
     226                 : 
     227             108 :     while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END)
     228 ECB             :     {
     229 GIC          83 :         switch (type)
     230 ECB             :         {
     231 GIC          50 :             case VAL:
     232 GNC          50 :                 if (!pushval_asis(state, VAL, strval, lenval, flag))
     233 UNC           0 :                     return ERR;
     234 CBC          79 :                 while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
     235 GIC           8 :                                     stack[lenstack - 1] == (int32) '!'))
     236 ECB             :                 {
     237 CBC          29 :                     lenstack--;
     238 GNC          29 :                     if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
     239 UNC           0 :                         return ERR;
     240                 :                 }
     241 CBC          50 :                 break;
     242 GIC          31 :             case OPR:
     243 CBC          31 :                 if (lenstack && val == (int32) '|')
     244                 :                 {
     245 UNC           0 :                     if (!pushquery(state, OPR, val, 0, 0, 0))
     246               0 :                         return ERR;
     247                 :                 }
     248 ECB             :                 else
     249                 :                 {
     250 CBC          31 :                     if (lenstack == STACKDEPTH)
     251 ECB             :                         /* internal error */
     252 UBC           0 :                         elog(ERROR, "stack too short");
     253 CBC          31 :                     stack[lenstack] = val;
     254              31 :                     lenstack++;
     255                 :                 }
     256              31 :                 break;
     257 LBC           0 :             case OPEN:
     258 UBC           0 :                 if (makepol(state) == ERR)
     259 UIC           0 :                     return ERR;
     260 LBC           0 :                 while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
     261               0 :                                     stack[lenstack - 1] == (int32) '!'))
     262 ECB             :                 {
     263 UIC           0 :                     lenstack--;
     264 UNC           0 :                     if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
     265               0 :                         return ERR;
     266 EUB             :                 }
     267 UIC           0 :                 break;
     268               0 :             case CLOSE:
     269               0 :                 while (lenstack)
     270 ECB             :                 {
     271 UIC           0 :                     lenstack--;
     272 UNC           0 :                     if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
     273               0 :                         return ERR;
     274 ECB             :                 };
     275 LBC           0 :                 return END;
     276                 :                 break;
     277 CBC           2 :             case ERR:
     278 GNC           2 :                 if (SOFT_ERROR_OCCURRED(state->escontext))
     279               2 :                     return ERR;
     280                 :                 /* fall through */
     281 EUB             :             default:
     282 UNC           0 :                 ereturn(state->escontext, ERR,
     283 EUB             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     284                 :                          errmsg("syntax error")));
     285                 : 
     286                 :         }
     287                 :     }
     288 GBC          27 :     while (lenstack)
     289                 :     {
     290               2 :         lenstack--;
     291 GNC           2 :         if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
     292 UNC           0 :             return ERR;
     293 EUB             :     };
     294 GIC          25 :     return END;
     295 EUB             : }
     296                 : 
     297                 : static void
     298 GIC          81 : findoprnd(ITEM *ptr, int32 *pos)
     299 EUB             : {
     300                 :     /* since this function recurses, it could be driven to stack overflow. */
     301 CBC          81 :     check_stack_depth();
     302 ECB             : 
     303 CBC          81 :     if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE)
     304                 :     {
     305 GIC          50 :         ptr[*pos].left = 0;
     306 GBC          50 :         (*pos)++;
     307                 :     }
     308 GIC          31 :     else if (ptr[*pos].val == (int32) '!')
     309                 :     {
     310               6 :         ptr[*pos].left = 1;
     311               6 :         (*pos)++;
     312 CBC           6 :         findoprnd(ptr, pos);
     313                 :     }
     314 ECB             :     else
     315                 :     {
     316 GBC          25 :         ITEM       *curitem = &ptr[*pos];
     317 GIC          25 :         int32       tmp = *pos;
     318 ECB             : 
     319 GIC          25 :         (*pos)++;
     320              25 :         findoprnd(ptr, pos);
     321              25 :         curitem->left = *pos - tmp;
     322 CBC          25 :         findoprnd(ptr, pos);
     323                 :     }
     324 GIC          81 : }
     325 ECB             : 
     326                 : 
     327                 : /*
     328                 :  * input
     329                 :  */
     330                 : static ltxtquery *
     331 GNC          27 : queryin(char *buf, struct Node *escontext)
     332 ECB             : {
     333                 :     QPRS_STATE  state;
     334                 :     int32       i;
     335                 :     ltxtquery  *query;
     336                 :     int32       commonlen;
     337                 :     ITEM       *ptr;
     338                 :     NODE       *tmp;
     339 GIC          27 :     int32       pos = 0;
     340 ECB             : 
     341                 : #ifdef BS_DEBUG
     342                 :     char        pbuf[16384],
     343                 :                *cur;
     344                 : #endif
     345                 : 
     346                 :     /* init state */
     347 GIC          27 :     state.buf = buf;
     348 CBC          27 :     state.state = WAITOPERAND;
     349 GIC          27 :     state.count = 0;
     350              27 :     state.num = 0;
     351              27 :     state.str = NULL;
     352 GNC          27 :     state.escontext = escontext;
     353                 : 
     354                 :     /* init list of operand */
     355 GIC          27 :     state.sumlen = 0;
     356 CBC          27 :     state.lenop = 64;
     357 GIC          27 :     state.curop = state.op = (char *) palloc(state.lenop);
     358              27 :     *(state.curop) = '\0';
     359                 : 
     360                 :     /* parse query & make polish notation (postfix, but in reverse order) */
     361 GNC          27 :     if (makepol(&state) == ERR)
     362               2 :         return NULL;
     363 GIC          25 :     if (!state.num)
     364 UNC           0 :         ereturn(escontext, NULL,
     365 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
     366                 :                  errmsg("syntax error"),
     367                 :                  errdetail("Empty query.")));
     368                 : 
     369 GIC          25 :     if (LTXTQUERY_TOO_BIG(state.num, state.sumlen))
     370 UNC           0 :         ereturn(escontext, NULL,
     371                 :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     372                 :                  errmsg("ltxtquery is too large")));
     373 CBC          25 :     commonlen = COMPUTESIZE(state.num, state.sumlen);
     374 ECB             : 
     375 CBC          25 :     query = (ltxtquery *) palloc0(commonlen);
     376              25 :     SET_VARSIZE(query, commonlen);
     377              25 :     query->size = state.num;
     378              25 :     ptr = GETQUERY(query);
     379                 : 
     380                 :     /* set item in polish notation */
     381             106 :     for (i = 0; i < state.num; i++)
     382 ECB             :     {
     383 CBC          81 :         ptr[i].type = state.str->type;
     384              81 :         ptr[i].val = state.str->val;
     385 GIC          81 :         ptr[i].distance = state.str->distance;
     386              81 :         ptr[i].length = state.str->length;
     387 CBC          81 :         ptr[i].flag = state.str->flag;
     388              81 :         tmp = state.str->next;
     389              81 :         pfree(state.str);
     390 GBC          81 :         state.str = tmp;
     391                 :     }
     392                 : 
     393                 :     /* set user-friendly operand view */
     394 GNC          25 :     memcpy(GETOPERAND(query), state.op, state.sumlen);
     395 CBC          25 :     pfree(state.op);
     396 EUB             : 
     397                 :     /* set left operand's position for every operator */
     398 GIC          25 :     pos = 0;
     399 CBC          25 :     findoprnd(ptr, &pos);
     400                 : 
     401              25 :     return query;
     402 ECB             : }
     403                 : 
     404                 : /*
     405                 :  * in without morphology
     406                 :  */
     407 CBC           3 : PG_FUNCTION_INFO_V1(ltxtq_in);
     408                 : Datum
     409              27 : ltxtq_in(PG_FUNCTION_ARGS)
     410 ECB             : {
     411                 :     ltxtquery *res;
     412                 : 
     413 GNC          27 :     if ((res = queryin((char *) PG_GETARG_POINTER(0), fcinfo->context)) == NULL)
     414               2 :         PG_RETURN_NULL();
     415              25 :     PG_RETURN_POINTER(res);
     416 ECB             : }
     417                 : 
     418                 : /*
     419                 :  * ltxtquery type recv function
     420                 :  *
     421                 :  * The type is sent as text in binary mode, so this is almost the same
     422                 :  * as the input function, but it's prefixed with a version number so we
     423                 :  * can change the binary format sent in future if necessary. For now,
     424                 :  * only version 1 is supported.
     425                 :  */
     426 GIC           2 : PG_FUNCTION_INFO_V1(ltxtq_recv);
     427                 : Datum
     428 LBC           0 : ltxtq_recv(PG_FUNCTION_ARGS)
     429 ECB             : {
     430 UIC           0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     431 LBC           0 :     int         version = pq_getmsgint(buf, 1);
     432                 :     char       *str;
     433                 :     int         nbytes;
     434                 :     ltxtquery  *res;
     435                 : 
     436 UIC           0 :     if (version != 1)
     437 LBC           0 :         elog(ERROR, "unsupported ltxtquery version number %d", version);
     438                 : 
     439               0 :     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
     440 UNC           0 :     res = queryin(str, NULL);
     441 UIC           0 :     pfree(str);
     442                 : 
     443 LBC           0 :     PG_RETURN_POINTER(res);
     444 ECB             : }
     445                 : 
     446                 : /*
     447                 :  * out function
     448                 :  */
     449                 : typedef struct
     450                 : {
     451                 :     ITEM       *curpol;
     452                 :     char       *buf;
     453                 :     char       *cur;
     454                 :     char       *op;
     455                 :     int32       buflen;
     456                 : } INFIX;
     457                 : 
     458 EUB             : #define RESIZEBUF(inf,addsize) \
     459                 : while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
     460                 : { \
     461                 :     int32 len = (inf)->cur - (inf)->buf; \
     462                 :     (inf)->buflen *= 2; \
     463                 :     (inf)->buf = (char*) repalloc( (void*)(inf)->buf, (inf)->buflen ); \
     464                 :     (inf)->cur = (inf)->buf + len; \
     465                 : }
     466                 : 
     467                 : /*
     468                 :  * recursive walk on tree and print it in
     469                 :  * infix (human-readable) view
     470                 :  */
     471                 : static void
     472 GIC          10 : infix(INFIX *in, bool first)
     473 EUB             : {
     474                 :     /* since this function recurses, it could be driven to stack overflow. */
     475 GIC          10 :     check_stack_depth();
     476                 : 
     477              10 :     if (in->curpol->type == VAL)
     478                 :     {
     479               6 :         char       *op = in->op + in->curpol->distance;
     480                 : 
     481               8 :         RESIZEBUF(in, in->curpol->length * 2 + 5);
     482              32 :         while (*op)
     483                 :         {
     484              26 :             *(in->cur) = *op;
     485              26 :             op++;
     486              26 :             in->cur++;
     487                 :         }
     488               6 :         if (in->curpol->flag & LVAR_SUBLEXEME)
     489                 :         {
     490               2 :             *(in->cur) = '%';
     491               2 :             in->cur++;
     492                 :         }
     493               6 :         if (in->curpol->flag & LVAR_INCASE)
     494                 :         {
     495               1 :             *(in->cur) = '@';
     496               1 :             in->cur++;
     497                 :         }
     498               6 :         if (in->curpol->flag & LVAR_ANYEND)
     499                 :         {
     500               3 :             *(in->cur) = '*';
     501               3 :             in->cur++;
     502 ECB             :         }
     503 GIC           6 :         *(in->cur) = '\0';
     504               6 :         in->curpol++;
     505 ECB             :     }
     506 GIC           4 :     else if (in->curpol->val == (int32) '!')
     507 ECB             :     {
     508 GIC           1 :         bool        isopr = false;
     509 ECB             : 
     510 GIC           1 :         RESIZEBUF(in, 1);
     511 CBC           1 :         *(in->cur) = '!';
     512               1 :         in->cur++;
     513 GIC           1 :         *(in->cur) = '\0';
     514 CBC           1 :         in->curpol++;
     515               1 :         if (in->curpol->type == OPR)
     516 ECB             :         {
     517 UIC           0 :             isopr = true;
     518 LBC           0 :             RESIZEBUF(in, 2);
     519 UIC           0 :             sprintf(in->cur, "( ");
     520 LBC           0 :             in->cur = strchr(in->cur, '\0');
     521 ECB             :         }
     522 GIC           1 :         infix(in, isopr);
     523 CBC           1 :         if (isopr)
     524                 :         {
     525 LBC           0 :             RESIZEBUF(in, 2);
     526               0 :             sprintf(in->cur, " )");
     527 UIC           0 :             in->cur = strchr(in->cur, '\0');
     528 ECB             :         }
     529                 :     }
     530                 :     else
     531                 :     {
     532 GIC           3 :         int32       op = in->curpol->val;
     533 ECB             :         INFIX       nrm;
     534                 : 
     535 GIC           3 :         in->curpol++;
     536 CBC           3 :         if (op == (int32) '|' && !first)
     537                 :         {
     538 LBC           0 :             RESIZEBUF(in, 2);
     539 UIC           0 :             sprintf(in->cur, "( ");
     540 LBC           0 :             in->cur = strchr(in->cur, '\0');
     541 ECB             :         }
     542                 : 
     543 CBC           3 :         nrm.curpol = in->curpol;
     544               3 :         nrm.op = in->op;
     545               3 :         nrm.buflen = 16;
     546 GIC           3 :         nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
     547 EUB             : 
     548                 :         /* get right operand */
     549 GBC           3 :         infix(&nrm, false);
     550 EUB             : 
     551                 :         /* get & print left operand */
     552 CBC           3 :         in->curpol = nrm.curpol;
     553               3 :         infix(in, false);
     554                 : 
     555 EUB             :         /* print operator & right operand */
     556 GBC           3 :         RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
     557               3 :         sprintf(in->cur, " %c %s", op, nrm.buf);
     558 GIC           3 :         in->cur = strchr(in->cur, '\0');
     559               3 :         pfree(nrm.buf);
     560                 : 
     561               3 :         if (op == (int32) '|' && !first)
     562 ECB             :         {
     563 UIC           0 :             RESIZEBUF(in, 2);
     564               0 :             sprintf(in->cur, " )");
     565 LBC           0 :             in->cur = strchr(in->cur, '\0');
     566 ECB             :         }
     567                 :     }
     568 GBC          10 : }
     569 EUB             : 
     570 GBC           3 : PG_FUNCTION_INFO_V1(ltxtq_out);
     571                 : Datum
     572 GIC           3 : ltxtq_out(PG_FUNCTION_ARGS)
     573 ECB             : {
     574 CBC           3 :     ltxtquery  *query = PG_GETARG_LTXTQUERY_P(0);
     575 ECB             :     INFIX       nrm;
     576                 : 
     577 GIC           3 :     if (query->size == 0)
     578 UIC           0 :         ereport(ERROR,
     579 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
     580                 :                  errmsg("syntax error"),
     581                 :                  errdetail("Empty query.")));
     582                 : 
     583 CBC           3 :     nrm.curpol = GETQUERY(query);
     584 GIC           3 :     nrm.buflen = 32;
     585               3 :     nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
     586 CBC           3 :     *(nrm.cur) = '\0';
     587               3 :     nrm.op = GETOPERAND(query);
     588               3 :     infix(&nrm, true);
     589 ECB             : 
     590 GIC           3 :     PG_RETURN_POINTER(nrm.buf);
     591 ECB             : }
     592                 : 
     593 EUB             : /*
     594                 :  * ltxtquery type send function
     595                 :  *
     596                 :  * The type is sent as text in binary mode, so this is almost the same
     597                 :  * as the output function, but it's prefixed with a version number so we
     598 ECB             :  * can change the binary format sent in future if necessary. For now,
     599                 :  * only version 1 is supported.
     600                 :  */
     601 GIC           2 : PG_FUNCTION_INFO_V1(ltxtq_send);
     602 ECB             : Datum
     603 UIC           0 : ltxtq_send(PG_FUNCTION_ARGS)
     604 ECB             : {
     605 UIC           0 :     ltxtquery  *query = PG_GETARG_LTXTQUERY_P(0);
     606                 :     StringInfoData buf;
     607 LBC           0 :     int         version = 1;
     608 EUB             :     INFIX       nrm;
     609                 : 
     610 UIC           0 :     if (query->size == 0)
     611               0 :         ereport(ERROR,
     612                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
     613 ECB             :                  errmsg("syntax error"),
     614                 :                  errdetail("Empty query.")));
     615                 : 
     616 LBC           0 :     nrm.curpol = GETQUERY(query);
     617               0 :     nrm.buflen = 32;
     618               0 :     nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
     619 UIC           0 :     *(nrm.cur) = '\0';
     620 LBC           0 :     nrm.op = GETOPERAND(query);
     621 UIC           0 :     infix(&nrm, true);
     622                 : 
     623               0 :     pq_begintypsend(&buf);
     624               0 :     pq_sendint8(&buf, version);
     625               0 :     pq_sendtext(&buf, nrm.buf, strlen(nrm.buf));
     626               0 :     pfree(nrm.buf);
     627                 : 
     628               0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     629                 : }
        

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