summaryrefslogtreecommitdiff
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rw-r--r--cpp/src/qpid/broker/SelectorExpression.cpp69
-rw-r--r--cpp/src/tests/Selector.cpp7
2 files changed, 57 insertions, 19 deletions
diff --git a/cpp/src/qpid/broker/SelectorExpression.cpp b/cpp/src/qpid/broker/SelectorExpression.cpp
index 5b8621b518..62de067396 100644
--- a/cpp/src/qpid/broker/SelectorExpression.cpp
+++ b/cpp/src/qpid/broker/SelectorExpression.cpp
@@ -67,8 +67,10 @@
*
* ComparisonExpression ::= PrimaryExpression "IS" "NULL" |
* PrimaryExpression "IS" "NOT" "NULL" |
- * PrimaryExpression "LIKE" LiteralString [ "ESCAPE" LiteralString ]
- * PrimaryExpression "NOT" "LIKE" LiteralString [ "ESCAPE" LiteralString ]
+ * PrimaryExpression "LIKE" LiteralString [ "ESCAPE" LiteralString ] |
+ * PrimaryExpression "NOT" "LIKE" LiteralString [ "ESCAPE" LiteralString ] |
+ * PrimaryExpression "BETWEEN" PrimaryExpression "AND" PrimaryExpression |
+ * PrimaryExpression "NOT" "BETWEEN" PrimaryExpression "AND" PrimaryExpression |
* PrimaryExpression ComparisonOpsOps PrimaryExpression |
* "NOT" ComparisonExpression |
* "(" OrExpression ")"
@@ -318,6 +320,34 @@ public:
}
};
+class BetweenExpression : public BoolExpression {
+ boost::scoped_ptr<Expression> e;
+ boost::scoped_ptr<Expression> l;
+ boost::scoped_ptr<Expression> u;
+
+public:
+ BetweenExpression(Expression* e_, Expression* l_, Expression* u_) :
+ e(e_),
+ l(l_),
+ u(u_)
+ {}
+
+ void repr(ostream& os) const {
+ os << *e << " BETWEEN " << *l << " AND " << *u;
+ }
+
+ BoolOrNone eval_bool(const SelectorEnv& env) const {
+ Value ve(e->eval(env));
+ if (unknown(ve)) return BN_UNKNOWN;
+ Value vl(l->eval(env));
+ if (unknown(vl)) return BN_UNKNOWN;
+ if (ve<vl) return BN_FALSE;
+ Value vu(u->eval(env));
+ if (unknown(vu)) return BN_UNKNOWN;
+ return BoolOrNone(ve<=vu);
+ }
+};
+
// Expression types...
class Literal : public Expression {
@@ -570,23 +600,25 @@ BoolExpression* parseSpecialComparisons(Tokeniser& tokeniser, std::auto_ptr<Expr
switch (tokeniser.nextToken().type) {
case T_LIKE: {
const Token t = tokeniser.nextToken();
- if ( t.type==T_STRING ) {
- // Check for "ESCAPE"
- if ( tokeniser.nextToken().type==T_ESCAPE ) {
- const Token e = tokeniser.nextToken();
- if ( e.type==T_STRING ) {
- return new LikeExpression(e1.release(), t.val, e.val);
- } else {
- return 0;
- }
- } else {
- tokeniser.returnTokens();
- return new LikeExpression(e1.release(), t.val);
- }
+ if ( t.type!=T_STRING ) return 0;
+ // Check for "ESCAPE"
+ if ( tokeniser.nextToken().type==T_ESCAPE ) {
+ const Token e = tokeniser.nextToken();
+ if ( e.type!=T_STRING ) return 0;
+ return new LikeExpression(e1.release(), t.val, e.val);
} else {
- return 0;
+ tokeniser.returnTokens();
+ return new LikeExpression(e1.release(), t.val);
}
}
+ case T_BETWEEN: {
+ std::auto_ptr<Expression> lower(parsePrimaryExpression(tokeniser));
+ if ( !lower.get() ) return 0;
+ if ( tokeniser.nextToken().type!=T_AND ) return 0;
+ std::auto_ptr<Expression> upper(parsePrimaryExpression(tokeniser));
+ if ( !upper.get() ) return 0;
+ return new BetweenExpression(e1.release(), lower.release(), upper.release());
+ }
default:
return 0;
}
@@ -628,11 +660,10 @@ BoolExpression* parseComparisonExpression(Tokeniser& tokeniser)
if (!e.get()) return 0;
return new UnaryBooleanExpression<BoolExpression>(&notOp, e.release());
}
+ case T_BETWEEN:
case T_LIKE: {
tokeniser.returnTokens();
- std::auto_ptr<BoolExpression> e(parseSpecialComparisons(tokeniser, e1));
- if (!e.get()) return 0;
- return e.release();
+ return parseSpecialComparisons(tokeniser, e1);
}
default:
break;
diff --git a/cpp/src/tests/Selector.cpp b/cpp/src/tests/Selector.cpp
index 7208f80e85..1b0eea3d7e 100644
--- a/cpp/src/tests/Selector.cpp
+++ b/cpp/src/tests/Selector.cpp
@@ -186,6 +186,9 @@ QPID_AUTO_TEST_CASE(parseStringFail)
BOOST_CHECK_THROW(qb::Selector e("A not 234 escape"), std::range_error);
BOOST_CHECK_THROW(qb::Selector e("A not like 'eclecti_' escape 'happy'"), std::range_error);
BOOST_CHECK_THROW(qb::Selector e("A not like 'eclecti_' escape happy"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A BETWEEN AND 'true'"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A NOT BETWEEN (X=Y) AND 3.9"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A NOT BETWEEN 34 OR 3.9"), std::range_error);
}
class TestSelectorEnv : public qpid::broker::SelectorEnv {
@@ -240,6 +243,8 @@ QPID_AUTO_TEST_CASE(parseString)
BOOST_CHECK_NO_THROW(qb::Selector e("A LIKE 'excep%ional'"));
BOOST_CHECK_NO_THROW(qb::Selector e("B NOT LIKE 'excep%ional'"));
BOOST_CHECK_NO_THROW(qb::Selector e("A LIKE 'excep%ional' EScape '\'"));
+ BOOST_CHECK_NO_THROW(qb::Selector e("A BETWEEN 13 AND 'true'"));
+ BOOST_CHECK_NO_THROW(qb::Selector e("A NOT BETWEEN 100 AND 3.9"));
}
QPID_AUTO_TEST_CASE(simpleEval)
@@ -291,6 +296,8 @@ QPID_AUTO_TEST_CASE(numericEval)
BOOST_CHECK(qb::Selector("B=39.0").eval(env));
BOOST_CHECK(qb::Selector("Not A=17 or B=5.6").eval(env));
BOOST_CHECK(!qb::Selector("A<>17 and B=5.6e17").eval(env));
+ BOOST_CHECK(qb::Selector("A BETWEEN B and 98.5").eval(env));
+ BOOST_CHECK(!qb::Selector("B NOT BETWEEN 35 AND 100").eval(env));
}
QPID_AUTO_TEST_CASE(comparisonEval)