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/08/24 08:48:57 UTC
[05/19] ignite git commit: Scalar function escape sequence support
prototype implemented. Quotation support added.
Scalar function escape sequence support prototype implemented.
Quotation support added.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/06df2492
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/06df2492
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/06df2492
Branch: refs/heads/ignite-3716
Commit: 06df24921b3e36ef14813688e52e93baba77b4f1
Parents: 98a2125
Author: Andrey V. Mashenkov <an...@gmail.com>
Authored: Mon Aug 22 18:12:31 2016 +0300
Committer: Andrey V. Mashenkov <an...@gmail.com>
Committed: Mon Aug 22 18:18:51 2016 +0300
----------------------------------------------------------------------
.../processors/odbc/escape/EscapeSQLParser.java | 108 ----------------
.../odbc/escape/OdbcEscapeSequenceParser.java | 126 +++++++++++++++++++
.../OdbcScalarFunctionEscapeSequenceTest.java | 80 ++++++++++--
3 files changed, 197 insertions(+), 117 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/06df2492/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSQLParser.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSQLParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSQLParser.java
deleted file mode 100644
index 4630e7d..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSQLParser.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.apache.ignite.internal.processors.odbc.escape;
-
-import org.apache.ignite.internal.util.typedef.T2;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Process ODBC escape sequences in sql query.
- * See ODBC escape sequence syntax.
- */
-public class EscapeSQLParser {
-
- /**
- * Process ODBC escape sequences in sql query.
- * @param sql - sql query text
- * @return - processed sql query text
- */
- public String parse(String sql) {
- T2<Integer, String> value = parseInternal(sql, 0, false);
-
- return value.get2();
- }
-
- /**
- * Parse escape sequence using appropriate parser.
- * Supports:
- * - Scalar function escape sequence. Example: "{fn func(arg1, arg2)}"
- *
- * @param sql - sql query text
- * @param startPosition - parser start position
- * @return pair of end of processed sequence position and parse result
- */
- T2<Integer, String> parseEscapeSqeuence(String sql, int startPosition) {
- assert sql.charAt(startPosition) == '{';
-
- int pos = sql.indexOf(' ', startPosition + 1);
-
- if (pos == -1)
- throw new IllegalStateException("Escape sequence parsing error at (" + startPosition + "): " + sql);
-
- String esType = sql.substring(startPosition + 1, pos);
-
- switch (esType) {
- case "fn":
- return parseInternal(sql, pos + 1, true);
-
- default:
- throw new IllegalStateException("Unsupported escape sequence found at (" + startPosition + "): " + sql);
- }
- }
-
- /**
- * Process ODBC escape sequences in sql query.
- * @param sql - sql query text
- * @param startPosition - parser start position
- * @param insideEscapeSequence - inside escape sequence flag
- * @return pair of end of processed sequence position and parse result
- */
- @NotNull private T2<Integer, String> parseInternal(String sql, int startPosition, boolean insideEscapeSequence) {
- StringBuffer sb = null;
-
- int end = -1;
- int offset = startPosition;
-
- for (int i = startPosition; i < sql.length(); i++) {
- // Current escape sequence ends up.
- if (sql.charAt(i) == '}') {
- end = i;
-
- break;
- }
- // Inner escape sequence starts
- else if (sql.charAt(i) == '{') {
- T2<Integer, String> res = parseEscapeSqeuence(sql, i);
-
- if (sb == null)
- sb = new StringBuffer();
-
- sb.append(sql, offset, i);
- sb.append(res.get2());
-
- i = res.get1();
-
- assert sql.charAt(i) == '}';
-
- offset = res.get1() + 1;
- }
- }
-
- if (insideEscapeSequence && end == -1)
- // Closing bracket character '}' was not found in inner escape sequence
- throw new IllegalStateException("Escape sequence started at position (" + startPosition + ") is not closed: " + sql);
- else if (!insideEscapeSequence && end != -1)
- // Closing bracket character '}' was found out of escape sequence
- throw new IllegalStateException("Unexpected end of escaped sequence found at position (" + startPosition + ") is not closed: " + sql);
-
- if (end == -1)
- end = sql.length();
-
- // Add tail to the result
- if (sb == null)
- return new T2<>(end, sql.substring(startPosition, end));
- else if (offset < end)
- sb.append(sql, offset, end);
-
- return new T2<>(end, sb.toString());
- }
-
-}
http://git-wip-us.apache.org/repos/asf/ignite/blob/06df2492/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceParser.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceParser.java
new file mode 100644
index 0000000..cfaa7c0
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceParser.java
@@ -0,0 +1,126 @@
+package org.apache.ignite.internal.processors.odbc.escape;
+
+import org.apache.ignite.internal.util.typedef.T2;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Process ODBC escape sequences in sql query.
+ * See ODBC escape sequence syntax.
+ */
+public class OdbcEscapeSequenceParser {
+
+ /**
+ * Process ODBC escape sequences in sql query.
+ *
+ * @param sql - sql query text
+ * @return - processed sql query text
+ */
+ public String parse(String sql) {
+ T2<Integer, String> val = parseInternal(sql, 0, false);
+
+ return val.get2();
+ }
+
+ /**
+ * Parse escape sequence using appropriate parser.
+ * Supports:
+ * - Scalar function escape sequence. Example: "{fn func(arg1, arg2)}"
+ *
+ * @param sql - sql query text
+ * @param startPosition - parser start position
+ * @return pair of end of processed sequence position and parse result
+ */
+ private T2<Integer, String> parseEscapeSqeuence(String sql, int startPosition) {
+ assert sql.charAt(startPosition) == '{';
+
+ int pos = sql.indexOf(' ', startPosition + 1);
+
+ if (pos == -1)
+ throw new IllegalStateException("Escape sequence parsing error at (" + startPosition + "): " + sql);
+
+ String esType = sql.substring(startPosition + 1, pos);
+
+ switch (esType) {
+ case "fn":
+ return parseInternal(sql, pos + 1, true);
+
+ default:
+ throw new IllegalStateException("Unsupported escape sequence found at (" + startPosition + "): " + sql);
+ }
+ }
+
+ /**
+ * Process ODBC escape sequences in sql query.
+ *
+ * @param sql - sql query text
+ * @param startPosition - parser start position
+ * @param insideEscapeSeq - inside escape sequence flag
+ * @return pair of end of processed sequence position and parse result
+ */
+ @NotNull private T2<Integer, String> parseInternal(String sql, int startPosition, boolean insideEscapeSeq) {
+ StringBuffer sb = null;
+
+ int off = startPosition;
+ int seqEndPos = -1;
+
+ char quoted = 0;
+
+ for (int i = startPosition; i < sql.length(); i++) {
+ char ch = sql.charAt(i);
+
+ if ((ch == '\'' || ch == '"') && (i == 0 || sql.charAt(i - 1) != '\\')) {
+ if (quoted == 0)
+ quoted = ch;
+ else if (quoted == ch)
+ quoted = 0;
+
+ continue;
+ }
+
+ if (quoted > 0)
+ continue;
+
+ // Current escape sequence ends up.
+ if (ch == '}') {
+ seqEndPos = i;
+
+ break;
+ }
+ // Inner escape sequence starts
+ else if (ch == '{') {
+ T2<Integer, String> res = parseEscapeSqeuence(sql, i);
+
+ if (sb == null)
+ sb = new StringBuffer();
+
+ sb.append(sql, off, i);
+ sb.append(res.get2());
+
+ i = res.get1();
+
+ assert sql.charAt(res.get1()) == '}';
+
+ off = res.get1() + 1;
+ }
+ }
+
+ if (insideEscapeSeq && seqEndPos == -1)
+ // Closing bracket character '}' was not found in inner escape sequence
+ throw new IllegalStateException("Escape sequence started at position (" + startPosition + ") is not closed: " + sql);
+ else if (!insideEscapeSeq && seqEndPos != -1)
+ // Closing bracket character '}' was found out of escape sequence
+ throw new IllegalStateException("Unexpected seqEndPos of escaped sequence found at position (" + startPosition + ") is not closed: " + sql);
+
+ if (seqEndPos == -1)
+ seqEndPos = sql.length();
+
+ // Add tail to the result
+ if (sb == null)
+ return new T2<>(seqEndPos, sql.substring(startPosition, seqEndPos));
+ else if (off < seqEndPos)
+ sb.append(sql, off, seqEndPos);
+
+ return new T2<>(seqEndPos, sb.toString());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/06df2492/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcScalarFunctionEscapeSequenceTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcScalarFunctionEscapeSequenceTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcScalarFunctionEscapeSequenceTest.java
index 7d60b42..9c6cf7f 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcScalarFunctionEscapeSequenceTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcScalarFunctionEscapeSequenceTest.java
@@ -1,15 +1,21 @@
package org.apache.ignite.internal.processors.odbc;
+import java.util.concurrent.Callable;
import junit.framework.TestCase;
-import org.apache.ignite.internal.processors.odbc.escape.EscapeSQLParser;
+import org.apache.ignite.internal.processors.odbc.escape.OdbcEscapeSequenceParser;
+import org.apache.ignite.testframework.GridTestUtils;
+/**
+ *
+ */
public class OdbcScalarFunctionEscapeSequenceTest extends TestCase {
+ /** */
public void testTrivialFunction() throws Exception {
String sqlQry = "select {fn func(field1)} {fn func(field2)} from table;";
String expRes = "select func(field1) func(field2) from table;";
- EscapeSQLParser parser = new EscapeSQLParser();
+ OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
String actualRes = parser.parse(sqlQry);
@@ -19,31 +25,87 @@ public class OdbcScalarFunctionEscapeSequenceTest extends TestCase {
sqlQry = "select {fn func(field1)} {fn func(field2)}";
expRes = "select func(field1) func(field2)";
- parser = new EscapeSQLParser();
+ parser = new OdbcEscapeSequenceParser();
actualRes = parser.parse(sqlQry);
assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
}
+ /** */
public void testNestedFunction() throws Exception {
String sqlQry = "select {fn func1(field1, {fn func2(field2)}, field3)} from SomeTable;";
String expRes = "select func1(field1, func2(field2), field3) from SomeTable;";
- EscapeSQLParser parser = new EscapeSQLParser();
+ OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
- String actualResult = parser.parse(sqlQry);
+ String actualRes = parser.parse(sqlQry);
- assertEquals("Scalar function escape sequence parsing fails", expRes, actualResult);
+ assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
sqlQry = "select {fn func1(field1, {fn func2(field2)}, field3)}";
expRes = "select func1(field1, func2(field2), field3)";
- parser = new EscapeSQLParser();
+ parser = new OdbcEscapeSequenceParser();
+
+ actualRes = parser.parse(sqlQry);
+
+ assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
+ }
+
+ /** */
+ public void testEscapeSequenceWithQuotation() throws Exception {
+ String sqlQry = "select {fn func1(field1, {fn func2(\"}\")}, field3)} from SomeTable;";
+ String expRes = "select func1(field1, func2(\"}\"), field3) from SomeTable;";
+
+ OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
+
+ String actualRes = parser.parse(sqlQry);
+
+ assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
+
+ sqlQry = "select {fn func1(field1, '\\'{fn f(arg)}', field3)} from SomeTable;";
+ expRes = "select func1(field1, '\\\'{fn f(arg)}', field3) from SomeTable;";
+
+ parser = new OdbcEscapeSequenceParser();
+
+ actualRes = parser.parse(sqlQry);
+
+ assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
+ }
+
+ /** */
+ public void testFailedOnNotClosedSequence() throws Exception {
+ GridTestUtils.assertThrows(null, new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ String sqlQry = "select {fn func1(field1, {fn func2(field2), field3)} from SomeTable;";
+
+ OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
+
+ parser.parse(sqlQry);
+
+ fail("Scalar function escape sequence parsing should failed");
+
+ return null;
+ }
+ }, IllegalStateException.class, null);
+ }
+
+ /** */
+ public void testFailedOnClosingNotOpenedSequence() throws Exception {
+ GridTestUtils.assertThrows(null, new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ String sqlQry = "select {fn func1(field1, func2(field2)}, field3)} from SomeTable;";
+
+ OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
+
+ parser.parse(sqlQry);
- actualResult = parser.parse(sqlQry);
+ fail("Scalar function escape sequence parsing should failed");
- assertEquals("Scalar function escape sequence parsing fails", expRes, actualResult);
+ return null;
+ }
+ }, IllegalStateException.class, null);
}
}