2 * op function for ltree and lquery
3 * Teodor Sigaev <teodor@stack.net>
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
,