Age Owner Branch data 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
5011 peter_e@gmx.net 61 :CBC 108 : gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint16 *flag)
62 : : {
63 : : int charlen;
64 : :
65 : : for (;;)
66 : : {
67 tmunro@postgresql.or 67 : 365 : charlen = pg_mblen_cstr(state->buf);
68 : :
8629 bruce@momjian.us 69 [ + + + - ]: 365 : switch (state->state)
70 : : {
71 : 83 : case WAITOPERAND:
1256 tgl@sss.pgh.pa.us 72 [ + + ]: 83 : if (t_iseq(state->buf, '!'))
73 : : {
8629 bruce@momjian.us 74 : 6 : (state->buf)++;
5011 peter_e@gmx.net 75 : 6 : *val = (int32) '!';
8629 bruce@momjian.us 76 : 6 : return OPR;
77 : : }
1256 tgl@sss.pgh.pa.us 78 [ - + ]: 77 : else if (t_iseq(state->buf, '('))
79 : : {
8629 bruce@momjian.us 80 :UBC 0 : state->count++;
81 : 0 : (state->buf)++;
82 : 0 : return OPEN;
83 : : }
1164 andrew@dunslane.net 84 [ + + + - :CBC 77 : else if (ISLABEL(state->buf))
- + ]
85 : : {
8629 bruce@momjian.us 86 : 50 : state->state = INOPERAND;
87 : 50 : *strval = state->buf;
6467 teodor@sigaev.ru 88 : 50 : *lenval = charlen;
8629 bruce@momjian.us 89 : 50 : *flag = 0;
90 : : }
453 peter@eisentraut.org 91 [ + + ]: 27 : else if (!isspace((unsigned char) *state->buf))
1173 andrew@dunslane.net 92 [ + + ]: 2 : ereturn(state->escontext, ERR,
93 : : (errcode(ERRCODE_SYNTAX_ERROR),
94 : : errmsg("operand syntax error")));
8629 bruce@momjian.us 95 : 75 : break;
96 : 207 : case INOPERAND:
1164 andrew@dunslane.net 97 [ + + + + : 207 : if (ISLABEL(state->buf))
+ + ]
98 : : {
8593 bruce@momjian.us 99 [ - + ]: 127 : if (*flag)
1173 andrew@dunslane.net 100 [ # # ]:UBC 0 : ereturn(state->escontext, ERR,
101 : : (errcode(ERRCODE_SYNTAX_ERROR),
102 : : errmsg("modifiers syntax error")));
6467 teodor@sigaev.ru 103 :CBC 127 : *lenval += charlen;
104 : : }
1256 tgl@sss.pgh.pa.us 105 [ + + ]: 80 : else if (t_iseq(state->buf, '%'))
7319 neilc@samurai.com 106 : 4 : *flag |= LVAR_SUBLEXEME;
1256 tgl@sss.pgh.pa.us 107 [ + + ]: 76 : else if (t_iseq(state->buf, '@'))
8629 bruce@momjian.us 108 : 12 : *flag |= LVAR_INCASE;
1256 tgl@sss.pgh.pa.us 109 [ + + ]: 64 : else if (t_iseq(state->buf, '*'))
8629 bruce@momjian.us 110 : 14 : *flag |= LVAR_ANYEND;
111 : : else
112 : : {
113 : 50 : state->state = WAITOPERATOR;
114 : 50 : return VAL;
115 : : }
116 : 157 : break;
117 : 75 : case WAITOPERATOR:
1256 tgl@sss.pgh.pa.us 118 [ + + + + ]: 75 : if (t_iseq(state->buf, '&') || t_iseq(state->buf, '|'))
119 : : {
8629 bruce@momjian.us 120 : 25 : state->state = WAITOPERAND;
5011 peter_e@gmx.net 121 : 25 : *val = (int32) *(state->buf);
8629 bruce@momjian.us 122 : 25 : (state->buf)++;
123 : 25 : return OPR;
124 : : }
1256 tgl@sss.pgh.pa.us 125 [ - + ]: 50 : else if (t_iseq(state->buf, ')'))
126 : : {
8629 bruce@momjian.us 127 :UBC 0 : (state->buf)++;
128 : 0 : state->count--;
129 [ # # ]: 0 : return (state->count < 0) ? ERR : CLOSE;
130 : : }
8629 bruce@momjian.us 131 [ + + ]:CBC 50 : else if (*(state->buf) == '\0')
132 : : {
133 : 25 : return (state->count) ? ERR : END;
134 : : }
1256 tgl@sss.pgh.pa.us 135 [ - + ]: 25 : else if (!t_iseq(state->buf, ' '))
136 : : {
8629 bruce@momjian.us 137 :UBC 0 : return ERR;
138 : : }
8629 bruce@momjian.us 139 :CBC 25 : break;
8629 bruce@momjian.us 140 :UBC 0 : default:
141 : 0 : return ERR;
142 : : break;
143 : : }
144 : :
6467 teodor@sigaev.ru 145 :CBC 257 : state->buf += charlen;
146 : : }
147 : :
148 : : /* should not get here */
149 : : }
150 : :
151 : : /*
152 : : * push new one in polish notation reverse view
153 : : */
154 : : static bool
5011 peter_e@gmx.net 155 : 81 : pushquery(QPRS_STATE *state, int32 type, int32 val, int32 distance, int32 lenval, uint16 flag)
156 : : {
100 michael@paquier.xyz 157 :GNC 81 : NODE *tmp = palloc_object(NODE);
158 : :
8629 bruce@momjian.us 159 :CBC 81 : tmp->type = type;
160 : 81 : tmp->val = val;
161 : 81 : tmp->flag = flag;
162 [ - + ]: 81 : if (distance > 0xffff)
1173 andrew@dunslane.net 163 [ # # ]:UBC 0 : ereturn(state->escontext, false,
164 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
165 : : errmsg("value is too big")));
8629 bruce@momjian.us 166 [ - + ]:CBC 81 : if (lenval > 0xff)
1173 andrew@dunslane.net 167 [ # # ]:UBC 0 : ereturn(state->escontext, false,
168 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
169 : : errmsg("operand is too long")));
8629 bruce@momjian.us 170 :CBC 81 : tmp->distance = distance;
171 : 81 : tmp->length = lenval;
172 : 81 : tmp->next = state->str;
173 : 81 : state->str = tmp;
174 : 81 : state->num++;
1173 andrew@dunslane.net 175 : 81 : return true;
176 : : }
177 : :
178 : : /*
179 : : * This function is used for query text parsing
180 : : */
181 : : static bool
6121 bruce@momjian.us 182 : 50 : pushval_asis(QPRS_STATE *state, int type, char *strval, int lenval, uint16 flag)
183 : : {
8629 184 [ - + ]: 50 : if (lenval > 0xffff)
1173 andrew@dunslane.net 185 [ # # ]:UBC 0 : ereturn(state->escontext, false,
186 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
187 : : errmsg("word is too long")));
188 : :
1031 tgl@sss.pgh.pa.us 189 [ - + ]:CBC 50 : if (!pushquery(state, type, ltree_crc32_sz(strval, lenval),
190 : 50 : state->curop - state->op, lenval, flag))
1173 andrew@dunslane.net 191 :UBC 0 : return false;
192 : :
8629 bruce@momjian.us 193 [ - + ]:CBC 50 : while (state->curop - state->op + lenval + 1 >= state->lenop)
194 : : {
5011 peter_e@gmx.net 195 :UBC 0 : int32 tmp = state->curop - state->op;
196 : :
8629 bruce@momjian.us 197 : 0 : state->lenop *= 2;
1132 peter@eisentraut.org 198 : 0 : state->op = (char *) repalloc(state->op, state->lenop);
8629 bruce@momjian.us 199 : 0 : state->curop = state->op + tmp;
200 : : }
1132 peter@eisentraut.org 201 :CBC 50 : memcpy(state->curop, strval, lenval);
8629 bruce@momjian.us 202 : 50 : state->curop += lenval;
203 : 50 : *(state->curop) = '\0';
204 : 50 : state->curop++;
205 : 50 : state->sumlen += lenval + 1;
1173 andrew@dunslane.net 206 : 50 : return true;
207 : : }
208 : :
209 : : #define STACKDEPTH 32
210 : : /*
211 : : * make polish notation of query
212 : : */
213 : : static int32
6121 bruce@momjian.us 214 : 27 : makepol(QPRS_STATE *state)
215 : : {
5011 peter_e@gmx.net 216 : 27 : int32 val = 0,
217 : : type;
218 : 27 : int32 lenval = 0;
7477 tgl@sss.pgh.pa.us 219 : 27 : char *strval = NULL;
220 : : int32 stack[STACKDEPTH];
5011 peter_e@gmx.net 221 : 27 : int32 lenstack = 0;
7477 tgl@sss.pgh.pa.us 222 : 27 : uint16 flag = 0;
223 : :
224 : : /* since this function recurses, it could be driven to stack overflow */
4409 noah@leadboat.com 225 : 27 : check_stack_depth();
226 : :
8593 bruce@momjian.us 227 [ + + ]: 108 : while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END)
228 : : {
8629 229 [ + + - - : 83 : switch (type)
+ - ]
230 : : {
231 : 50 : case VAL:
1173 andrew@dunslane.net 232 [ - + ]: 50 : if (!pushval_asis(state, VAL, strval, lenval, flag))
1173 andrew@dunslane.net 233 :UBC 0 : return ERR;
5011 peter_e@gmx.net 234 [ + + + + ]:CBC 79 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
235 [ + + ]: 8 : stack[lenstack - 1] == (int32) '!'))
236 : : {
8629 bruce@momjian.us 237 : 29 : lenstack--;
1173 andrew@dunslane.net 238 [ - + ]: 29 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
1173 andrew@dunslane.net 239 :UBC 0 : return ERR;
240 : : }
8629 bruce@momjian.us 241 :CBC 50 : break;
242 : 31 : case OPR:
5011 peter_e@gmx.net 243 [ - + - - ]: 31 : if (lenstack && val == (int32) '|')
244 : : {
1173 andrew@dunslane.net 245 [ # # ]:UBC 0 : if (!pushquery(state, OPR, val, 0, 0, 0))
246 : 0 : return ERR;
247 : : }
248 : : else
249 : : {
8629 bruce@momjian.us 250 [ - + ]:CBC 31 : if (lenstack == STACKDEPTH)
251 : : /* internal error */
8270 tgl@sss.pgh.pa.us 252 [ # # ]:UBC 0 : elog(ERROR, "stack too short");
8629 bruce@momjian.us 253 :CBC 31 : stack[lenstack] = val;
254 : 31 : lenstack++;
255 : : }
256 : 31 : break;
8629 bruce@momjian.us 257 :UBC 0 : case OPEN:
258 [ # # ]: 0 : if (makepol(state) == ERR)
259 : 0 : return ERR;
5011 peter_e@gmx.net 260 [ # # # # ]: 0 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
261 [ # # ]: 0 : stack[lenstack - 1] == (int32) '!'))
262 : : {
8629 bruce@momjian.us 263 : 0 : lenstack--;
1173 andrew@dunslane.net 264 [ # # ]: 0 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
265 : 0 : return ERR;
266 : : }
8629 bruce@momjian.us 267 : 0 : break;
268 : 0 : case CLOSE:
269 [ # # ]: 0 : while (lenstack)
270 : : {
271 : 0 : lenstack--;
1173 andrew@dunslane.net 272 [ # # ]: 0 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
273 : 0 : return ERR;
274 : : };
8629 bruce@momjian.us 275 : 0 : return END;
276 : : break;
8629 bruce@momjian.us 277 :CBC 2 : case ERR:
1173 andrew@dunslane.net 278 [ + - + - : 2 : if (SOFT_ERROR_OCCURRED(state->escontext))
+ - ]
279 : 2 : return ERR;
280 : : pg_fallthrough;
281 : : default:
1173 andrew@dunslane.net 282 [ # # ]:UBC 0 : ereturn(state->escontext, ERR,
283 : : (errcode(ERRCODE_SYNTAX_ERROR),
284 : : errmsg("syntax error")));
285 : :
286 : : }
287 : : }
8593 bruce@momjian.us 288 [ + + ]:CBC 27 : while (lenstack)
289 : : {
8629 290 : 2 : lenstack--;
1173 andrew@dunslane.net 291 [ - + ]: 2 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
1173 andrew@dunslane.net 292 :UBC 0 : return ERR;
293 : : };
8629 bruce@momjian.us 294 :CBC 25 : return END;
295 : : }
296 : :
297 : : static void
5011 peter_e@gmx.net 298 : 81 : findoprnd(ITEM *ptr, int32 *pos)
299 : : {
300 : : /* since this function recurses, it could be driven to stack overflow. */
4409 noah@leadboat.com 301 : 81 : check_stack_depth();
302 : :
8629 bruce@momjian.us 303 [ + + - + ]: 81 : if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE)
304 : : {
305 : 50 : ptr[*pos].left = 0;
306 : 50 : (*pos)++;
307 : : }
5011 peter_e@gmx.net 308 [ + + ]: 31 : else if (ptr[*pos].val == (int32) '!')
309 : : {
8629 bruce@momjian.us 310 : 6 : ptr[*pos].left = 1;
311 : 6 : (*pos)++;
312 : 6 : findoprnd(ptr, pos);
313 : : }
314 : : else
315 : : {
8593 316 : 25 : ITEM *curitem = &ptr[*pos];
5011 peter_e@gmx.net 317 : 25 : int32 tmp = *pos;
318 : :
8629 bruce@momjian.us 319 : 25 : (*pos)++;
320 : 25 : findoprnd(ptr, pos);
321 : 25 : curitem->left = *pos - tmp;
322 : 25 : findoprnd(ptr, pos);
323 : : }
324 : 81 : }
325 : :
326 : :
327 : : /*
328 : : * input
329 : : */
330 : : static ltxtquery *
1173 andrew@dunslane.net 331 : 27 : queryin(char *buf, struct Node *escontext)
332 : : {
333 : : QPRS_STATE state;
334 : : int32 i;
335 : : ltxtquery *query;
336 : : int32 commonlen;
337 : : ITEM *ptr;
338 : : NODE *tmp;
5011 peter_e@gmx.net 339 : 27 : int32 pos = 0;
340 : :
341 : : /* init state */
8629 bruce@momjian.us 342 : 27 : state.buf = buf;
343 : 27 : state.state = WAITOPERAND;
344 : 27 : state.count = 0;
345 : 27 : state.num = 0;
346 : 27 : state.str = NULL;
1173 andrew@dunslane.net 347 : 27 : state.escontext = escontext;
348 : :
349 : : /* init list of operand */
8629 bruce@momjian.us 350 : 27 : state.sumlen = 0;
351 : 27 : state.lenop = 64;
352 : 27 : state.curop = state.op = (char *) palloc(state.lenop);
353 : 27 : *(state.curop) = '\0';
354 : :
355 : : /* parse query & make polish notation (postfix, but in reverse order) */
1173 andrew@dunslane.net 356 [ + + ]: 27 : if (makepol(&state) == ERR)
357 : 2 : return NULL;
8629 bruce@momjian.us 358 [ - + ]: 25 : if (!state.num)
1173 andrew@dunslane.net 359 [ # # ]:UBC 0 : ereturn(escontext, NULL,
360 : : (errcode(ERRCODE_SYNTAX_ERROR),
361 : : errmsg("syntax error"),
362 : : errdetail("Empty query.")));
363 : :
4409 noah@leadboat.com 364 [ - + ]:CBC 25 : if (LTXTQUERY_TOO_BIG(state.num, state.sumlen))
1173 andrew@dunslane.net 365 [ # # ]:UBC 0 : ereturn(escontext, NULL,
366 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
367 : : errmsg("ltxtquery is too large")));
8629 bruce@momjian.us 368 :CBC 25 : commonlen = COMPUTESIZE(state.num, state.sumlen);
369 : :
3659 andres@anarazel.de 370 : 25 : query = (ltxtquery *) palloc0(commonlen);
6955 tgl@sss.pgh.pa.us 371 : 25 : SET_VARSIZE(query, commonlen);
8629 bruce@momjian.us 372 : 25 : query->size = state.num;
373 : 25 : ptr = GETQUERY(query);
374 : :
375 : : /* set item in polish notation */
376 [ + + ]: 106 : for (i = 0; i < state.num; i++)
377 : : {
378 : 81 : ptr[i].type = state.str->type;
379 : 81 : ptr[i].val = state.str->val;
380 : 81 : ptr[i].distance = state.str->distance;
381 : 81 : ptr[i].length = state.str->length;
382 : 81 : ptr[i].flag = state.str->flag;
383 : 81 : tmp = state.str->next;
384 : 81 : pfree(state.str);
385 : 81 : state.str = tmp;
386 : : }
387 : :
388 : : /* set user-friendly operand view */
1132 peter@eisentraut.org 389 : 25 : memcpy(GETOPERAND(query), state.op, state.sumlen);
8629 bruce@momjian.us 390 : 25 : pfree(state.op);
391 : :
392 : : /* set left operand's position for every operator */
393 : 25 : pos = 0;
394 : 25 : findoprnd(ptr, &pos);
395 : :
396 : 25 : return query;
397 : : }
398 : :
399 : : /*
400 : : * in without morphology
401 : : */
2174 tgl@sss.pgh.pa.us 402 : 3 : PG_FUNCTION_INFO_V1(ltxtq_in);
403 : : Datum
8629 bruce@momjian.us 404 : 27 : ltxtq_in(PG_FUNCTION_ARGS)
405 : : {
406 : : ltxtquery *res;
407 : :
388 peter@eisentraut.org 408 [ + + ]: 27 : if ((res = queryin(PG_GETARG_POINTER(0), fcinfo->context)) == NULL)
1173 andrew@dunslane.net 409 : 2 : PG_RETURN_NULL();
410 : 25 : PG_RETURN_POINTER(res);
411 : : }
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 : : */
2174 tgl@sss.pgh.pa.us 421 : 2 : PG_FUNCTION_INFO_V1(ltxtq_recv);
422 : : Datum
2174 tgl@sss.pgh.pa.us 423 :UBC 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 : : char *str;
428 : : int nbytes;
429 : : 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);
1173 andrew@dunslane.net 435 : 0 : res = queryin(str, NULL);
2174 tgl@sss.pgh.pa.us 436 : 0 : pfree(str);
437 : :
438 : 0 : PG_RETURN_POINTER(res);
439 : : }
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
6695 bruce@momjian.us 467 :CBC 10 : infix(INFIX *in, bool first)
468 : : {
469 : : /* since this function recurses, it could be driven to stack overflow. */
3814 noah@leadboat.com 470 : 10 : check_stack_depth();
471 : :
8629 bruce@momjian.us 472 [ + + ]: 10 : if (in->curpol->type == VAL)
473 : : {
8593 474 : 6 : char *op = in->op + in->curpol->distance;
475 : :
8629 476 [ + + ]: 8 : RESIZEBUF(in, in->curpol->length * 2 + 5);
8593 477 [ + + ]: 32 : while (*op)
478 : : {
8629 479 : 26 : *(in->cur) = *op;
480 : 26 : op++;
481 : 26 : in->cur++;
482 : : }
7319 neilc@samurai.com 483 [ + + ]: 6 : if (in->curpol->flag & LVAR_SUBLEXEME)
484 : : {
8629 bruce@momjian.us 485 : 2 : *(in->cur) = '%';
486 : 2 : in->cur++;
487 : : }
8593 488 [ + + ]: 6 : if (in->curpol->flag & LVAR_INCASE)
489 : : {
8629 490 : 1 : *(in->cur) = '@';
491 : 1 : in->cur++;
492 : : }
8593 493 [ + + ]: 6 : if (in->curpol->flag & LVAR_ANYEND)
494 : : {
8629 495 : 3 : *(in->cur) = '*';
496 : 3 : in->cur++;
497 : : }
498 : 6 : *(in->cur) = '\0';
499 : 6 : in->curpol++;
500 : : }
5011 peter_e@gmx.net 501 [ + + ]: 4 : else if (in->curpol->val == (int32) '!')
502 : : {
8593 bruce@momjian.us 503 : 1 : bool isopr = false;
504 : :
8629 505 [ - + ]: 1 : RESIZEBUF(in, 1);
506 : 1 : *(in->cur) = '!';
507 : 1 : in->cur++;
508 : 1 : *(in->cur) = '\0';
509 : 1 : in->curpol++;
510 [ - + ]: 1 : if (in->curpol->type == OPR)
511 : : {
8629 bruce@momjian.us 512 :UBC 0 : isopr = true;
513 [ # # ]: 0 : RESIZEBUF(in, 2);
514 : 0 : sprintf(in->cur, "( ");
515 : 0 : in->cur = strchr(in->cur, '\0');
516 : : }
8629 bruce@momjian.us 517 :CBC 1 : infix(in, isopr);
518 [ - + ]: 1 : if (isopr)
519 : : {
8629 bruce@momjian.us 520 [ # # ]:UBC 0 : RESIZEBUF(in, 2);
521 : 0 : sprintf(in->cur, " )");
522 : 0 : in->cur = strchr(in->cur, '\0');
523 : : }
524 : : }
525 : : else
526 : : {
5011 peter_e@gmx.net 527 :CBC 3 : int32 op = in->curpol->val;
528 : : INFIX nrm;
529 : :
8629 bruce@momjian.us 530 : 3 : in->curpol++;
5011 peter_e@gmx.net 531 [ - + - - ]: 3 : if (op == (int32) '|' && !first)
532 : : {
8629 bruce@momjian.us 533 [ # # ]:UBC 0 : RESIZEBUF(in, 2);
534 : 0 : sprintf(in->cur, "( ");
535 : 0 : in->cur = strchr(in->cur, '\0');
536 : : }
537 : :
8629 bruce@momjian.us 538 :CBC 3 : nrm.curpol = in->curpol;
539 : 3 : nrm.op = in->op;
540 : 3 : nrm.buflen = 16;
100 michael@paquier.xyz 541 :GNC 3 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
542 : :
543 : : /* get right operand */
8629 bruce@momjian.us 544 :CBC 3 : infix(&nrm, false);
545 : :
546 : : /* get & print left operand */
547 : 3 : in->curpol = nrm.curpol;
548 : 3 : infix(in, false);
549 : :
550 : : /* print operator & right operand */
551 [ - + ]: 3 : RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
552 : 3 : sprintf(in->cur, " %c %s", op, nrm.buf);
553 : 3 : in->cur = strchr(in->cur, '\0');
554 : 3 : pfree(nrm.buf);
555 : :
5011 peter_e@gmx.net 556 [ - + - - ]: 3 : if (op == (int32) '|' && !first)
557 : : {
8629 bruce@momjian.us 558 [ # # ]:UBC 0 : RESIZEBUF(in, 2);
559 : 0 : sprintf(in->cur, " )");
560 : 0 : in->cur = strchr(in->cur, '\0');
561 : : }
562 : : }
8629 bruce@momjian.us 563 :CBC 10 : }
564 : :
2174 tgl@sss.pgh.pa.us 565 : 3 : PG_FUNCTION_INFO_V1(ltxtq_out);
566 : : Datum
8629 bruce@momjian.us 567 : 3 : ltxtq_out(PG_FUNCTION_ARGS)
568 : : {
3100 tgl@sss.pgh.pa.us 569 : 3 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(0);
570 : : INFIX nrm;
571 : :
8629 bruce@momjian.us 572 [ - + ]: 3 : if (query->size == 0)
8270 tgl@sss.pgh.pa.us 573 [ # # ]:UBC 0 : ereport(ERROR,
574 : : (errcode(ERRCODE_SYNTAX_ERROR),
575 : : errmsg("syntax error"),
576 : : errdetail("Empty query.")));
577 : :
8629 bruce@momjian.us 578 :CBC 3 : nrm.curpol = GETQUERY(query);
579 : 3 : nrm.buflen = 32;
100 michael@paquier.xyz 580 :GNC 3 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
8629 bruce@momjian.us 581 :CBC 3 : *(nrm.cur) = '\0';
582 : 3 : nrm.op = GETOPERAND(query);
583 : 3 : infix(&nrm, true);
584 : :
585 : 3 : PG_RETURN_POINTER(nrm.buf);
586 : : }
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 : : */
2174 tgl@sss.pgh.pa.us 596 : 2 : PG_FUNCTION_INFO_V1(ltxtq_send);
597 : : Datum
2174 tgl@sss.pgh.pa.us 598 :UBC 0 : ltxtq_send(PG_FUNCTION_ARGS)
599 : : {
600 : 0 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(0);
601 : : StringInfoData buf;
602 : 0 : int version = 1;
603 : : 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;
100 michael@paquier.xyz 613 :UNC 0 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
2174 tgl@sss.pgh.pa.us 614 :UBC 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 : : }
|