6 #include "utils/builtins.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
);
34 #define WAITENDOPERAND 2
35 #define WAITOPERATOR 3
38 * node of query tree, also used
39 * for storing polish notation in parser
53 /* reverse polish notation in list (for temporary usage) */
60 * get token from query string
63 gettoken(WORKSTATE
*state
, int4
*val
)
68 *val
= 0; /* default result */
77 if ((*(state
->buf
) >= '0' && *(state
->buf
) <= '9') ||
80 state
->state
= WAITENDOPERAND
;
81 *curnnn
= *(state
->buf
);
84 else if (*(state
->buf
) == '!')
90 else if (*(state
->buf
) == '(')
96 else if (*(state
->buf
) != ' ')
100 if (*(state
->buf
) >= '0' && *(state
->buf
) <= '9')
102 *curnnn
= *(state
->buf
);
108 *val
= (int4
) atoi(nnn
);
109 state
->state
= WAITOPERATOR
;
110 return (state
->count
&& *(state
->buf
) == '\0')
115 if (*(state
->buf
) == '&' || *(state
->buf
) == '|')
117 state
->state
= WAITOPERAND
;
118 *val
= (int4
) *(state
->buf
);
122 else if (*(state
->buf
) == ')')
126 return (state
->count
< 0) ? ERR
: CLOSE
;
128 else if (*(state
->buf
) == '\0')
129 return (state
->count
) ? ERR
: END
;
130 else if (*(state
->buf
) != ' ')
143 * push new one in polish notation reverse view
146 pushquery(WORKSTATE
*state
, int4 type
, int4 val
)
148 NODE
*tmp
= (NODE
*) palloc(sizeof(NODE
));
152 tmp
->next
= state
->str
;
157 #define STACKDEPTH 16
160 * make polish notation of query
163 makepol(WORKSTATE
*state
)
167 int4 stack
[STACKDEPTH
];
170 while ((type
= gettoken(state
, &val
)) != END
)
175 pushquery(state
, type
, val
);
176 while (lenstack
&& (stack
[lenstack
- 1] == (int4
) '&' ||
177 stack
[lenstack
- 1] == (int4
) '!'))
180 pushquery(state
, OPR
, stack
[lenstack
]);
184 if (lenstack
&& val
== (int4
) '|')
185 pushquery(state
, OPR
, val
);
188 if (lenstack
== STACKDEPTH
)
190 (errcode(ERRCODE_STATEMENT_TOO_COMPLEX
),
191 errmsg("statement too complex")));
192 stack
[lenstack
] = val
;
197 if (makepol(state
) == ERR
)
199 if (lenstack
&& (stack
[lenstack
- 1] == (int4
) '&' ||
200 stack
[lenstack
- 1] == (int4
) '!'))
203 pushquery(state
, OPR
, stack
[lenstack
]);
210 pushquery(state
, OPR
, stack
[lenstack
]);
217 (errcode(ERRCODE_SYNTAX_ERROR
),
218 errmsg("syntax error")));
227 pushquery(state
, OPR
, stack
[lenstack
]);
239 * is there value 'val' in array or not ?
242 checkcondition_arr(void *checkval
, ITEM
*item
)
244 int4
*StopLow
= ((CHKVAL
*) checkval
)->arrb
;
245 int4
*StopHigh
= ((CHKVAL
*) checkval
)->arre
;
248 /* Loop invariant: StopLow <= val < StopHigh */
250 while (StopLow
< StopHigh
)
252 StopMiddle
= StopLow
+ (StopHigh
- StopLow
) / 2;
253 if (*StopMiddle
== item
->val
)
255 else if (*StopMiddle
< item
->val
)
256 StopLow
= StopMiddle
+ 1;
258 StopHigh
= StopMiddle
;
264 checkcondition_bit(void *checkval
, ITEM
*item
)
266 return GETBIT(checkval
, HASHVAL(item
->val
));
270 * check for boolean condition
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
) '!')
281 ((execute(curitem
- 1, checkval
, calcnot
, chkcond
)) ? false : true)
284 else if (curitem
->val
== (int4
) '&')
286 if (execute(curitem
+ curitem
->left
, checkval
, calcnot
, chkcond
))
287 return execute(curitem
- 1, checkval
, calcnot
, chkcond
);
293 if (execute(curitem
+ curitem
->left
, checkval
, calcnot
, chkcond
))
296 return execute(curitem
- 1, checkval
, calcnot
, chkcond
);
302 * signconsistent & execconsistent called by *_consistent
305 signconsistent(QUERYTYPE
*query
, BITVEC sign
, bool calcnot
)
308 GETQUERY(query
) + query
->size
- 1,
309 (void *) sign
, calcnot
,
315 execconsistent(QUERYTYPE
*query
, ArrayType
*array
, bool calcnot
)
319 CHECKARRVALID(array
);
320 chkval
.arrb
= ARRPTR(array
);
321 chkval
.arre
= chkval
.arrb
+ ARRNELEMS(array
);
323 GETQUERY(query
) + query
->size
- 1,
324 (void *) &chkval
, calcnot
,
336 checkcondition_gin(void *checkval
, ITEM
*item
)
338 GinChkVal
*gcv
= (GinChkVal
*) checkval
;
340 return gcv
->mapped_check
[item
- gcv
->first
];
344 ginconsistent(QUERYTYPE
*query
, bool *check
)
347 ITEM
*items
= GETQUERY(query
);
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
++];
361 GETQUERY(query
) + query
->size
- 1,
371 rboolop(PG_FUNCTION_ARGS
)
373 return DirectFunctionCall2(
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));
392 PG_FREE_IF_COPY(query
, 1);
393 PG_RETURN_BOOL(false);
397 chkval
.arrb
= ARRPTR(val
);
398 chkval
.arre
= chkval
.arrb
+ ARRNELEMS(val
);
400 GETQUERY(query
) + query
->size
- 1,
406 PG_FREE_IF_COPY(query
, 1);
407 PG_RETURN_BOOL(result
);
411 findoprnd(ITEM
*ptr
, int4
*pos
)
414 elog(DEBUG3
, (ptr
[*pos
].type
== OPR
) ?
415 "%d %c" : "%d %d", *pos
, ptr
[*pos
].val
);
417 if (ptr
[*pos
].type
== VAL
)
422 else if (ptr
[*pos
].val
== (int4
) '!')
430 ITEM
*curitem
= &ptr
[*pos
];
435 curitem
->left
= *pos
- tmp
;
445 bqarr_in(PG_FUNCTION_ARGS
)
447 char *buf
= (char *) PG_GETARG_POINTER(0);
461 state
.state
= WAITOPERAND
;
466 /* make polish notation (postfix, but in reverse order) */
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
;
488 pos
= query
->size
- 1;
489 findoprnd(ptr
, &pos
);
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
);
497 appendStringInfo(&pbuf
, "%d ", ptr
[i
].val
);
499 elog(DEBUG3
, "POR: %s", pbuf
.data
);
503 PG_RETURN_POINTER(query
);
518 #define RESIZEBUF(inf,addsize) while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) { \
519 int4 len = inf->cur - inf->buf; \
521 inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
522 inf->cur = inf->buf + len; \
526 infix(INFIX
*in
, bool first
)
528 if (in
->curpol
->type
== VAL
)
531 sprintf(in
->cur
, "%d", in
->curpol
->val
);
532 in
->cur
= strchr(in
->cur
, '\0');
535 else if (in
->curpol
->val
== (int4
) '!')
544 if (in
->curpol
->type
== OPR
)
548 sprintf(in
->cur
, "( ");
549 in
->cur
= strchr(in
->cur
, '\0');
555 sprintf(in
->cur
, " )");
556 in
->cur
= strchr(in
->cur
, '\0');
561 int4 op
= in
->curpol
->val
;
565 if (op
== (int4
) '|' && !first
)
568 sprintf(in
->cur
, "( ");
569 in
->cur
= strchr(in
->cur
, '\0');
572 nrm
.curpol
= in
->curpol
;
574 nrm
.cur
= nrm
.buf
= (char *) palloc(sizeof(char) * nrm
.buflen
);
576 /* get right operand */
579 /* get & print left operand */
580 in
->curpol
= nrm
.curpol
;
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');
589 if (op
== (int4
) '|' && !first
)
592 sprintf(in
->cur
, " )");
593 in
->cur
= strchr(in
->cur
, '\0');
600 bqarr_out(PG_FUNCTION_ARGS
)
602 QUERYTYPE
*query
= (QUERYTYPE
*) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
605 if (query
->size
== 0)
607 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
608 errmsg("empty query")));
610 nrm
.curpol
= GETQUERY(query
) + query
->size
- 1;
612 nrm
.cur
= nrm
.buf
= (char *) palloc(sizeof(char) * nrm
.buflen
);
616 PG_FREE_IF_COPY(query
, 0);
617 PG_RETURN_POINTER(nrm
.buf
);
621 countdroptree(ITEM
*q
, int4 pos
)
623 if (q
[pos
].type
== VAL
)
625 else if (q
[pos
].val
== (int4
) '!')
626 return 1 + countdroptree(q
, pos
- 1);
628 return 1 + countdroptree(q
, pos
- 1) + countdroptree(q
, pos
+ q
[pos
].left
);
633 * result of all '!' will be = 'true', so
634 * we can modify query tree for clearing
637 shorterquery(ITEM
*q
, int4 len
)
642 bool notisleft
= false;
652 for (posnot
= 0; posnot
< len
; posnot
++)
653 if (q
[posnot
].type
== OPR
&& q
[posnot
].val
== (int4
) '!')
662 /* last operator is ! */
663 if (posnot
== len
- 1)
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)
676 else if (q
[poscor
].left
+ poscor
== posnot
)
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)));
695 else if (q
[poscor
].val
== (int4
) '|')
697 drop
= countdroptree(q
, poscor
);
698 q
[poscor
- 1].type
= VAL
;
699 q
[poscor
].val
= (int4
) '!';
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)));
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
) '!')
718 drop
= countdroptree(q
, poscor
);
719 q
[poscor
- 1].type
= VAL
;
720 q
[poscor
].val
= (int4
) '!';
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)));
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
;
755 querytree(PG_FUNCTION_ARGS
)
757 QUERYTYPE
*query
= (QUERYTYPE
*) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
763 if (query
->size
== 0)
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);
775 res
= cstring_to_text("T");
779 nrm
.curpol
= q
+ len
- 1;
781 nrm
.cur
= nrm
.buf
= (char *) palloc(sizeof(char) * nrm
.buflen
);
784 res
= cstring_to_text_with_len(nrm
.buf
, nrm
.cur
- nrm
.buf
);
788 PG_RETURN_TEXT_P(res
);