aboutsummaryrefslogtreecommitdiff
path: root/contrib/intarray/_int_bool.c
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2003-06-11 19:31:05 +0000
committerBruce Momjian <bruce@momjian.us>2003-06-11 19:31:05 +0000
commita237dd2b30b64d5070e1160b036480c44e3ba89d (patch)
tree9fb0161f729e6c7bf36d6099d638076e2ac9ff32 /contrib/intarray/_int_bool.c
parenta24c5a7b124378c054fd0a36dd98581596e74308 (diff)
downloadpostgresql-a237dd2b30b64d5070e1160b036480c44e3ba89d.tar.gz
postgresql-a237dd2b30b64d5070e1160b036480c44e3ba89d.zip
Add missing intarray files.
Diffstat (limited to 'contrib/intarray/_int_bool.c')
-rw-r--r--contrib/intarray/_int_bool.c735
1 files changed, 735 insertions, 0 deletions
diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c
new file mode 100644
index 00000000000..3e8cfd9342c
--- /dev/null
+++ b/contrib/intarray/_int_bool.c
@@ -0,0 +1,735 @@
+#include "_int.h"
+
+PG_FUNCTION_INFO_V1(bqarr_in);
+PG_FUNCTION_INFO_V1(bqarr_out);
+Datum bqarr_in(PG_FUNCTION_ARGS);
+Datum bqarr_out(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(boolop);
+Datum boolop(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(rboolop);
+Datum rboolop(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(querytree);
+Datum querytree(PG_FUNCTION_ARGS);
+
+
+#define END 0
+#define ERR 1
+#define VAL 2
+#define OPR 3
+#define OPEN 4
+#define CLOSE 5
+
+/* parser's states */
+#define WAITOPERAND 1
+#define WAITENDOPERAND 2
+#define WAITOPERATOR 3
+
+/*
+ * node of query tree, also used
+ * for storing polish notation in parser
+ */
+typedef struct NODE
+{
+ int4 type;
+ int4 val;
+ struct NODE *next;
+} NODE;
+
+typedef struct
+{
+ char *buf;
+ int4 state;
+ int4 count;
+ /* reverse polish notation in list (for temporary usage) */
+ NODE *str;
+ /* number in str */
+ int4 num;
+} WORKSTATE;
+
+/*
+ * get token from query string
+ */
+static int4
+gettoken(WORKSTATE * state, int4 *val)
+{
+ char nnn[16],
+ *curnnn;
+
+ curnnn = nnn;
+ while (1)
+ {
+ switch (state->state)
+ {
+ case WAITOPERAND:
+ curnnn = nnn;
+ if ((*(state->buf) >= '0' && *(state->buf) <= '9') ||
+ *(state->buf) == '-')
+ {
+ state->state = WAITENDOPERAND;
+ *curnnn = *(state->buf);
+ curnnn++;
+ }
+ else if (*(state->buf) == '!')
+ {
+ (state->buf)++;
+ *val = (int4) '!';
+ return OPR;
+ }
+ else if (*(state->buf) == '(')
+ {
+ state->count++;
+ (state->buf)++;
+ return OPEN;
+ }
+ else if (*(state->buf) != ' ')
+ return ERR;
+ break;
+ case WAITENDOPERAND:
+ if (*(state->buf) >= '0' && *(state->buf) <= '9')
+ {
+ *curnnn = *(state->buf);
+ curnnn++;
+ }
+ else
+ {
+ *curnnn = '\0';
+ *val = (int4) atoi(nnn);
+ state->state = WAITOPERATOR;
+ return (state->count && *(state->buf) == '\0')
+ ? ERR : VAL;
+ }
+ break;
+ case WAITOPERATOR:
+ if (*(state->buf) == '&' || *(state->buf) == '|')
+ {
+ state->state = WAITOPERAND;
+ *val = (int4) *(state->buf);
+ (state->buf)++;
+ return OPR;
+ }
+ else if (*(state->buf) == ')')
+ {
+ (state->buf)++;
+ state->count--;
+ return (state->count < 0) ? ERR : CLOSE;
+ }
+ else if (*(state->buf) == '\0')
+ return (state->count) ? ERR : END;
+ else if (*(state->buf) != ' ')
+ return ERR;
+ break;
+ default:
+ return ERR;
+ break;
+ }
+ (state->buf)++;
+ }
+ return END;
+}
+
+/*
+ * push new one in polish notation reverse view
+ */
+static void
+pushquery(WORKSTATE * state, int4 type, int4 val)
+{
+ NODE *tmp = (NODE *) palloc(sizeof(NODE));
+
+ tmp->type = type;
+ tmp->val = val;
+ tmp->next = state->str;
+ state->str = tmp;
+ state->num++;
+}
+
+#define STACKDEPTH 16
+
+/*
+ * make polish notation of query
+ */
+static int4
+makepol(WORKSTATE * state)
+{
+ int4 val,
+ type;
+ int4 stack[STACKDEPTH];
+ int4 lenstack = 0;
+
+ while ((type = gettoken(state, &val)) != END)
+ {
+ switch (type)
+ {
+ case VAL:
+ pushquery(state, type, val);
+ while (lenstack && (stack[lenstack - 1] == (int4) '&' ||
+ stack[lenstack - 1] == (int4) '!'))
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack]);
+ }
+ break;
+ case OPR:
+ if (lenstack && val == (int4) '|')
+ pushquery(state, OPR, val);
+ else
+ {
+ if (lenstack == STACKDEPTH)
+ elog(ERROR, "Stack too short");
+ stack[lenstack] = val;
+ lenstack++;
+ }
+ break;
+ case OPEN:
+ if (makepol(state) == ERR)
+ return ERR;
+ if (lenstack && (stack[lenstack - 1] == (int4) '&' ||
+ stack[lenstack - 1] == (int4) '!'))
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack]);
+ }
+ break;
+ case CLOSE:
+ while (lenstack)
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack]);
+ };
+ return END;
+ break;
+ case ERR:
+ default:
+ elog(ERROR, "Syntax error");
+ return ERR;
+
+ }
+ }
+
+ while (lenstack)
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack]);
+ };
+ return END;
+}
+
+typedef struct
+{
+ int4 *arrb;
+ int4 *arre;
+} CHKVAL;
+
+/*
+ * is there value 'val' in array or not ?
+ */
+static bool
+checkcondition_arr(void *checkval, int4 val)
+{
+ int4 *StopLow = ((CHKVAL *) checkval)->arrb;
+ int4 *StopHigh = ((CHKVAL *) checkval)->arre;
+ int4 *StopMiddle;
+
+ /* Loop invariant: StopLow <= val < StopHigh */
+
+ while (StopLow < StopHigh)
+ {
+ StopMiddle = StopLow + (StopHigh - StopLow) / 2;
+ if (*StopMiddle == val)
+ return (true);
+ else if (*StopMiddle < val)
+ StopLow = StopMiddle + 1;
+ else
+ StopHigh = StopMiddle;
+ }
+ return false;
+}
+
+static bool
+checkcondition_bit(void *checkval, int4 val)
+{
+ return GETBIT(checkval, HASHVAL(val));
+}
+
+/*
+ * check for boolean condition
+ */
+static bool
+execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, int4 val))
+{
+
+ if (curitem->type == VAL)
+ return (*chkcond) (checkval, curitem->val);
+ else if (curitem->val == (int4) '!')
+ {
+ return (calcnot) ?
+ ((execute(curitem - 1, checkval, calcnot, chkcond)) ? false : true)
+ : true;
+ }
+ else if (curitem->val == (int4) '&')
+ {
+ if (execute(curitem + curitem->left, checkval, calcnot, chkcond))
+ return execute(curitem - 1, checkval, calcnot, chkcond);
+ else
+ return false;
+ }
+ else
+ { /* |-operator */
+ if (execute(curitem + curitem->left, checkval, calcnot, chkcond))
+ return true;
+ else
+ return execute(curitem - 1, checkval, calcnot, chkcond);
+ }
+ return false;
+}
+
+/*
+ * signconsistent & execconsistent called by *_consistent
+ */
+bool
+signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot)
+{
+ return execute(
+ GETQUERY(query) + query->size - 1,
+ (void *) sign, calcnot,
+ checkcondition_bit
+ );
+}
+
+bool
+execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot)
+{
+ CHKVAL chkval;
+
+ chkval.arrb = ARRPTR(array);
+ chkval.arre = chkval.arrb + ARRNELEMS(array);
+ return execute(
+ GETQUERY(query) + query->size - 1,
+ (void *) &chkval, calcnot,
+ checkcondition_arr
+ );
+}
+
+/*
+ * boolean operations
+ */
+Datum
+rboolop(PG_FUNCTION_ARGS)
+{
+ return DirectFunctionCall2(
+ boolop,
+ PG_GETARG_DATUM(1),
+ PG_GETARG_DATUM(0)
+ );
+}
+
+Datum
+boolop(PG_FUNCTION_ARGS)
+{
+ ArrayType *val = (ArrayType *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
+ QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(1));
+ CHKVAL chkval;
+ bool result;
+
+ if (ARRISVOID(val))
+ {
+ pfree(val);
+ PG_FREE_IF_COPY(query, 1);
+ PG_RETURN_BOOL(false);
+ }
+
+ PREPAREARR(val);
+ chkval.arrb = ARRPTR(val);
+ chkval.arre = chkval.arrb + ARRNELEMS(val);
+ result = execute(
+ GETQUERY(query) + query->size - 1,
+ &chkval, true,
+ checkcondition_arr
+ );
+ pfree(val);
+
+ PG_FREE_IF_COPY(query, 1);
+ PG_RETURN_BOOL(result);
+}
+
+static void
+findoprnd(ITEM * ptr, int4 *pos)
+{
+#ifdef BS_DEBUG
+ elog(DEBUG3, (ptr[*pos].type == OPR) ?
+ "%d %c" : "%d %d ", *pos, ptr[*pos].val);
+#endif
+ if (ptr[*pos].type == VAL)
+ {
+ ptr[*pos].left = 0;
+ (*pos)--;
+ }
+ else if (ptr[*pos].val == (int4) '!')
+ {
+ ptr[*pos].left = -1;
+ (*pos)--;
+ findoprnd(ptr, pos);
+ }
+ else
+ {
+ ITEM *curitem = &ptr[*pos];
+ int4 tmp = *pos;
+
+ (*pos)--;
+ findoprnd(ptr, pos);
+ curitem->left = *pos - tmp;
+ findoprnd(ptr, pos);
+ }
+}
+
+
+/*
+ * input
+ */
+Datum
+bqarr_in(PG_FUNCTION_ARGS)
+{
+ char *buf = (char *) PG_GETARG_POINTER(0);
+ WORKSTATE state;
+ int4 i;
+ QUERYTYPE *query;
+ int4 commonlen;
+ ITEM *ptr;
+ NODE *tmp;
+ int4 pos = 0;
+
+#ifdef BS_DEBUG
+ StringInfoData pbuf;
+#endif
+
+ state.buf = buf;
+ state.state = WAITOPERAND;
+ state.count = 0;
+ state.num = 0;
+ state.str = NULL;
+
+ /* make polish notation (postfix, but in reverse order) */
+ makepol(&state);
+ if (!state.num)
+ elog(ERROR, "Empty query");
+
+ commonlen = COMPUTESIZE(state.num);
+ query = (QUERYTYPE *) palloc(commonlen);
+ query->len = commonlen;
+ query->size = state.num;
+ ptr = GETQUERY(query);
+
+ for (i = state.num - 1; i >= 0; i--)
+ {
+ ptr[i].type = state.str->type;
+ ptr[i].val = state.str->val;
+ tmp = state.str->next;
+ pfree(state.str);
+ state.str = tmp;
+ }
+
+ pos = query->size - 1;
+ findoprnd(ptr, &pos);
+#ifdef BS_DEBUG
+ initStringInfo(&pbuf);
+ for (i = 0; i < query->size; i++)
+ {
+ if (ptr[i].type == OPR)
+ appendStringInfo(&pbuf, "%c(%d) ", ptr[i].val, ptr[i].left);
+ else
+ appendStringInfo(&pbuf, "%d ", ptr[i].val);
+ }
+ elog(DEBUG3, "POR: %s", pbuf.data);
+ pfree(pbuf.data);
+#endif
+
+ PG_RETURN_POINTER(query);
+}
+
+
+/*
+ * out function
+ */
+typedef struct
+{
+ ITEM *curpol;
+ char *buf;
+ char *cur;
+ int4 buflen;
+} INFIX;
+
+#define RESIZEBUF(inf,addsize) while( ( inf->cur - inf->buf ) + addsize + 1 >= inf->buflen ) { \
+ int4 len = inf->cur - inf->buf; \
+ inf->buflen *= 2; \
+ inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
+ inf->cur = inf->buf + len; \
+}
+
+static void
+infix(INFIX * in, bool first)
+{
+ if (in->curpol->type == VAL)
+ {
+ RESIZEBUF(in, 11);
+ sprintf(in->cur, "%d", in->curpol->val);
+ in->cur = strchr(in->cur, '\0');
+ in->curpol--;
+ }
+ else if (in->curpol->val == (int4) '!')
+ {
+ bool isopr = false;
+
+ RESIZEBUF(in, 1);
+ *(in->cur) = '!';
+ in->cur++;
+ *(in->cur) = '\0';
+ in->curpol--;
+ if (in->curpol->type == OPR)
+ {
+ isopr = true;
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, "( ");
+ in->cur = strchr(in->cur, '\0');
+ }
+ infix(in, isopr);
+ if (isopr)
+ {
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, " )");
+ in->cur = strchr(in->cur, '\0');
+ }
+ }
+ else
+ {
+ int4 op = in->curpol->val;
+ INFIX nrm;
+
+ in->curpol--;
+ if (op == (int4) '|' && !first)
+ {
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, "( ");
+ in->cur = strchr(in->cur, '\0');
+ }
+
+ nrm.curpol = in->curpol;
+ nrm.buflen = 16;
+ nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
+
+ /* get right operand */
+ infix(&nrm, false);
+
+ /* get & print left operand */
+ in->curpol = nrm.curpol;
+ infix(in, false);
+
+ /* print operator & right operand */
+ RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
+ sprintf(in->cur, " %c %s", op, nrm.buf);
+ in->cur = strchr(in->cur, '\0');
+ pfree(nrm.buf);
+
+ if (op == (int4) '|' && !first)
+ {
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, " )");
+ in->cur = strchr(in->cur, '\0');
+ }
+ }
+}
+
+
+Datum
+bqarr_out(PG_FUNCTION_ARGS)
+{
+ QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
+ INFIX nrm;
+
+ if (query->size == 0)
+ elog(ERROR, "Empty");
+ nrm.curpol = GETQUERY(query) + query->size - 1;
+ nrm.buflen = 32;
+ nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
+ *(nrm.cur) = '\0';
+ infix(&nrm, true);
+
+ PG_FREE_IF_COPY(query, 0);
+ PG_RETURN_POINTER(nrm.buf);
+}
+
+static int4
+countdroptree(ITEM * q, int4 pos)
+{
+ if (q[pos].type == VAL)
+ return 1;
+ else if (q[pos].val == (int4) '!')
+ return 1 + countdroptree(q, pos - 1);
+ else
+ return 1 + countdroptree(q, pos - 1) + countdroptree(q, pos + q[pos].left);
+}
+
+/*
+ * common algorithm:
+ * result of all '!' will be = 'true', so
+ * we can modify query tree for clearing
+ */
+static int4
+shorterquery(ITEM * q, int4 len)
+{
+ int4 index,
+ posnot,
+ poscor;
+ bool notisleft = false;
+ int4 drop,
+ i;
+
+ /* out all '!' */
+ do
+ {
+ index = 0;
+ drop = 0;
+ /* find ! */
+ for (posnot = 0; posnot < len; posnot++)
+ if (q[posnot].type == OPR && q[posnot].val == (int4) '!')
+ {
+ index = 1;
+ break;
+ }
+
+ if (posnot == len)
+ return len;
+
+ /* last operator is ! */
+ if (posnot == len - 1)
+ return 0;
+
+ /* find operator for this operand */
+ for (poscor = posnot + 1; poscor < len; poscor++)
+ {
+ if (q[poscor].type == OPR)
+ {
+ if (poscor == posnot + 1)
+ {
+ notisleft = false;
+ break;
+ }
+ else if (q[poscor].left + poscor == posnot)
+ {
+ notisleft = true;
+ break;
+ }
+ }
+ }
+ if (q[poscor].val == (int4) '!')
+ {
+ drop = countdroptree(q, poscor);
+ q[poscor - 1].type = VAL;
+ for (i = poscor + 1; i < len; i++)
+ if (q[i].type == OPR && q[i].left + i <= poscor)
+ q[i].left += drop - 2;
+ memcpy((void *) &q[poscor - drop + 1],
+ (void *) &q[poscor - 1],
+ sizeof(ITEM) * (len - (poscor - 1)));
+ len -= drop - 2;
+ }
+ else if (q[poscor].val == (int4) '|')
+ {
+ drop = countdroptree(q, poscor);
+ q[poscor - 1].type = VAL;
+ q[poscor].val = (int4) '!';
+ q[poscor].left = -1;
+ for (i = poscor + 1; i < len; i++)
+ if (q[i].type == OPR && q[i].left + i < poscor)
+ q[i].left += drop - 2;
+ memcpy((void *) &q[poscor - drop + 1],
+ (void *) &q[poscor - 1],
+ sizeof(ITEM) * (len - (poscor - 1)));
+ len -= drop - 2;
+ }
+ else
+ { /* &-operator */
+ if (
+ (notisleft && q[poscor - 1].type == OPR &&
+ q[poscor - 1].val == (int4) '!') ||
+ (!notisleft && q[poscor + q[poscor].left].type == OPR &&
+ q[poscor + q[poscor].left].val == (int4) '!')
+ )
+ { /* drop subtree */
+ drop = countdroptree(q, poscor);
+ q[poscor - 1].type = VAL;
+ q[poscor].val = (int4) '!';
+ q[poscor].left = -1;
+ for (i = poscor + 1; i < len; i++)
+ if (q[i].type == OPR && q[i].left + i < poscor)
+ q[i].left += drop - 2;
+ memcpy((void *) &q[poscor - drop + 1],
+ (void *) &q[poscor - 1],
+ sizeof(ITEM) * (len - (poscor - 1)));
+ len -= drop - 2;
+ }
+ else
+ { /* drop only operator */
+ int4 subtreepos = (notisleft) ?
+ poscor - 1 : poscor + q[poscor].left;
+ int4 subtreelen = countdroptree(q, subtreepos);
+
+ drop = countdroptree(q, poscor);
+ for (i = poscor + 1; i < len; i++)
+ if (q[i].type == OPR && q[i].left + i < poscor)
+ q[i].left += drop - subtreelen;
+ memcpy((void *) &q[subtreepos + 1],
+ (void *) &q[poscor + 1],
+ sizeof(ITEM) * (len - (poscor - 1)));
+ memcpy((void *) &q[poscor - drop + 1],
+ (void *) &q[subtreepos - subtreelen + 1],
+ sizeof(ITEM) * (len - (drop - subtreelen)));
+ len -= drop - subtreelen;
+ }
+ }
+ } while (index);
+ return len;
+}
+
+
+Datum
+querytree(PG_FUNCTION_ARGS)
+{
+ QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_POINTER(0));
+ INFIX nrm;
+ text *res;
+ ITEM *q;
+ int4 len;
+
+ if (query->size == 0)
+ elog(ERROR, "Empty");
+
+ q = (ITEM *) palloc(sizeof(ITEM) * query->size);
+ memcpy((void *) q, GETQUERY(query), sizeof(ITEM) * query->size);
+ len = shorterquery(q, query->size);
+ PG_FREE_IF_COPY(query, 0);
+
+ if (len == 0)
+ {
+ res = (text *) palloc(1 + VARHDRSZ);
+ VARATT_SIZEP(res) = 1 + VARHDRSZ;
+ *((char *) VARDATA(res)) = 'T';
+ }
+ else
+ {
+ nrm.curpol = q + len - 1;
+ nrm.buflen = 32;
+ nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
+ *(nrm.cur) = '\0';
+ infix(&nrm, true);
+
+ res = (text *) palloc(nrm.cur - nrm.buf + VARHDRSZ);
+ VARATT_SIZEP(res) = nrm.cur - nrm.buf + VARHDRSZ;
+ strncpy(VARDATA(res), nrm.buf, nrm.cur - nrm.buf);
+ }
+ pfree(q);
+
+ PG_RETURN_POINTER(res);
+}
+