]> granicus.if.org Git - postgresql/blob - contrib/intarray/_int_bool.c
Add CVS tag lines to files that were lacking them.
[postgresql] / contrib / intarray / _int_bool.c
1 #include "_int.h"
2
3 PG_FUNCTION_INFO_V1(bqarr_in);
4 PG_FUNCTION_INFO_V1(bqarr_out);
5 Datum           bqarr_in(PG_FUNCTION_ARGS);
6 Datum           bqarr_out(PG_FUNCTION_ARGS);
7
8 PG_FUNCTION_INFO_V1(boolop);
9 Datum           boolop(PG_FUNCTION_ARGS);
10
11 PG_FUNCTION_INFO_V1(rboolop);
12 Datum           rboolop(PG_FUNCTION_ARGS);
13
14 PG_FUNCTION_INFO_V1(querytree);
15 Datum           querytree(PG_FUNCTION_ARGS);
16
17
18 #define END             0
19 #define ERR             1
20 #define VAL             2
21 #define OPR             3
22 #define OPEN    4
23 #define CLOSE   5
24
25 /* parser's states */
26 #define WAITOPERAND 1
27 #define WAITENDOPERAND  2
28 #define WAITOPERATOR    3
29
30 /*
31  * node of query tree, also used
32  * for storing polish notation in parser
33  */
34 typedef struct NODE
35 {
36         int4            type;
37         int4            val;
38         struct NODE *next;
39 }       NODE;
40
41 typedef struct
42 {
43         char       *buf;
44         int4            state;
45         int4            count;
46         /* reverse polish notation in list (for temporary usage) */
47         NODE       *str;
48         /* number in str */
49         int4            num;
50 }       WORKSTATE;
51
52 /*
53  * get token from query string
54  */
55 static int4
56 gettoken(WORKSTATE * state, int4 *val)
57 {
58         char            nnn[16],
59                            *curnnn;
60
61         *val = 0;                                       /* default result */
62
63         curnnn = nnn;
64         while (1)
65         {
66                 switch (state->state)
67                 {
68                         case WAITOPERAND:
69                                 curnnn = nnn;
70                                 if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
71                                         *(state->buf) == '-')
72                                 {
73                                         state->state = WAITENDOPERAND;
74                                         *curnnn = *(state->buf);
75                                         curnnn++;
76                                 }
77                                 else if (*(state->buf) == '!')
78                                 {
79                                         (state->buf)++;
80                                         *val = (int4) '!';
81                                         return OPR;
82                                 }
83                                 else if (*(state->buf) == '(')
84                                 {
85                                         state->count++;
86                                         (state->buf)++;
87                                         return OPEN;
88                                 }
89                                 else if (*(state->buf) != ' ')
90                                         return ERR;
91                                 break;
92                         case WAITENDOPERAND:
93                                 if (*(state->buf) >= '0' && *(state->buf) <= '9')
94                                 {
95                                         *curnnn = *(state->buf);
96                                         curnnn++;
97                                 }
98                                 else
99                                 {
100                                         *curnnn = '\0';
101                                         *val = (int4) atoi(nnn);
102                                         state->state = WAITOPERATOR;
103                                         return (state->count && *(state->buf) == '\0')
104                                                 ? ERR : VAL;
105                                 }
106                                 break;
107                         case WAITOPERATOR:
108                                 if (*(state->buf) == '&' || *(state->buf) == '|')
109                                 {
110                                         state->state = WAITOPERAND;
111                                         *val = (int4) *(state->buf);
112                                         (state->buf)++;
113                                         return OPR;
114                                 }
115                                 else if (*(state->buf) == ')')
116                                 {
117                                         (state->buf)++;
118                                         state->count--;
119                                         return (state->count < 0) ? ERR : CLOSE;
120                                 }
121                                 else if (*(state->buf) == '\0')
122                                         return (state->count) ? ERR : END;
123                                 else if (*(state->buf) != ' ')
124                                         return ERR;
125                                 break;
126                         default:
127                                 return ERR;
128                                 break;
129                 }
130                 (state->buf)++;
131         }
132         return END;
133 }
134
135 /*
136  * push new one in polish notation reverse view
137  */
138 static void
139 pushquery(WORKSTATE * state, int4 type, int4 val)
140 {
141         NODE       *tmp = (NODE *) palloc(sizeof(NODE));
142
143         tmp->type = type;
144         tmp->val = val;
145         tmp->next = state->str;
146         state->str = tmp;
147         state->num++;
148 }
149
150 #define STACKDEPTH      16
151
152 /*
153  * make polish notation of query
154  */
155 static int4
156 makepol(WORKSTATE * state)
157 {
158         int4            val,
159                                 type;
160         int4            stack[STACKDEPTH];
161         int4            lenstack = 0;
162
163         while ((type = gettoken(state, &val)) != END)
164         {
165                 switch (type)
166                 {
167                         case VAL:
168                                 pushquery(state, type, val);
169                                 while (lenstack && (stack[lenstack - 1] == (int4) '&' ||
170                                                                         stack[lenstack - 1] == (int4) '!'))
171                                 {
172                                         lenstack--;
173                                         pushquery(state, OPR, stack[lenstack]);
174                                 }
175                                 break;
176                         case OPR:
177                                 if (lenstack && val == (int4) '|')
178                                         pushquery(state, OPR, val);
179                                 else
180                                 {
181                                         if (lenstack == STACKDEPTH)
182                                                 ereport(ERROR,
183                                                                 (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
184                                                                  errmsg("statement too complex")));
185                                         stack[lenstack] = val;
186                                         lenstack++;
187                                 }
188                                 break;
189                         case OPEN:
190                                 if (makepol(state) == ERR)
191                                         return ERR;
192                                 if (lenstack && (stack[lenstack - 1] == (int4) '&' ||
193                                                                  stack[lenstack - 1] == (int4) '!'))
194                                 {
195                                         lenstack--;
196                                         pushquery(state, OPR, stack[lenstack]);
197                                 }
198                                 break;
199                         case CLOSE:
200                                 while (lenstack)
201                                 {
202                                         lenstack--;
203                                         pushquery(state, OPR, stack[lenstack]);
204                                 };
205                                 return END;
206                                 break;
207                         case ERR:
208                         default:
209                                 ereport(ERROR,
210                                                 (errcode(ERRCODE_SYNTAX_ERROR),
211                                                  errmsg("syntax error")));
212                                 return ERR;
213
214                 }
215         }
216
217         while (lenstack)
218         {
219                 lenstack--;
220                 pushquery(state, OPR, stack[lenstack]);
221         };
222         return END;
223 }
224
225 typedef struct
226 {
227         int4       *arrb;
228         int4       *arre;
229 }       CHKVAL;
230
231 /*
232  * is there value 'val' in array or not ?
233  */
234 static bool
235 checkcondition_arr(void *checkval, int4 val)
236 {
237         int4       *StopLow = ((CHKVAL *) checkval)->arrb;
238         int4       *StopHigh = ((CHKVAL *) checkval)->arre;
239         int4       *StopMiddle;
240
241         /* Loop invariant: StopLow <= val < StopHigh */
242
243         while (StopLow < StopHigh)
244         {
245                 StopMiddle = StopLow + (StopHigh - StopLow) / 2;
246                 if (*StopMiddle == val)
247                         return (true);
248                 else if (*StopMiddle < val)
249                         StopLow = StopMiddle + 1;
250                 else
251                         StopHigh = StopMiddle;
252         }
253         return false;
254 }
255
256 static bool
257 checkcondition_bit(void *checkval, int4 val)
258 {
259         return GETBIT(checkval, HASHVAL(val));
260 }
261
262 /*
263  * check for boolean condition
264  */
265 static bool
266 execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, int4 val))
267 {
268
269         if (curitem->type == VAL)
270                 return (*chkcond) (checkval, curitem->val);
271         else if (curitem->val == (int4) '!')
272         {
273                 return (calcnot) ?
274                         ((execute(curitem - 1, checkval, calcnot, chkcond)) ? false : true)
275                         : true;
276         }
277         else if (curitem->val == (int4) '&')
278         {
279                 if (execute(curitem + curitem->left, checkval, calcnot, chkcond))
280                         return execute(curitem - 1, checkval, calcnot, chkcond);
281                 else
282                         return false;
283         }
284         else
285         {                                                       /* |-operator */
286                 if (execute(curitem + curitem->left, checkval, calcnot, chkcond))
287                         return true;
288                 else
289                         return execute(curitem - 1, checkval, calcnot, chkcond);
290         }
291         return false;
292 }
293
294 /*
295  * signconsistent & execconsistent called by *_consistent
296  */
297 bool
298 signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot)
299 {
300         return execute(
301                                    GETQUERY(query) + query->size - 1,
302                                    (void *) sign, calcnot,
303                                    checkcondition_bit
304                 );
305 }
306
307 bool
308 execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
309 {
310         CHKVAL          chkval;
311
312         CHECKARRVALID(array);
313         chkval.arrb = ARRPTR(array);
314         chkval.arre = chkval.arrb + ARRNELEMS(array);
315         return execute(
316                                    GETQUERY(query) + query->size - 1,
317                                    (void *) &chkval, calcnot,
318                                    checkcondition_arr
319                 );
320 }
321
322 /*
323  * boolean operations
324  */
325 Datum
326 rboolop(PG_FUNCTION_ARGS)
327 {
328         return DirectFunctionCall2(
329                                                            boolop,
330                                                            PG_GETARG_DATUM(1),
331                                                            PG_GETARG_DATUM(0)
332                 );
333 }
334
335 Datum
336 boolop(PG_FUNCTION_ARGS)
337 {
338         ArrayType  *val = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
339         QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1));
340         CHKVAL          chkval;
341         bool            result;
342
343         CHECKARRVALID(val);
344         if (ARRISVOID(val))
345         {
346                 pfree(val);
347                 PG_FREE_IF_COPY(query, 1);
348                 PG_RETURN_BOOL(false);
349         }
350
351         PREPAREARR(val);
352         chkval.arrb = ARRPTR(val);
353         chkval.arre = chkval.arrb + ARRNELEMS(val);
354         result = execute(
355                                          GETQUERY(query) + query->size - 1,
356                                          &chkval, true,
357                                          checkcondition_arr
358                 );
359         pfree(val);
360
361         PG_FREE_IF_COPY(query, 1);
362         PG_RETURN_BOOL(result);
363 }
364
365 static void
366 findoprnd(ITEM * ptr, int4 *pos)
367 {
368 #ifdef BS_DEBUG
369         elog(DEBUG3, (ptr[*pos].type == OPR) ?
370                  "%d  %c" : "%d  %d", *pos, ptr[*pos].val);
371 #endif
372         if (ptr[*pos].type == VAL)
373         {
374                 ptr[*pos].left = 0;
375                 (*pos)--;
376         }
377         else if (ptr[*pos].val == (int4) '!')
378         {
379                 ptr[*pos].left = -1;
380                 (*pos)--;
381                 findoprnd(ptr, pos);
382         }
383         else
384         {
385                 ITEM       *curitem = &ptr[*pos];
386                 int4            tmp = *pos;
387
388                 (*pos)--;
389                 findoprnd(ptr, pos);
390                 curitem->left = *pos - tmp;
391                 findoprnd(ptr, pos);
392         }
393 }
394
395
396 /*
397  * input
398  */
399 Datum
400 bqarr_in(PG_FUNCTION_ARGS)
401 {
402         char       *buf = (char *) PG_GETARG_POINTER(0);
403         WORKSTATE       state;
404         int4            i;
405         QUERYTYPE  *query;
406         int4            commonlen;
407         ITEM       *ptr;
408         NODE       *tmp;
409         int4            pos = 0;
410
411 #ifdef BS_DEBUG
412         StringInfoData pbuf;
413 #endif
414
415         state.buf = buf;
416         state.state = WAITOPERAND;
417         state.count = 0;
418         state.num = 0;
419         state.str = NULL;
420
421         /* make polish notation (postfix, but in reverse order) */
422         makepol(&state);
423         if (!state.num)
424                 ereport(ERROR,
425                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
426                                  errmsg("empty query")));
427
428         commonlen = COMPUTESIZE(state.num);
429         query = (QUERYTYPE *) palloc(commonlen);
430         query->len = commonlen;
431         query->size = state.num;
432         ptr = GETQUERY(query);
433
434         for (i = state.num - 1; i >= 0; i--)
435         {
436                 ptr[i].type = state.str->type;
437                 ptr[i].val = state.str->val;
438                 tmp = state.str->next;
439                 pfree(state.str);
440                 state.str = tmp;
441         }
442
443         pos = query->size - 1;
444         findoprnd(ptr, &pos);
445 #ifdef BS_DEBUG
446         initStringInfo(&pbuf);
447         for (i = 0; i < query->size; i++)
448         {
449                 if (ptr[i].type == OPR)
450                         appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
451                 else
452                         appendStringInfo(&pbuf, "%d ", ptr[i].val);
453         }
454         elog(DEBUG3, "POR: %s", pbuf.data);
455         pfree(pbuf.data);
456 #endif
457
458         PG_RETURN_POINTER(query);
459 }
460
461
462 /*
463  * out function
464  */
465 typedef struct
466 {
467         ITEM       *curpol;
468         char       *buf;
469         char       *cur;
470         int4            buflen;
471 }       INFIX;
472
473 #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
474         int4 len = inf->cur - inf->buf; \
475         inf->buflen *= 2; \
476         inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
477         inf->cur = inf->buf + len; \
478 }
479
480 static void
481 infix(INFIX * in, bool first)
482 {
483         if (in->curpol->type == VAL)
484         {
485                 RESIZEBUF(in, 11);
486                 sprintf(in->cur, "%d", in->curpol->val);
487                 in->cur = strchr(in->cur, '\0');
488                 in->curpol--;
489         }
490         else if (in->curpol->val == (int4) '!')
491         {
492                 bool            isopr = false;
493
494                 RESIZEBUF(in, 1);
495                 *(in->cur) = '!';
496                 in->cur++;
497                 *(in->cur) = '\0';
498                 in->curpol--;
499                 if (in->curpol->type == OPR)
500                 {
501                         isopr = true;
502                         RESIZEBUF(in, 2);
503                         sprintf(in->cur, "( ");
504                         in->cur = strchr(in->cur, '\0');
505                 }
506                 infix(in, isopr);
507                 if (isopr)
508                 {
509                         RESIZEBUF(in, 2);
510                         sprintf(in->cur, " )");
511                         in->cur = strchr(in->cur, '\0');
512                 }
513         }
514         else
515         {
516                 int4            op = in->curpol->val;
517                 INFIX           nrm;
518
519                 in->curpol--;
520                 if (op == (int4) '|' && !first)
521                 {
522                         RESIZEBUF(in, 2);
523                         sprintf(in->cur, "( ");
524                         in->cur = strchr(in->cur, '\0');
525                 }
526
527                 nrm.curpol = in->curpol;
528                 nrm.buflen = 16;
529                 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
530
531                 /* get right operand */
532                 infix(&nrm, false);
533
534                 /* get & print left operand */
535                 in->curpol = nrm.curpol;
536                 infix(in, false);
537
538                 /* print operator & right operand */
539                 RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
540                 sprintf(in->cur, " %c %s", op, nrm.buf);
541                 in->cur = strchr(in->cur, '\0');
542                 pfree(nrm.buf);
543
544                 if (op == (int4) '|' && !first)
545                 {
546                         RESIZEBUF(in, 2);
547                         sprintf(in->cur, " )");
548                         in->cur = strchr(in->cur, '\0');
549                 }
550         }
551 }
552
553
554 Datum
555 bqarr_out(PG_FUNCTION_ARGS)
556 {
557         QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
558         INFIX           nrm;
559
560         if (query->size == 0)
561                 ereport(ERROR,
562                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
563                                  errmsg("empty query")));
564
565         nrm.curpol = GETQUERY(query) + query->size - 1;
566         nrm.buflen = 32;
567         nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
568         *(nrm.cur) = '\0';
569         infix(&nrm, true);
570
571         PG_FREE_IF_COPY(query, 0);
572         PG_RETURN_POINTER(nrm.buf);
573 }
574
575 static int4
576 countdroptree(ITEM * q, int4 pos)
577 {
578         if (q[pos].type == VAL)
579                 return 1;
580         else if (q[pos].val == (int4) '!')
581                 return 1 + countdroptree(q, pos - 1);
582         else
583                 return 1 + countdroptree(q, pos - 1) + countdroptree(q, pos + q[pos].left);
584 }
585
586 /*
587  * common algorithm:
588  * result of all '!' will be = 'true', so
589  * we can modify query tree for clearing
590  */
591 static int4
592 shorterquery(ITEM * q, int4 len)
593 {
594         int4            index,
595                                 posnot,
596                                 poscor;
597         bool            notisleft = false;
598         int4            drop,
599                                 i;
600
601         /* out all '!' */
602         do
603         {
604                 index = 0;
605                 drop = 0;
606                 /* find ! */
607                 for (posnot = 0; posnot < len; posnot++)
608                         if (q[posnot].type == OPR && q[posnot].val == (int4) '!')
609                         {
610                                 index = 1;
611                                 break;
612                         }
613
614                 if (posnot == len)
615                         return len;
616
617                 /* last operator is ! */
618                 if (posnot == len - 1)
619                         return 0;
620
621                 /* find operator for this operand */
622                 for (poscor = posnot + 1; poscor < len; poscor++)
623                 {
624                         if (q[poscor].type == OPR)
625                         {
626                                 if (poscor == posnot + 1)
627                                 {
628                                         notisleft = false;
629                                         break;
630                                 }
631                                 else if (q[poscor].left + poscor == posnot)
632                                 {
633                                         notisleft = true;
634                                         break;
635                                 }
636                         }
637                 }
638                 if (q[poscor].val == (int4) '!')
639                 {
640                         drop = countdroptree(q, poscor);
641                         q[poscor - 1].type = VAL;
642                         for (i = poscor + 1; i < len; i++)
643                                 if (q[i].type == OPR && q[i].left + i <= poscor)
644                                         q[i].left += drop - 2;
645                         memcpy((void *) &q[poscor - drop + 1],
646                                    (void *) &q[poscor - 1],
647                                    sizeof(ITEM) * (len - (poscor - 1)));
648                         len -= drop - 2;
649                 }
650                 else if (q[poscor].val == (int4) '|')
651                 {
652                         drop = countdroptree(q, poscor);
653                         q[poscor - 1].type = VAL;
654                         q[poscor].val = (int4) '!';
655                         q[poscor].left = -1;
656                         for (i = poscor + 1; i < len; i++)
657                                 if (q[i].type == OPR && q[i].left + i < poscor)
658                                         q[i].left += drop - 2;
659                         memcpy((void *) &q[poscor - drop + 1],
660                                    (void *) &q[poscor - 1],
661                                    sizeof(ITEM) * (len - (poscor - 1)));
662                         len -= drop - 2;
663                 }
664                 else
665                 {                                               /* &-operator */
666                         if (
667                                 (notisleft && q[poscor - 1].type == OPR &&
668                                  q[poscor - 1].val == (int4) '!') ||
669                                 (!notisleft && q[poscor + q[poscor].left].type == OPR &&
670                                  q[poscor + q[poscor].left].val == (int4) '!')
671                                 )
672                         {                                       /* drop subtree */
673                                 drop = countdroptree(q, poscor);
674                                 q[poscor - 1].type = VAL;
675                                 q[poscor].val = (int4) '!';
676                                 q[poscor].left = -1;
677                                 for (i = poscor + 1; i < len; i++)
678                                         if (q[i].type == OPR && q[i].left + i < poscor)
679                                                 q[i].left += drop - 2;
680                                 memcpy((void *) &q[poscor - drop + 1],
681                                            (void *) &q[poscor - 1],
682                                            sizeof(ITEM) * (len - (poscor - 1)));
683                                 len -= drop - 2;
684                         }
685                         else
686                         {                                       /* drop only operator */
687                                 int4            subtreepos = (notisleft) ?
688                                 poscor - 1 : poscor + q[poscor].left;
689                                 int4            subtreelen = countdroptree(q, subtreepos);
690
691                                 drop = countdroptree(q, poscor);
692                                 for (i = poscor + 1; i < len; i++)
693                                         if (q[i].type == OPR && q[i].left + i < poscor)
694                                                 q[i].left += drop - subtreelen;
695                                 memcpy((void *) &q[subtreepos + 1],
696                                            (void *) &q[poscor + 1],
697                                            sizeof(ITEM) * (len - (poscor - 1)));
698                                 memcpy((void *) &q[poscor - drop + 1],
699                                            (void *) &q[subtreepos - subtreelen + 1],
700                                            sizeof(ITEM) * (len - (drop - subtreelen)));
701                                 len -= drop - subtreelen;
702                         }
703                 }
704         } while (index);
705         return len;
706 }
707
708
709 Datum
710 querytree(PG_FUNCTION_ARGS)
711 {
712         QUERYTYPE  *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
713         INFIX           nrm;
714         text       *res;
715         ITEM       *q;
716         int4            len;
717
718         if (query->size == 0)
719                 ereport(ERROR,
720                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
721                                  errmsg("empty query")));
722
723         q = (ITEM *) palloc(sizeof(ITEM) * query->size);
724         memcpy((void *) q, GETQUERY(query), sizeof(ITEM) * query->size);
725         len = shorterquery(q, query->size);
726         PG_FREE_IF_COPY(query, 0);
727
728         if (len == 0)
729         {
730                 res = (text *) palloc(1 + VARHDRSZ);
731                 VARATT_SIZEP(res) = 1 + VARHDRSZ;
732                 *((char *) VARDATA(res)) = 'T';
733         }
734         else
735         {
736                 nrm.curpol = q + len - 1;
737                 nrm.buflen = 32;
738                 nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
739                 *(nrm.cur) = '\0';
740                 infix(&nrm, true);
741
742                 res = (text *) palloc(nrm.cur - nrm.buf + VARHDRSZ);
743                 VARATT_SIZEP(res) = nrm.cur - nrm.buf + VARHDRSZ;
744                 strncpy(VARDATA(res), nrm.buf, nrm.cur - nrm.buf);
745         }
746         pfree(q);
747
748         PG_RETURN_POINTER(res);
749 }