Line data Source code
1 : /*
2 : * contrib/intarray/_int_bool.c
3 : */
4 : #include "postgres.h"
5 :
6 : #include "_int.h"
7 : #include "miscadmin.h"
8 :
9 2 : PG_FUNCTION_INFO_V1(bqarr_in);
10 2 : PG_FUNCTION_INFO_V1(bqarr_out);
11 2 : PG_FUNCTION_INFO_V1(boolop);
12 1 : PG_FUNCTION_INFO_V1(rboolop);
13 1 : PG_FUNCTION_INFO_V1(querytree);
14 :
15 :
16 : /* parser's states */
17 : #define WAITOPERAND 1
18 : #define WAITENDOPERAND 2
19 : #define WAITOPERATOR 3
20 :
21 : /*
22 : * node of query tree, also used
23 : * for storing polish notation in parser
24 : */
25 : typedef struct NODE
26 : {
27 : int32 type;
28 : int32 val;
29 : struct NODE *next;
30 : } NODE;
31 :
32 : typedef struct
33 : {
34 : char *buf;
35 : int32 state;
36 : int32 count;
37 : struct Node *escontext;
38 : /* reverse polish notation in list (for temporary usage) */
39 : NODE *str;
40 : /* number in str */
41 : int32 num;
42 : } WORKSTATE;
43 :
44 : /*
45 : * get token from query string
46 : */
47 : static int32
48 131685 : gettoken(WORKSTATE *state, int32 *val)
49 : {
50 : char nnn[16];
51 : int innn;
52 :
53 131685 : *val = 0; /* default result */
54 :
55 131685 : innn = 0;
56 : while (1)
57 : {
58 164897 : if (innn >= sizeof(nnn))
59 0 : return ERR; /* buffer overrun => syntax error */
60 164897 : switch (state->state)
61 : {
62 65903 : case WAITOPERAND:
63 65903 : innn = 0;
64 65903 : if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
65 32908 : *(state->buf) == '-')
66 : {
67 32995 : state->state = WAITENDOPERAND;
68 32995 : nnn[innn++] = *(state->buf);
69 : }
70 32908 : else if (*(state->buf) == '!')
71 : {
72 55 : (state->buf)++;
73 55 : *val = (int32) '!';
74 55 : return OPR;
75 : }
76 32853 : else if (*(state->buf) == '(')
77 : {
78 32819 : state->count++;
79 32819 : (state->buf)++;
80 32819 : return OPEN;
81 : }
82 34 : else if (*(state->buf) != ' ')
83 2 : return ERR;
84 33027 : break;
85 33149 : case WAITENDOPERAND:
86 33149 : if (*(state->buf) >= '0' && *(state->buf) <= '9')
87 : {
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);
97 32995 : *val = (int32) lval;
98 32995 : if (errno != 0 || (long) *val != lval)
99 0 : return ERR;
100 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;
109 32904 : *val = (int32) *(state->buf);
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;
124 0 : default:
125 0 : return ERR;
126 : break;
127 : }
128 33212 : (state->buf)++;
129 : }
130 : }
131 :
132 : /*
133 : * push new one in polish notation reverse view
134 : */
135 : static void
136 65954 : pushquery(WORKSTATE *state, int32 type, int32 val)
137 : {
138 65954 : NODE *tmp = palloc_object(NODE);
139 :
140 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
153 32912 : makepol(WORKSTATE *state)
154 : {
155 : int32 val,
156 : type;
157 : int32 stack[STACKDEPTH];
158 32912 : int32 lenstack = 0;
159 :
160 : /* since this function recurses, it could be driven to stack overflow */
161 32912 : check_stack_depth();
162 :
163 131685 : while ((type = gettoken(state, &val)) != END)
164 : {
165 131596 : switch (type)
166 : {
167 32995 : case VAL:
168 32995 : pushquery(state, type, val);
169 49483 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
170 97 : stack[lenstack - 1] == (int32) '!'))
171 : {
172 16488 : lenstack--;
173 16488 : pushquery(state, OPR, stack[lenstack]);
174 : }
175 32995 : break;
176 32959 : case OPR:
177 32959 : if (lenstack && val == (int32) '|')
178 3 : pushquery(state, OPR, val);
179 : else
180 : {
181 32956 : if (lenstack == STACKDEPTH)
182 0 : ereturn(state->escontext, ERR,
183 : (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
184 : errmsg("statement too complex")));
185 32956 : stack[lenstack] = val;
186 32956 : lenstack++;
187 : }
188 32959 : break;
189 32819 : case OPEN:
190 32819 : if (makepol(state) == ERR)
191 0 : return ERR;
192 49232 : while (lenstack && (stack[lenstack - 1] == (int32) '&' ||
193 20 : stack[lenstack - 1] == (int32) '!'))
194 : {
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:
209 4 : ereturn(state->escontext, ERR,
210 : (errcode(ERRCODE_SYNTAX_ERROR),
211 : errmsg("syntax error")));
212 : }
213 : }
214 :
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
233 319904 : checkcondition_arr(void *checkval, ITEM *item, void *options)
234 : {
235 319904 : int32 *StopLow = ((CHKVAL *) checkval)->arrb;
236 319904 : int32 *StopHigh = ((CHKVAL *) checkval)->arre;
237 : int32 *StopMiddle;
238 :
239 : /* Loop invariant: StopLow <= val < StopHigh */
240 :
241 1147304 : while (StopLow < StopHigh)
242 : {
243 840077 : StopMiddle = StopLow + (StopHigh - StopLow) / 2;
244 840077 : if (*StopMiddle == item->val)
245 12677 : return true;
246 827400 : else if (*StopMiddle < item->val)
247 243169 : StopLow = StopMiddle + 1;
248 : else
249 584231 : StopHigh = StopMiddle;
250 : }
251 307227 : return false;
252 : }
253 :
254 : static bool
255 44169 : checkcondition_bit(void *checkval, ITEM *item, void *siglen)
256 : {
257 44169 : 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
264 894946 : 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 */
268 894946 : check_stack_depth();
269 :
270 894946 : if (curitem->type == VAL)
271 393114 : return (*chkcond) (checkval, curitem, options);
272 501832 : else if (curitem->val == (int32) '!')
273 : {
274 : return calcnot ?
275 153833 : ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true)
276 362582 : : true;
277 : }
278 293083 : else if (curitem->val == (int32) '&')
279 : {
280 157751 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
281 85963 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
282 : else
283 71788 : return false;
284 : }
285 : else
286 : { /* |-operator */
287 135332 : if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond))
288 6794 : return true;
289 : else
290 128538 : return execute(curitem - 1, checkval, options, calcnot, chkcond);
291 : }
292 : }
293 :
294 : /*
295 : * signconsistent & execconsistent called by *_consistent
296 : */
297 : bool
298 50696 : signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot)
299 : {
300 101392 : return execute(GETQUERY(query) + query->size - 1,
301 50696 : sign, (void *) (intptr_t) siglen, calcnot,
302 : checkcondition_bit);
303 : }
304 :
305 : /* Array must be sorted! */
306 : bool
307 85916 : execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot)
308 : {
309 : CHKVAL chkval;
310 :
311 85916 : CHECKARRVALID(array);
312 85916 : chkval.arrb = ARRPTR(array);
313 85916 : chkval.arre = chkval.arrb + ARRNELEMS(array);
314 85916 : 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
326 29041 : checkcondition_gin(void *checkval, ITEM *item, void *options)
327 : {
328 29041 : GinChkVal *gcv = (GinChkVal *) checkval;
329 :
330 29041 : return gcv->mapped_check[item - gcv->first];
331 : }
332 :
333 : bool
334 14919 : gin_bool_consistent(QUERYTYPE *query, bool *check)
335 : {
336 : GinChkVal gcv;
337 14919 : ITEM *items = GETQUERY(query);
338 : int i,
339 14919 : j = 0;
340 :
341 14919 : if (query->size <= 0)
342 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 : */
348 14919 : gcv.first = items;
349 14919 : gcv.mapped_check = palloc_array(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 :
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;
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 : */
376 8 : return false;
377 : }
378 20 : else if (curitem->val == (int32) '&')
379 : {
380 : /* If either side has a required value, we're good */
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
392 0 : return false;
393 : }
394 : }
395 :
396 : bool
397 14 : query_has_required_values(QUERYTYPE *query)
398 : {
399 14 : if (query->size <= 0)
400 0 : return false;
401 14 : return contains_required_value(GETQUERY(query) + query->size - 1);
402 : }
403 :
404 : /*
405 : * boolean operations
406 : */
407 : Datum
408 0 : rboolop(PG_FUNCTION_ARGS)
409 : {
410 : /* just reverse the operands */
411 0 : return DirectFunctionCall2(boolop,
412 : PG_GETARG_DATUM(1),
413 : PG_GETARG_DATUM(0));
414 : }
415 :
416 : Datum
417 81998 : boolop(PG_FUNCTION_ARGS)
418 : {
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 :
424 81998 : CHECKARRVALID(val);
425 81998 : PREPAREARR(val);
426 81998 : chkval.arrb = ARRPTR(val);
427 81998 : chkval.arre = chkval.arrb + ARRNELEMS(val);
428 81998 : result = execute(GETQUERY(query) + query->size - 1,
429 : &chkval, NULL, true,
430 : checkcondition_arr);
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
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. */
457 65951 : check_stack_depth();
458 :
459 : /* get the position this call is supposed to update */
460 65951 : mypos = *pos;
461 : 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))
482 0 : return false;
483 : }
484 : else
485 : {
486 : /* binary operator */
487 : int32 delta;
488 :
489 : /* recurse to scan right operand */
490 32904 : if (!findoprnd(state, ptr, pos))
491 0 : return false;
492 : /* we must fill left with offset to left operand's top */
493 : /* abs(delta) < QUERYTYPEMAXITEMS, so it can't overflow ... */
494 32904 : delta = *pos - mypos;
495 : /* ... but it might be too large to fit in the 16-bit left field */
496 : 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))
504 0 : return false;
505 : }
506 :
507 65950 : return true;
508 : }
509 :
510 :
511 : /*
512 : * input
513 : */
514 : Datum
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;
524 93 : int32 pos = 0;
525 93 : struct Node *escontext = fcinfo->context;
526 :
527 : #ifdef BS_DEBUG
528 : StringInfoData pbuf;
529 : #endif
530 :
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;
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();
541 89 : if (!state.num)
542 0 : ereturn(escontext, (Datum) 0,
543 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
544 : errmsg("empty query")));
545 :
546 89 : if (state.num > QUERYTYPEMAXITEMS)
547 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)));
551 89 : commonlen = COMPUTESIZE(state.num);
552 :
553 89 : query = (QUERYTYPE *) palloc(commonlen);
554 89 : SET_VARSIZE(query, commonlen);
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;
570 89 : if (!findoprnd(&state, ptr, &pos))
571 0 : PG_RETURN_NULL();
572 : /* if successful, findoprnd should have scanned the whole array */
573 : 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 :
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
611 180 : infix(INFIX *in, bool first)
612 : {
613 : /* since this function recurses, it could be driven to stack overflow. */
614 180 : check_stack_depth();
615 :
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 : }
623 85 : else if (in->curpol->val == (int32) '!')
624 : {
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 : {
649 58 : int32 op = in->curpol->val;
650 : INFIX nrm;
651 :
652 58 : in->curpol--;
653 58 : if (op == (int32) '|' && !first)
654 : {
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;
662 58 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
663 :
664 : /* get right operand */
665 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 :
677 58 : if (op == (int32) '|' && !first)
678 : {
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 : {
690 37 : QUERYTYPE *query = PG_GETARG_QUERYTYPE_P(0);
691 : INFIX nrm;
692 :
693 37 : if (query->size == 0)
694 0 : ereport(ERROR,
695 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
696 : errmsg("empty query")));
697 :
698 37 : nrm.curpol = GETQUERY(query) + query->size - 1;
699 37 : nrm.buflen = 32;
700 37 : nrm.cur = nrm.buf = palloc_array(char, nrm.buflen);
701 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
711 0 : querytree(PG_FUNCTION_ARGS)
712 : {
713 0 : elog(ERROR, "querytree is no longer implemented");
714 : PG_RETURN_NULL();
715 : }
|