You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2016/09/14 11:10:34 UTC
[18/50] ignite git commit: IGNITE-3741: ODBC: Added character escape
support to expression parser. This closes #1004.
IGNITE-3741: ODBC: Added character escape support to expression parser. This closes #1004.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/008cf644
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/008cf644
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/008cf644
Branch: refs/heads/ignite-3661
Commit: 008cf64429f40635e396a71f2c0aaf184077ff2b
Parents: e353301
Author: Andrey V. Mashenkov <an...@gmail.com>
Authored: Mon Sep 5 15:17:53 2016 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Mon Sep 5 15:17:53 2016 +0300
----------------------------------------------------------------------
.../processors/odbc/escape/OdbcEscapeType.java | 9 ++-
.../processors/odbc/escape/OdbcEscapeUtils.java | 53 ++++++------
.../odbc/OdbcEscapeSequenceSelfTest.java | 85 +++++++++++++++++++-
3 files changed, 119 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/008cf644/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeType.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeType.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeType.java
index c7e3234..44d8361 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeType.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeType.java
@@ -42,8 +42,11 @@ public enum OdbcEscapeType {
/** GUID. */
GUID("guid", true, false),
- /** LIKE clause. */
- LIKE("\'", false, true);
+ /** LIKE escape character clause. */
+ ESCAPE_WO_TOKEN("\'", false, false),
+
+ /** LIKE escape character clause. */
+ ESCAPE("escape", true, false);
/** Values in convenient order. */
private static final OdbcEscapeType[] VALS = new OdbcEscapeType[] {
@@ -51,7 +54,7 @@ public enum OdbcEscapeType {
DATE, TIMESTAMP, // Date and timestamp are relatively frequent as well; also TS must go before T.
OUTER_JOIN, // Joins are less frequent,
CALL, // Procedure calls are less frequent than joins.
- LIKE, TIME, GUID // LIKE, TIME and GUID are even less frequent.
+ ESCAPE_WO_TOKEN, ESCAPE, TIME, GUID // LIKE, TIME and GUID are even less frequent.
};
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/008cf644/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
index 88afc52..bbf19c7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeUtils.java
@@ -76,12 +76,9 @@ public class OdbcEscapeUtils {
while (curPos < text.length()) {
char curChar = text.charAt(curPos);
- if (curChar == '\'') {
- if (!insideLiteral)
- insideLiteral = true;
- else if (text.charAt(curPos - 1) != '\\')
- insideLiteral = false;
- }
+ if (curChar == '\'')
+ /* Escaped quote in odbc is two successive singe quotes. They'll flip flag twice without side-effect. */
+ insideLiteral = !insideLiteral;
else if (!insideLiteral) {
if (curChar == '{') {
if (openPos == -1) {
@@ -173,11 +170,7 @@ public class OdbcEscapeUtils {
OdbcEscapeToken token = parseToken(text, startPos, len);
- if (token.type().standard())
- return parseStandardExpression(text, startPos, len, token);
- else
- throw new IgniteException("Unsupported escape sequence token [text=" +
- substring(text, startPos, len) + ", token=" + token.type().body() + ']');
+ return parseEscapeSequence(text, startPos, len, token);
}
else {
// Nothing to escape, return original string.
@@ -209,20 +202,17 @@ public class OdbcEscapeUtils {
for (OdbcEscapeType typ : OdbcEscapeType.sortedValues()) {
if (text.startsWith(typ.body(), pos)) {
- pos += typ.body().length();
+ if (typ.standard())
+ pos += typ.body().length();
- if (typ == OdbcEscapeType.LIKE)
- throw new IgniteException("LIKE escape sequence is not supported yet.");
- else {
- empty = (startPos + len == pos + 1);
+ empty = (startPos + len == pos + 1);
- if (!empty && typ.standard()) {
- char charAfter = text.charAt(pos);
+ if (!empty && typ.standard()) {
+ char charAfter = text.charAt(pos);
- if (!Character.isWhitespace(charAfter))
- throw new IgniteException("Unexpected escape sequence token: " +
- substring(text, startPos, len));
- }
+ if (!Character.isWhitespace(charAfter))
+ throw new IgniteException("Unexpected escape sequence token: " +
+ substring(text, startPos, len));
}
curTyp = typ;
@@ -249,7 +239,7 @@ public class OdbcEscapeUtils {
* @param token Token.
* @return Result.
*/
- private static String parseStandardExpression(String text, int startPos, int len, OdbcEscapeToken token) {
+ private static String parseEscapeSequence(String text, int startPos, int len, OdbcEscapeToken token) {
assert validSubstring(text, startPos, len);
// Get expression borders.
@@ -283,6 +273,11 @@ public class OdbcEscapeUtils {
return "CALL " + val;
}
+
+ case ESCAPE:
+ case ESCAPE_WO_TOKEN:
+ return parseLikeEscCharacterExpression(text, startPos0, len0);
+
default:
throw new IgniteException("Unsupported escape sequence token [text=" +
substring(text, startPos, len) + ", token=" + token.type().body() + ']');
@@ -302,6 +297,18 @@ public class OdbcEscapeUtils {
}
/**
+ * Parse LIKE escape character expression.
+ *
+ * @param text Text.
+ * @param startPos Start position.
+ * @param len Length.
+ * @return Parsed expression.
+ */
+ private static String parseLikeEscCharacterExpression(String text, int startPos, int len) {
+ return "ESCAPE " + substring(text, startPos, len).trim();
+ }
+
+ /**
* Parse expression and validate against ODBC specification with regex pattern.
*
* @param text Text.
http://git-wip-us.apache.org/repos/asf/ignite/blob/008cf644/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
index 26221ea..5303c6e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcEscapeSequenceSelfTest.java
@@ -528,9 +528,10 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest {
"select '{' + {fn func()} + '}' from table;"
);
+ // quoted two single quotes should be interpret as apostrophe
check(
- "select '{\\'{fn test()}\\'}' from table;",
- "select '{\\'{fn test()}\\'}' from table;"
+ "select '{''{fn test()}''}' from table;",
+ "select '{''{fn test()}''}' from table;"
);
checkFail("'{fn test()}");
@@ -666,6 +667,86 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest {
}
/**
+ * Test escape sequence series.
+ */
+ public void testLikeEscapeSequence() throws Exception {
+ check(
+ "ESCAPE '\\'",
+ "{'\\'}"
+ );
+
+ check(
+ "ESCAPE '\\'",
+ "{escape '\\'}"
+ );
+
+ check(
+ "ESCAPE ''",
+ "{''}"
+ );
+
+ check(
+ "ESCAPE ''",
+ "{escape ''}"
+ );
+
+ check(
+ "select * from t where value LIKE '\\%AAA%' ESCAPE '\\'",
+ "select * from t where value LIKE '\\%AAA%' {'\\'}"
+ );
+
+ check(
+ "select * from t where value LIKE '\\%AAA%' ESCAPE '\\'",
+ "select * from t where value LIKE '\\%AAA%' {escape '\\'}"
+ );
+
+ check(
+ "select * from t where value LIKE '\\%AAA%' ESCAPE '\\' ORDER BY id;",
+ "select * from t where value LIKE '\\%AAA%' {'\\'} ORDER BY id;"
+ );
+
+ check(
+ "select * from t where value LIKE '\\%AAA%' ESCAPE '\\' ORDER BY id;",
+ "select * from t where value LIKE '\\%AAA%' {escape '\\'} ORDER BY id;"
+ );
+
+ check(
+ "select * from t where value LIKE '\\%AAA''s%' ESCAPE '\\'",
+ "select * from t where value LIKE '\\%AAA''s%' {escape '\\'}"
+ );
+ }
+
+ /**
+ * Test escape sequences with additional whitespace characters
+ */
+ public void testLikeEscapeSequenceWithWhitespaces() throws Exception {
+ check("ESCAPE '\\'", "{ '\\' }");
+ check("ESCAPE '\\'", "{ escape '\\'}");
+
+ check("ESCAPE '\\'", "{ '\\' }");
+ check("ESCAPE '\\'", "{ escape '\\' }");
+
+ check("ESCAPE '\\'", "{ \n '\\' }");
+ check("ESCAPE '\\'", "{ \n escape\n'\\' }");
+ }
+
+ /**
+ * Test invalid escape sequence.
+ */
+ public void testLikeOnInvalidLikeEscapeSequence() {
+ checkFail("LIKE 'AAA's'");
+ checkFail("LIKE 'AAA\'s'");
+
+ checkFail("LIKE '\\%AAA%' {escape'\\' }");
+
+ checkFail("LIKE '\\%AAA%' {'\\' ORDER BY id");
+ checkFail("LIKE '\\%AAA%' {escape '\\' ORDER BY id;");
+
+ checkFail("LIKE '\\%AAA%' '\\'} ORDER BY id");
+ checkFail("LIKE '\\%AAA%' escape '\\'} ORDER BY id;");
+ }
+
+ /**
* Check parsing logic.
*
* @param exp Expected result.