1 /*
2 * txtquery operations with ltree
3 * Teodor Sigaev <teodor@stack.net>
4 * contrib/ltree/ltxtquery_op.c
5 */
6 #include "postgres.h"
7
8 #include <ctype.h>
9
10 #include "ltree.h"
11 #include "miscadmin.h"
12
13 PG_FUNCTION_INFO_V1(ltxtq_exec);
14 PG_FUNCTION_INFO_V1(ltxtq_rexec);
15
16 /*
17 * check for boolean condition
18 */
19 bool
ltree_execute(ITEM * curitem,void * checkval,bool calcnot,bool (* chkcond)(void * checkval,ITEM * val))20 ltree_execute(ITEM *curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM *val))
21 {
22 /* since this function recurses, it could be driven to stack overflow */
23 check_stack_depth();
24
25 if (curitem->type == VAL)
26 return (*chkcond) (checkval, curitem);
27 else if (curitem->val == (int32) '!')
28 {
29 return (calcnot) ?
30 ((ltree_execute(curitem + 1, checkval, calcnot, chkcond)) ? false : true)
31 : true;
32 }
33 else if (curitem->val == (int32) '&')
34 {
35 if (ltree_execute(curitem + curitem->left, checkval, calcnot, chkcond))
36 return ltree_execute(curitem + 1, checkval, calcnot, chkcond);
37 else
38 return false;
39 }
40 else
41 { /* |-operator */
42 if (ltree_execute(curitem + curitem->left, checkval, calcnot, chkcond))
43 return true;
44 else
45 return ltree_execute(curitem + 1, checkval, calcnot, chkcond);
46 }
47 }
48
49 typedef struct
50 {
51 ltree *node;
52 char *operand;
53 } CHKVAL;
54
55 static bool
checkcondition_str(void * checkval,ITEM * val)56 checkcondition_str(void *checkval, ITEM *val)
57 {
58 ltree_level *level = LTREE_FIRST(((CHKVAL *) checkval)->node);
59 int tlen = ((CHKVAL *) checkval)->node->numlevel;
60 char *op = ((CHKVAL *) checkval)->operand + val->distance;
61 int (*cmpptr) (const char *, const char *, size_t);
62
63 cmpptr = (val->flag & LVAR_INCASE) ? ltree_strncasecmp : strncmp;
64 while (tlen > 0)
65 {
66 if (val->flag & LVAR_SUBLEXEME)
67 {
68 if (compare_subnode(level, op, val->length, cmpptr, (val->flag & LVAR_ANYEND)))
69 return true;
70 }
71 else if (
72 (
73 val->length == level->len ||
74 (level->len > val->length && (val->flag & LVAR_ANYEND))
75 ) &&
76 (*cmpptr) (op, level->name, val->length) == 0)
77 return true;
78
79 tlen--;
80 level = LEVEL_NEXT(level);
81 }
82
83 return false;
84 }
85
86 Datum
ltxtq_exec(PG_FUNCTION_ARGS)87 ltxtq_exec(PG_FUNCTION_ARGS)
88 {
89 ltree *val = PG_GETARG_LTREE(0);
90 ltxtquery *query = PG_GETARG_LTXTQUERY(1);
91 CHKVAL chkval;
92 bool result;
93
94 chkval.node = val;
95 chkval.operand = GETOPERAND(query);
96
97 result = ltree_execute(
98 GETQUERY(query),
99 &chkval,
100 true,
101 checkcondition_str
102 );
103
104 PG_FREE_IF_COPY(val, 0);
105 PG_FREE_IF_COPY(query, 1);
106 PG_RETURN_BOOL(result);
107 }
108
109 Datum
ltxtq_rexec(PG_FUNCTION_ARGS)110 ltxtq_rexec(PG_FUNCTION_ARGS)
111 {
112 PG_RETURN_DATUM(DirectFunctionCall2(ltxtq_exec,
113 PG_GETARG_DATUM(1),
114 PG_GETARG_DATUM(0)
115 ));
116 }
117