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/23 09:39:17 UTC
[08/12] 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/902b45ba
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/902b45ba
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/902b45ba
Branch: refs/heads/ignite-3716-1
Commit: 902b45ba0a85a8b66b7f40d3865b7aaa3a367a30
Parents: 4c96007
Author: Andrey V. Mashenkov <an...@gmail.com>
Authored: Mon Aug 22 20:27:34 2016 +0300
Committer: Andrey V. Mashenkov <an...@gmail.com>
Committed: Mon Aug 22 20:27:34 2016 +0300
----------------------------------------------------------------------
.../odbc/escape/EscapeSequenceParseResult.java | 46 +++++++
.../odbc/escape/EscapeSequenceParser.java | 32 +++++
.../odbc/escape/OdbcEscapeSequenceParser.java | 129 -------------------
.../odbc/escape/OdbcEscapeSequenceUtils.java | 98 ++++++++++++++
.../ScalarFunctionEscapeSequenceParser.java | 73 +++++++++++
.../OdbcScalarFunctionEscapeSequenceTest.java | 88 +++++++------
6 files changed, 292 insertions(+), 174 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/902b45ba/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParseResult.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParseResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParseResult.java
new file mode 100644
index 0000000..1039028
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParseResult.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.odbc.escape;
+
+/**
+ * Uses in parsing Odbc escape sequences
+ */
+class EscapeSequenceParseResult {
+
+ /** Sequence last character position in source sql query string. */
+ private int endPosition;
+
+ /** Escape sequence calculated value. */
+ private String value;
+
+ /** */
+ public EscapeSequenceParseResult(int endPosition, String value) {
+ this.endPosition = endPosition;
+ this.value = value;
+ }
+
+ /** */
+ public int endPosition() {
+ return endPosition;
+ }
+
+ /** */
+ public String value() {
+ return value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/902b45ba/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParser.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParser.java
new file mode 100644
index 0000000..26bbff6
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/EscapeSequenceParser.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.odbc.escape;
+
+/** */
+interface EscapeSequenceParser {
+
+ /**
+ * Process ODBC escape sequences in sql query.
+ *
+ * @param sql - sql query string
+ * @param start - start position in given sql string
+ * @return escape sequence parse result
+ */
+ EscapeSequenceParseResult parse(String sql, int start);
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/902b45ba/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
deleted file mode 100644
index 911aede..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceParser.java
+++ /dev/null
@@ -1,129 +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 OdbcEscapeSequenceParser {
-
- /**
- * Process ODBC escape sequences in sql query.
- *
- * @param sql - sql query text
- * @return - processed sql query text
- */
- // TODO: Set static.
- public String parse(String sql) {
- // TODO: The whole string could be escape sequence. Need to check it here, not simply pass false.
- T2<Integer, String> val = parse0(sql, 0, false);
-
- return val.get2();
- }
-
- /**
- * 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
- */
- // TODO: Do not use T2, create separate class instead.
- @NotNull private T2<Integer, String> parse0(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);
-
- // TODO: This should be implemented as separate parsers.
- 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 = processEscapeSequence(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());
- }
-
- /**
- * 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> processEscapeSequence(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 parse0(sql, pos + 1, true);
-
- default:
- throw new IllegalStateException("Unsupported escape sequence found at (" + startPosition + "): " + sql);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/ignite/blob/902b45ba/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceUtils.java
new file mode 100644
index 0000000..da44914
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/OdbcEscapeSequenceUtils.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.odbc.escape;
+
+/**
+ * Process ODBC escape sequences in sql query.
+ * See ODBC escape sequence syntax.
+ */
+public class OdbcEscapeSequenceUtils {
+
+ /** Scalar function escape sequence parser */
+ private static EscapeSequenceParser FN = new ScalarFunctionEscapeSequenceParser();
+
+ /**
+ * Process ODBC escape sequences in sql query.
+ *
+ * @param sql - sql query text
+ * @return - processed sql query text
+ */
+ public static String parse(String sql) {
+ return parse0(sql, 0);
+ }
+
+ /**
+ * Process ODBC escape sequences in sql query.
+ *
+ * @param sql - sql query text
+ * @return - processed sql query text
+ */
+ private static String parse0(String sql, int startPos) {
+ StringBuffer res = null;
+
+ int off = startPos;
+
+ for (int i = startPos; i < sql.length(); i++) {
+ char ch = sql.charAt(i);
+
+ // Current escape sequence ends up.
+ if (ch == '}')
+ throw new IllegalStateException("Unexpected end of escaped sequence found at (" + i + "): " + sql);
+ // Inner escape sequence starts
+ else if (ch == '{') {
+ EscapeSequenceParseResult escapeRes = processEscapeSequence(sql, i);
+
+ if (res == null)
+ res = new StringBuffer();
+
+ res.append(sql, off, i);
+ res.append(escapeRes.value());
+
+ i = escapeRes.endPosition();
+
+ assert sql.charAt(escapeRes.endPosition()) == '}';
+
+ off = escapeRes.endPosition() + 1;
+ }
+ }
+
+ if (res == null)
+ return sql;
+ else if (off < sql.length())
+ res.append(sql, off, sql.length());
+
+ return res.toString();
+ }
+
+ /**
+ * Parse escape sequence using appropriate parser.
+ *
+ * @param sql - sql query text
+ * @param startPosition - parser start position
+ * @return pair of end of processed sequence position and parse result
+ */
+ static EscapeSequenceParseResult processEscapeSequence(String sql, int startPosition) {
+ assert sql.charAt(startPosition) == '{';
+
+ // New escape sequence parsers should be added here.
+ if (sql.startsWith("fn ", startPosition + 1))
+ return FN.parse(sql, startPosition + 4);
+
+ throw new IllegalStateException("Unsupported escape sequence found at (" + startPosition + "): " + sql);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/902b45ba/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/ScalarFunctionEscapeSequenceParser.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/ScalarFunctionEscapeSequenceParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/ScalarFunctionEscapeSequenceParser.java
new file mode 100644
index 0000000..9b2a09c
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/escape/ScalarFunctionEscapeSequenceParser.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.odbc.escape;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Scalar function escape sequence parser.
+ * Escape sequence example: "{fn func(arg1, arg2)}"
+ */
+class ScalarFunctionEscapeSequenceParser implements EscapeSequenceParser {
+
+ /** {@inheritDoc} */
+ @NotNull public EscapeSequenceParseResult parse(String sql, int start) {
+ int off = start;
+ int end = -1;
+
+ StringBuffer sb = null;
+
+ for (int i = start; i < sql.length(); i++) {
+ char ch = sql.charAt(i);
+
+ // Current escape sequence ends up.
+ if (ch == '}') {
+ end = i;
+
+ break;
+ }
+ // Inner escape sequence starts
+ else if (ch == '{') {
+ EscapeSequenceParseResult res = OdbcEscapeSequenceUtils.processEscapeSequence(sql, i);
+
+ if (sb == null)
+ sb = new StringBuffer();
+
+ sb.append(sql, off, i);
+ sb.append(res.value());
+
+ i = res.endPosition();
+
+ assert sql.charAt(res.endPosition()) == '}';
+
+ off = res.endPosition() + 1;
+ }
+ }
+
+ if (end == -1)
+ // Closing bracket character '}' was not found in escape sequence
+ throw new IllegalStateException("Escape sequence started at position (" + start + ") is not closed: " + sql);
+
+ if (sb != null && off < end)
+ sb.append(sql, off, end);
+
+ String res = (sb != null) ? sb.toString() : sql.substring(start, end);
+
+ return new EscapeSequenceParseResult(end, res);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/902b45ba/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 9c6cf7f..bab9feb 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,76 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.apache.ignite.internal.processors.odbc;
import java.util.concurrent.Callable;
import junit.framework.TestCase;
-import org.apache.ignite.internal.processors.odbc.escape.OdbcEscapeSequenceParser;
+import org.apache.ignite.internal.processors.odbc.escape.OdbcEscapeSequenceUtils;
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;";
-
- OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
+ public void testTrivial() throws Exception {
+ String sqlQry = "{fn test()}";
+ String expRes = "test()";
- String actualRes = parser.parse(sqlQry);
+ String actualRes = OdbcEscapeSequenceUtils.parse(sqlQry);
assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
+ sqlQry = "select * from table;";
+ expRes = "select * from table;";
- sqlQry = "select {fn func(field1)} {fn func(field2)}";
- expRes = "select func(field1) func(field2)";
-
- parser = new OdbcEscapeSequenceParser();
-
- actualRes = parser.parse(sqlQry);
+ actualRes = OdbcEscapeSequenceUtils.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;";
- OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
+ /** */
+ public void testSimpleFunction() throws Exception {
+ String sqlQry = "select {fn func(field1)} {fn func(field2)} from table;";
+ String expRes = "select func(field1) func(field2) from table;";
- String actualRes = parser.parse(sqlQry);
+ String actualRes = OdbcEscapeSequenceUtils.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)";
- sqlQry = "select {fn func1(field1, {fn func2(field2)}, field3)}";
- expRes = "select func1(field1, func2(field2), field3)";
-
- parser = new OdbcEscapeSequenceParser();
-
- actualRes = parser.parse(sqlQry);
+ actualRes = OdbcEscapeSequenceUtils.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();
+ 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;";
- String actualRes = parser.parse(sqlQry);
+ String actualRes = OdbcEscapeSequenceUtils.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();
+ sqlQry = "select {fn func1(field1, {fn func2(field2)}, field3)}";
+ expRes = "select func1(field1, func2(field2), field3)";
- actualRes = parser.parse(sqlQry);
+ actualRes = OdbcEscapeSequenceUtils.parse(sqlQry);
assertEquals("Scalar function escape sequence parsing fails", expRes, actualRes);
}
@@ -81,9 +83,7 @@ public class OdbcScalarFunctionEscapeSequenceTest extends TestCase {
@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);
+ String actualRes = OdbcEscapeSequenceUtils.parse(sqlQry);
fail("Scalar function escape sequence parsing should failed");
@@ -98,9 +98,7 @@ public class OdbcScalarFunctionEscapeSequenceTest extends TestCase {
@Override public Void call() throws Exception {
String sqlQry = "select {fn func1(field1, func2(field2)}, field3)} from SomeTable;";
- OdbcEscapeSequenceParser parser = new OdbcEscapeSequenceParser();
-
- parser.parse(sqlQry);
+ OdbcEscapeSequenceUtils.parse(sqlQry);
fail("Scalar function escape sequence parsing should failed");