Check nsl library for gethostbyname_r() on all platforms (HP-UX uses it
[PostgreSQL.git] / contrib / intarray / _int_bool.c
blob092709aa3e996daf2f455ffefd2c66f2e65f4f66
1 /*
2 * $PostgreSQL:$
3 */
4 #include "postgres.h"
6 #include "utils/builtins.h"
8 #include "_int.h"
10 PG_FUNCTION_INFO_V1(bqarr_in);
11 PG_FUNCTION_INFO_V1(bqarr_out);
12 Datum bqarr_in(PG_FUNCTION_ARGS);
13 Datum bqarr_out(PG_FUNCTION_ARGS);
15 PG_FUNCTION_INFO_V1(boolop);
16 Datum boolop(PG_FUNCTION_ARGS);
18 PG_FUNCTION_INFO_V1(rboolop);
19 Datum rboolop(PG_FUNCTION_ARGS);
21 PG_FUNCTION_INFO_V1(querytree);
22 Datum querytree(PG_FUNCTION_ARGS);
25 #define END 0
26 #define ERR 1
27 #define VAL 2
28 #define OPR 3
29 #define OPEN 4
30 #define CLOSE 5
32 /* parser's states */
33 #define WAITOPERAND 1
34 #define WAITENDOPERAND 2
35 #define WAITOPERATOR 3
38 * node of query tree, also used
39 * for storing polish notation in parser
41 typedef struct NODE
43 int4 type;
44 int4 val;
45 struct NODE *next;
46 } NODE;
48 typedef struct
50 char *buf;
51 int4 state;
52 int4 count;
53 /* reverse polish notation in list (for temporary usage) */
54 NODE *str;
55 /* number in str */
56 int4 num;
57 } WORKSTATE;
60 * get token from query string
62 static int4
63 gettoken(WORKSTATE * state, int4 *val)
65 char nnn[16],
66 *curnnn;
68 *val = 0; /* default result */
70 curnnn = nnn;
71 while (1)
73 switch (state->state)
75 case WAITOPERAND:
76 curnnn = nnn;
77 if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
78 *(state->buf) == '-')
80 state->state = WAITENDOPERAND;
81 *curnnn = *(state->buf);
82 curnnn++;
84 else if (*(state->buf) == '!')
86 (state->buf)++;
87 *val = (int4) '!';
88 return OPR;
90 else if (*(state->buf) == '(')
92 state->count++;
93 (state->buf)++;
94 return OPEN;
96 else if (*(state->buf) != ' ')
97 return ERR;
98 break;
99 case WAITENDOPERAND:
100 if (*(state->buf) >= '0' && *(state->buf) <= '9')
102 *curnnn = *(state->buf);
103 curnnn++;
105 else
107 *curnnn = '\0';
108 *val = (int4) atoi(nnn);
109 state->state = WAITOPERATOR;
110 return (state->count && *(state->buf) == '\0')
111 ? ERR : VAL;
113 break;
114 case WAITOPERATOR:
115 if (*(state->buf) == '&' || *(state->buf) == '|')
117 state->state = WAITOPERAND;
118 *val = (int4) *(state->buf);
119 (state->buf)++;
120 return OPR;
122 else if (*(state->buf) == ')')
124 (state->buf)++;
125 state->count--;
126 return (state->count < 0) ? ERR : CLOSE;
128 else if (*(state->buf) == '\0')
129 return (state->count) ? ERR : END;
130 else if (*(state->buf) != ' ')
131 return ERR;
132 break;
133 default:
134 return ERR;
135 break;
137 (state->buf)++;
139 return END;
143 * push new one in polish notation reverse view
145 static void
146 pushquery(WORKSTATE * state, int4 type, int4 val)
148 NODE *tmp = (NODE *) palloc(sizeof(NODE));
150 tmp->type = type;
151 tmp->val = val;
152 tmp->next = state->str;
153 state->str = tmp;
154 state->num++;
157 #define STACKDEPTH 16
160 * make polish notation of query
162 static int4
163 makepol(WORKSTATE * state)
165 int4 val,
166 type;
167 int4 stack[STACKDEPTH];
168 int4 lenstack = 0;
170 while ((type = gettoken(state, &val)) != END)
172 switch (type)
174 case VAL:
175 pushquery(state, type, val);
176 while (lenstack && (stack[lenstack - 1] == (int4) '&' ||
177 stack[lenstack - 1] == (int4) '!'))
179 lenstack--;
180 pushquery(state, OPR, stack[lenstack]);
182 break;
183 case OPR:
184 if (lenstack && val == (int4) '|')
185 pushquery(state, OPR, val);
186 else
188 if (lenstack == STACKDEPTH)
189 ereport(ERROR,
190 (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
191 errmsg("statement too complex")));
192 stack[lenstack] = val;
193 lenstack++;
195 break;
196 case OPEN:
197 if (makepol(state) == ERR)
198 return ERR;
199 if (lenstack && (stack[lenstack - 1] == (int4) '&' ||
200 stack[lenstack - 1] == (int4) '!'))
202 lenstack--;
203 pushquery(state, OPR, stack[lenstack]);
205 break;
206 case CLOSE:
207 while (lenstack)
209 lenstack--;
210 pushquery(state, OPR, stack[lenstack]);
212 return END;
213 break;
214 case ERR:
215 default:
216 ereport(ERROR,
217 (errcode(ERRCODE_SYNTAX_ERROR),
218 errmsg("syntax error")));
219 return ERR;
224 while (lenstack)
226 lenstack--;
227 pushquery(state, OPR, stack[lenstack]);
229 return END;
232 typedef struct
234 int4 *arrb;
235 int4 *arre;
236 } CHKVAL;
239 * is there value 'val' in array or not ?
241 static bool
242 checkcondition_arr(void *checkval, ITEM * item)
244 int4 *StopLow = ((CHKVAL *) checkval)->arrb;
245 int4 *StopHigh = ((CHKVAL *) checkval)->arre;
246 int4 *StopMiddle;
248 /* Loop invariant: StopLow <= val < StopHigh */
250 while (StopLow < StopHigh)
252 StopMiddle = StopLow + (StopHigh - StopLow) / 2;
253 if (*StopMiddle == item->val)
254 return (true);
255 else if (*StopMiddle < item->val)
256 StopLow = StopMiddle + 1;
257 else
258 StopHigh = StopMiddle;
260 return false;
263 static bool
264 checkcondition_bit(void *checkval, ITEM * item)
266 return GETBIT(checkval, HASHVAL(item->val));
270 * check for boolean condition
272 static bool
273 execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM * item))
276 if (curitem->type == VAL)
277 return (*chkcond) (checkval, curitem);
278 else if (curitem->val == (int4) '!')
280 return (calcnot) ?
281 ((execute(curitem - 1, checkval, calcnot, chkcond)) ? false : true)
282 : true;
284 else if (curitem->val == (int4) '&')
286 if (execute(curitem + curitem->left, checkval, calcnot, chkcond))
287 return execute(curitem - 1, checkval, calcnot, chkcond);
288 else
289 return false;
291 else
292 { /* |-operator */
293 if (execute(curitem + curitem->left, checkval, calcnot, chkcond))
294 return true;
295 else
296 return execute(curitem - 1, checkval, calcnot, chkcond);
298 return false;
302 * signconsistent & execconsistent called by *_consistent
304 bool
305 signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot)
307 return execute(
308 GETQUERY(query) + query->size - 1,
309 (void *) sign, calcnot,
310 checkcondition_bit
314 bool
315 execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
317 CHKVAL chkval;
319 CHECKARRVALID(array);
320 chkval.arrb = ARRPTR(array);
321 chkval.arre = chkval.arrb + ARRNELEMS(array);
322 return execute(
323 GETQUERY(query) + query->size - 1,
324 (void *) &chkval, calcnot,
325 checkcondition_arr
329 typedef struct
331 ITEM *first;
332 bool *mapped_check;
333 } GinChkVal;
335 static bool
336 checkcondition_gin(void *checkval, ITEM * item)
338 GinChkVal *gcv = (GinChkVal *) checkval;
340 return gcv->mapped_check[item - gcv->first];
343 bool
344 ginconsistent(QUERYTYPE * query, bool *check)
346 GinChkVal gcv;
347 ITEM *items = GETQUERY(query);
348 int i,
349 j = 0;
351 if (query->size < 0)
352 return FALSE;
354 gcv.first = items;
355 gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
356 for (i = 0; i < query->size; i++)
357 if (items[i].type == VAL)
358 gcv.mapped_check[i] = check[j++];
360 return execute(
361 GETQUERY(query) + query->size - 1,
362 (void *) &gcv, true,
363 checkcondition_gin
368 * boolean operations
370 Datum
371 rboolop(PG_FUNCTION_ARGS)
373 return DirectFunctionCall2(
374 boolop,
375 PG_GETARG_DATUM(1),
376 PG_GETARG_DATUM(0)
380 Datum
381 boolop(PG_FUNCTION_ARGS)
383 ArrayType *val = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
384 QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1));
385 CHKVAL chkval;
386 bool result;
388 CHECKARRVALID(val);
389 if (ARRISVOID(val))
391 pfree(val);
392 PG_FREE_IF_COPY(query, 1);
393 PG_RETURN_BOOL(false);
396 PREPAREARR(val);
397 chkval.arrb = ARRPTR(val);
398 chkval.arre = chkval.arrb + ARRNELEMS(val);
399 result = execute(
400 GETQUERY(query) + query->size - 1,
401 &chkval, true,
402 checkcondition_arr
404 pfree(val);
406 PG_FREE_IF_COPY(query, 1);
407 PG_RETURN_BOOL(result);
410 static void
411 findoprnd(ITEM * ptr, int4 *pos)
413 #ifdef BS_DEBUG
414 elog(DEBUG3, (ptr[*pos].type == OPR) ?
415 "%d %c" : "%d %d", *pos, ptr[*pos].val);
416 #endif
417 if (ptr[*pos].type == VAL)
419 ptr[*pos].left = 0;
420 (*pos)--;
422 else if (ptr[*pos].val == (int4) '!')
424 ptr[*pos].left = -1;
425 (*pos)--;
426 findoprnd(ptr, pos);
428 else
430 ITEM *curitem = &ptr[*pos];
431 int4 tmp = *pos;
433 (*pos)--;
434 findoprnd(ptr, pos);
435 curitem->left = *pos - tmp;
436 findoprnd(ptr, pos);
442 * input
444 Datum
445 bqarr_in(PG_FUNCTION_ARGS)
447 char *buf = (char *) PG_GETARG_POINTER(0);
448 WORKSTATE state;
449 int4 i;
450 QUERYTYPE *query;
451 int4 commonlen;
452 ITEM *ptr;
453 NODE *tmp;
454 int4 pos = 0;
456 #ifdef BS_DEBUG
457 StringInfoData pbuf;
458 #endif
460 state.buf = buf;
461 state.state = WAITOPERAND;
462 state.count = 0;
463 state.num = 0;
464 state.str = NULL;
466 /* make polish notation (postfix, but in reverse order) */
467 makepol(&state);
468 if (!state.num)
469 ereport(ERROR,
470 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
471 errmsg("empty query")));
473 commonlen = COMPUTESIZE(state.num);
474 query = (QUERYTYPE *) palloc(commonlen);
475 SET_VARSIZE(query, commonlen);
476 query->size = state.num;
477 ptr = GETQUERY(query);
479 for (i = state.num - 1; i >= 0; i--)
481 ptr[i].type = state.str->type;
482 ptr[i].val = state.str->val;
483 tmp = state.str->next;
484 pfree(state.str);
485 state.str = tmp;
488 pos = query->size - 1;
489 findoprnd(ptr, &pos);
490 #ifdef BS_DEBUG
491 initStringInfo(&pbuf);
492 for (i = 0; i < query->size; i++)
494 if (ptr[i].type == OPR)
495 appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
496 else
497 appendStringInfo(&pbuf, "%d ", ptr[i].val);
499 elog(DEBUG3, "POR: %s", pbuf.data);
500 pfree(pbuf.data);
501 #endif
503 PG_RETURN_POINTER(query);
508 * out function
510 typedef struct
512 ITEM *curpol;
513 char *buf;
514 char *cur;
515 int4 buflen;
516 } INFIX;
518 #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
519 int4 len = inf->cur - inf->buf; \
520 inf->buflen *= 2; \
521 inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
522 inf->cur = inf->buf + len; \
525 static void
526 infix(INFIX *in, bool first)
528 if (in->curpol->type == VAL)
530 RESIZEBUF(in, 11);
531 sprintf(in->cur, "%d", in->curpol->val);
532 in->cur = strchr(in->cur, '\0');
533 in->curpol--;
535 else if (in->curpol->val == (int4) '!')
537 bool isopr = false;
539 RESIZEBUF(in, 1);
540 *(in->cur) = '!';
541 in->cur++;
542 *(in->cur) = '\0';
543 in->curpol--;
544 if (in->curpol->type == OPR)
546 isopr = true;
547 RESIZEBUF(in, 2);
548 sprintf(in->cur, "( ");
549 in->cur = strchr(in->cur, '\0');
551 infix(in, isopr);
552 if (isopr)
554 RESIZEBUF(in, 2);
555 sprintf(in->cur, " )");
556 in->cur = strchr(in->cur, '\0');
559 else
561 int4 op = in->curpol->val;
562 INFIX nrm;
564 in->curpol--;
565 if (op == (int4) '|' && !first)
567 RESIZEBUF(in, 2);
568 sprintf(in->cur, "( ");
569 in->cur = strchr(in->cur, '\0');
572 nrm.curpol = in->curpol;
573 nrm.buflen = 16;
574 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
576 /* get right operand */
577 infix(&nrm, false);
579 /* get & print left operand */
580 in->curpol = nrm.curpol;
581 infix(in, false);
583 /* print operator & right operand */
584 RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
585 sprintf(in->cur, " %c %s", op, nrm.buf);
586 in->cur = strchr(in->cur, '\0');
587 pfree(nrm.buf);
589 if (op == (int4) '|' && !first)
591 RESIZEBUF(in, 2);
592 sprintf(in->cur, " )");
593 in->cur = strchr(in->cur, '\0');
599 Datum
600 bqarr_out(PG_FUNCTION_ARGS)
602 QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
603 INFIX nrm;
605 if (query->size == 0)
606 ereport(ERROR,
607 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
608 errmsg("empty query")));
610 nrm.curpol = GETQUERY(query) + query->size - 1;
611 nrm.buflen = 32;
612 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
613 *(nrm.cur) = '\0';
614 infix(&nrm, true);
616 PG_FREE_IF_COPY(query, 0);
617 PG_RETURN_POINTER(nrm.buf);
620 static int4
621 countdroptree(ITEM * q, int4 pos)
623 if (q[pos].type == VAL)
624 return 1;
625 else if (q[pos].val == (int4) '!')
626 return 1 + countdroptree(q, pos - 1);
627 else
628 return 1 + countdroptree(q, pos - 1) + countdroptree(q, pos + q[pos].left);
632 * common algorithm:
633 * result of all '!' will be = 'true', so
634 * we can modify query tree for clearing
636 int4
637 shorterquery(ITEM * q, int4 len)
639 int4 index,
640 posnot,
641 poscor;
642 bool notisleft = false;
643 int4 drop,
646 /* out all '!' */
649 index = 0;
650 drop = 0;
651 /* find ! */
652 for (posnot = 0; posnot < len; posnot++)
653 if (q[posnot].type == OPR && q[posnot].val == (int4) '!')
655 index = 1;
656 break;
659 if (posnot == len)
660 return len;
662 /* last operator is ! */
663 if (posnot == len - 1)
664 return 0;
666 /* find operator for this operand */
667 for (poscor = posnot + 1; poscor < len; poscor++)
669 if (q[poscor].type == OPR)
671 if (poscor == posnot + 1)
673 notisleft = false;
674 break;
676 else if (q[poscor].left + poscor == posnot)
678 notisleft = true;
679 break;
683 if (q[poscor].val == (int4) '!')
685 drop = countdroptree(q, poscor);
686 q[poscor - 1].type = VAL;
687 for (i = poscor + 1; i < len; i++)
688 if (q[i].type == OPR && q[i].left + i <= poscor)
689 q[i].left += drop - 2;
690 memcpy((void *) &q[poscor - drop + 1],
691 (void *) &q[poscor - 1],
692 sizeof(ITEM) * (len - (poscor - 1)));
693 len -= drop - 2;
695 else if (q[poscor].val == (int4) '|')
697 drop = countdroptree(q, poscor);
698 q[poscor - 1].type = VAL;
699 q[poscor].val = (int4) '!';
700 q[poscor].left = -1;
701 for (i = poscor + 1; i < len; i++)
702 if (q[i].type == OPR && q[i].left + i < poscor)
703 q[i].left += drop - 2;
704 memcpy((void *) &q[poscor - drop + 1],
705 (void *) &q[poscor - 1],
706 sizeof(ITEM) * (len - (poscor - 1)));
707 len -= drop - 2;
709 else
710 { /* &-operator */
711 if (
712 (notisleft && q[poscor - 1].type == OPR &&
713 q[poscor - 1].val == (int4) '!') ||
714 (!notisleft && q[poscor + q[poscor].left].type == OPR &&
715 q[poscor + q[poscor].left].val == (int4) '!')
717 { /* drop subtree */
718 drop = countdroptree(q, poscor);
719 q[poscor - 1].type = VAL;
720 q[poscor].val = (int4) '!';
721 q[poscor].left = -1;
722 for (i = poscor + 1; i < len; i++)
723 if (q[i].type == OPR && q[i].left + i < poscor)
724 q[i].left += drop - 2;
725 memcpy((void *) &q[poscor - drop + 1],
726 (void *) &q[poscor - 1],
727 sizeof(ITEM) * (len - (poscor - 1)));
728 len -= drop - 2;
730 else
731 { /* drop only operator */
732 int4 subtreepos = (notisleft) ?
733 poscor - 1 : poscor + q[poscor].left;
734 int4 subtreelen = countdroptree(q, subtreepos);
736 drop = countdroptree(q, poscor);
737 for (i = poscor + 1; i < len; i++)
738 if (q[i].type == OPR && q[i].left + i < poscor)
739 q[i].left += drop - subtreelen;
740 memcpy((void *) &q[subtreepos + 1],
741 (void *) &q[poscor + 1],
742 sizeof(ITEM) * (len - (poscor - 1)));
743 memcpy((void *) &q[poscor - drop + 1],
744 (void *) &q[subtreepos - subtreelen + 1],
745 sizeof(ITEM) * (len - (drop - subtreelen)));
746 len -= drop - subtreelen;
749 } while (index);
750 return len;
754 Datum
755 querytree(PG_FUNCTION_ARGS)
757 QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
758 INFIX nrm;
759 text *res;
760 ITEM *q;
761 int4 len;
763 if (query->size == 0)
764 ereport(ERROR,
765 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
766 errmsg("empty query")));
768 q = (ITEM *) palloc(sizeof(ITEM) * query->size);
769 memcpy((void *) q, GETQUERY(query), sizeof(ITEM) * query->size);
770 len = shorterquery(q, query->size);
771 PG_FREE_IF_COPY(query, 0);
773 if (len == 0)
775 res = cstring_to_text("T");
777 else
779 nrm.curpol = q + len - 1;
780 nrm.buflen = 32;
781 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
782 *(nrm.cur) = '\0';
783 infix(&nrm, true);
784 res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
786 pfree(q);
788 PG_RETURN_TEXT_P(res);