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