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
4311 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 : : {
5767 teodor@sigaev.ru 67 : 365 : charlen = pg_mblen(state->buf);
68 : :
7929 bruce@momjian.us 69 [ + + + - ]: 365 : switch (state->state)
70 : : {
71 : 83 : case WAITOPERAND:
556 tgl@sss.pgh.pa.us 72 [ + + ]: 83 : if (t_iseq(state->buf, '!'))
73 : : {
7929 bruce@momjian.us 74 : 6 : (state->buf)++;
4311 peter_e@gmx.net 75 : 6 : *val = (int32) '!';
7929 bruce@momjian.us 76 : 6 : return OPR;
77 : : }
556 tgl@sss.pgh.pa.us 78 [ - + ]: 77 : else if (t_iseq(state->buf, '('))
79 : : {
7929 bruce@momjian.us 80 :UBC 0 : state->count++;
81 : 0 : (state->buf)++;
82 : 0 : return OPEN;
83 : : }
464 andrew@dunslane.net 84 [ + + + - :CBC 77 : else if (ISLABEL(state->buf))
- + ]
85 : : {
7929 bruce@momjian.us 86 : 50 : state->state = INOPERAND;
87 : 50 : *strval = state->buf;
5767 teodor@sigaev.ru 88 : 50 : *lenval = charlen;
7929 bruce@momjian.us 89 : 50 : *flag = 0;
90 : : }
5767 teodor@sigaev.ru 91 [ + + ]: 27 : else if (!t_isspace(state->buf))
473 andrew@dunslane.net 92 [ + + ]: 2 : ereturn(state->escontext, ERR,
93 : : (errcode(ERRCODE_SYNTAX_ERROR),
94 : : errmsg("operand syntax error")));
7929 bruce@momjian.us 95 : 75 : break;
96 : 207 : case INOPERAND:
464 andrew@dunslane.net 97 [ + + + + : 207 : if (ISLABEL(state->buf))
+ + ]
98 : : {
7893 bruce@momjian.us 99 [ - + ]: 127 : if (*flag)
473 andrew@dunslane.net 100 [ # # ]:UBC 0 : ereturn(state->escontext, ERR,
101 : : (errcode(ERRCODE_SYNTAX_ERROR),
102 : : errmsg("modifiers syntax error")));
5767 teodor@sigaev.ru 103 :CBC 127 : *lenval += charlen;
104 : : }
556 tgl@sss.pgh.pa.us 105 [ + + ]: 80 : else if (t_iseq(state->buf, '%'))
6619 neilc@samurai.com 106 : 4 : *flag |= LVAR_SUBLEXEME;
556 tgl@sss.pgh.pa.us 107 [ + + ]: 76 : else if (t_iseq(state->buf, '@'))
7929 bruce@momjian.us 108 : 12 : *flag |= LVAR_INCASE;
556 tgl@sss.pgh.pa.us 109 [ + + ]: 64 : else if (t_iseq(state->buf, '*'))
7929 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:
556 tgl@sss.pgh.pa.us 118 [ + + + + ]: 75 : if (t_iseq(state->buf, '&') || t_iseq(state->buf, '|'))
119 : : {
7929 bruce@momjian.us 120 : 25 : state->state = WAITOPERAND;
4311 peter_e@gmx.net 121 : 25 : *val = (int32) *(state->buf);
7929 bruce@momjian.us 122 : 25 : (state->buf)++;
123 : 25 : return OPR;
124 : : }
556 tgl@sss.pgh.pa.us 125 [ - + ]: 50 : else if (t_iseq(state->buf, ')'))
126 : : {
7929 bruce@momjian.us 127 :UBC 0 : (state->buf)++;
128 : 0 : state->count--;
129 [ # # ]: 0 : return (state->count < 0) ? ERR : CLOSE;
130 : : }
7929 bruce@momjian.us 131 [ + + ]:CBC 50 : else if (*(state->buf) == '\0')
132 : : {
133 : 25 : return (state->count) ? ERR : END;
134 : : }
556 tgl@sss.pgh.pa.us 135 [ - + ]: 25 : else if (!t_iseq(state->buf, ' '))
136 : : {
7929 bruce@momjian.us 137 :UBC 0 : return ERR;
138 : : }
7929 bruce@momjian.us 139 :CBC 25 : break;
7929 bruce@momjian.us 140 :UBC 0 : default:
141 : 0 : return ERR;
142 : : break;
143 : : }
144 : :
5767 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
4311 peter_e@gmx.net 155 : 81 : pushquery(QPRS_STATE *state, int32 type, int32 val, int32 distance, int32 lenval, uint16 flag)
156 : : {
7893 bruce@momjian.us 157 : 81 : NODE *tmp = (NODE *) palloc(sizeof(NODE));
158 : :
7929 159 : 81 : tmp->type = type;
160 : 81 : tmp->val = val;
161 : 81 : tmp->flag = flag;
162 [ - + ]: 81 : if (distance > 0xffff)
473 andrew@dunslane.net 163 [ # # ]:UBC 0 : ereturn(state->escontext, false,
164 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
165 : : errmsg("value is too big")));
7929 bruce@momjian.us 166 [ - + ]:CBC 81 : if (lenval > 0xff)
473 andrew@dunslane.net 167 [ # # ]:UBC 0 : ereturn(state->escontext, false,
168 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
169 : : errmsg("operand is too long")));
7929 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++;
473 andrew@dunslane.net 175 : 81 : return true;
176 : : }
177 : :
178 : : /*
179 : : * This function is used for query text parsing
180 : : */
181 : : static bool
5421 bruce@momjian.us 182 : 50 : pushval_asis(QPRS_STATE *state, int type, char *strval, int lenval, uint16 flag)
183 : : {
7929 184 [ - + ]: 50 : if (lenval > 0xffff)
473 andrew@dunslane.net 185 [ # # ]:UBC 0 : ereturn(state->escontext, false,
186 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
187 : : errmsg("word is too long")));
188 : :
331 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))
473 andrew@dunslane.net 191 :UBC 0 : return false;
192 : :
7929 bruce@momjian.us 193 [ - + ]:CBC 50 : while (state->curop - state->op + lenval + 1 >= state->lenop)
194 : : {
4311 peter_e@gmx.net 195 :UBC 0 : int32 tmp = state->curop - state->op;
196 : :
7929 bruce@momjian.us 197 : 0 : state->lenop *= 2;
432 peter@eisentraut.org 198 : 0 : state->op = (char *) repalloc(state->op, state->lenop);
7929 bruce@momjian.us 199 : 0 : state->curop = state->op + tmp;
200 : : }
432 peter@eisentraut.org 201 :CBC 50 : memcpy(state->curop, strval, lenval);
7929 bruce@momjian.us 202 : 50 : state->curop += lenval;
203 : 50 : *(state->curop) = '\0';
204 : 50 : state->curop++;
205 : 50 : state->sumlen += lenval + 1;
473 andrew@dunslane.net 206 : 50 : return true;
207 : : }
208 : :
209 : : #define STACKDEPTH 32
210 : : /*
211 : : * make polish notation of query
212 : : */
213 : : static int32
5421 bruce@momjian.us 214 : 27 : makepol(QPRS_STATE *state)
215 : : {
4311 peter_e@gmx.net 216 : 27 : int32 val = 0,
217 : : type;
218 : 27 : int32 lenval = 0;
6777 tgl@sss.pgh.pa.us 219 : 27 : char *strval = NULL;
220 : : int32 stack[STACKDEPTH];
4311 peter_e@gmx.net 221 : 27 : int32 lenstack = 0;
6777 tgl@sss.pgh.pa.us 222 : 27 : uint16 flag = 0;
223 : :
224 : : /* since this function recurses, it could be driven to stack overflow */
3709 noah@leadboat.com 225 : 27 : check_stack_depth();
226 : :
7893 bruce@momjian.us 227 [ + + ]: 108 : while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END)
228 : : {
7929 229 [ + + - - : 83 : switch (type)
+ - ]
230 : : {
231 : 50 : case VAL:
473 andrew@dunslane.net 232 [ - + ]: 50 : if (!pushval_asis(state, VAL, strval, lenval, flag))
473 andrew@dunslane.net 233 :UBC 0 : return ERR;
4311 peter_e@gmx.net 234 [ + + + + ]:CBC 79 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
235 [ + + ]: 8 : stack[lenstack - 1] == (int32) '!'))
236 : : {
7929 bruce@momjian.us 237 : 29 : lenstack--;
473 andrew@dunslane.net 238 [ - + ]: 29 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
473 andrew@dunslane.net 239 :UBC 0 : return ERR;
240 : : }
7929 bruce@momjian.us 241 :CBC 50 : break;
242 : 31 : case OPR:
4311 peter_e@gmx.net 243 [ - + - - ]: 31 : if (lenstack && val == (int32) '|')
244 : : {
473 andrew@dunslane.net 245 [ # # ]:UBC 0 : if (!pushquery(state, OPR, val, 0, 0, 0))
246 : 0 : return ERR;
247 : : }
248 : : else
249 : : {
7929 bruce@momjian.us 250 [ - + ]:CBC 31 : if (lenstack == STACKDEPTH)
251 : : /* internal error */
7570 tgl@sss.pgh.pa.us 252 [ # # ]:UBC 0 : elog(ERROR, "stack too short");
7929 bruce@momjian.us 253 :CBC 31 : stack[lenstack] = val;
254 : 31 : lenstack++;
255 : : }
256 : 31 : break;
7929 bruce@momjian.us 257 :UBC 0 : case OPEN:
258 [ # # ]: 0 : if (makepol(state) == ERR)
259 : 0 : return ERR;
4311 peter_e@gmx.net 260 [ # # # # ]: 0 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
261 [ # # ]: 0 : stack[lenstack - 1] == (int32) '!'))
262 : : {
7929 bruce@momjian.us 263 : 0 : lenstack--;
473 andrew@dunslane.net 264 [ # # ]: 0 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
265 : 0 : return ERR;
266 : : }
7929 bruce@momjian.us 267 : 0 : break;
268 : 0 : case CLOSE:
269 [ # # ]: 0 : while (lenstack)
270 : : {
271 : 0 : lenstack--;
473 andrew@dunslane.net 272 [ # # ]: 0 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
273 : 0 : return ERR;
274 : : };
7929 bruce@momjian.us 275 : 0 : return END;
276 : : break;
7929 bruce@momjian.us 277 :CBC 2 : case ERR:
473 andrew@dunslane.net 278 [ + - + - : 2 : if (SOFT_ERROR_OCCURRED(state->escontext))
+ - ]
279 : 2 : return ERR;
280 : : /* fall through */
281 : : default:
473 andrew@dunslane.net 282 [ # # ]:UBC 0 : ereturn(state->escontext, ERR,
283 : : (errcode(ERRCODE_SYNTAX_ERROR),
284 : : errmsg("syntax error")));
285 : :
286 : : }
287 : : }
7893 bruce@momjian.us 288 [ + + ]:CBC 27 : while (lenstack)
289 : : {
7929 290 : 2 : lenstack--;
473 andrew@dunslane.net 291 [ - + ]: 2 : if (!pushquery(state, OPR, stack[lenstack], 0, 0, 0))
473 andrew@dunslane.net 292 :UBC 0 : return ERR;
293 : : };
7929 bruce@momjian.us 294 :CBC 25 : return END;
295 : : }
296 : :
297 : : static void
4311 peter_e@gmx.net 298 : 81 : findoprnd(ITEM *ptr, int32 *pos)
299 : : {
300 : : /* since this function recurses, it could be driven to stack overflow. */
3709 noah@leadboat.com 301 : 81 : check_stack_depth();
302 : :
7929 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 : : }
4311 peter_e@gmx.net 308 [ + + ]: 31 : else if (ptr[*pos].val == (int32) '!')
309 : : {
7929 bruce@momjian.us 310 : 6 : ptr[*pos].left = 1;
311 : 6 : (*pos)++;
312 : 6 : findoprnd(ptr, pos);
313 : : }
314 : : else
315 : : {
7893 316 : 25 : ITEM *curitem = &ptr[*pos];
4311 peter_e@gmx.net 317 : 25 : int32 tmp = *pos;
318 : :
7929 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 *
473 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;
4311 peter_e@gmx.net 339 : 27 : int32 pos = 0;
340 : :
341 : : #ifdef BS_DEBUG
342 : : char pbuf[16384],
343 : : *cur;
344 : : #endif
345 : :
346 : : /* init state */
7929 bruce@momjian.us 347 : 27 : state.buf = buf;
348 : 27 : state.state = WAITOPERAND;
349 : 27 : state.count = 0;
350 : 27 : state.num = 0;
351 : 27 : state.str = NULL;
473 andrew@dunslane.net 352 : 27 : state.escontext = escontext;
353 : :
354 : : /* init list of operand */
7929 bruce@momjian.us 355 : 27 : state.sumlen = 0;
356 : 27 : state.lenop = 64;
357 : 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) */
473 andrew@dunslane.net 361 [ + + ]: 27 : if (makepol(&state) == ERR)
362 : 2 : return NULL;
7929 bruce@momjian.us 363 [ - + ]: 25 : if (!state.num)
473 andrew@dunslane.net 364 [ # # ]:UBC 0 : ereturn(escontext, NULL,
365 : : (errcode(ERRCODE_SYNTAX_ERROR),
366 : : errmsg("syntax error"),
367 : : errdetail("Empty query.")));
368 : :
3709 noah@leadboat.com 369 [ - + ]:CBC 25 : if (LTXTQUERY_TOO_BIG(state.num, state.sumlen))
473 andrew@dunslane.net 370 [ # # ]:UBC 0 : ereturn(escontext, NULL,
371 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
372 : : errmsg("ltxtquery is too large")));
7929 bruce@momjian.us 373 :CBC 25 : commonlen = COMPUTESIZE(state.num, state.sumlen);
374 : :
2959 andres@anarazel.de 375 : 25 : query = (ltxtquery *) palloc0(commonlen);
6255 tgl@sss.pgh.pa.us 376 : 25 : SET_VARSIZE(query, commonlen);
7929 bruce@momjian.us 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 : : {
383 : 81 : ptr[i].type = state.str->type;
384 : 81 : ptr[i].val = state.str->val;
385 : 81 : ptr[i].distance = state.str->distance;
386 : 81 : ptr[i].length = state.str->length;
387 : 81 : ptr[i].flag = state.str->flag;
388 : 81 : tmp = state.str->next;
389 : 81 : pfree(state.str);
390 : 81 : state.str = tmp;
391 : : }
392 : :
393 : : /* set user-friendly operand view */
432 peter@eisentraut.org 394 : 25 : memcpy(GETOPERAND(query), state.op, state.sumlen);
7929 bruce@momjian.us 395 : 25 : pfree(state.op);
396 : :
397 : : /* set left operand's position for every operator */
398 : 25 : pos = 0;
399 : 25 : findoprnd(ptr, &pos);
400 : :
401 : 25 : return query;
402 : : }
403 : :
404 : : /*
405 : : * in without morphology
406 : : */
1474 tgl@sss.pgh.pa.us 407 : 3 : PG_FUNCTION_INFO_V1(ltxtq_in);
408 : : Datum
7929 bruce@momjian.us 409 : 27 : ltxtq_in(PG_FUNCTION_ARGS)
410 : : {
411 : : ltxtquery *res;
412 : :
473 andrew@dunslane.net 413 [ + + ]: 27 : if ((res = queryin((char *) PG_GETARG_POINTER(0), fcinfo->context)) == NULL)
414 : 2 : PG_RETURN_NULL();
415 : 25 : PG_RETURN_POINTER(res);
416 : : }
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 : : */
1474 tgl@sss.pgh.pa.us 426 : 2 : PG_FUNCTION_INFO_V1(ltxtq_recv);
427 : : Datum
1474 tgl@sss.pgh.pa.us 428 :UBC 0 : ltxtq_recv(PG_FUNCTION_ARGS)
429 : : {
430 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
431 : 0 : int version = pq_getmsgint(buf, 1);
432 : : char *str;
433 : : int nbytes;
434 : : ltxtquery *res;
435 : :
436 [ # # ]: 0 : if (version != 1)
437 [ # # ]: 0 : elog(ERROR, "unsupported ltxtquery version number %d", version);
438 : :
439 : 0 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
473 andrew@dunslane.net 440 : 0 : res = queryin(str, NULL);
1474 tgl@sss.pgh.pa.us 441 : 0 : pfree(str);
442 : :
443 : 0 : PG_RETURN_POINTER(res);
444 : : }
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 : : #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
5995 bruce@momjian.us 472 :CBC 10 : infix(INFIX *in, bool first)
473 : : {
474 : : /* since this function recurses, it could be driven to stack overflow. */
3114 noah@leadboat.com 475 : 10 : check_stack_depth();
476 : :
7929 bruce@momjian.us 477 [ + + ]: 10 : if (in->curpol->type == VAL)
478 : : {
7893 479 : 6 : char *op = in->op + in->curpol->distance;
480 : :
7929 481 [ + + ]: 8 : RESIZEBUF(in, in->curpol->length * 2 + 5);
7893 482 [ + + ]: 32 : while (*op)
483 : : {
7929 484 : 26 : *(in->cur) = *op;
485 : 26 : op++;
486 : 26 : in->cur++;
487 : : }
6619 neilc@samurai.com 488 [ + + ]: 6 : if (in->curpol->flag & LVAR_SUBLEXEME)
489 : : {
7929 bruce@momjian.us 490 : 2 : *(in->cur) = '%';
491 : 2 : in->cur++;
492 : : }
7893 493 [ + + ]: 6 : if (in->curpol->flag & LVAR_INCASE)
494 : : {
7929 495 : 1 : *(in->cur) = '@';
496 : 1 : in->cur++;
497 : : }
7893 498 [ + + ]: 6 : if (in->curpol->flag & LVAR_ANYEND)
499 : : {
7929 500 : 3 : *(in->cur) = '*';
501 : 3 : in->cur++;
502 : : }
503 : 6 : *(in->cur) = '\0';
504 : 6 : in->curpol++;
505 : : }
4311 peter_e@gmx.net 506 [ + + ]: 4 : else if (in->curpol->val == (int32) '!')
507 : : {
7893 bruce@momjian.us 508 : 1 : bool isopr = false;
509 : :
7929 510 [ - + ]: 1 : RESIZEBUF(in, 1);
511 : 1 : *(in->cur) = '!';
512 : 1 : in->cur++;
513 : 1 : *(in->cur) = '\0';
514 : 1 : in->curpol++;
515 [ - + ]: 1 : if (in->curpol->type == OPR)
516 : : {
7929 bruce@momjian.us 517 :UBC 0 : isopr = true;
518 [ # # ]: 0 : RESIZEBUF(in, 2);
519 : 0 : sprintf(in->cur, "( ");
520 : 0 : in->cur = strchr(in->cur, '\0');
521 : : }
7929 bruce@momjian.us 522 :CBC 1 : infix(in, isopr);
523 [ - + ]: 1 : if (isopr)
524 : : {
7929 bruce@momjian.us 525 [ # # ]:UBC 0 : RESIZEBUF(in, 2);
526 : 0 : sprintf(in->cur, " )");
527 : 0 : in->cur = strchr(in->cur, '\0');
528 : : }
529 : : }
530 : : else
531 : : {
4311 peter_e@gmx.net 532 :CBC 3 : int32 op = in->curpol->val;
533 : : INFIX nrm;
534 : :
7929 bruce@momjian.us 535 : 3 : in->curpol++;
4311 peter_e@gmx.net 536 [ - + - - ]: 3 : if (op == (int32) '|' && !first)
537 : : {
7929 bruce@momjian.us 538 [ # # ]:UBC 0 : RESIZEBUF(in, 2);
539 : 0 : sprintf(in->cur, "( ");
540 : 0 : in->cur = strchr(in->cur, '\0');
541 : : }
542 : :
7929 bruce@momjian.us 543 :CBC 3 : nrm.curpol = in->curpol;
544 : 3 : nrm.op = in->op;
545 : 3 : nrm.buflen = 16;
546 : 3 : nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
547 : :
548 : : /* get right operand */
549 : 3 : infix(&nrm, false);
550 : :
551 : : /* get & print left operand */
552 : 3 : in->curpol = nrm.curpol;
553 : 3 : infix(in, false);
554 : :
555 : : /* print operator & right operand */
556 [ - + ]: 3 : RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
557 : 3 : sprintf(in->cur, " %c %s", op, nrm.buf);
558 : 3 : in->cur = strchr(in->cur, '\0');
559 : 3 : pfree(nrm.buf);
560 : :
4311 peter_e@gmx.net 561 [ - + - - ]: 3 : if (op == (int32) '|' && !first)
562 : : {
7929 bruce@momjian.us 563 [ # # ]:UBC 0 : RESIZEBUF(in, 2);
564 : 0 : sprintf(in->cur, " )");
565 : 0 : in->cur = strchr(in->cur, '\0');
566 : : }
567 : : }
7929 bruce@momjian.us 568 :CBC 10 : }
569 : :
1474 tgl@sss.pgh.pa.us 570 : 3 : PG_FUNCTION_INFO_V1(ltxtq_out);
571 : : Datum
7929 bruce@momjian.us 572 : 3 : ltxtq_out(PG_FUNCTION_ARGS)
573 : : {
2400 tgl@sss.pgh.pa.us 574 : 3 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(0);
575 : : INFIX nrm;
576 : :
7929 bruce@momjian.us 577 [ - + ]: 3 : if (query->size == 0)
7570 tgl@sss.pgh.pa.us 578 [ # # ]:UBC 0 : ereport(ERROR,
579 : : (errcode(ERRCODE_SYNTAX_ERROR),
580 : : errmsg("syntax error"),
581 : : errdetail("Empty query.")));
582 : :
7929 bruce@momjian.us 583 :CBC 3 : nrm.curpol = GETQUERY(query);
584 : 3 : nrm.buflen = 32;
585 : 3 : nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
586 : 3 : *(nrm.cur) = '\0';
587 : 3 : nrm.op = GETOPERAND(query);
588 : 3 : infix(&nrm, true);
589 : :
590 : 3 : PG_RETURN_POINTER(nrm.buf);
591 : : }
592 : :
593 : : /*
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 : : * can change the binary format sent in future if necessary. For now,
599 : : * only version 1 is supported.
600 : : */
1474 tgl@sss.pgh.pa.us 601 : 2 : PG_FUNCTION_INFO_V1(ltxtq_send);
602 : : Datum
1474 tgl@sss.pgh.pa.us 603 :UBC 0 : ltxtq_send(PG_FUNCTION_ARGS)
604 : : {
605 : 0 : ltxtquery *query = PG_GETARG_LTXTQUERY_P(0);
606 : : StringInfoData buf;
607 : 0 : int version = 1;
608 : : INFIX nrm;
609 : :
610 [ # # ]: 0 : if (query->size == 0)
611 [ # # ]: 0 : ereport(ERROR,
612 : : (errcode(ERRCODE_SYNTAX_ERROR),
613 : : errmsg("syntax error"),
614 : : errdetail("Empty query.")));
615 : :
616 : 0 : nrm.curpol = GETQUERY(query);
617 : 0 : nrm.buflen = 32;
618 : 0 : nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
619 : 0 : *(nrm.cur) = '\0';
620 : 0 : nrm.op = GETOPERAND(query);
621 : 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 : : }
|