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