diff --git a/artemis-selector/src/main/java/org/apache/activemq/artemis/selector/filter/ComparisonExpression.java b/artemis-selector/src/main/java/org/apache/activemq/artemis/selector/filter/ComparisonExpression.java index 7ed8a08b08..7419788d70 100755 --- a/artemis-selector/src/main/java/org/apache/activemq/artemis/selector/filter/ComparisonExpression.java +++ b/artemis-selector/src/main/java/org/apache/activemq/artemis/selector/filter/ComparisonExpression.java @@ -86,29 +86,14 @@ public abstract class ComparisonExpression extends BinaryExpression implements B regexp.append("\\A"); // The beginning of the input for (int i = 0; i < like.length(); i++) { char c = like.charAt(i); - if (escape == (0xFFFF & c)) { + if (escape == (0xFFFF & c) && shouldEscapeNext(like, i, c)) { i++; - if (i >= like.length()) { - // nothing left to escape... - break; - } - char t = like.charAt(i); regexp.append("\\x"); regexp.append(Integer.toHexString(0xFFFF & t)); } - else if (c == '%') { - regexp.append(".*?"); // Do a non-greedy match - } - else if (c == '_') { - regexp.append("."); // match one - } - else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) { - regexp.append("\\x"); - regexp.append(Integer.toHexString(0xFFFF & c)); - } else { - regexp.append(c); + append(regexp, c); } } regexp.append("\\z"); // The end of the input @@ -116,6 +101,31 @@ public abstract class ComparisonExpression extends BinaryExpression implements B likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL); } + private boolean shouldEscapeNext(String selector, int i, char escape) { + int next = i + 1; + if (next < selector.length()) { + final char c = selector.charAt(next); + return (c == '_' || c == '%' || c == escape); + } + return false; + } + + private void append(StringBuffer regexp, char c) { + if (c == '%') { + regexp.append(".*?"); // Do a non-greedy match + } + else if (c == '_') { + regexp.append("."); // match one + } + else if (REGEXP_CONTROL_CHARS.contains(new Character(c))) { + regexp.append("\\x"); + regexp.append(Integer.toHexString(0xFFFF & c)); + } + else { + regexp.append(c); + } + } + /** * @see org.apache.activemq.filter.UnaryExpression#getExpressionSymbol() */ diff --git a/artemis-selector/src/test/java/org/apache/activemq/artemis/selector/SelectorTest.java b/artemis-selector/src/test/java/org/apache/activemq/artemis/selector/SelectorTest.java index bfb67a7e91..223a0df6ab 100755 --- a/artemis-selector/src/test/java/org/apache/activemq/artemis/selector/SelectorTest.java +++ b/artemis-selector/src/test/java/org/apache/activemq/artemis/selector/SelectorTest.java @@ -448,6 +448,22 @@ public class SelectorTest { assertSelector(message, "punctuation LIKE '!#$&()*+,-./:;<=>?@[\\]^`{|}~'", true); } + @Test + public void testSpecialEscapeLiteral() throws Exception { + MockMessage message = createMessage(); + assertSelector(message, "foo LIKE '%_%' ESCAPE '%'", true); + assertSelector(message, "endingUnderScore LIKE '_D7xlJIQn$_' ESCAPE '$'", true); + assertSelector(message, "endingUnderScore LIKE '_D7xlJIQn__' ESCAPE '_'", true); + assertSelector(message, "endingUnderScore LIKE '%D7xlJIQn%_' ESCAPE '%'", true); + assertSelector(message, "endingUnderScore LIKE '%D7xlJIQn%' ESCAPE '%'", true); + + // literal '%' at the end, no match + assertSelector(message, "endingUnderScore LIKE '%D7xlJIQn%%' ESCAPE '%'", false); + + assertSelector(message, "endingUnderScore LIKE '_D7xlJIQn\\_' ESCAPE '\\'", true); + assertSelector(message, "endingUnderScore LIKE '%D7xlJIQn\\_' ESCAPE '\\'", true); + } + @Test public void testInvalidSelector() throws Exception { MockMessage message = createMessage(); @@ -476,6 +492,7 @@ public class SelectorTest { message.setStringProperty("quote", "'In God We Trust'"); message.setStringProperty("foo", "_foo"); message.setStringProperty("punctuation", "!#$&()*+,-./:;<=>?@[\\]^`{|}~"); + message.setStringProperty("endingUnderScore", "XD7xlJIQn_"); message.setBooleanProperty("trueProp", true); message.setBooleanProperty("falseProp", false); return message;