/* * 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 GinTernaryValue TS_execute_ternary(QueryItem *curitem, void *checkval, GinTernaryValue (*chkcond) (void *checkval, QueryOperand *val)) { GinTernaryValue 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_triconsistent(PG_FUNCTION_ARGS) { GinTernaryValue *check = (GinTernaryValue *) 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); GinTernaryValue res = GIN_FALSE; bool recheck; /* The query requires recheck only if it involves weights */ recheck = false; 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_TERNARY_VALUE(res); }
/* * Evaluate tsquery boolean expression using ternary logic. */ static GinTernaryValue TS_execute_ternary(GinChkVal *gcv, QueryItem *curitem, bool in_phrase) { GinTernaryValue val1, val2, result; /* since this function recurses, it could be driven to stack overflow */ check_stack_depth(); if (curitem->type == QI_VAL) return checkcondition_gin_internal(gcv, (QueryOperand *) curitem, NULL /* don't have position info */ ); switch (curitem->qoperator.oper) { case OP_NOT: /* In phrase search, always return MAYBE since we lack positions */ if (in_phrase) return GIN_MAYBE; result = TS_execute_ternary(gcv, curitem + 1, in_phrase); if (result == GIN_MAYBE) return result; return !result; case OP_PHRASE: /* * GIN doesn't contain any information about positions, so treat * OP_PHRASE as OP_AND with recheck requirement */ *(gcv->need_recheck) = true; /* Pass down in_phrase == true in case there's a NOT below */ in_phrase = true; /* FALL THRU */ case OP_AND: val1 = TS_execute_ternary(gcv, curitem + curitem->qoperator.left, in_phrase); if (val1 == GIN_FALSE) return GIN_FALSE; val2 = TS_execute_ternary(gcv, curitem + 1, in_phrase); 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(gcv, curitem + curitem->qoperator.left, in_phrase); if (val1 == GIN_TRUE) return GIN_TRUE; val2 = TS_execute_ternary(gcv, curitem + 1, in_phrase); 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; }