ARTEMIS-356 - better support for special characters in like selector escape

https://issues.apache.org/jira/browse/ARTEMIS-356
https://issues.apache.org/jira/browse/AMQ-6137
This commit is contained in:
gtully 2016-01-22 16:19:49 +00:00
parent 1c782e0bc3
commit a337df705e
2 changed files with 44 additions and 17 deletions

View File

@ -86,29 +86,14 @@ public abstract class ComparisonExpression extends BinaryExpression implements B
regexp.append("\\A"); // The beginning of the input regexp.append("\\A"); // The beginning of the input
for (int i = 0; i < like.length(); i++) { for (int i = 0; i < like.length(); i++) {
char c = like.charAt(i); char c = like.charAt(i);
if (escape == (0xFFFF & c)) { if (escape == (0xFFFF & c) && shouldEscapeNext(like, i, c)) {
i++; i++;
if (i >= like.length()) {
// nothing left to escape...
break;
}
char t = like.charAt(i); char t = like.charAt(i);
regexp.append("\\x"); regexp.append("\\x");
regexp.append(Integer.toHexString(0xFFFF & t)); 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 { else {
regexp.append(c); append(regexp, c);
} }
} }
regexp.append("\\z"); // The end of the input 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); 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() * @see org.apache.activemq.filter.UnaryExpression#getExpressionSymbol()
*/ */

View File

@ -448,6 +448,22 @@ public class SelectorTest {
assertSelector(message, "punctuation LIKE '!#$&()*+,-./:;<=>?@[\\]^`{|}~'", true); 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 @Test
public void testInvalidSelector() throws Exception { public void testInvalidSelector() throws Exception {
MockMessage message = createMessage(); MockMessage message = createMessage();
@ -476,6 +492,7 @@ public class SelectorTest {
message.setStringProperty("quote", "'In God We Trust'"); message.setStringProperty("quote", "'In God We Trust'");
message.setStringProperty("foo", "_foo"); message.setStringProperty("foo", "_foo");
message.setStringProperty("punctuation", "!#$&()*+,-./:;<=>?@[\\]^`{|}~"); message.setStringProperty("punctuation", "!#$&()*+,-./:;<=>?@[\\]^`{|}~");
message.setStringProperty("endingUnderScore", "XD7xlJIQn_");
message.setBooleanProperty("trueProp", true); message.setBooleanProperty("trueProp", true);
message.setBooleanProperty("falseProp", false); message.setBooleanProperty("falseProp", false);
return message; return message;