Age Owner Branch data TLA 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 : :
8548 bruce@momjian.us 9 :CBC 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
5246 peter_e@gmx.net 48 : 131688 : gettoken(WORKSTATE *state, int32 *val)
49 : : {
50 : : char nnn[16];
51 : : int innn;
52 : :
7712 tgl@sss.pgh.pa.us 53 : 131688 : *val = 0; /* default result */
54 : :
5761 55 : 131688 : innn = 0;
56 : : while (1)
57 : : {
58 [ - + ]: 164904 : if (innn >= sizeof(nnn))
5761 tgl@sss.pgh.pa.us 59 :UBC 0 : return ERR; /* buffer overrun => syntax error */
8548 bruce@momjian.us 60 [ + + + - ]:CBC 164904 : switch (state->state)
61 : : {
62 : 65905 : case WAITOPERAND:
5761 tgl@sss.pgh.pa.us 63 : 65905 : innn = 0;
8548 bruce@momjian.us 64 [ + + + + ]: 65905 : if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
65 [ + + ]: 32909 : *(state->buf) == '-')
66 : : {
67 : 32997 : state->state = WAITENDOPERAND;
5761 tgl@sss.pgh.pa.us 68 : 32997 : nnn[innn++] = *(state->buf);
69 : : }
8548 bruce@momjian.us 70 [ + + ]: 32908 : else if (*(state->buf) == '!')
71 : : {
72 : 55 : (state->buf)++;
5246 peter_e@gmx.net 73 : 55 : *val = (int32) '!';
8548 bruce@momjian.us 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 : : {
5761 tgl@sss.pgh.pa.us 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;
16 97 : 32997 : lval = strtol(nnn, &endptr, 10);
5246 peter_e@gmx.net 98 : 32997 : *val = (int32) lval;
16 tgl@sss.pgh.pa.us 99 [ + - + + : 32997 : if (errno != 0 || *endptr != '\0' || (long) *val != lval)
- + ]
5761 100 : 1 : return ERR;
8548 bruce@momjian.us 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;
5246 peter_e@gmx.net 110 : 32904 : *val = (int32) *(state->buf);
8548 bruce@momjian.us 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;
8548 bruce@momjian.us 125 :UBC 0 : default:
126 : 0 : return ERR;
127 : : break;
128 : : }
8548 bruce@momjian.us 129 :CBC 33216 : (state->buf)++;
130 : : }
131 : : }
132 : :
133 : : /*
134 : : * push new one in polish notation reverse view
135 : : */
136 : : static void
5246 peter_e@gmx.net 137 : 65955 : pushquery(WORKSTATE *state, int32 type, int32 val)
138 : : {
335 michael@paquier.xyz 139 : 65955 : NODE *tmp = palloc_object(NODE);
140 : :
8548 bruce@momjian.us 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
6356 154 : 32914 : makepol(WORKSTATE *state)
155 : : {
156 : : int32 val,
157 : : type;
158 : : int32 stack[STACKDEPTH];
5246 peter_e@gmx.net 159 : 32914 : int32 lenstack = 0;
160 : :
161 : : /* since this function recurses, it could be driven to stack overflow */
5779 tgl@sss.pgh.pa.us 162 : 32914 : check_stack_depth();
163 : :
8548 bruce@momjian.us 164 [ + + ]: 131688 : while ((type = gettoken(state, &val)) != END)
165 : : {
166 [ + + + + : 131598 : switch (type)
+ ]
167 : : {
168 : 32996 : case VAL:
169 : 32996 : pushquery(state, type, val);
5246 peter_e@gmx.net 170 [ + + + + ]: 49484 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
171 [ + + ]: 97 : stack[lenstack - 1] == (int32) '!'))
172 : : {
8548 bruce@momjian.us 173 : 16488 : lenstack--;
174 : 16488 : pushquery(state, OPR, stack[lenstack]);
175 : : }
176 : 32996 : break;
177 : 32959 : case OPR:
5246 peter_e@gmx.net 178 [ + + + + ]: 32959 : if (lenstack && val == (int32) '|')
8548 bruce@momjian.us 179 : 3 : pushquery(state, OPR, val);
180 : : else
181 : : {
182 [ - + ]: 32956 : if (lenstack == STACKDEPTH)
1408 andrew@dunslane.net 183 [ # # ]:UBC 0 : ereturn(state->escontext, ERR,
184 : : (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
185 : : errmsg("statement too complex")));
8548 bruce@momjian.us 186 :CBC 32956 : stack[lenstack] = val;
187 : 32956 : lenstack++;
188 : : }
189 : 32959 : break;
190 : 32819 : case OPEN:
191 [ - + ]: 32819 : if (makepol(state) == ERR)
8548 bruce@momjian.us 192 :UBC 0 : return ERR;
5246 peter_e@gmx.net 193 [ + + + + ]:CBC 49232 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
194 [ + + ]: 20 : stack[lenstack - 1] == (int32) '!'))
195 : : {
8548 bruce@momjian.us 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:
1408 andrew@dunslane.net 210 [ + + ]: 5 : ereturn(state->escontext, ERR,
211 : : (errcode(ERRCODE_SYNTAX_ERROR),
212 : : errmsg("syntax error")));
213 : : }
214 : : }
215 : :
8548 bruce@momjian.us 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
2411 akorotkov@postgresql 234 : 314649 : checkcondition_arr(void *checkval, ITEM *item, void *options)
235 : : {
5246 peter_e@gmx.net 236 : 314649 : int32 *StopLow = ((CHKVAL *) checkval)->arrb;
237 : 314649 : int32 *StopHigh = ((CHKVAL *) checkval)->arre;
238 : : int32 *StopMiddle;
239 : :
240 : : /* Loop invariant: StopLow <= val < StopHigh */
241 : :
8548 bruce@momjian.us 242 [ + + ]: 1129023 : while (StopLow < StopHigh)
243 : : {
244 : 827025 : StopMiddle = StopLow + (StopHigh - StopLow) / 2;
7491 teodor@sigaev.ru 245 [ + + ]: 827025 : if (*StopMiddle == item->val)
3367 peter_e@gmx.net 246 : 12651 : return true;
7491 teodor@sigaev.ru 247 [ + + ]: 814374 : else if (*StopMiddle < item->val)
8548 bruce@momjian.us 248 : 238199 : StopLow = StopMiddle + 1;
249 : : else
250 : 576175 : StopHigh = StopMiddle;
251 : : }
252 : 301998 : return false;
253 : : }
254 : :
255 : : static bool
2411 akorotkov@postgresql 256 : 44732 : checkcondition_bit(void *checkval, ITEM *item, void *siglen)
257 : : {
2366 tgl@sss.pgh.pa.us 258 : 44732 : 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
2411 akorotkov@postgresql 265 : 884034 : 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 */
5779 tgl@sss.pgh.pa.us 269 : 884034 : check_stack_depth();
270 : :
8548 bruce@momjian.us 271 [ + + ]: 884034 : if (curitem->type == VAL)
2411 akorotkov@postgresql 272 : 388422 : return (*chkcond) (checkval, curitem, options);
5246 peter_e@gmx.net 273 [ + + ]: 495612 : else if (curitem->val == (int32) '!')
274 : : {
275 : : return calcnot ?
2411 akorotkov@postgresql 276 : 153511 : ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true)
8548 bruce@momjian.us 277 [ + + + + ]: 361938 : : true;
278 : : }
5246 peter_e@gmx.net 279 [ + + ]: 287185 : else if (curitem->val == (int32) '&')
280 : : {
2411 akorotkov@postgresql 281 [ + + ]: 153306 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
282 : 85603 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
283 : : else
8548 bruce@momjian.us 284 : 67703 : return false;
285 : : }
286 : : else
287 : : { /* |-operator */
2411 akorotkov@postgresql 288 [ + + ]: 133879 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
8548 bruce@momjian.us 289 : 6820 : return true;
290 : : else
2411 akorotkov@postgresql 291 : 127059 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
292 : : }
293 : : }
294 : :
295 : : /*
296 : : * signconsistent & execconsistent called by *_consistent
297 : : */
298 : : bool
299 : 51018 : signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot)
300 : : {
5779 tgl@sss.pgh.pa.us 301 : 102036 : return execute(GETQUERY(query) + query->size - 1,
707 peter@eisentraut.org 302 : 51018 : sign, (void *) (intptr_t) siglen, calcnot,
303 : : checkcondition_bit);
304 : : }
305 : :
306 : : /* Array must be sorted! */
307 : : bool
6356 bruce@momjian.us 308 : 82741 : execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
309 : : {
310 : : CHKVAL chkval;
311 : :
7656 tgl@sss.pgh.pa.us 312 [ - + - - : 82741 : CHECKARRVALID(array);
- - ]
8548 bruce@momjian.us 313 [ - + ]: 82741 : chkval.arrb = ARRPTR(array);
314 : 82741 : chkval.arre = chkval.arrb + ARRNELEMS(array);
5779 tgl@sss.pgh.pa.us 315 : 82741 : 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
2411 akorotkov@postgresql 327 : 29041 : checkcondition_gin(void *checkval, ITEM *item, void *options)
328 : : {
7337 bruce@momjian.us 329 : 29041 : GinChkVal *gcv = (GinChkVal *) checkval;
330 : :
331 : 29041 : return gcv->mapped_check[item - gcv->first];
332 : : }
333 : :
334 : : bool
5779 tgl@sss.pgh.pa.us 335 : 14919 : gin_bool_consistent(QUERYTYPE *query, bool *check)
336 : : {
337 : : GinChkVal gcv;
7337 bruce@momjian.us 338 : 14919 : ITEM *items = GETQUERY(query);
339 : : int i,
340 : 14919 : j = 0;
341 : :
5779 tgl@sss.pgh.pa.us 342 [ - + ]: 14919 : if (query->size <= 0)
3368 peter_e@gmx.net 343 :UBC 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 : : */
7491 teodor@sigaev.ru 349 :CBC 14919 : gcv.first = items;
335 michael@paquier.xyz 350 : 14919 : gcv.mapped_check = palloc_array(bool, query->size);
7337 bruce@momjian.us 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 : :
5779 tgl@sss.pgh.pa.us 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;
5246 peter_e@gmx.net 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 : : */
5779 tgl@sss.pgh.pa.us 377 : 8 : return false;
378 : : }
5246 peter_e@gmx.net 379 [ + + ]: 20 : else if (curitem->val == (int32) '&')
380 : : {
381 : : /* If either side has a required value, we're good */
5779 tgl@sss.pgh.pa.us 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
5779 tgl@sss.pgh.pa.us 393 :UBC 0 : return false;
394 : : }
395 : : }
396 : :
397 : : bool
5779 tgl@sss.pgh.pa.us 398 :CBC 14 : query_has_required_values(QUERYTYPE *query)
399 : : {
400 [ - + ]: 14 : if (query->size <= 0)
5779 tgl@sss.pgh.pa.us 401 :UBC 0 : return false;
5779 tgl@sss.pgh.pa.us 402 :CBC 14 : return contains_required_value(GETQUERY(query) + query->size - 1);
403 : : }
404 : :
405 : : /*
406 : : * boolean operations
407 : : */
408 : : Datum
8548 bruce@momjian.us 409 :UBC 0 : rboolop(PG_FUNCTION_ARGS)
410 : : {
411 : : /* just reverse the operands */
5779 tgl@sss.pgh.pa.us 412 : 0 : return DirectFunctionCall2(boolop,
413 : : PG_GETARG_DATUM(1),
414 : : PG_GETARG_DATUM(0));
415 : : }
416 : :
417 : : Datum
8548 bruce@momjian.us 418 :CBC 81998 : boolop(PG_FUNCTION_ARGS)
419 : : {
5779 tgl@sss.pgh.pa.us 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 : :
7656 425 [ - + - - : 81998 : CHECKARRVALID(val);
- - ]
8548 bruce@momjian.us 426 [ - + ]: 81998 : PREPAREARR(val);
427 [ - + ]: 81998 : chkval.arrb = ARRPTR(val);
428 : 81998 : chkval.arre = chkval.arrb + ARRNELEMS(val);
5779 tgl@sss.pgh.pa.us 429 : 81998 : result = execute(GETQUERY(query) + query->size - 1,
430 : : &chkval, NULL, true,
431 : : checkcondition_arr);
8548 bruce@momjian.us 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
178 tgl@sss.pgh.pa.us 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. */
4644 noah@leadboat.com 458 : 65952 : check_stack_depth();
459 : :
460 : : /* get the position this call is supposed to update */
178 tgl@sss.pgh.pa.us 461 : 65952 : mypos = *pos;
462 [ - + ]: 65952 : 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))
178 tgl@sss.pgh.pa.us 483 :UBC 0 : return false;
484 : : }
485 : : else
486 : : {
487 : : /* binary operator */
488 : : int32 delta;
489 : :
490 : : /* recurse to scan right operand */
178 tgl@sss.pgh.pa.us 491 [ - + ]:CBC 32904 : if (!findoprnd(state, ptr, pos))
178 tgl@sss.pgh.pa.us 492 :UBC 0 : return false;
493 : : /* we must fill left with offset to left operand's top */
494 : : /* abs(delta) < QUERYTYPEMAXITEMS, so it can't overflow ... */
178 tgl@sss.pgh.pa.us 495 :CBC 32904 : delta = *pos - mypos;
496 : : /* ... but it might be too large to fit in the 16-bit left field */
497 [ - + ]: 32904 : 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))
178 tgl@sss.pgh.pa.us 505 :UBC 0 : return false;
506 : : }
507 : :
178 tgl@sss.pgh.pa.us 508 :CBC 65951 : return true;
509 : : }
510 : :
511 : :
512 : : /*
513 : : * input
514 : : */
515 : : Datum
8548 bruce@momjian.us 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;
5246 peter_e@gmx.net 525 : 95 : int32 pos = 0;
1408 andrew@dunslane.net 526 : 95 : struct Node *escontext = fcinfo->context;
527 : :
528 : : #ifdef BS_DEBUG
529 : : StringInfoData pbuf;
530 : : #endif
531 : :
8548 bruce@momjian.us 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;
1408 andrew@dunslane.net 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();
8548 bruce@momjian.us 542 [ - + ]: 90 : if (!state.num)
1408 andrew@dunslane.net 543 [ # # ]:UBC 0 : ereturn(escontext, (Datum) 0,
544 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
545 : : errmsg("empty query")));
546 : :
4644 noah@leadboat.com 547 [ - + ]:CBC 90 : if (state.num > QUERYTYPEMAXITEMS)
1408 andrew@dunslane.net 548 [ # # ]:UBC 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)));
8548 bruce@momjian.us 552 :CBC 90 : commonlen = COMPUTESIZE(state.num);
553 : :
554 : 90 : query = (QUERYTYPE *) palloc(commonlen);
7190 tgl@sss.pgh.pa.us 555 : 90 : SET_VARSIZE(query, commonlen);
8548 bruce@momjian.us 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;
178 tgl@sss.pgh.pa.us 571 [ - + ]: 90 : if (!findoprnd(&state, ptr, &pos))
178 tgl@sss.pgh.pa.us 572 :UBC 0 : PG_RETURN_NULL();
573 : : /* if successful, findoprnd should have scanned the whole array */
178 tgl@sss.pgh.pa.us 574 [ - + ]:CBC 89 : 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 : :
8548 bruce@momjian.us 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
6930 612 : 181 : infix(INFIX *in, bool first)
613 : : {
614 : : /* since this function recurses, it could be driven to stack overflow. */
4049 noah@leadboat.com 615 : 181 : check_stack_depth();
616 : :
8548 bruce@momjian.us 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 : : }
5246 peter_e@gmx.net 624 [ + + ]: 85 : else if (in->curpol->val == (int32) '!')
625 : : {
8548 bruce@momjian.us 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 : : {
5246 peter_e@gmx.net 650 : 58 : int32 op = in->curpol->val;
651 : : INFIX nrm;
652 : :
8548 bruce@momjian.us 653 : 58 : in->curpol--;
5246 peter_e@gmx.net 654 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
655 : : {
8548 bruce@momjian.us 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;
335 michael@paquier.xyz 663 : 58 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
664 : :
665 : : /* get right operand */
8548 bruce@momjian.us 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 : :
5246 peter_e@gmx.net 678 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
679 : : {
8548 bruce@momjian.us 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 : : {
5779 tgl@sss.pgh.pa.us 691 : 38 : QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0);
692 : : INFIX nrm;
693 : :
8548 bruce@momjian.us 694 [ - + ]: 38 : if (query->size == 0)
8505 tgl@sss.pgh.pa.us 695 [ # # ]:UBC 0 : ereport(ERROR,
696 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
697 : : errmsg("empty query")));
698 : :
8548 bruce@momjian.us 699 :CBC 38 : nrm.curpol = GETQUERY(query) + query->size - 1;
700 : 38 : nrm.buflen = 32;
335 michael@paquier.xyz 701 : 38 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
8548 bruce@momjian.us 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
8548 bruce@momjian.us 712 :UBC 0 : querytree(PG_FUNCTION_ARGS)
713 : : {
5779 tgl@sss.pgh.pa.us 714 [ # # ]: 0 : elog(ERROR, "querytree is no longer implemented");
715 : : PG_RETURN_NULL();
716 : : }
|