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 : :
8123 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
4821 peter_e@gmx.net 48 : 613 : gettoken(WORKSTATE *state, int32 *val)
49 : : {
50 : : char nnn[16];
51 : : int innn;
52 : :
7287 tgl@sss.pgh.pa.us 53 : 613 : *val = 0; /* default result */
54 : :
5336 55 : 613 : innn = 0;
56 : : while (1)
57 : : {
58 [ - + ]: 1056 : if (innn >= sizeof(nnn))
5336 tgl@sss.pgh.pa.us 59 :UBC 0 : return ERR; /* buffer overrun => syntax error */
8123 bruce@momjian.us 60 [ + + + - ]:CBC 1056 : switch (state->state)
61 : : {
62 : 367 : case WAITOPERAND:
5336 tgl@sss.pgh.pa.us 63 : 367 : innn = 0;
8123 bruce@momjian.us 64 [ + + + + ]: 367 : if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
65 [ - + ]: 141 : *(state->buf) == '-')
66 : : {
67 : 226 : state->state = WAITENDOPERAND;
5336 tgl@sss.pgh.pa.us 68 : 226 : nnn[innn++] = *(state->buf);
69 : : }
8123 bruce@momjian.us 70 [ + + ]: 141 : else if (*(state->buf) == '!')
71 : : {
72 : 55 : (state->buf)++;
4821 peter_e@gmx.net 73 : 55 : *val = (int32) '!';
8123 bruce@momjian.us 74 : 55 : return OPR;
75 : : }
76 [ + + ]: 86 : else if (*(state->buf) == '(')
77 : : {
78 : 52 : state->count++;
79 : 52 : (state->buf)++;
80 : 52 : return OPEN;
81 : : }
82 [ + + ]: 34 : else if (*(state->buf) != ' ')
83 : 2 : return ERR;
84 : 258 : break;
85 : 380 : case WAITENDOPERAND:
86 [ + + + + ]: 380 : if (*(state->buf) >= '0' && *(state->buf) <= '9')
87 : : {
5336 tgl@sss.pgh.pa.us 88 : 154 : nnn[innn++] = *(state->buf);
89 : : }
90 : : else
91 : : {
92 : : long lval;
93 : :
94 : 226 : nnn[innn] = '\0';
95 : 226 : errno = 0;
96 : 226 : lval = strtol(nnn, NULL, 0);
4821 peter_e@gmx.net 97 : 226 : *val = (int32) lval;
5336 tgl@sss.pgh.pa.us 98 [ + - - + ]: 226 : if (errno != 0 || (long) *val != lval)
5336 tgl@sss.pgh.pa.us 99 :UBC 0 : return ERR;
8123 bruce@momjian.us 100 :CBC 226 : state->state = WAITOPERATOR;
101 [ - + ]: 90 : return (state->count && *(state->buf) == '\0')
102 [ + + ]: 316 : ? ERR : VAL;
103 : : }
104 : 154 : break;
105 : 309 : case WAITOPERATOR:
106 [ + + + + ]: 309 : if (*(state->buf) == '&' || *(state->buf) == '|')
107 : : {
108 : 136 : state->state = WAITOPERAND;
4821 peter_e@gmx.net 109 : 136 : *val = (int32) *(state->buf);
8123 bruce@momjian.us 110 : 136 : (state->buf)++;
111 : 136 : return OPR;
112 : : }
113 [ + + ]: 173 : else if (*(state->buf) == ')')
114 : : {
115 : 52 : (state->buf)++;
116 : 52 : state->count--;
117 [ - + ]: 52 : return (state->count < 0) ? ERR : CLOSE;
118 : : }
119 [ + + ]: 121 : else if (*(state->buf) == '\0')
120 : 88 : return (state->count) ? ERR : END;
121 [ + + ]: 33 : else if (*(state->buf) != ' ')
122 : 2 : return ERR;
123 : 31 : break;
8123 bruce@momjian.us 124 :UBC 0 : default:
125 : 0 : return ERR;
126 : : break;
127 : : }
8123 bruce@momjian.us 128 :CBC 443 : (state->buf)++;
129 : : }
130 : : }
131 : :
132 : : /*
133 : : * push new one in polish notation reverse view
134 : : */
135 : : static void
4821 peter_e@gmx.net 136 : 417 : pushquery(WORKSTATE *state, int32 type, int32 val)
137 : : {
8123 bruce@momjian.us 138 : 417 : NODE *tmp = (NODE *) palloc(sizeof(NODE));
139 : :
140 : 417 : tmp->type = type;
141 : 417 : tmp->val = val;
142 : 417 : tmp->next = state->str;
143 : 417 : state->str = tmp;
144 : 417 : state->num++;
145 : 417 : }
146 : :
147 : : #define STACKDEPTH 16
148 : :
149 : : /*
150 : : * make polish notation of query
151 : : */
152 : : static int32
5931 153 : 144 : makepol(WORKSTATE *state)
154 : : {
155 : : int32 val,
156 : : type;
157 : : int32 stack[STACKDEPTH];
4821 peter_e@gmx.net 158 : 144 : int32 lenstack = 0;
159 : :
160 : : /* since this function recurses, it could be driven to stack overflow */
5354 tgl@sss.pgh.pa.us 161 : 144 : check_stack_depth();
162 : :
8123 bruce@momjian.us 163 [ + + ]: 613 : while ((type = gettoken(state, &val)) != END)
164 : : {
165 [ + + + + : 525 : switch (type)
+ ]
166 : : {
167 : 226 : case VAL:
168 : 226 : pushquery(state, type, val);
4821 peter_e@gmx.net 169 [ + + + + ]: 330 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
170 [ + + ]: 97 : stack[lenstack - 1] == (int32) '!'))
171 : : {
8123 bruce@momjian.us 172 : 104 : lenstack--;
173 : 104 : pushquery(state, OPR, stack[lenstack]);
174 : : }
175 : 226 : break;
176 : 191 : case OPR:
4821 peter_e@gmx.net 177 [ + + + + ]: 191 : if (lenstack && val == (int32) '|')
8123 bruce@momjian.us 178 : 3 : pushquery(state, OPR, val);
179 : : else
180 : : {
181 [ - + ]: 188 : if (lenstack == STACKDEPTH)
983 andrew@dunslane.net 182 [ # # ]:UBC 0 : ereturn(state->escontext, ERR,
183 : : (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
184 : : errmsg("statement too complex")));
8123 bruce@momjian.us 185 :CBC 188 : stack[lenstack] = val;
186 : 188 : lenstack++;
187 : : }
188 : 191 : break;
189 : 52 : case OPEN:
190 [ - + ]: 52 : if (makepol(state) == ERR)
8123 bruce@momjian.us 191 :UBC 0 : return ERR;
4821 peter_e@gmx.net 192 [ + + + + ]:CBC 82 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
193 [ + + ]: 19 : stack[lenstack - 1] == (int32) '!'))
194 : : {
8123 bruce@momjian.us 195 : 30 : lenstack--;
196 : 30 : pushquery(state, OPR, stack[lenstack]);
197 : : }
198 : 52 : break;
199 : 52 : case CLOSE:
200 [ + + ]: 73 : while (lenstack)
201 : : {
202 : 21 : lenstack--;
203 : 21 : pushquery(state, OPR, stack[lenstack]);
204 : : };
205 : 52 : return END;
206 : : break;
207 : 4 : case ERR:
208 : : default:
983 andrew@dunslane.net 209 [ + + ]: 4 : ereturn(state->escontext, ERR,
210 : : (errcode(ERRCODE_SYNTAX_ERROR),
211 : : errmsg("syntax error")));
212 : : }
213 : : }
214 : :
8123 bruce@momjian.us 215 [ + + ]: 121 : while (lenstack)
216 : : {
217 : 33 : lenstack--;
218 : 33 : pushquery(state, OPR, stack[lenstack]);
219 : : };
220 : 88 : 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
1986 akorotkov@postgresql 233 : 314957 : checkcondition_arr(void *checkval, ITEM *item, void *options)
234 : : {
4821 peter_e@gmx.net 235 : 314957 : int32 *StopLow = ((CHKVAL *) checkval)->arrb;
236 : 314957 : int32 *StopHigh = ((CHKVAL *) checkval)->arre;
237 : : int32 *StopMiddle;
238 : :
239 : : /* Loop invariant: StopLow <= val < StopHigh */
240 : :
8123 bruce@momjian.us 241 [ + + ]: 1129721 : while (StopLow < StopHigh)
242 : : {
243 : 827228 : StopMiddle = StopLow + (StopHigh - StopLow) / 2;
7066 teodor@sigaev.ru 244 [ + + ]: 827228 : if (*StopMiddle == item->val)
2942 peter_e@gmx.net 245 : 12464 : return true;
7066 teodor@sigaev.ru 246 [ + + ]: 814764 : else if (*StopMiddle < item->val)
8123 bruce@momjian.us 247 : 238450 : StopLow = StopMiddle + 1;
248 : : else
249 : 576314 : StopHigh = StopMiddle;
250 : : }
251 : 302493 : return false;
252 : : }
253 : :
254 : : static bool
1986 akorotkov@postgresql 255 : 45833 : checkcondition_bit(void *checkval, ITEM *item, void *siglen)
256 : : {
1941 tgl@sss.pgh.pa.us 257 : 45833 : 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
1986 akorotkov@postgresql 264 : 887839 : 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 */
5354 tgl@sss.pgh.pa.us 268 : 887839 : check_stack_depth();
269 : :
8123 bruce@momjian.us 270 [ + + ]: 887839 : if (curitem->type == VAL)
1986 akorotkov@postgresql 271 : 389831 : return (*chkcond) (checkval, curitem, options);
4821 peter_e@gmx.net 272 [ + + ]: 498008 : else if (curitem->val == (int32) '!')
273 : : {
274 : : return calcnot ?
1986 akorotkov@postgresql 275 : 153599 : ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true)
8123 bruce@momjian.us 276 [ + + + + ]: 362182 : : true;
277 : : }
4821 peter_e@gmx.net 278 [ + + ]: 289425 : else if (curitem->val == (int32) '&')
279 : : {
1986 akorotkov@postgresql 280 [ + + ]: 154133 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
281 : 85849 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
282 : : else
8123 bruce@momjian.us 283 : 68284 : return false;
284 : : }
285 : : else
286 : : { /* |-operator */
1986 akorotkov@postgresql 287 [ + + ]: 135292 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
8123 bruce@momjian.us 288 : 6820 : return true;
289 : : else
1986 akorotkov@postgresql 290 : 128472 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
291 : : }
292 : : }
293 : :
294 : : /*
295 : : * signconsistent & execconsistent called by *_consistent
296 : : */
297 : : bool
298 : 51715 : signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot)
299 : : {
5354 tgl@sss.pgh.pa.us 300 : 103430 : return execute(GETQUERY(query) + query->size - 1,
282 peter@eisentraut.org 301 : 51715 : sign, (void *) (intptr_t) siglen, calcnot,
302 : : checkcondition_bit);
303 : : }
304 : :
305 : : /* Array must be sorted! */
306 : : bool
5931 bruce@momjian.us 307 : 81862 : execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
308 : : {
309 : : CHKVAL chkval;
310 : :
7231 tgl@sss.pgh.pa.us 311 [ - + - - : 81862 : CHECKARRVALID(array);
- - ]
8123 bruce@momjian.us 312 [ - + ]: 81862 : chkval.arrb = ARRPTR(array);
313 : 81862 : chkval.arre = chkval.arrb + ARRNELEMS(array);
5354 tgl@sss.pgh.pa.us 314 : 81862 : 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
1986 akorotkov@postgresql 326 : 29041 : checkcondition_gin(void *checkval, ITEM *item, void *options)
327 : : {
6912 bruce@momjian.us 328 : 29041 : GinChkVal *gcv = (GinChkVal *) checkval;
329 : :
330 : 29041 : return gcv->mapped_check[item - gcv->first];
331 : : }
332 : :
333 : : bool
5354 tgl@sss.pgh.pa.us 334 : 14919 : gin_bool_consistent(QUERYTYPE *query, bool *check)
335 : : {
336 : : GinChkVal gcv;
6912 bruce@momjian.us 337 : 14919 : ITEM *items = GETQUERY(query);
338 : : int i,
339 : 14919 : j = 0;
340 : :
5354 tgl@sss.pgh.pa.us 341 [ - + ]: 14919 : if (query->size <= 0)
2943 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 : : */
7066 teodor@sigaev.ru 348 :CBC 14919 : gcv.first = items;
6912 bruce@momjian.us 349 : 14919 : gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
350 [ + + ]: 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 : :
5354 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;
4821 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 : : */
5354 tgl@sss.pgh.pa.us 376 : 8 : return false;
377 : : }
4821 peter_e@gmx.net 378 [ + + ]: 20 : else if (curitem->val == (int32) '&')
379 : : {
380 : : /* If either side has a required value, we're good */
5354 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
5354 tgl@sss.pgh.pa.us 392 :UBC 0 : return false;
393 : : }
394 : : }
395 : :
396 : : bool
5354 tgl@sss.pgh.pa.us 397 :CBC 14 : query_has_required_values(QUERYTYPE *query)
398 : : {
399 [ - + ]: 14 : if (query->size <= 0)
5354 tgl@sss.pgh.pa.us 400 :UBC 0 : return false;
5354 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
8123 bruce@momjian.us 408 :UBC 0 : rboolop(PG_FUNCTION_ARGS)
409 : : {
410 : : /* just reverse the operands */
5354 tgl@sss.pgh.pa.us 411 : 0 : return DirectFunctionCall2(boolop,
412 : : PG_GETARG_DATUM(1),
413 : : PG_GETARG_DATUM(0));
414 : : }
415 : :
416 : : Datum
8123 bruce@momjian.us 417 :CBC 81998 : boolop(PG_FUNCTION_ARGS)
418 : : {
5354 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 : :
7231 424 [ - + - - : 81998 : CHECKARRVALID(val);
- - ]
8123 bruce@momjian.us 425 [ - + ]: 81998 : PREPAREARR(val);
426 [ - + ]: 81998 : chkval.arrb = ARRPTR(val);
427 : 81998 : chkval.arre = chkval.arrb + ARRNELEMS(val);
5354 tgl@sss.pgh.pa.us 428 : 81998 : result = execute(GETQUERY(query) + query->size - 1,
429 : : &chkval, NULL, true,
430 : : checkcondition_arr);
8123 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 : : static void
4821 peter_e@gmx.net 438 : 415 : findoprnd(ITEM *ptr, int32 *pos)
439 : : {
440 : : /* since this function recurses, it could be driven to stack overflow. */
4219 noah@leadboat.com 441 : 415 : check_stack_depth();
442 : :
443 : : #ifdef BS_DEBUG
444 : : elog(DEBUG3, (ptr[*pos].type == OPR) ?
445 : : "%d %c" : "%d %d", *pos, ptr[*pos].val);
446 : : #endif
8123 bruce@momjian.us 447 [ + + ]: 415 : if (ptr[*pos].type == VAL)
448 : : {
449 : 224 : ptr[*pos].left = 0;
450 : 224 : (*pos)--;
451 : : }
4821 peter_e@gmx.net 452 [ + + ]: 191 : else if (ptr[*pos].val == (int32) '!')
453 : : {
8123 bruce@momjian.us 454 : 55 : ptr[*pos].left = -1;
455 : 55 : (*pos)--;
456 : 55 : findoprnd(ptr, pos);
457 : : }
458 : : else
459 : : {
460 : 136 : ITEM *curitem = &ptr[*pos];
4821 peter_e@gmx.net 461 : 136 : int32 tmp = *pos;
462 : :
8123 bruce@momjian.us 463 : 136 : (*pos)--;
464 : 136 : findoprnd(ptr, pos);
465 : 136 : curitem->left = *pos - tmp;
466 : 136 : findoprnd(ptr, pos);
467 : : }
468 : 415 : }
469 : :
470 : :
471 : : /*
472 : : * input
473 : : */
474 : : Datum
475 : 92 : bqarr_in(PG_FUNCTION_ARGS)
476 : : {
477 : 92 : char *buf = (char *) PG_GETARG_POINTER(0);
478 : : WORKSTATE state;
479 : : int32 i;
480 : : QUERYTYPE *query;
481 : : int32 commonlen;
482 : : ITEM *ptr;
483 : : NODE *tmp;
4821 peter_e@gmx.net 484 : 92 : int32 pos = 0;
983 andrew@dunslane.net 485 : 92 : struct Node *escontext = fcinfo->context;
486 : :
487 : : #ifdef BS_DEBUG
488 : : StringInfoData pbuf;
489 : : #endif
490 : :
8123 bruce@momjian.us 491 : 92 : state.buf = buf;
492 : 92 : state.state = WAITOPERAND;
493 : 92 : state.count = 0;
494 : 92 : state.num = 0;
495 : 92 : state.str = NULL;
983 andrew@dunslane.net 496 : 92 : state.escontext = escontext;
497 : :
498 : : /* make polish notation (postfix, but in reverse order) */
499 [ + + ]: 92 : if (makepol(&state) == ERR)
500 : 4 : PG_RETURN_NULL();
8123 bruce@momjian.us 501 [ - + ]: 88 : if (!state.num)
983 andrew@dunslane.net 502 [ # # ]:UBC 0 : ereturn(escontext, (Datum) 0,
503 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
504 : : errmsg("empty query")));
505 : :
4219 noah@leadboat.com 506 [ - + ]:CBC 88 : if (state.num > QUERYTYPEMAXITEMS)
983 andrew@dunslane.net 507 [ # # ]:UBC 0 : ereturn(escontext, (Datum) 0,
508 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
509 : : errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
510 : : state.num, (int) QUERYTYPEMAXITEMS)));
8123 bruce@momjian.us 511 :CBC 88 : commonlen = COMPUTESIZE(state.num);
512 : :
513 : 88 : query = (QUERYTYPE *) palloc(commonlen);
6765 tgl@sss.pgh.pa.us 514 : 88 : SET_VARSIZE(query, commonlen);
8123 bruce@momjian.us 515 : 88 : query->size = state.num;
516 : 88 : ptr = GETQUERY(query);
517 : :
518 [ + + ]: 503 : for (i = state.num - 1; i >= 0; i--)
519 : : {
520 : 415 : ptr[i].type = state.str->type;
521 : 415 : ptr[i].val = state.str->val;
522 : 415 : tmp = state.str->next;
523 : 415 : pfree(state.str);
524 : 415 : state.str = tmp;
525 : : }
526 : :
527 : 88 : pos = query->size - 1;
528 : 88 : findoprnd(ptr, &pos);
529 : : #ifdef BS_DEBUG
530 : : initStringInfo(&pbuf);
531 : : for (i = 0; i < query->size; i++)
532 : : {
533 : : if (ptr[i].type == OPR)
534 : : appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
535 : : else
536 : : appendStringInfo(&pbuf, "%d ", ptr[i].val);
537 : : }
538 : : elog(DEBUG3, "POR: %s", pbuf.data);
539 : : pfree(pbuf.data);
540 : : #endif
541 : :
542 : 88 : PG_RETURN_POINTER(query);
543 : : }
544 : :
545 : :
546 : : /*
547 : : * out function
548 : : */
549 : : typedef struct
550 : : {
551 : : ITEM *curpol;
552 : : char *buf;
553 : : char *cur;
554 : : int32 buflen;
555 : : } INFIX;
556 : :
557 : : #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
558 : : int32 len = inf->cur - inf->buf; \
559 : : inf->buflen *= 2; \
560 : : inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
561 : : inf->cur = inf->buf + len; \
562 : : }
563 : :
564 : : static void
6505 565 : 180 : infix(INFIX *in, bool first)
566 : : {
567 : : /* since this function recurses, it could be driven to stack overflow. */
3624 noah@leadboat.com 568 : 180 : check_stack_depth();
569 : :
8123 bruce@momjian.us 570 [ + + ]: 180 : if (in->curpol->type == VAL)
571 : : {
572 [ - + ]: 95 : RESIZEBUF(in, 11);
573 : 95 : sprintf(in->cur, "%d", in->curpol->val);
574 : 95 : in->cur = strchr(in->cur, '\0');
575 : 95 : in->curpol--;
576 : : }
4821 peter_e@gmx.net 577 [ + + ]: 85 : else if (in->curpol->val == (int32) '!')
578 : : {
8123 bruce@momjian.us 579 : 27 : bool isopr = false;
580 : :
581 [ - + ]: 27 : RESIZEBUF(in, 1);
582 : 27 : *(in->cur) = '!';
583 : 27 : in->cur++;
584 : 27 : *(in->cur) = '\0';
585 : 27 : in->curpol--;
586 [ + + ]: 27 : if (in->curpol->type == OPR)
587 : : {
588 : 6 : isopr = true;
589 [ - + ]: 6 : RESIZEBUF(in, 2);
590 : 6 : sprintf(in->cur, "( ");
591 : 6 : in->cur = strchr(in->cur, '\0');
592 : : }
593 : 27 : infix(in, isopr);
594 [ + + ]: 27 : if (isopr)
595 : : {
596 [ - + ]: 6 : RESIZEBUF(in, 2);
597 : 6 : sprintf(in->cur, " )");
598 : 6 : in->cur = strchr(in->cur, '\0');
599 : : }
600 : : }
601 : : else
602 : : {
4821 peter_e@gmx.net 603 : 58 : int32 op = in->curpol->val;
604 : : INFIX nrm;
605 : :
8123 bruce@momjian.us 606 : 58 : in->curpol--;
4821 peter_e@gmx.net 607 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
608 : : {
8123 bruce@momjian.us 609 [ - + ]: 10 : RESIZEBUF(in, 2);
610 : 10 : sprintf(in->cur, "( ");
611 : 10 : in->cur = strchr(in->cur, '\0');
612 : : }
613 : :
614 : 58 : nrm.curpol = in->curpol;
615 : 58 : nrm.buflen = 16;
616 : 58 : nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
617 : :
618 : : /* get right operand */
619 : 58 : infix(&nrm, false);
620 : :
621 : : /* get & print left operand */
622 : 58 : in->curpol = nrm.curpol;
623 : 58 : infix(in, false);
624 : :
625 : : /* print operator & right operand */
626 [ + + ]: 62 : RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
627 : 58 : sprintf(in->cur, " %c %s", op, nrm.buf);
628 : 58 : in->cur = strchr(in->cur, '\0');
629 : 58 : pfree(nrm.buf);
630 : :
4821 peter_e@gmx.net 631 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
632 : : {
8123 bruce@momjian.us 633 [ - + ]: 10 : RESIZEBUF(in, 2);
634 : 10 : sprintf(in->cur, " )");
635 : 10 : in->cur = strchr(in->cur, '\0');
636 : : }
637 : : }
638 : 180 : }
639 : :
640 : :
641 : : Datum
642 : 37 : bqarr_out(PG_FUNCTION_ARGS)
643 : : {
5354 tgl@sss.pgh.pa.us 644 : 37 : QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0);
645 : : INFIX nrm;
646 : :
8123 bruce@momjian.us 647 [ - + ]: 37 : if (query->size == 0)
8080 tgl@sss.pgh.pa.us 648 [ # # ]:UBC 0 : ereport(ERROR,
649 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
650 : : errmsg("empty query")));
651 : :
8123 bruce@momjian.us 652 :CBC 37 : nrm.curpol = GETQUERY(query) + query->size - 1;
653 : 37 : nrm.buflen = 32;
654 : 37 : nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
655 : 37 : *(nrm.cur) = '\0';
656 : 37 : infix(&nrm, true);
657 : :
658 [ - + ]: 37 : PG_FREE_IF_COPY(query, 0);
659 : 37 : PG_RETURN_POINTER(nrm.buf);
660 : : }
661 : :
662 : :
663 : : /* Useless old "debugging" function for a fundamentally wrong algorithm */
664 : : Datum
8123 bruce@momjian.us 665 :UBC 0 : querytree(PG_FUNCTION_ARGS)
666 : : {
5354 tgl@sss.pgh.pa.us 667 [ # # ]: 0 : elog(ERROR, "querytree is no longer implemented");
668 : : PG_RETURN_NULL();
669 : : }
|