aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/tsquery.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/tsquery.c')
-rw-r--r--src/backend/utils/adt/tsquery.c114
1 files changed, 52 insertions, 62 deletions
diff --git a/src/backend/utils/adt/tsquery.c b/src/backend/utils/adt/tsquery.c
index 21a18bfbc44..72e608eb913 100644
--- a/src/backend/utils/adt/tsquery.c
+++ b/src/backend/utils/adt/tsquery.c
@@ -26,10 +26,10 @@
/* FTS operator priorities, see ts_type.h */
const int tsearch_op_priority[OP_COUNT] =
{
- 3, /* OP_NOT */
+ 4, /* OP_NOT */
2, /* OP_AND */
1, /* OP_OR */
- 4 /* OP_PHRASE */
+ 3 /* OP_PHRASE */
};
struct TSQueryParserStateData
@@ -430,6 +430,40 @@ pushStop(TSQueryParserState state)
#define STACKDEPTH 32
+typedef struct OperatorElement {
+ int8 op;
+ int16 distance;
+} OperatorElement;
+
+static void
+pushOpStack(OperatorElement *stack, int *lenstack, int8 op, int16 distance)
+{
+ if (*lenstack == STACKDEPTH) /* internal error */
+ elog(ERROR, "tsquery stack too small");
+
+ stack[*lenstack].op = op;
+ stack[*lenstack].distance = distance;
+
+ (*lenstack)++;
+}
+
+static void
+cleanOpStack(TSQueryParserState state,
+ OperatorElement *stack, int *lenstack, int8 op)
+{
+ int opPriority = OP_PRIORITY(op);
+
+ while(*lenstack)
+ {
+ if (opPriority > OP_PRIORITY(stack[*lenstack - 1].op))
+ break;
+
+ (*lenstack)--;
+ pushOperator(state, stack[*lenstack].op,
+ stack[*lenstack].distance);
+ }
+}
+
/*
* Make polish (prefix) notation of query.
*
@@ -444,11 +478,7 @@ makepol(TSQueryParserState state,
ts_tokentype type;
int lenval = 0;
char *strval = NULL;
- struct
- {
- int8 op;
- int16 distance;
- } opstack[STACKDEPTH];
+ OperatorElement opstack[STACKDEPTH];
int lenstack = 0;
int16 weight = 0;
bool prefix;
@@ -462,49 +492,16 @@ makepol(TSQueryParserState state,
{
case PT_VAL:
pushval(opaque, state, strval, lenval, weight, prefix);
- while (lenstack && (opstack[lenstack - 1].op == OP_AND ||
- opstack[lenstack - 1].op == OP_PHRASE ||
- opstack[lenstack - 1].op == OP_NOT))
- {
- lenstack--;
- pushOperator(state,
- opstack[lenstack].op,
- opstack[lenstack].distance);
- }
break;
case PT_OPR:
- if (lenstack && operator == OP_OR)
- pushOperator(state, OP_OR, 0);
- else
- {
- if (lenstack == STACKDEPTH) /* internal error */
- elog(ERROR, "tsquery stack too small");
- opstack[lenstack].op = operator;
- opstack[lenstack].distance = weight;
- lenstack++;
- }
+ cleanOpStack(state, opstack, &lenstack, operator);
+ pushOpStack(opstack, &lenstack, operator, weight);
break;
case PT_OPEN:
makepol(state, pushval, opaque);
-
- while (lenstack && (opstack[lenstack - 1].op == OP_AND ||
- opstack[lenstack - 1].op == OP_PHRASE ||
- opstack[lenstack - 1].op == OP_NOT))
- {
- lenstack--;
- pushOperator(state,
- opstack[lenstack].op,
- opstack[lenstack].distance);
- }
break;
case PT_CLOSE:
- while (lenstack)
- {
- lenstack--;
- pushOperator(state,
- opstack[lenstack].op,
- opstack[lenstack].distance);
- };
+ cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */);
return;
case PT_ERR:
default:
@@ -514,13 +511,8 @@ makepol(TSQueryParserState state,
state->buffer)));
}
}
- while (lenstack)
- {
- lenstack--;
- pushOperator(state,
- opstack[lenstack].op,
- opstack[lenstack].distance);
- }
+
+ cleanOpStack(state, opstack, &lenstack, OP_OR /* lowest */);
}
static void
@@ -750,7 +742,7 @@ while( ( (inf)->cur - (inf)->buf ) + (addsize) + 1 >= (inf)->buflen ) \
* print it in infix (human-readable) form
*/
static void
-infix(INFIX *in, int parentPriority)
+infix(INFIX *in, int parentPriority, bool rightPhraseOp)
{
/* since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
@@ -819,7 +811,7 @@ infix(INFIX *in, int parentPriority)
}
else if (in->curpol->qoperator.oper == OP_NOT)
{
- int priority = PRINT_PRIORITY(in->curpol);
+ int priority = QO_PRIORITY(in->curpol);
if (priority < parentPriority)
{
@@ -833,7 +825,7 @@ infix(INFIX *in, int parentPriority)
*(in->cur) = '\0';
in->curpol++;
- infix(in, priority);
+ infix(in, priority, false);
if (priority < parentPriority)
{
RESIZEBUF(in, 2);
@@ -844,17 +836,15 @@ infix(INFIX *in, int parentPriority)
else
{
int8 op = in->curpol->qoperator.oper;
- int priority = PRINT_PRIORITY(in->curpol);
+ int priority = QO_PRIORITY(in->curpol);
int16 distance = in->curpol->qoperator.distance;
INFIX nrm;
bool needParenthesis = false;
in->curpol++;
if (priority < parentPriority ||
- (op == OP_PHRASE &&
- (priority == parentPriority || /* phrases are not
- * commutative! */
- parentPriority == OP_PRIORITY(OP_AND))))
+ /* phrase operator depends on order */
+ (op == OP_PHRASE && rightPhraseOp))
{
needParenthesis = true;
RESIZEBUF(in, 2);
@@ -868,11 +858,11 @@ infix(INFIX *in, int parentPriority)
nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
/* get right operand */
- infix(&nrm, priority);
+ infix(&nrm, priority, (op == OP_PHRASE));
/* get & print left operand */
in->curpol = nrm.curpol;
- infix(in, priority);
+ infix(in, priority, false);
/* print operator & right operand */
RESIZEBUF(in, 3 + (2 + 10 /* distance */ ) + (nrm.cur - nrm.buf));
@@ -924,7 +914,7 @@ tsqueryout(PG_FUNCTION_ARGS)
nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
*(nrm.cur) = '\0';
nrm.op = GETOPERAND(query);
- infix(&nrm, -1 /* lowest priority */ );
+ infix(&nrm, -1 /* lowest priority */, false);
PG_FREE_IF_COPY(query, 0);
PG_RETURN_CSTRING(nrm.buf);
@@ -1151,7 +1141,7 @@ tsquerytree(PG_FUNCTION_ARGS)
nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
*(nrm.cur) = '\0';
nrm.op = GETOPERAND(query);
- infix(&nrm, true);
+ infix(&nrm, -1, false);
res = cstring_to_text_with_len(nrm.buf, nrm.cur - nrm.buf);
pfree(q);
}