Datum lquery_in(PG_FUNCTION_ARGS) { char *buf = (char *) PG_GETARG_POINTER(0); char *ptr; int num = 0, totallen = 0, numOR = 0; int state = LQPRS_WAITLEVEL; lquery *result; nodeitem *lptr = NULL; lquery_level *cur, *curqlevel, *tmpql; lquery_variant *lrptr = NULL; bool hasnot = false; bool wasbad = false; int charlen; int pos = 0; ptr = buf; while (*ptr) { charlen = pg_mblen(ptr); if (charlen == 1) { if (t_iseq(ptr, '.')) num++; else if (t_iseq(ptr, '|')) numOR++; } ptr += charlen; } num++; curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num); ptr = buf; while (*ptr) { charlen = pg_mblen(ptr); if (state == LQPRS_WAITLEVEL) { if (ISALNUM(ptr)) { GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1)); lptr->start = ptr; state = LQPRS_WAITDELIM; curqlevel->numvar = 1; } else if (charlen == 1 && t_iseq(ptr, '!')) { GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1)); lptr->start = ptr + 1; state = LQPRS_WAITDELIM; curqlevel->numvar = 1; curqlevel->flag |= LQL_NOT; hasnot = true; } else if (charlen == 1 && t_iseq(ptr, '*')) state = LQPRS_WAITOPEN; else UNCHAR; } else if (state == LQPRS_WAITVAR) { if (ISALNUM(ptr)) { lptr++; lptr->start = ptr; state = LQPRS_WAITDELIM; curqlevel->numvar++; } else UNCHAR; } else if (state == LQPRS_WAITDELIM) { if (charlen == 1 && t_iseq(ptr, '@')) { if (lptr->start == ptr) UNCHAR; lptr->flag |= LVAR_INCASE; curqlevel->flag |= LVAR_INCASE; } else if (charlen == 1 && t_iseq(ptr, '*')) { if (lptr->start == ptr) UNCHAR; lptr->flag |= LVAR_ANYEND; curqlevel->flag |= LVAR_ANYEND; } else if (charlen == 1 && t_iseq(ptr, '%')) { if (lptr->start == ptr) UNCHAR; lptr->flag |= LVAR_SUBLEXEME; curqlevel->flag |= LVAR_SUBLEXEME; } else if (charlen == 1 && t_iseq(ptr, '|')) { lptr->len = ptr - lptr->start - ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) - ((lptr->flag & LVAR_INCASE) ? 1 : 0) - ((lptr->flag & LVAR_ANYEND) ? 1 : 0); if (lptr->wlen > 255) ereport(ERROR, (errcode(ERRCODE_NAME_TOO_LONG), errmsg("name of level is too long"), errdetail("Name length is %d, must " "be < 256, in position %d.", lptr->wlen, pos))); state = LQPRS_WAITVAR; } else if (charlen == 1 && t_iseq(ptr, '.')) { lptr->len = ptr - lptr->start - ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) - ((lptr->flag & LVAR_INCASE) ? 1 : 0) - ((lptr->flag & LVAR_ANYEND) ? 1 : 0); if (lptr->wlen > 255) ereport(ERROR, (errcode(ERRCODE_NAME_TOO_LONG), errmsg("name of level is too long"), errdetail("Name length is %d, must " "be < 256, in position %d.", lptr->wlen, pos))); state = LQPRS_WAITLEVEL; curqlevel = NEXTLEV(curqlevel); } else if (ISALNUM(ptr)) { if (lptr->flag) UNCHAR; } else UNCHAR; } else if (state == LQPRS_WAITOPEN) { if (charlen == 1 && t_iseq(ptr, '{')) state = LQPRS_WAITFNUM; else if (charlen == 1 && t_iseq(ptr, '.')) { curqlevel->low = 0; curqlevel->high = 0xffff; curqlevel = NEXTLEV(curqlevel); state = LQPRS_WAITLEVEL; } else UNCHAR; } else if (state == LQPRS_WAITFNUM) { if (charlen == 1 && t_iseq(ptr, ',')) state = LQPRS_WAITSNUM; else if (t_isdigit(ptr)) { curqlevel->low = atoi(ptr); state = LQPRS_WAITND; } else UNCHAR; } else if (state == LQPRS_WAITSNUM) { if (t_isdigit(ptr)) { curqlevel->high = atoi(ptr); state = LQPRS_WAITCLOSE; } else if (charlen == 1 && t_iseq(ptr, '}')) { curqlevel->high = 0xffff; state = LQPRS_WAITEND; } else UNCHAR; } else if (state == LQPRS_WAITCLOSE) { if (charlen == 1 && t_iseq(ptr, '}')) state = LQPRS_WAITEND; else if (!t_isdigit(ptr)) UNCHAR; } else if (state == LQPRS_WAITND) { if (charlen == 1 && t_iseq(ptr, '}')) { curqlevel->high = curqlevel->low; state = LQPRS_WAITEND; } else if (charlen == 1 && t_iseq(ptr, ',')) state = LQPRS_WAITSNUM; else if (!t_isdigit(ptr)) UNCHAR; } else if (state == LQPRS_WAITEND) { if (charlen == 1 && t_iseq(ptr, '.')) { state = LQPRS_WAITLEVEL; curqlevel = NEXTLEV(curqlevel); } else UNCHAR; } else /* internal error */ elog(ERROR, "internal error in parser"); ptr += charlen; if (state == LQPRS_WAITDELIM) lptr->wlen++; pos++; } if (state == LQPRS_WAITDELIM) { if (lptr->start == ptr) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error"), errdetail("Unexpected end of line."))); lptr->len = ptr - lptr->start - ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) - ((lptr->flag & LVAR_INCASE) ? 1 : 0) - ((lptr->flag & LVAR_ANYEND) ? 1 : 0); if (lptr->len == 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error"), errdetail("Unexpected end of line."))); if (lptr->wlen > 255) ereport(ERROR, (errcode(ERRCODE_NAME_TOO_LONG), errmsg("name of level is too long"), errdetail("Name length is %d, must " "be < 256, in position %d.", lptr->wlen, pos))); } else if (state == LQPRS_WAITOPEN) curqlevel->high = 0xffff; else if (state != LQPRS_WAITEND) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error"), errdetail("Unexpected end of line."))); curqlevel = tmpql; totallen = LQUERY_HDRSIZE; while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE) { totallen += LQL_HDRSIZE; if (curqlevel->numvar) { lptr = GETVAR(curqlevel); while (lptr - GETVAR(curqlevel) < curqlevel->numvar) { totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len); lptr++; } } else if (curqlevel->low > curqlevel->high) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error"), errdetail("Low limit(%d) is greater than upper(%d).", curqlevel->low, curqlevel->high))); curqlevel = NEXTLEV(curqlevel); } result = (lquery *) palloc0(totallen); SET_VARSIZE(result, totallen); result->numlevel = num; result->firstgood = 0; result->flag = 0; if (hasnot) result->flag |= LQUERY_HASNOT; cur = LQUERY_FIRST(result); curqlevel = tmpql; while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE) { memcpy(cur, curqlevel, LQL_HDRSIZE); cur->totallen = LQL_HDRSIZE; if (curqlevel->numvar) { lrptr = LQL_FIRST(cur); lptr = GETVAR(curqlevel); while (lptr - GETVAR(curqlevel) < curqlevel->numvar) { cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len); lrptr->len = lptr->len; lrptr->flag = lptr->flag; lrptr->val = ltree_crc32_sz(lptr->start, lptr->len); memcpy(lrptr->name, lptr->start, lptr->len); lptr++; lrptr = LVAR_NEXT(lrptr); } pfree(GETVAR(curqlevel)); if (cur->numvar > 1 || cur->flag != 0) wasbad = true; else if (wasbad == false) (result->firstgood)++; } else wasbad = true; curqlevel = NEXTLEV(curqlevel); cur = LQL_NEXT(cur); } pfree(tmpql); PG_RETURN_POINTER(result); }
Datum lquery_out(PG_FUNCTION_ARGS) { lquery *in = PG_GETARG_LQUERY(0); char *buf, *ptr; int i, j, totallen = 1; lquery_level *curqlevel; lquery_variant *curtlevel; curqlevel = LQUERY_FIRST(in); for (i = 0; i < in->numlevel; i++) { totallen++; if (curqlevel->numvar) totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen; else totallen += 2 * 11 + 4; curqlevel = LQL_NEXT(curqlevel); } ptr = buf = (char *) palloc(totallen); curqlevel = LQUERY_FIRST(in); for (i = 0; i < in->numlevel; i++) { if (i != 0) { *ptr = '.'; ptr++; } if (curqlevel->numvar) { if (curqlevel->flag & LQL_NOT) { *ptr = '!'; ptr++; } curtlevel = LQL_FIRST(curqlevel); for (j = 0; j < curqlevel->numvar; j++) { if (j != 0) { *ptr = '|'; ptr++; } memcpy(ptr, curtlevel->name, curtlevel->len); ptr += curtlevel->len; if ((curtlevel->flag & LVAR_SUBLEXEME)) { *ptr = '%'; ptr++; } if ((curtlevel->flag & LVAR_INCASE)) { *ptr = '@'; ptr++; } if ((curtlevel->flag & LVAR_ANYEND)) { *ptr = '*'; ptr++; } curtlevel = LVAR_NEXT(curtlevel); } } else { if (curqlevel->low == curqlevel->high) { sprintf(ptr, "*{%d}", curqlevel->low); } else if (curqlevel->low == 0) { if (curqlevel->high == 0xffff) { *ptr = '*'; *(ptr + 1) = '\0'; } else sprintf(ptr, "*{,%d}", curqlevel->high); } else if (curqlevel->high == 0xffff) { sprintf(ptr, "*{%d,}", curqlevel->low); } else sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high); ptr = strchr(ptr, '\0'); } curqlevel = LQL_NEXT(curqlevel); } *ptr = '\0'; PG_FREE_IF_COPY(in, 0); PG_RETURN_POINTER(buf); }
static bool checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_numlevel, FieldNot * ptr) { uint32 low_pos = 0, high_pos = 0, cur_tpos = 0; int tlen = tree_numlevel, qlen = query_numlevel; int isok; lquery_level *prevq = NULL; ltree_level *prevt = NULL; if (SomeStack.muse) { high_pos = SomeStack.high_pos; qlen--; prevq = curq; curq = LQL_NEXT(curq); SomeStack.muse = false; } while (tlen > 0 && qlen > 0) { if (curq->numvar) { prevt = curt; while (cur_tpos < low_pos) { curt = LEVEL_NEXT(curt); tlen--; cur_tpos++; if (tlen == 0) return false; if (ptr && ptr->q) ptr->nt++; } if (ptr && curq->flag & LQL_NOT) { if (!(prevq && prevq->numvar == 0)) prevq = curq; if (ptr->q == NULL) { ptr->t = prevt; ptr->q = prevq; ptr->nt = 1; ptr->nq = 1 + ((prevq == curq) ? 0 : 1); ptr->posq = query_numlevel - qlen - ((prevq == curq) ? 0 : 1); ptr->post = cur_tpos; } else { ptr->nt++; ptr->nq++; } if (qlen == 1 && ptr->q->numvar == 0) ptr->nt = tree_numlevel - ptr->post; curt = LEVEL_NEXT(curt); tlen--; cur_tpos++; if (high_pos < cur_tpos) high_pos++; } else { isok = false; while (cur_tpos <= high_pos && tlen > 0 && !isok) { isok = checkLevel(curq, curt); curt = LEVEL_NEXT(curt); tlen--; cur_tpos++; if (isok && prevq && prevq->numvar == 0 && tlen > 0 && cur_tpos <= high_pos) { FieldNot tmpptr; if (ptr) memcpy(&tmpptr, ptr, sizeof(FieldNot)); SomeStack.high_pos = high_pos - cur_tpos; SomeStack.muse = true; if (checkCond(prevq, qlen + 1, curt, tlen, (ptr) ? &tmpptr : NULL)) return true; } if (!isok && ptr) ptr->nt++; } if (!isok) return false; if (ptr && ptr->q) { if (checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL)) return false; ptr->q = NULL; } low_pos = cur_tpos; high_pos = cur_tpos; } } else { low_pos = cur_tpos + curq->low; high_pos = cur_tpos + curq->high; if (ptr && ptr->q) { ptr->nq++; if (qlen == 1) ptr->nt = tree_numlevel - ptr->post; } } prevq = curq; curq = LQL_NEXT(curq); qlen--; } if (low_pos > tree_numlevel || tree_numlevel > high_pos) return false; while (qlen > 0) { if (curq->numvar) { if (!(curq->flag & LQL_NOT)) return false; } else { low_pos = cur_tpos + curq->low; high_pos = cur_tpos + curq->high; } curq = LQL_NEXT(curq); qlen--; } if (low_pos > tree_numlevel || tree_numlevel > high_pos) return false; if (ptr && ptr->q && checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL)) return false; return true; }