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 : : #include "utils/builtins.h"
9 : :
7613 bruce@momjian.us 10 :CBC 2 : PG_FUNCTION_INFO_V1(bqarr_in);
11 : 2 : PG_FUNCTION_INFO_V1(bqarr_out);
12 : 2 : PG_FUNCTION_INFO_V1(boolop);
13 : 1 : PG_FUNCTION_INFO_V1(rboolop);
14 : 1 : PG_FUNCTION_INFO_V1(querytree);
15 : :
16 : :
17 : : /* parser's states */
18 : : #define WAITOPERAND 1
19 : : #define WAITENDOPERAND 2
20 : : #define WAITOPERATOR 3
21 : :
22 : : /*
23 : : * node of query tree, also used
24 : : * for storing polish notation in parser
25 : : */
26 : : typedef struct NODE
27 : : {
28 : : int32 type;
29 : : int32 val;
30 : : struct NODE *next;
31 : : } NODE;
32 : :
33 : : typedef struct
34 : : {
35 : : char *buf;
36 : : int32 state;
37 : : int32 count;
38 : : struct Node *escontext;
39 : : /* reverse polish notation in list (for temporary usage) */
40 : : NODE *str;
41 : : /* number in str */
42 : : int32 num;
43 : : } WORKSTATE;
44 : :
45 : : /*
46 : : * get token from query string
47 : : */
48 : : static int32
4311 peter_e@gmx.net 49 : 550 : gettoken(WORKSTATE *state, int32 *val)
50 : : {
51 : : char nnn[16];
52 : : int innn;
53 : :
6777 tgl@sss.pgh.pa.us 54 : 550 : *val = 0; /* default result */
55 : :
4826 56 : 550 : innn = 0;
57 : : while (1)
58 : : {
59 [ - + ]: 888 : if (innn >= sizeof(nnn))
4826 tgl@sss.pgh.pa.us 60 :UBC 0 : return ERR; /* buffer overrun => syntax error */
7613 bruce@momjian.us 61 [ + + + - ]:CBC 888 : switch (state->state)
62 : : {
63 : 318 : case WAITOPERAND:
4826 tgl@sss.pgh.pa.us 64 : 318 : innn = 0;
7613 bruce@momjian.us 65 [ + + + + ]: 318 : if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
66 [ - + ]: 113 : *(state->buf) == '-')
67 : : {
68 : 205 : state->state = WAITENDOPERAND;
4826 tgl@sss.pgh.pa.us 69 : 205 : nnn[innn++] = *(state->buf);
70 : : }
7613 bruce@momjian.us 71 [ + + ]: 113 : else if (*(state->buf) == '!')
72 : : {
73 : 48 : (state->buf)++;
4311 peter_e@gmx.net 74 : 48 : *val = (int32) '!';
7613 bruce@momjian.us 75 : 48 : return OPR;
76 : : }
77 [ + + ]: 65 : else if (*(state->buf) == '(')
78 : : {
79 : 45 : state->count++;
80 : 45 : (state->buf)++;
81 : 45 : return OPEN;
82 : : }
83 [ + + ]: 20 : else if (*(state->buf) != ' ')
84 : 2 : return ERR;
85 : 223 : break;
86 : 303 : case WAITENDOPERAND:
87 [ + + + + ]: 303 : if (*(state->buf) >= '0' && *(state->buf) <= '9')
88 : : {
4826 tgl@sss.pgh.pa.us 89 : 98 : nnn[innn++] = *(state->buf);
90 : : }
91 : : else
92 : : {
93 : : long lval;
94 : :
95 : 205 : nnn[innn] = '\0';
96 : 205 : errno = 0;
97 : 205 : lval = strtol(nnn, NULL, 0);
4311 peter_e@gmx.net 98 : 205 : *val = (int32) lval;
4826 tgl@sss.pgh.pa.us 99 [ + - - + ]: 205 : if (errno != 0 || (long) *val != lval)
4826 tgl@sss.pgh.pa.us 100 :UBC 0 : return ERR;
7613 bruce@momjian.us 101 :CBC 205 : state->state = WAITOPERATOR;
102 [ - + ]: 76 : return (state->count && *(state->buf) == '\0')
103 [ + + ]: 281 : ? ERR : VAL;
104 : : }
105 : 98 : break;
106 : 267 : case WAITOPERATOR:
107 [ + + + + ]: 267 : if (*(state->buf) == '&' || *(state->buf) == '|')
108 : : {
109 : 122 : state->state = WAITOPERAND;
4311 peter_e@gmx.net 110 : 122 : *val = (int32) *(state->buf);
7613 bruce@momjian.us 111 : 122 : (state->buf)++;
112 : 122 : return OPR;
113 : : }
114 [ + + ]: 145 : else if (*(state->buf) == ')')
115 : : {
116 : 45 : (state->buf)++;
117 : 45 : state->count--;
118 [ - + ]: 45 : return (state->count < 0) ? ERR : CLOSE;
119 : : }
120 [ + + ]: 100 : else if (*(state->buf) == '\0')
121 : 81 : return (state->count) ? ERR : END;
122 [ + + ]: 19 : else if (*(state->buf) != ' ')
123 : 2 : return ERR;
124 : 17 : break;
7613 bruce@momjian.us 125 :UBC 0 : default:
126 : 0 : return ERR;
127 : : break;
128 : : }
7613 bruce@momjian.us 129 :CBC 338 : (state->buf)++;
130 : : }
131 : : }
132 : :
133 : : /*
134 : : * push new one in polish notation reverse view
135 : : */
136 : : static void
4311 peter_e@gmx.net 137 : 375 : pushquery(WORKSTATE *state, int32 type, int32 val)
138 : : {
7613 bruce@momjian.us 139 : 375 : NODE *tmp = (NODE *) palloc(sizeof(NODE));
140 : :
141 : 375 : tmp->type = type;
142 : 375 : tmp->val = val;
143 : 375 : tmp->next = state->str;
144 : 375 : state->str = tmp;
145 : 375 : state->num++;
146 : 375 : }
147 : :
148 : : #define STACKDEPTH 16
149 : :
150 : : /*
151 : : * make polish notation of query
152 : : */
153 : : static int32
5421 154 : 130 : makepol(WORKSTATE *state)
155 : : {
156 : : int32 val,
157 : : type;
158 : : int32 stack[STACKDEPTH];
4311 peter_e@gmx.net 159 : 130 : int32 lenstack = 0;
160 : :
161 : : /* since this function recurses, it could be driven to stack overflow */
4844 tgl@sss.pgh.pa.us 162 : 130 : check_stack_depth();
163 : :
7613 bruce@momjian.us 164 [ + + ]: 550 : while ((type = gettoken(state, &val)) != END)
165 : : {
166 [ + + + + : 469 : switch (type)
+ ]
167 : : {
168 : 205 : case VAL:
169 : 205 : pushquery(state, type, val);
4311 peter_e@gmx.net 170 [ + + + + ]: 302 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
171 [ + + ]: 83 : stack[lenstack - 1] == (int32) '!'))
172 : : {
7613 bruce@momjian.us 173 : 97 : lenstack--;
174 : 97 : pushquery(state, OPR, stack[lenstack]);
175 : : }
176 : 205 : break;
177 : 170 : case OPR:
4311 peter_e@gmx.net 178 [ + + + + ]: 170 : if (lenstack && val == (int32) '|')
7613 bruce@momjian.us 179 : 3 : pushquery(state, OPR, val);
180 : : else
181 : : {
182 [ - + ]: 167 : if (lenstack == STACKDEPTH)
473 andrew@dunslane.net 183 [ # # ]:UBC 0 : ereturn(state->escontext, ERR,
184 : : (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
185 : : errmsg("statement too complex")));
7613 bruce@momjian.us 186 :CBC 167 : stack[lenstack] = val;
187 : 167 : lenstack++;
188 : : }
189 : 170 : break;
190 : 45 : case OPEN:
191 [ - + ]: 45 : if (makepol(state) == ERR)
7613 bruce@momjian.us 192 :UBC 0 : return ERR;
4311 peter_e@gmx.net 193 [ + + + + ]:CBC 68 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
194 [ + + ]: 19 : stack[lenstack - 1] == (int32) '!'))
195 : : {
7613 bruce@momjian.us 196 : 23 : lenstack--;
197 : 23 : pushquery(state, OPR, stack[lenstack]);
198 : : }
199 : 45 : break;
200 : 45 : case CLOSE:
201 [ + + ]: 59 : while (lenstack)
202 : : {
203 : 14 : lenstack--;
204 : 14 : pushquery(state, OPR, stack[lenstack]);
205 : : };
206 : 45 : return END;
207 : : break;
208 : 4 : case ERR:
209 : : default:
473 andrew@dunslane.net 210 [ + + ]: 4 : ereturn(state->escontext, ERR,
211 : : (errcode(ERRCODE_SYNTAX_ERROR),
212 : : errmsg("syntax error")));
213 : : }
214 : : }
215 : :
7613 bruce@momjian.us 216 [ + + ]: 114 : while (lenstack)
217 : : {
218 : 33 : lenstack--;
219 : 33 : pushquery(state, OPR, stack[lenstack]);
220 : : };
221 : 81 : 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
1476 akorotkov@postgresql 234 : 272827 : checkcondition_arr(void *checkval, ITEM *item, void *options)
235 : : {
4311 peter_e@gmx.net 236 : 272827 : int32 *StopLow = ((CHKVAL *) checkval)->arrb;
237 : 272827 : int32 *StopHigh = ((CHKVAL *) checkval)->arre;
238 : : int32 *StopMiddle;
239 : :
240 : : /* Loop invariant: StopLow <= val < StopHigh */
241 : :
7613 bruce@momjian.us 242 [ + + ]: 1013651 : while (StopLow < StopHigh)
243 : : {
244 : 753386 : StopMiddle = StopLow + (StopHigh - StopLow) / 2;
6556 teodor@sigaev.ru 245 [ + + ]: 753386 : if (*StopMiddle == item->val)
2432 peter_e@gmx.net 246 : 12562 : return true;
6556 teodor@sigaev.ru 247 [ + + ]: 740824 : else if (*StopMiddle < item->val)
7613 bruce@momjian.us 248 : 160821 : StopLow = StopMiddle + 1;
249 : : else
250 : 580003 : StopHigh = StopMiddle;
251 : : }
252 : 260265 : return false;
253 : : }
254 : :
255 : : static bool
1476 akorotkov@postgresql 256 : 45038 : checkcondition_bit(void *checkval, ITEM *item, void *siglen)
257 : : {
1431 tgl@sss.pgh.pa.us 258 : 45038 : 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
1476 akorotkov@postgresql 265 : 802024 : 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 */
4844 tgl@sss.pgh.pa.us 269 : 802024 : check_stack_depth();
270 : :
7613 bruce@momjian.us 271 [ + + ]: 802024 : if (curitem->type == VAL)
1476 akorotkov@postgresql 272 : 346859 : return (*chkcond) (checkval, curitem, options);
4311 peter_e@gmx.net 273 [ + + ]: 455165 : else if (curitem->val == (int32) '!')
274 : : {
275 : : return calcnot ?
1476 akorotkov@postgresql 276 : 138786 : ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true)
7613 bruce@momjian.us 277 [ + + + + ]: 331974 : : true;
278 : : }
4311 peter_e@gmx.net 279 [ + + ]: 261977 : else if (curitem->val == (int32) '&')
280 : : {
1476 akorotkov@postgresql 281 [ + + ]: 141457 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
282 : 70421 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
283 : : else
7613 bruce@momjian.us 284 : 71036 : return false;
285 : : }
286 : : else
287 : : { /* |-operator */
1476 akorotkov@postgresql 288 [ + + ]: 120520 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
7613 bruce@momjian.us 289 : 6847 : return true;
290 : : else
1476 akorotkov@postgresql 291 : 113673 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
292 : : }
293 : : }
294 : :
295 : : /*
296 : : * signconsistent & execconsistent called by *_consistent
297 : : */
298 : : bool
299 : 51267 : signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot)
300 : : {
4844 tgl@sss.pgh.pa.us 301 : 102534 : return execute(GETQUERY(query) + query->size - 1,
1431 302 : 51267 : (void *) sign, (void *) (intptr_t) siglen, calcnot,
303 : : checkcondition_bit);
304 : : }
305 : :
306 : : /* Array must be sorted! */
307 : : bool
5421 bruce@momjian.us 308 : 82537 : execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
309 : : {
310 : : CHKVAL chkval;
311 : :
6721 tgl@sss.pgh.pa.us 312 [ - + - - : 82537 : CHECKARRVALID(array);
- - ]
7613 bruce@momjian.us 313 [ - + ]: 82537 : chkval.arrb = ARRPTR(array);
314 : 82537 : chkval.arre = chkval.arrb + ARRNELEMS(array);
4844 tgl@sss.pgh.pa.us 315 : 82537 : return execute(GETQUERY(query) + query->size - 1,
316 : : (void *) &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
1476 akorotkov@postgresql 327 : 28994 : checkcondition_gin(void *checkval, ITEM *item, void *options)
328 : : {
6402 bruce@momjian.us 329 : 28994 : GinChkVal *gcv = (GinChkVal *) checkval;
330 : :
331 : 28994 : return gcv->mapped_check[item - gcv->first];
332 : : }
333 : :
334 : : bool
4844 tgl@sss.pgh.pa.us 335 : 14903 : gin_bool_consistent(QUERYTYPE *query, bool *check)
336 : : {
337 : : GinChkVal gcv;
6402 bruce@momjian.us 338 : 14903 : ITEM *items = GETQUERY(query);
339 : : int i,
340 : 14903 : j = 0;
341 : :
4844 tgl@sss.pgh.pa.us 342 [ - + ]: 14903 : if (query->size <= 0)
2433 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 : : */
6556 teodor@sigaev.ru 349 :CBC 14903 : gcv.first = items;
6402 bruce@momjian.us 350 : 14903 : gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
351 [ + + ]: 82221 : for (i = 0; i < query->size; i++)
352 : : {
353 [ + + ]: 67318 : if (items[i].type == VAL)
354 : 30968 : gcv.mapped_check[i] = check[j++];
355 : : }
356 : :
4844 tgl@sss.pgh.pa.us 357 : 14903 : return execute(GETQUERY(query) + query->size - 1,
358 : : (void *) &gcv, NULL, true,
359 : : checkcondition_gin);
360 : : }
361 : :
362 : : static bool
363 : 36 : contains_required_value(ITEM *curitem)
364 : : {
365 : : /* since this function recurses, it could be driven to stack overflow */
366 : 36 : check_stack_depth();
367 : :
368 [ + + ]: 36 : if (curitem->type == VAL)
369 : 14 : return true;
4311 peter_e@gmx.net 370 [ + + ]: 22 : 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 : : */
4844 tgl@sss.pgh.pa.us 377 : 6 : return false;
378 : : }
4311 peter_e@gmx.net 379 [ + + ]: 16 : else if (curitem->val == (int32) '&')
380 : : {
381 : : /* If either side has a required value, we're good */
4844 tgl@sss.pgh.pa.us 382 [ + + ]: 10 : if (contains_required_value(curitem + curitem->left))
383 : 8 : return true;
384 : : else
385 : 2 : return contains_required_value(curitem - 1);
386 : : }
387 : : else
388 : : { /* |-operator */
389 : : /* Both sides must have required values */
390 [ + - ]: 6 : if (contains_required_value(curitem + curitem->left))
391 : 6 : return contains_required_value(curitem - 1);
392 : : else
4844 tgl@sss.pgh.pa.us 393 :UBC 0 : return false;
394 : : }
395 : : }
396 : :
397 : : bool
4844 tgl@sss.pgh.pa.us 398 :CBC 12 : query_has_required_values(QUERYTYPE *query)
399 : : {
400 [ - + ]: 12 : if (query->size <= 0)
4844 tgl@sss.pgh.pa.us 401 :UBC 0 : return false;
4844 tgl@sss.pgh.pa.us 402 :CBC 12 : return contains_required_value(GETQUERY(query) + query->size - 1);
403 : : }
404 : :
405 : : /*
406 : : * boolean operations
407 : : */
408 : : Datum
7613 bruce@momjian.us 409 :UBC 0 : rboolop(PG_FUNCTION_ARGS)
410 : : {
411 : : /* just reverse the operands */
4844 tgl@sss.pgh.pa.us 412 : 0 : return DirectFunctionCall2(boolop,
413 : : PG_GETARG_DATUM(1),
414 : : PG_GETARG_DATUM(0));
415 : : }
416 : :
417 : : Datum
7613 bruce@momjian.us 418 :CBC 68460 : boolop(PG_FUNCTION_ARGS)
419 : : {
4844 tgl@sss.pgh.pa.us 420 : 68460 : ArrayType *val = PG_GETARG_ARRAYTYPE_P_COPY(0);
421 : 68460 : QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(1);
422 : : CHKVAL chkval;
423 : : bool result;
424 : :
6721 425 [ - + - - : 68460 : CHECKARRVALID(val);
- - ]
7613 bruce@momjian.us 426 [ + + - + : 68460 : PREPAREARR(val);
+ + ]
427 [ - + ]: 68460 : chkval.arrb = ARRPTR(val);
428 : 68460 : chkval.arre = chkval.arrb + ARRNELEMS(val);
4844 tgl@sss.pgh.pa.us 429 : 68460 : result = execute(GETQUERY(query) + query->size - 1,
430 : : &chkval, NULL, true,
431 : : checkcondition_arr);
7613 bruce@momjian.us 432 : 68460 : pfree(val);
433 : :
434 [ - + ]: 68460 : PG_FREE_IF_COPY(query, 1);
435 : 68460 : PG_RETURN_BOOL(result);
436 : : }
437 : :
438 : : static void
4311 peter_e@gmx.net 439 : 373 : findoprnd(ITEM *ptr, int32 *pos)
440 : : {
441 : : /* since this function recurses, it could be driven to stack overflow. */
3709 noah@leadboat.com 442 : 373 : check_stack_depth();
443 : :
444 : : #ifdef BS_DEBUG
445 : : elog(DEBUG3, (ptr[*pos].type == OPR) ?
446 : : "%d %c" : "%d %d", *pos, ptr[*pos].val);
447 : : #endif
7613 bruce@momjian.us 448 [ + + ]: 373 : if (ptr[*pos].type == VAL)
449 : : {
450 : 203 : ptr[*pos].left = 0;
451 : 203 : (*pos)--;
452 : : }
4311 peter_e@gmx.net 453 [ + + ]: 170 : else if (ptr[*pos].val == (int32) '!')
454 : : {
7613 bruce@momjian.us 455 : 48 : ptr[*pos].left = -1;
456 : 48 : (*pos)--;
457 : 48 : findoprnd(ptr, pos);
458 : : }
459 : : else
460 : : {
461 : 122 : ITEM *curitem = &ptr[*pos];
4311 peter_e@gmx.net 462 : 122 : int32 tmp = *pos;
463 : :
7613 bruce@momjian.us 464 : 122 : (*pos)--;
465 : 122 : findoprnd(ptr, pos);
466 : 122 : curitem->left = *pos - tmp;
467 : 122 : findoprnd(ptr, pos);
468 : : }
469 : 373 : }
470 : :
471 : :
472 : : /*
473 : : * input
474 : : */
475 : : Datum
476 : 85 : bqarr_in(PG_FUNCTION_ARGS)
477 : : {
478 : 85 : char *buf = (char *) PG_GETARG_POINTER(0);
479 : : WORKSTATE state;
480 : : int32 i;
481 : : QUERYTYPE *query;
482 : : int32 commonlen;
483 : : ITEM *ptr;
484 : : NODE *tmp;
4311 peter_e@gmx.net 485 : 85 : int32 pos = 0;
473 andrew@dunslane.net 486 : 85 : struct Node *escontext = fcinfo->context;
487 : :
488 : : #ifdef BS_DEBUG
489 : : StringInfoData pbuf;
490 : : #endif
491 : :
7613 bruce@momjian.us 492 : 85 : state.buf = buf;
493 : 85 : state.state = WAITOPERAND;
494 : 85 : state.count = 0;
495 : 85 : state.num = 0;
496 : 85 : state.str = NULL;
473 andrew@dunslane.net 497 : 85 : state.escontext = escontext;
498 : :
499 : : /* make polish notation (postfix, but in reverse order) */
500 [ + + ]: 85 : if (makepol(&state) == ERR)
501 : 4 : PG_RETURN_NULL();
7613 bruce@momjian.us 502 [ - + ]: 81 : if (!state.num)
473 andrew@dunslane.net 503 [ # # ]:UBC 0 : ereturn(escontext, (Datum) 0,
504 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
505 : : errmsg("empty query")));
506 : :
3709 noah@leadboat.com 507 [ - + ]:CBC 81 : if (state.num > QUERYTYPEMAXITEMS)
473 andrew@dunslane.net 508 [ # # ]:UBC 0 : ereturn(escontext, (Datum) 0,
509 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
510 : : errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
511 : : state.num, (int) QUERYTYPEMAXITEMS)));
7613 bruce@momjian.us 512 :CBC 81 : commonlen = COMPUTESIZE(state.num);
513 : :
514 : 81 : query = (QUERYTYPE *) palloc(commonlen);
6255 tgl@sss.pgh.pa.us 515 : 81 : SET_VARSIZE(query, commonlen);
7613 bruce@momjian.us 516 : 81 : query->size = state.num;
517 : 81 : ptr = GETQUERY(query);
518 : :
519 [ + + ]: 454 : for (i = state.num - 1; i >= 0; i--)
520 : : {
521 : 373 : ptr[i].type = state.str->type;
522 : 373 : ptr[i].val = state.str->val;
523 : 373 : tmp = state.str->next;
524 : 373 : pfree(state.str);
525 : 373 : state.str = tmp;
526 : : }
527 : :
528 : 81 : pos = query->size - 1;
529 : 81 : findoprnd(ptr, &pos);
530 : : #ifdef BS_DEBUG
531 : : initStringInfo(&pbuf);
532 : : for (i = 0; i < query->size; i++)
533 : : {
534 : : if (ptr[i].type == OPR)
535 : : appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
536 : : else
537 : : appendStringInfo(&pbuf, "%d ", ptr[i].val);
538 : : }
539 : : elog(DEBUG3, "POR: %s", pbuf.data);
540 : : pfree(pbuf.data);
541 : : #endif
542 : :
543 : 81 : PG_RETURN_POINTER(query);
544 : : }
545 : :
546 : :
547 : : /*
548 : : * out function
549 : : */
550 : : typedef struct
551 : : {
552 : : ITEM *curpol;
553 : : char *buf;
554 : : char *cur;
555 : : int32 buflen;
556 : : } INFIX;
557 : :
558 : : #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
559 : : int32 len = inf->cur - inf->buf; \
560 : : inf->buflen *= 2; \
561 : : inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
562 : : inf->cur = inf->buf + len; \
563 : : }
564 : :
565 : : static void
5995 566 : 180 : infix(INFIX *in, bool first)
567 : : {
568 : : /* since this function recurses, it could be driven to stack overflow. */
3114 noah@leadboat.com 569 : 180 : check_stack_depth();
570 : :
7613 bruce@momjian.us 571 [ + + ]: 180 : if (in->curpol->type == VAL)
572 : : {
573 [ - + ]: 95 : RESIZEBUF(in, 11);
574 : 95 : sprintf(in->cur, "%d", in->curpol->val);
575 : 95 : in->cur = strchr(in->cur, '\0');
576 : 95 : in->curpol--;
577 : : }
4311 peter_e@gmx.net 578 [ + + ]: 85 : else if (in->curpol->val == (int32) '!')
579 : : {
7613 bruce@momjian.us 580 : 27 : bool isopr = false;
581 : :
582 [ - + ]: 27 : RESIZEBUF(in, 1);
583 : 27 : *(in->cur) = '!';
584 : 27 : in->cur++;
585 : 27 : *(in->cur) = '\0';
586 : 27 : in->curpol--;
587 [ + + ]: 27 : if (in->curpol->type == OPR)
588 : : {
589 : 6 : isopr = true;
590 [ - + ]: 6 : RESIZEBUF(in, 2);
591 : 6 : sprintf(in->cur, "( ");
592 : 6 : in->cur = strchr(in->cur, '\0');
593 : : }
594 : 27 : infix(in, isopr);
595 [ + + ]: 27 : if (isopr)
596 : : {
597 [ - + ]: 6 : RESIZEBUF(in, 2);
598 : 6 : sprintf(in->cur, " )");
599 : 6 : in->cur = strchr(in->cur, '\0');
600 : : }
601 : : }
602 : : else
603 : : {
4311 peter_e@gmx.net 604 : 58 : int32 op = in->curpol->val;
605 : : INFIX nrm;
606 : :
7613 bruce@momjian.us 607 : 58 : in->curpol--;
4311 peter_e@gmx.net 608 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
609 : : {
7613 bruce@momjian.us 610 [ - + ]: 10 : RESIZEBUF(in, 2);
611 : 10 : sprintf(in->cur, "( ");
612 : 10 : in->cur = strchr(in->cur, '\0');
613 : : }
614 : :
615 : 58 : nrm.curpol = in->curpol;
616 : 58 : nrm.buflen = 16;
617 : 58 : nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
618 : :
619 : : /* get right operand */
620 : 58 : infix(&nrm, false);
621 : :
622 : : /* get & print left operand */
623 : 58 : in->curpol = nrm.curpol;
624 : 58 : infix(in, false);
625 : :
626 : : /* print operator & right operand */
627 [ + + ]: 62 : RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
628 : 58 : sprintf(in->cur, " %c %s", op, nrm.buf);
629 : 58 : in->cur = strchr(in->cur, '\0');
630 : 58 : pfree(nrm.buf);
631 : :
4311 peter_e@gmx.net 632 [ + + + + ]: 58 : if (op == (int32) '|' && !first)
633 : : {
7613 bruce@momjian.us 634 [ - + ]: 10 : RESIZEBUF(in, 2);
635 : 10 : sprintf(in->cur, " )");
636 : 10 : in->cur = strchr(in->cur, '\0');
637 : : }
638 : : }
639 : 180 : }
640 : :
641 : :
642 : : Datum
643 : 37 : bqarr_out(PG_FUNCTION_ARGS)
644 : : {
4844 tgl@sss.pgh.pa.us 645 : 37 : QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0);
646 : : INFIX nrm;
647 : :
7613 bruce@momjian.us 648 [ - + ]: 37 : if (query->size == 0)
7570 tgl@sss.pgh.pa.us 649 [ # # ]:UBC 0 : ereport(ERROR,
650 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
651 : : errmsg("empty query")));
652 : :
7613 bruce@momjian.us 653 :CBC 37 : nrm.curpol = GETQUERY(query) + query->size - 1;
654 : 37 : nrm.buflen = 32;
655 : 37 : nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
656 : 37 : *(nrm.cur) = '\0';
657 : 37 : infix(&nrm, true);
658 : :
659 [ - + ]: 37 : PG_FREE_IF_COPY(query, 0);
660 : 37 : PG_RETURN_POINTER(nrm.buf);
661 : : }
662 : :
663 : :
664 : : /* Useless old "debugging" function for a fundamentally wrong algorithm */
665 : : Datum
7613 bruce@momjian.us 666 :UBC 0 : querytree(PG_FUNCTION_ARGS)
667 : : {
4844 tgl@sss.pgh.pa.us 668 [ # # ]: 0 : elog(ERROR, "querytree is no longer implemented");
669 : : PG_RETURN_NULL();
670 : : }
|