int ltree_compare(const ltree *a, const ltree *b) { ltree_level *al = LTREE_FIRST(a); ltree_level *bl = LTREE_FIRST(b); int an = a->numlevel; int bn = b->numlevel; int res = 0; while (an > 0 && bn > 0) { if ((res = strncmp(al->name, bl->name, Min(al->len, bl->len))) == 0) { if (al->len != bl->len) return (al->len - bl->len) * 10 * (an + 1); } else return res * 10 * (an + 1); an--; bn--; al = LEVEL_NEXT(al); bl = LEVEL_NEXT(bl); } return (a->numlevel - b->numlevel) * 10 * (an + 1); }
Datum ltree_index(PG_FUNCTION_ARGS) { ltree *a = PG_GETARG_LTREE(0); ltree *b = PG_GETARG_LTREE(1); int start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0; int i, j; ltree_level *startptr, *aptr, *bptr; bool found = false; if (start < 0) { if (-start >= a->numlevel) start = 0; else start = (int) (a->numlevel) + start; } if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0) { PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); PG_RETURN_INT32(-1); } startptr = LTREE_FIRST(a); for (i = 0; i <= a->numlevel - b->numlevel; i++) { if (i >= start) { aptr = startptr; bptr = LTREE_FIRST(b); for (j = 0; j < b->numlevel; j++) { if (!(aptr->len == bptr->len && strncmp(aptr->name, bptr->name, aptr->len) == 0)) break; aptr = LEVEL_NEXT(aptr); bptr = LEVEL_NEXT(bptr); } if (j == b->numlevel) { found = true; break; } } startptr = LEVEL_NEXT(startptr); } if (!found) i = -1; PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(b, 1); PG_RETURN_INT32(i); }
Datum ltree2text(PG_FUNCTION_ARGS) { ltree *in = PG_GETARG_LTREE(0); char *ptr; int i; ltree_level *curlevel; text *out; out = (text *) palloc(VARSIZE(in) + VARHDRSZ); ptr = VARDATA(out); curlevel = LTREE_FIRST(in); for (i = 0; i < in->numlevel; i++) { if (i != 0) { *ptr = '.'; ptr++; } memcpy(ptr, curlevel->name, curlevel->len); ptr += curlevel->len; curlevel = LEVEL_NEXT(curlevel); } SET_VARSIZE(out, ptr - ((char *) out)); PG_FREE_IF_COPY(in, 0); PG_RETURN_POINTER(out); }
static bool checkcondition_str(void *checkval, ITEM *val) { ltree_level *level = LTREE_FIRST(((CHKVAL *) checkval)->node); int tlen = ((CHKVAL *) checkval)->node->numlevel; char *op = ((CHKVAL *) checkval)->operand + val->distance; int (*cmpptr) (const char *, const char *, size_t); cmpptr = (val->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp; while (tlen > 0) { if (val->flag & LVAR_SUBLEXEME) { if (compare_subnode(level, op, val->length, cmpptr, (val->flag & LVAR_ANYEND))) return true; } else if ( ( val->length == level->len || (level->len > val->length && (val->flag & LVAR_ANYEND)) ) && (*cmpptr) (op, level->name, val->length) == 0) return true; tlen--; level = LEVEL_NEXT(level); } return false; }
Datum ltree_out(PG_FUNCTION_ARGS) { ltree *in = PG_GETARG_LTREE(0); char *buf, *ptr; int i; ltree_level *curlevel; ptr = buf = (char *) palloc(VARSIZE(in)); curlevel = LTREE_FIRST(in); for (i = 0; i < in->numlevel; i++) { if (i != 0) { *ptr = '.'; ptr++; } memcpy(ptr, curlevel->name, curlevel->len); ptr += curlevel->len; curlevel = LEVEL_NEXT(curlevel); } *ptr = '\0'; PG_FREE_IF_COPY(in, 0); PG_RETURN_POINTER(buf); }
Datum ltree_to_plpython(PG_FUNCTION_ARGS) { ltree *in = PG_GETARG_LTREE_P(0); int i; PyObject *list; ltree_level *curlevel; list = PyList_New(in->numlevel); if (!list) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); curlevel = LTREE_FIRST(in); for (i = 0; i < in->numlevel; i++) { PyList_SetItem(list, i, PyString_FromStringAndSize(curlevel->name, curlevel->len)); curlevel = LEVEL_NEXT(curlevel); } PG_FREE_IF_COPY(in, 0); return PointerGetDatum(list); }
static ltree * inner_subltree(ltree *t, int4 startpos, int4 endpos) { char *start = NULL, *end = NULL; ltree_level *ptr = LTREE_FIRST(t); ltree *res; int i; if (startpos < 0 || endpos < 0 || startpos >= t->numlevel || startpos > endpos) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid positions"))); if (endpos > t->numlevel) endpos = t->numlevel; start = end = (char *) ptr; for (i = 0; i < endpos; i++) { if (i == startpos) start = (char *) ptr; if (i == endpos - 1) { end = (char *) LEVEL_NEXT(ptr); break; } ptr = LEVEL_NEXT(ptr); } res = (ltree *) palloc(LTREE_HDRSIZE + (end - start)); SET_VARSIZE(res, LTREE_HDRSIZE + (end - start)); res->numlevel = endpos - startpos; memcpy(LTREE_FIRST(res), start, end - start); return res; }
bool inner_isparent(const ltree *c, const ltree *p) { ltree_level *cl = LTREE_FIRST(c); ltree_level *pl = LTREE_FIRST(p); int pn = p->numlevel; if (pn > c->numlevel) return false; while (pn > 0) { if (cl->len != pl->len) return false; if (strncmp(cl->name, pl->name, cl->len)) return false; pn--; cl = LEVEL_NEXT(cl); pl = LEVEL_NEXT(pl); } return true; }
static void hashing(BITVECP sign, ltree * t) { int tlen = t->numlevel; ltree_level *cur = LTREE_FIRST(t); int hash; while (tlen > 0) { hash = ltree_crc32_sz(cur->name, cur->len); AHASH(sign, hash); cur = LEVEL_NEXT(cur); tlen--; } }
ltree * lca_inner(ltree **a, int len) { int tmp, num = ((*a)->numlevel) ? (*a)->numlevel - 1 : 0; ltree **ptr = a + 1; int i, reslen = LTREE_HDRSIZE; ltree_level *l1, *l2; ltree *res; if ((*a)->numlevel == 0) return NULL; while (ptr - a < len) { if ((*ptr)->numlevel == 0) return NULL; else if ((*ptr)->numlevel == 1) num = 0; else { l1 = LTREE_FIRST(*a); l2 = LTREE_FIRST(*ptr); tmp = num; num = 0; for (i = 0; i < Min(tmp, (*ptr)->numlevel - 1); i++) { if (l1->len == l2->len && strncmp(l1->name, l2->name, l1->len) == 0) num = i + 1; else break; l1 = LEVEL_NEXT(l1); l2 = LEVEL_NEXT(l2); } } ptr++; } l1 = LTREE_FIRST(*a); for (i = 0; i < num; i++) { reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE); l1 = LEVEL_NEXT(l1); } res = (ltree *) palloc(reslen); SET_VARSIZE(res, reslen); res->numlevel = num; l1 = LTREE_FIRST(*a); l2 = LTREE_FIRST(res); for (i = 0; i < num; i++) { memcpy(l2, l1, MAXALIGN(l1->len + LEVEL_HDRSIZE)); l1 = LEVEL_NEXT(l1); l2 = LEVEL_NEXT(l2); } return res; }
Datum ltree_in(PG_FUNCTION_ARGS) { char *buf = (char *) PG_GETARG_POINTER(0); char *ptr; nodeitem *list, *lptr; int num = 0, totallen = 0; int state = LTPRS_WAITNAME; ltree *result; ltree_level *curlevel; int charlen; int pos = 0; ptr = buf; while (*ptr) { charlen = pg_mblen(ptr); if (charlen == 1 && t_iseq(ptr, '.')) num++; ptr += charlen; } if (num + 1 > MaxAllocSize / sizeof(nodeitem)) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of levels (%d) exceeds the maximum allowed (%d)", num + 1, (int) (MaxAllocSize / sizeof(nodeitem))))); list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1)); ptr = buf; while (*ptr) { charlen = pg_mblen(ptr); if (state == LTPRS_WAITNAME) { if (ISALNUM(ptr)) { lptr->start = ptr; lptr->wlen = 0; state = LTPRS_WAITDELIM; } else UNCHAR; } else if (state == LTPRS_WAITDELIM) { if (charlen == 1 && t_iseq(ptr, '.')) { lptr->len = ptr - lptr->start; 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))); totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE); lptr++; state = LTPRS_WAITNAME; } else if (!ISALNUM(ptr)) UNCHAR; } else /* internal error */ elog(ERROR, "internal error in parser"); ptr += charlen; lptr->wlen++; pos++; } if (state == LTPRS_WAITDELIM) { lptr->len = ptr - lptr->start; 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))); totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE); lptr++; } else if (!(state == LTPRS_WAITNAME && lptr == list)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error"), errdetail("Unexpected end of line."))); result = (ltree *) palloc0(LTREE_HDRSIZE + totallen); SET_VARSIZE(result, LTREE_HDRSIZE + totallen); result->numlevel = lptr - list; curlevel = LTREE_FIRST(result); lptr = list; while (lptr - list < result->numlevel) { curlevel->len = (uint16) lptr->len; memcpy(curlevel->name, lptr->start, lptr->len); curlevel = LEVEL_NEXT(curlevel); lptr++; } pfree(list); PG_RETURN_POINTER(result); }
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; }