Branch data Line data Source code
1 : : /*
2 : : * contrib/intarray/_int_bool.c
3 : : */
4 : : #include "postgres.h"
5 : :
6 : : #include "_int.h"
7 : : #include "miscadmin.h"
8 : :
9 : 2 : PG_FUNCTION_INFO_V1(bqarr_in);
10 : 2 : PG_FUNCTION_INFO_V1(bqarr_out);
11 : 2 : PG_FUNCTION_INFO_V1(boolop);
12 : 1 : PG_FUNCTION_INFO_V1(rboolop);
13 : 1 : PG_FUNCTION_INFO_V1(querytree);
14 : :
15 : :
16 : : /* parser's states */
17 : : #define WAITOPERAND 1
18 : : #define WAITENDOPERAND 2
19 : : #define WAITOPERATOR 3
20 : :
21 : : /*
22 : : * node of query tree, also used
23 : : * for storing polish notation in parser
24 : : */
25 : : typedef struct NODE
26 : : {
27 : : int32 type;
28 : : int32 val;
29 : : struct NODE *next;
30 : : } NODE;
31 : :
32 : : typedef struct
33 : : {
34 : : char *buf;
35 : : int32 state;
36 : : int32 count;
37 : : struct Node *escontext;
38 : : /* reverse polish notation in list (for temporary usage) */
39 : : NODE *str;
40 : : /* number in str */
41 : : int32 num;
42 : : } WORKSTATE;
43 : :
44 : : /*
45 : : * get token from query string
46 : : */
47 : : static int32
48 : 131688 : gettoken(WORKSTATE *state, int32 *val)
49 : : {
50 : : char nnn[16];
51 : : int innn;
52 : :
53 : 131688 : *val = 0; /* default result */
54 : :
55 : 131688 : innn = 0;
56 : : while (1)
57 : : {
58 [ - + ]: 164904 : if (innn >= sizeof(nnn))
59 : 0 : return ERR; /* buffer overrun => syntax error */
60 [ + + + - ]: 164904 : switch (state->state)
61 : : {
62 : 65905 : case WAITOPERAND:
63 : 65905 : innn = 0;
64 [ + + + + ]: 65905 : if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
65 [ + + ]: 32909 : *(state->buf) == '-')
66 : : {
67 : 32997 : state->state = WAITENDOPERAND;
68 : 32997 : nnn[innn++] = *(state->buf);
69 : : }
70 [ + + ]: 32908 : else if (*(state->buf) == '!')
71 : : {
72 : 55 : (state->buf)++;
73 : 55 : *val = (int32) '!';
74 : 55 : return OPR;
75 : : }
76 [ + + ]: 32853 : else if (*(state->buf) == '(')
77 : : {
78 : 32819 : state->count++;
79 : 32819 : (state->buf)++;
80 : 32819 : return OPEN;
81 : : }
82 [ + + ]: 34 : else if (*(state->buf) != ' ')
83 : 2 : return ERR;
84 : 33029 : break;
85 : 33153 : case WAITENDOPERAND:
86 [ + + + + ]: 33153 : if (*(state->buf) >= '0' && *(state->buf) <= '9')
87 : : {
88 : 156 : nnn[innn++] = *(state->buf);
89 : : }
90 : : else
91 : : {
92 : : long lval;
93 : : char *endptr;
94 : :
95 : 32997 : nnn[innn] = '\0';
96 : 32997 : errno = 0;
97 : 32997 : lval = strtol(nnn, &endptr, 10);
98 : 32997 : *val = (int32) lval;
99 [ + - + + : 32997 : if (errno != 0 || *endptr != '\0' || (long) *val != lval)
- + ]
100 : 1 : return ERR;
101 : 32996 : state->state = WAITOPERATOR;
102 [ - + ]: 32858 : return (state->count && *(state->buf) == '\0')
103 [ + + ]: 65854 : ? ERR : VAL;
104 : : }
105 : 156 : break;
106 : 65846 : case WAITOPERATOR:
107 [ + + + + ]: 65846 : if (*(state->buf) == '&' || *(state->buf) == '|')
108 : : {
109 : 32904 : state->state = WAITOPERAND;
110 : 32904 : *val = (int32) *(state->buf);
111 : 32904 : (state->buf)++;
112 : 32904 : return OPR;
113 : : }
114 [ + + ]: 32942 : else if (*(state->buf) == ')')
115 : : {
116 : 32819 : (state->buf)++;
117 : 32819 : state->count--;
118 [ - + ]: 32819 : return (state->count < 0) ? ERR : CLOSE;
119 : : }
120 [ + + ]: 123 : else if (*(state->buf) == '\0')
121 : 90 : return (state->count) ? ERR : END;
122 [ + + ]: 33 : else if (*(state->buf) != ' ')
123 : 2 : return ERR;
124 : 31 : break;
125 : 0 : default:
126 : 0 : return ERR;
127 : : break;
128 : : }
129 : 33216 : (state->buf)++;
130 : : }
131 : : }
132 : :
133 : : /*
134 : : * push new one in polish notation reverse view
135 : : */
136 : : static void
137 : 65955 : pushquery(WORKSTATE *state, int32 type, int32 val)
138 : : {
139 : 65955 : NODE *tmp = palloc_object(NODE);
140 : :
141 : 65955 : tmp->type = type;
142 : 65955 : tmp->val = val;
143 : 65955 : tmp->next = state->str;
144 : 65955 : state->str = tmp;
145 : 65955 : state->num++;
146 : 65955 : }
147 : :
148 : : #define STACKDEPTH 16
149 : :
150 : : /*
151 : : * make polish notation of query
152 : : */
153 : : static int32
154 : 32914 : makepol(WORKSTATE *state)
155 : : {
156 : : int32 val,
157 : : type;
158 : : int32 stack[STACKDEPTH];
159 : 32914 : int32 lenstack = 0;
160 : :
161 : : /* since this function recurses, it could be driven to stack overflow */
162 : 32914 : check_stack_depth();
163 : :
164 [ + + ]: 131688 : while ((type = gettoken(state, &val)) != END)
165 : : {
166 [ + + + + : 131598 : switch (type)
+ ]
167 : : {
168 : 32996 : case VAL:
169 : 32996 : pushquery(state, type, val);
170 [ + + + + ]: 49484 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
171 [ + + ]: 97 : stack[lenstack - 1] == (int32) '!'))
172 : : {
173 : 16488 : lenstack--;
174 : 16488 : pushquery(state, OPR, stack[lenstack]);
175 : : }
176 : 32996 : break;
177 : 32959 : case OPR:
178 [ + + + + ]: 32959 : if (lenstack && val == (int32) '|')
179 : 3 : pushquery(state, OPR, val);
180 : : else
181 : : {
182 [ - + ]: 32956 : if (lenstack == STACKDEPTH)
183 [ # # ]: 0 : ereturn(state->escontext, ERR,
184 : : (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
185 : : errmsg("statement too complex")));
186 : 32956 : stack[lenstack] = val;
187 : 32956 : lenstack++;
188 : : }
189 : 32959 : break;
190 : 32819 : case OPEN:
191 [ - + ]: 32819 : if (makepol(state) == ERR)
192 : 0 : return ERR;
193 [ + + + + ]: 49232 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
194 [ + + ]: 20 : stack[lenstack - 1] == (int32) '!'))
195 : : {
196 : 16413 : lenstack--;
197 : 16413 : pushquery(state, OPR, stack[lenstack]);
198 : : }
199 : 32819 : break;
200 : 32819 : case CLOSE:
201 [ + + ]: 32840 : while (lenstack)
202 : : {
203 : 21 : lenstack--;
204 : 21 : pushquery(state, OPR, stack[lenstack]);
205 : : };
206 : 32819 : return END;
207 : : break;
208 : 5 : case ERR:
209 : : default:
210 [ + + ]: 5 : ereturn(state->escontext, ERR,
211 : : (errcode(ERRCODE_SYNTAX_ERROR),
212 : : errmsg("syntax error")));
213 : : }
214 : : }
215 : :
216 [ + + ]: 124 : while (lenstack)
217 : : {
218 : 34 : lenstack--;
219 : 34 : pushquery(state, OPR, stack[lenstack]);
220 : : };
221 : 90 : return END;
222 : : }
223 : :
224 : : typedef struct
225 : : {
226 : : int32 *arrb;
227 : : int32 *arre;
228 : : } CHKVAL;
229 : :
230 : : /*
231 : : * is there value 'val' in (sorted) array or not ?
232 : : */
233 : : static bool
234 : 312576 : checkcondition_arr(void *checkval, ITEM *item, void *options)
235 : : {
236 : 312576 : int32 *StopLow = ((CHKVAL *) checkval)->arrb;
237 : 312576 : int32 *StopHigh = ((CHKVAL *) checkval)->arre;
238 : : int32 *StopMiddle;
239 : :
240 : : /* Loop invariant: StopLow <= val < StopHigh */
241 : :
242 [ + + ]: 1122932 : while (StopLow < StopHigh)
243 : : {
244 : 822680 : StopMiddle = StopLow + (StopHigh - StopLow) / 2;
245 [ + + ]: 822680 : if (*StopMiddle == item->val)
246 : 12324 : return true;
247 [ + + ]: 810356 : else if (*StopMiddle < item->val)
248 : 237975 : StopLow = StopMiddle + 1;
249 : : else
250 : 572381 : StopHigh = StopMiddle;
251 : : }
252 : 300252 : return false;
253 : : }
254 : :
255 : : static bool
256 : 45484 : checkcondition_bit(void *checkval, ITEM *item, void *siglen)
257 : : {
258 : 45484 : return GETBIT(checkval, HASHVAL(item->val, (int) (intptr_t) siglen));
259 : : }
260 : :
261 : : /*
262 : : * evaluate boolean expression, using chkcond() to test the primitive cases
263 : : */
264 : : static bool
265 : 881344 : execute(ITEM *curitem, void *checkval, void *options, bool calcnot,
266 : : bool (*chkcond) (void *checkval, ITEM *item, void *options))
267 : : {
268 : : /* since this function recurses, it could be driven to stack overflow */
269 : 881344 : check_stack_depth();
270 : :
271 [ + + ]: 881344 : if (curitem->type == VAL)
272 : 387101 : return (*chkcond) (checkval, curitem, options);
273 [ + + ]: 494243 : else if (curitem->val == (int32) '!')
274 : : {
275 : : return calcnot ?
276 : 153792 : ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true)
277 [ + + + + ]: 362705 : : true;
278 : : }
279 [ + + ]: 285330 : else if (curitem->val == (int32) '&')
280 : : {
281 [ + + ]: 151539 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
282 : 85788 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
283 : : else
284 : 65751 : return false;
285 : : }
286 : : else
287 : : { /* |-operator */
288 [ + + ]: 133791 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
289 : 6770 : return true;
290 : : else
291 : 127021 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
292 : : }
293 : : }
294 : :
295 : : /*
296 : : * signconsistent & execconsistent called by *_consistent
297 : : */
298 : : bool
299 : 51525 : signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot)
300 : : {
301 : 103050 : return execute(GETQUERY(query) + query->size - 1,
302 : 51525 : sign, (void *) (intptr_t) siglen, calcnot,
303 : : checkcondition_bit);
304 : : }
305 : :
306 : : /* Array must be sorted! */
307 : : bool
308 : 80971 : execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
309 : : {
310 : : CHKVAL chkval;
311 : :
312 [ - + - - : 80971 : CHECKARRVALID(array);
- - ]
313 [ - + ]: 80971 : chkval.arrb = ARRPTR(array);
314 : 80971 : chkval.arre = chkval.arrb + ARRNELEMS(array);
315 : 80971 : return execute(GETQUERY(query) + query->size - 1,
316 : : &chkval, NULL, calcnot,
317 : : checkcondition_arr);
318 : : }
319 : :
320 : : typedef struct
321 : : {
322 : : ITEM *first;
323 : : bool *mapped_check;
324 : : } GinChkVal;
325 : :
326 : : static bool
327 : 29041 : checkcondition_gin(void *checkval, ITEM *item, void *options)
328 : : {
329 : 29041 : GinChkVal *gcv = (GinChkVal *) checkval;
330 : :
331 : 29041 : return gcv->mapped_check[item - gcv->first];
332 : : }
333 : :
334 : : bool
335 : 14919 : gin_bool_consistent(QUERYTYPE *query, bool *check)
336 : : {
337 : : GinChkVal gcv;
338 : 14919 : ITEM *items = GETQUERY(query);
339 : : int i,
340 : 14919 : j = 0;
341 : :
342 [ - + ]: 14919 : if (query->size <= 0)
343 : 0 : return false;
344 : :
345 : : /*
346 : : * Set up data for checkcondition_gin. This must agree with the query
347 : : * extraction code in ginint4_queryextract.
348 : : */
349 : 14919 : gcv.first = items;
350 : 14919 : gcv.mapped_check = palloc_array(bool, query->size);
351 [ + + ]: 82333 : for (i = 0; i < query->size; i++)
352 : : {
353 [ + + ]: 67414 : if (items[i].type == VAL)
354 : 31016 : gcv.mapped_check[i] = check[j++];
355 : : }
356 : :
357 : 14919 : return execute(GETQUERY(query) + query->size - 1,
358 : : &gcv, NULL, true,
359 : : checkcondition_gin);
360 : : }
361 : :
362 : : static bool
363 : 46 : contains_required_value(ITEM *curitem)
364 : : {
365 : : /* since this function recurses, it could be driven to stack overflow */
366 : 46 : check_stack_depth();
367 : :
368 [ + + ]: 46 : if (curitem->type == VAL)
369 : 18 : return true;
370 [ + + ]: 28 : else if (curitem->val == (int32) '!')
371 : : {
372 : : /*
373 : : * Assume anything under a NOT is non-required. For some cases with
374 : : * nested NOTs, we could prove there's a required value, but it seems
375 : : * unlikely to be worth the trouble.
376 : : */
377 : 8 : return false;
378 : : }
379 [ + + ]: 20 : else if (curitem->val == (int32) '&')
380 : : {
381 : : /* If either side has a required value, we're good */
382 [ + + ]: 12 : if (contains_required_value(curitem + curitem->left))
383 : 8 : return true;
384 : : else
385 : 4 : return contains_required_value(curitem - 1);
386 : : }
387 : : else
388 : : { /* |-operator */
389 : : /* Both sides must have required values */
390 [ + - ]: 8 : if (contains_required_value(curitem + curitem->left))
391 : 8 : return contains_required_value(curitem - 1);
392 : : else
393 : 0 : return false;
394 : : }
395 : : }
396 : :
397 : : bool
398 : 14 : query_has_required_values(QUERYTYPE *query)
399 : : {
400 [ - + ]: 14 : if (query->size <= 0)
401 : 0 : return false;
402 : 14 : return contains_required_value(GETQUERY(query) + query->size - 1);
403 : : }
404 : :
405 : : /*
406 : : * boolean operations
407 : : */
408 : : Datum
409 : 0 : rboolop(PG_FUNCTION_ARGS)
410 : : {
411 : : /* just reverse the operands */
412 : 0 : return DirectFunctionCall2(boolop,
413 : : PG_GETARG_DATUM(1),
414 : : PG_GETARG_DATUM(0));
415 : : }
416 : :
417 : : Datum
418 : 81998 : boolop(PG_FUNCTION_ARGS)
419 : : {
420 : 81998 : ArrayType *val = PG_GETARG_ARRAYTYPE_P_COPY(0);
421 : 81998 : QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(1);
422 : : CHKVAL chkval;
423 : : bool result;
424 : :
425 [ - + - - : 81998 : CHECKARRVALID(val);
- - ]
426 [ - + ]: 81998 : PREPAREARR(val);
427 [ - + ]: 81998 : chkval.arrb = ARRPTR(val);
428 : 81998 : chkval.arre = chkval.arrb + ARRNELEMS(val);
429 : 81998 : result = execute(GETQUERY(query) + query->size - 1,
430 : : &chkval, NULL, true,
431 : : checkcondition_arr);
432 : 81998 : pfree(val);
433 : :
434 [ - + ]: 81998 : PG_FREE_IF_COPY(query, 1);
435 : 81998 : PG_RETURN_BOOL(result);
436 : : }
437 : :
438 : : /*
439 : : * Recursively fill the "left" fields of an ITEM array that represents
440 : : * a valid postfix tree.
441 : : *
442 : : * state: only needed for error reporting
443 : : * ptr: starting element of array
444 : : * pos: in/out argument, the array index this call is responsible to fill
445 : : *
446 : : * At exit, *pos has been decremented to point before the sub-tree whose
447 : : * top is the entry-time value of *pos.
448 : : *
449 : : * Returns true if okay, false if error (the only possible error is
450 : : * overflow of a "left" field).
451 : : */
452 : : static bool
453 : 65952 : findoprnd(WORKSTATE *state, ITEM *ptr, int32 *pos)
454 : : {
455 : : int32 mypos;
456 : :
457 : : /* since this function recurses, it could be driven to stack overflow. */
458 : 65952 : check_stack_depth();
459 : :
460 : : /* get the position this call is supposed to update */
461 : 65952 : mypos = *pos;
462 : : Assert(mypos >= 0);
463 : :
464 : : /* in all cases, we should decrement *pos to advance over this item */
465 : 65952 : (*pos)--;
466 : :
467 : : #ifdef BS_DEBUG
468 : : elog(DEBUG3, (ptr[mypos].type == OPR) ?
469 : : "%d %c" : "%d %d", mypos, ptr[mypos].val);
470 : : #endif
471 : :
472 [ + + ]: 65952 : if (ptr[mypos].type == VAL)
473 : : {
474 : : /* base case: a VAL has no operand, so just set its left to zero */
475 : 32993 : ptr[mypos].left = 0;
476 : : }
477 [ + + ]: 32959 : else if (ptr[mypos].val == (int32) '!')
478 : : {
479 : : /* unary operator, likewise easy: operand is just before it */
480 : 55 : ptr[mypos].left = -1;
481 : : /* recurse to scan operand */
482 [ - + ]: 55 : if (!findoprnd(state, ptr, pos))
483 : 0 : return false;
484 : : }
485 : : else
486 : : {
487 : : /* binary operator */
488 : : int32 delta;
489 : :
490 : : /* recurse to scan right operand */
491 [ - + ]: 32904 : if (!findoprnd(state, ptr, pos))
492 : 0 : return false;
493 : : /* we must fill left with offset to left operand's top */
494 : : /* abs(delta) < QUERYTYPEMAXITEMS, so it can't overflow ... */
495 : 32904 : delta = *pos - mypos;
496 : : /* ... but it might be too large to fit in the 16-bit left field */
497 : : Assert(delta < 0);
498 [ + + ]: 32904 : if (unlikely(delta < PG_INT16_MIN))
499 [ + - ]: 1 : ereturn(state->escontext, false,
500 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
501 : : errmsg("query_int expression is too complex")));
502 : 32903 : ptr[mypos].left = (int16) delta;
503 : : /* recurse to scan left operand */
504 [ - + ]: 32903 : if (!findoprnd(state, ptr, pos))
505 : 0 : return false;
506 : : }
507 : :
508 : 65951 : return true;
509 : : }
510 : :
511 : :
512 : : /*
513 : : * input
514 : : */
515 : : Datum
516 : 95 : bqarr_in(PG_FUNCTION_ARGS)
517 : : {
518 : 95 : char *buf = (char *) PG_GETARG_POINTER(0);
519 : : WORKSTATE state;
520 : : int32 i;
521 : : QUERYTYPE *query;
522 : : int32 commonlen;
523 : : ITEM *ptr;
524 : : NODE *tmp;
525 : 95 : int32 pos = 0;
526 : 95 : struct Node *escontext = fcinfo->context;
527 : :
528 : : #ifdef BS_DEBUG
529 : : StringInfoData pbuf;
530 : : #endif
531 : :
532 : 95 : state.buf = buf;
533 : 95 : state.state = WAITOPERAND;
534 : 95 : state.count = 0;
535 : 95 : state.num = 0;
536 : 95 : state.str = NULL;
537 : 95 : state.escontext = escontext;
538 : :
539 : : /* make polish notation (postfix, but in reverse order) */
540 [ + + ]: 95 : if (makepol(&state) == ERR)
541 : 4 : PG_RETURN_NULL();
542 [ - + ]: 90 : if (!state.num)
543 [ # # ]: 0 : ereturn(escontext, (Datum) 0,
544 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
545 : : errmsg("empty query")));
546 : :
547 [ - + ]: 90 : if (state.num > QUERYTYPEMAXITEMS)
548 [ # # ]: 0 : ereturn(escontext, (Datum) 0,
549 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
550 : : errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
551 : : state.num, (int) QUERYTYPEMAXITEMS)));
552 : 90 : commonlen = COMPUTESIZE(state.num);
553 : :
554 : 90 : query = (QUERYTYPE *) palloc(commonlen);
555 : 90 : SET_VARSIZE(query, commonlen);
556 : 90 : query->size = state.num;
557 : 90 : ptr = GETQUERY(query);
558 : :
559 : : /* fill the query array from the data makepol constructed */
560 [ + + ]: 66043 : for (i = state.num - 1; i >= 0; i--)
561 : : {
562 : 65953 : ptr[i].type = state.str->type;
563 : 65953 : ptr[i].val = state.str->val;
564 : 65953 : tmp = state.str->next;
565 : 65953 : pfree(state.str);
566 : 65953 : state.str = tmp;
567 : : }
568 : :
569 : : /* now fill the "left" fields */
570 : 90 : pos = query->size - 1;
571 [ - + ]: 90 : if (!findoprnd(&state, ptr, &pos))
572 : 0 : PG_RETURN_NULL();
573 : : /* if successful, findoprnd should have scanned the whole array */
574 : : Assert(pos == -1);
575 : :
576 : : #ifdef BS_DEBUG
577 : : initStringInfo(&pbuf);
578 : : for (i = 0; i < query->size; i++)
579 : : {
580 : : if (ptr[i].type == OPR)
581 : : appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
582 : : else
583 : : appendStringInfo(&pbuf, "%d ", ptr[i].val);
584 : : }
585 : : elog(DEBUG3, "POR: %s", pbuf.data);
586 : : pfree(pbuf.data);
587 : : #endif
588 : :
589 : 89 : PG_RETURN_POINTER(query);
590 : : }
591 : :
592 : :
593 : : /*
594 : : * out function
595 : : */
596 : : typedef struct
597 : : {
598 : : ITEM *curpol;
599 : : char *buf;
600 : : char *cur;
601 : : int32 buflen;
602 : : } INFIX;
603 : :
604 : : #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
605 : : int32 len = inf->cur - inf->buf; \
606 : : inf->buflen *= 2; \
607 : : inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
608 : : inf->cur = inf->buf + len; \
609 : : }
610 : :
611 : : static void
612 : 181 : infix(INFIX *in, bool first)
613 : : {
614 : : /* since this function recurses, it could be driven to stack overflow. */
615 : 181 : check_stack_depth();
616 : :
617 [ + + ]: 181 : if (in->curpol->type == VAL)
618 : : {
619 [ - + ]: 96 : RESIZEBUF(in, 11);
620 : 96 : sprintf(in->cur, "%d", in->curpol->val);
621 : 96 : in->cur = strchr(in->cur, '\0');
622 : 96 : in->curpol--;
623 : : }
624 [ + + ]: 85 : else if (in->curpol->val == (int32) '!')
625 : : {
626 : 27 : bool isopr = false;
627 : :
628 [ - + ]: 27 : RESIZEBUF(in, 1);
629 : 27 : *(in->cur) = '!';
630 : 27 : in->cur++;
631 : 27 : *(in->cur) = '\0';
632 : 27 : in->curpol--;
633 [ + + ]: 27 : if (in->curpol->type == OPR)
634 : : {
635 : 6 : isopr = true;
636 [ - + ]: 6 : RESIZEBUF(in, 2);
637 : 6 : sprintf(in->cur, "( ");
638 : 6 : in->cur = strchr(in->cur, '\0');
639 : : }
640 : 27 : infix(in, isopr);
641 [ + + ]: 27 : if (isopr)
642 : : {
643 [ - + ]: 6 : RESIZEBUF(in, 2);
644 : 6 : sprintf(in->cur, " )");
645 : 6 : in->cur = strchr(in->cur, '\0');
646 : : }
647 : : }
648 : : else
649 : : {
650 : 58 : int32 op = in->curpol->val;
651 : : INFIX nrm;
652 : :
653 : 58 : in->curpol--;
654 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
655 : : {
656 [ - + ]: 10 : RESIZEBUF(in, 2);
657 : 10 : sprintf(in->cur, "( ");
658 : 10 : in->cur = strchr(in->cur, '\0');
659 : : }
660 : :
661 : 58 : nrm.curpol = in->curpol;
662 : 58 : nrm.buflen = 16;
663 : 58 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
664 : :
665 : : /* get right operand */
666 : 58 : infix(&nrm, false);
667 : :
668 : : /* get & print left operand */
669 : 58 : in->curpol = nrm.curpol;
670 : 58 : infix(in, false);
671 : :
672 : : /* print operator & right operand */
673 [ + + ]: 62 : RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
674 : 58 : sprintf(in->cur, " %c %s", op, nrm.buf);
675 : 58 : in->cur = strchr(in->cur, '\0');
676 : 58 : pfree(nrm.buf);
677 : :
678 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
679 : : {
680 [ - + ]: 10 : RESIZEBUF(in, 2);
681 : 10 : sprintf(in->cur, " )");
682 : 10 : in->cur = strchr(in->cur, '\0');
683 : : }
684 : : }
685 : 181 : }
686 : :
687 : :
688 : : Datum
689 : 38 : bqarr_out(PG_FUNCTION_ARGS)
690 : : {
691 : 38 : QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0);
692 : : INFIX nrm;
693 : :
694 [ - + ]: 38 : if (query->size == 0)
695 [ # # ]: 0 : ereport(ERROR,
696 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
697 : : errmsg("empty query")));
698 : :
699 : 38 : nrm.curpol = GETQUERY(query) + query->size - 1;
700 : 38 : nrm.buflen = 32;
701 : 38 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
702 : 38 : *(nrm.cur) = '\0';
703 : 38 : infix(&nrm, true);
704 : :
705 [ - + ]: 38 : PG_FREE_IF_COPY(query, 0);
706 : 38 : PG_RETURN_POINTER(nrm.buf);
707 : : }
708 : :
709 : :
710 : : /* Useless old "debugging" function for a fundamentally wrong algorithm */
711 : : Datum
712 : 0 : querytree(PG_FUNCTION_ARGS)
713 : : {
714 [ # # ]: 0 : elog(ERROR, "querytree is no longer implemented");
715 : : PG_RETURN_NULL();
716 : : }
|