aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r--src/backend/utils/adt/tsginidx.c104
1 files changed, 102 insertions, 2 deletions
diff --git a/src/backend/utils/adt/tsginidx.c b/src/backend/utils/adt/tsginidx.c
index 9f6e8e9fd57..47685e8b930 100644
--- a/src/backend/utils/adt/tsginidx.c
+++ b/src/backend/utils/adt/tsginidx.c
@@ -15,6 +15,7 @@
#include "access/gin.h"
#include "access/skey.h"
+#include "miscadmin.h"
#include "tsearch/ts_type.h"
#include "tsearch/ts_utils.h"
#include "utils/builtins.h"
@@ -172,12 +173,12 @@ gin_extract_tsquery(PG_FUNCTION_ARGS)
typedef struct
{
QueryItem *first_item;
- bool *check;
+ GinLogicValue *check;
int *map_item_operand;
bool *need_recheck;
} GinChkVal;
-static bool
+static GinLogicValue
checkcondition_gin(void *checkval, QueryOperand *val)
{
GinChkVal *gcv = (GinChkVal *) checkval;
@@ -194,6 +195,66 @@ checkcondition_gin(void *checkval, QueryOperand *val)
return gcv->check[j];
}
+/*
+ * Evaluate tsquery boolean expression using ternary logic.
+ *
+ * chkcond is a callback function used to evaluate each VAL node in the query.
+ * checkval can be used to pass information to the callback. TS_execute doesn't
+ * do anything with it.
+ */
+static GinLogicValue
+TS_execute_ternary(QueryItem *curitem, void *checkval,
+ GinLogicValue (*chkcond) (void *checkval, QueryOperand *val))
+{
+ GinLogicValue val1, val2, result;
+ /* since this function recurses, it could be driven to stack overflow */
+ check_stack_depth();
+
+ if (curitem->type == QI_VAL)
+ return chkcond(checkval, (QueryOperand *) curitem);
+
+ switch (curitem->qoperator.oper)
+ {
+ case OP_NOT:
+ result = TS_execute_ternary(curitem + 1, checkval, chkcond);
+ if (result == GIN_MAYBE)
+ return result;
+ return !result;
+
+ case OP_AND:
+ val1 = TS_execute_ternary(curitem + curitem->qoperator.left,
+ checkval, chkcond);
+ if (val1 == GIN_FALSE)
+ return GIN_FALSE;
+ val2 = TS_execute_ternary(curitem + 1, checkval, chkcond);
+ if (val2 == GIN_FALSE)
+ return GIN_FALSE;
+ if (val1 == GIN_TRUE && val2 == GIN_TRUE)
+ return GIN_TRUE;
+ else
+ return GIN_MAYBE;
+
+ case OP_OR:
+ val1 = TS_execute_ternary(curitem + curitem->qoperator.left,
+ checkval, chkcond);
+ if (val1 == GIN_TRUE)
+ return GIN_TRUE;
+ val2 = TS_execute_ternary(curitem + 1, checkval, chkcond);
+ if (val2 == GIN_TRUE)
+ return GIN_TRUE;
+ if (val1 == GIN_FALSE && val2 == GIN_FALSE)
+ return GIN_FALSE;
+ else
+ return GIN_MAYBE;
+
+ default:
+ elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
+ }
+
+ /* not reachable, but keep compiler quiet */
+ return false;
+}
+
Datum
gin_tsquery_consistent(PG_FUNCTION_ARGS)
{
@@ -233,6 +294,45 @@ gin_tsquery_consistent(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(res);
}
+Datum
+gin_tsquery_triconsistent(PG_FUNCTION_ARGS)
+{
+ GinLogicValue *check = (GinLogicValue *) PG_GETARG_POINTER(0);
+
+ /* StrategyNumber strategy = PG_GETARG_UINT16(1); */
+ TSQuery query = PG_GETARG_TSQUERY(2);
+
+ /* int32 nkeys = PG_GETARG_INT32(3); */
+ Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
+ GinLogicValue res = GIN_FALSE;
+ bool recheck;
+
+ /* The query requires recheck only if it involves weights */
+ if (query->size > 0)
+ {
+ QueryItem *item;
+ GinChkVal gcv;
+
+ /*
+ * check-parameter array has one entry for each value (operand) in the
+ * query.
+ */
+ gcv.first_item = item = GETQUERY(query);
+ gcv.check = check;
+ gcv.map_item_operand = (int *) (extra_data[0]);
+ gcv.need_recheck = &recheck;
+
+ res = TS_execute_ternary(GETQUERY(query),
+ &gcv,
+ checkcondition_gin);
+
+ if (res == GIN_TRUE && recheck)
+ res = GIN_MAYBE;
+ }
+
+ PG_RETURN_GIN_LOGIC_VALUE(res);
+}
+
/*
* Formerly, gin_extract_tsvector had only two arguments. Now it has three,
* but we still need a pg_proc entry with two args to support reloading