summaryrefslogtreecommitdiffstats
path: root/contrib/ltree/ltxtquery_op.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ltree/ltxtquery_op.c')
-rw-r--r--contrib/ltree/ltxtquery_op.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/contrib/ltree/ltxtquery_op.c b/contrib/ltree/ltxtquery_op.c
new file mode 100644
index 0000000..002102c
--- /dev/null
+++ b/contrib/ltree/ltxtquery_op.c
@@ -0,0 +1,111 @@
+/*
+ * txtquery operations with ltree
+ * Teodor Sigaev <teodor@stack.net>
+ * contrib/ltree/ltxtquery_op.c
+ */
+#include "postgres.h"
+
+#include <ctype.h>
+
+#include "ltree.h"
+#include "miscadmin.h"
+
+PG_FUNCTION_INFO_V1(ltxtq_exec);
+PG_FUNCTION_INFO_V1(ltxtq_rexec);
+
+/*
+ * check for boolean condition
+ */
+bool
+ltree_execute(ITEM *curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM *val))
+{
+ /* since this function recurses, it could be driven to stack overflow */
+ check_stack_depth();
+
+ if (curitem->type == VAL)
+ return (*chkcond) (checkval, curitem);
+ else if (curitem->val == (int32) '!')
+ {
+ return calcnot ?
+ ((ltree_execute(curitem + 1, checkval, calcnot, chkcond)) ? false : true)
+ : true;
+ }
+ else if (curitem->val == (int32) '&')
+ {
+ if (ltree_execute(curitem + curitem->left, checkval, calcnot, chkcond))
+ return ltree_execute(curitem + 1, checkval, calcnot, chkcond);
+ else
+ return false;
+ }
+ else
+ { /* |-operator */
+ if (ltree_execute(curitem + curitem->left, checkval, calcnot, chkcond))
+ return true;
+ else
+ return ltree_execute(curitem + 1, checkval, calcnot, chkcond);
+ }
+}
+
+typedef struct
+{
+ ltree *node;
+ char *operand;
+} CHKVAL;
+
+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
+ltxtq_exec(PG_FUNCTION_ARGS)
+{
+ ltree *val = PG_GETARG_LTREE_P(0);
+ ltxtquery *query = PG_GETARG_LTXTQUERY_P(1);
+ CHKVAL chkval;
+ bool result;
+
+ chkval.node = val;
+ chkval.operand = GETOPERAND(query);
+
+ result = ltree_execute(GETQUERY(query),
+ &chkval,
+ true,
+ checkcondition_str);
+
+ PG_FREE_IF_COPY(val, 0);
+ PG_FREE_IF_COPY(query, 1);
+ PG_RETURN_BOOL(result);
+}
+
+Datum
+ltxtq_rexec(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_DATUM(DirectFunctionCall2(ltxtq_exec,
+ PG_GETARG_DATUM(1),
+ PG_GETARG_DATUM(0)
+ ));
+}