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:55 UTC

[03/19] ignite git commit: Scalar function escape sequence support prototype implemented.

Scalar function escape sequence support prototype implemented.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/98a21256
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/98a21256
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/98a21256

Branch: refs/heads/ignite-3716
Commit: 98a21256b9aff373766521c18e662811433bfa76
Parents: f376cbb
Author: Andrey V. Mashenkov <an...@gmail.com>
Authored: Mon Aug 22 17:10:11 2016 +0300
Committer: Andrey V. Mashenkov <an...@gmail.com>
Committed: Mon Aug 22 17:10:11 2016 +0300

----------------------------------------------------------------------
 .../processors/odbc/escape/EscapeSQLParser.java | 108 +++++++++++++++++++
 .../OdbcScalarFunctionEscapeSequenceTest.java   |  49 +++++++++
 2 files changed, 157 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/98a21256/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
new file mode 100644
index 0000000..4630e7d
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSQLParser.java
@@ -0,0 +1,108 @@
+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/98a21256/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
new file mode 100644
index 0000000..7d60b42
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/odbc/OdbcScalarFunctionEscapeSequenceTest.java
@@ -0,0 +1,49 @@
+package org.apache.ignite.internal.processors.odbc;
+
+import junit.framework.TestCase;
+import org.apache.ignite.internal.processors.odbc.escape.EscapeSQLParser;
+
+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();
+
+        String actualRes = parser.parse(sqlQry);
+
+        assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
+
+
+        sqlQry = "select {fn func(field1)} {fn func(field2)}";
+        expRes = "select func(field1) func(field2)";
+
+        parser = new EscapeSQLParser();
+
+        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();
+
+        String actualResult = parser.parse(sqlQry);
+
+        assertEquals("Scalar function escape sequence parsing fails", expRes, actualResult);
+
+
+        sqlQry = "select {fn func1(field1, {fn func2(field2)}, field3)}";
+        expRes = "select func1(field1, func2(field2), field3)";
+
+        parser = new EscapeSQLParser();
+
+        actualResult = parser.parse(sqlQry);
+
+        assertEquals("Scalar function escape sequence parsing fails", expRes, actualResult);
+    }
+}