LCOV - code coverage report
Current view: top level - contrib/ltree - ltxtquery_io.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 327 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 15 0
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.3.2-1