2 * op function for ltree and lquery
3 * Teodor Sigaev <teodor@stack.net>
4 * $PostgreSQL: pgsql/contrib/ltree/lquery_op.c,v 1.15 2010/02/24 18:02:24 tgl Exp $
10 #include "utils/array.h"
11 #include "utils/formatting.h"
14 PG_FUNCTION_INFO_V1(ltq_regex);
15 PG_FUNCTION_INFO_V1(ltq_rregex);
17 PG_FUNCTION_INFO_V1(lt_q_regex);
18 PG_FUNCTION_INFO_V1(lt_q_rregex);
20 #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
33 getlexeme(char *start, char *end, int *len)
38 while (start < end && (charlen = pg_mblen(start)) == 1 && t_iseq(start, '_'))
45 while (ptr < end && !((charlen = pg_mblen(ptr)) == 1 && t_iseq(ptr, '_')))
53 compare_subnode(ltree_level *t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
55 char *endt = t->name + t->len;
56 char *endq = qn + len;
62 while ((qn = getlexeme(qn, endq, &lenq)) != NULL)
66 while ((tn = getlexeme(tn, endt, &lent)) != NULL)
71 (lent > lenq && anyend)
73 (*cmpptr) (qn, tn, lenq) == 0)
91 ltree_strncasecmp(const char *a, const char *b, size_t s)
93 char *al = str_tolower(a, s);
94 char *bl = str_tolower(b, s);
97 res = strncmp(al, bl, s);
106 checkLevel(lquery_level *curq, ltree_level *curt)
108 int (*cmpptr) (const char *, const char *, size_t);
109 lquery_variant *curvar = LQL_FIRST(curq);
112 for (i = 0; i < curq->numvar; i++)
114 cmpptr = (curvar->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp;
116 if (curvar->flag & LVAR_SUBLEXEME)
118 if (compare_subnode(curt, curvar->name, curvar->len, cmpptr, (curvar->flag & LVAR_ANYEND)))
123 curvar->len == curt->len ||
124 (curt->len > curvar->len && (curvar->flag & LVAR_ANYEND))
126 (*cmpptr) (curvar->name, curt->name, curvar->len) == 0)
131 curvar = LVAR_NEXT(curvar);
138 printFieldNot(FieldNot *fn ) {
140 elog(NOTICE,"posQ:%d lenQ:%d posT:%d lenT:%d", fn->posq,fn->nq,fn->post,fn->nt);
157 checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_numlevel, FieldNot *ptr)
162 int tlen = tree_numlevel,
163 qlen = query_numlevel;
165 lquery_level *prevq = NULL;
166 ltree_level *prevt = NULL;
170 high_pos = SomeStack.high_pos;
173 curq = LQL_NEXT(curq);
174 SomeStack.muse = false;
177 while (tlen > 0 && qlen > 0)
182 while (cur_tpos < low_pos)
184 curt = LEVEL_NEXT(curt);
193 if (ptr && curq->flag & LQL_NOT)
195 if (!(prevq && prevq->numvar == 0))
202 ptr->nq = 1 + ((prevq == curq) ? 0 : 1);
203 ptr->posq = query_numlevel - qlen - ((prevq == curq) ? 0 : 1);
204 ptr->post = cur_tpos;
212 if (qlen == 1 && ptr->q->numvar == 0)
213 ptr->nt = tree_numlevel - ptr->post;
214 curt = LEVEL_NEXT(curt);
217 if (high_pos < cur_tpos)
223 while (cur_tpos <= high_pos && tlen > 0 && !isok)
225 isok = checkLevel(curq, curt);
226 curt = LEVEL_NEXT(curt);
229 if (isok && prevq && prevq->numvar == 0 && tlen > 0 && cur_tpos <= high_pos)
234 memcpy(&tmpptr, ptr, sizeof(FieldNot));
235 SomeStack.high_pos = high_pos - cur_tpos;
236 SomeStack.muse = true;
237 if (checkCond(prevq, qlen + 1, curt, tlen, (ptr) ? &tmpptr : NULL))
248 if (checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL))
258 low_pos = cur_tpos + curq->low;
259 high_pos = cur_tpos + curq->high;
264 ptr->nt = tree_numlevel - ptr->post;
269 curq = LQL_NEXT(curq);
273 if (low_pos > tree_numlevel || tree_numlevel > high_pos)
280 if (!(curq->flag & LQL_NOT))
285 low_pos = cur_tpos + curq->low;
286 high_pos = cur_tpos + curq->high;
289 curq = LQL_NEXT(curq);
293 if (low_pos > tree_numlevel || tree_numlevel > high_pos)
296 if (ptr && ptr->q && checkCond(ptr->q, ptr->nq, ptr->t, ptr->nt, NULL))
303 ltq_regex(PG_FUNCTION_ARGS)
305 ltree *tree = PG_GETARG_LTREE(0);
306 lquery *query = PG_GETARG_LQUERY(1);
309 if (query->flag & LQUERY_HASNOT)
315 res = checkCond(LQUERY_FIRST(query), query->numlevel,
316 LTREE_FIRST(tree), tree->numlevel, &fn);
320 res = checkCond(LQUERY_FIRST(query), query->numlevel,
321 LTREE_FIRST(tree), tree->numlevel, NULL);
324 PG_FREE_IF_COPY(tree, 0);
325 PG_FREE_IF_COPY(query, 1);
330 ltq_rregex(PG_FUNCTION_ARGS)
332 PG_RETURN_DATUM(DirectFunctionCall2(ltq_regex,
339 lt_q_regex(PG_FUNCTION_ARGS)
341 ltree *tree = PG_GETARG_LTREE(0);
342 ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
343 lquery *query = (lquery *) ARR_DATA_PTR(_query);
345 int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
347 if (ARR_NDIM(_query) > 1)
349 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
350 errmsg("array must be one-dimensional")));
351 if (ARR_HASNULL(_query))
353 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
354 errmsg("array must not contain nulls")));
358 if (DatumGetBool(DirectFunctionCall2(ltq_regex,
359 PointerGetDatum(tree), PointerGetDatum(query))))
366 query = NEXTVAL(query);
369 PG_FREE_IF_COPY(tree, 0);
370 PG_FREE_IF_COPY(_query, 1);
375 lt_q_rregex(PG_FUNCTION_ARGS)
377 PG_RETURN_DATUM(DirectFunctionCall2(lt_q_regex,