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