IGNITE-3798: ODBC: Added literals support. This closes #1005.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/fbbcaf43 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/fbbcaf43 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/fbbcaf43 Branch: refs/heads/master Commit: fbbcaf4322548f61d2f63bf5d4e8f6d5284e73d3 Parents: 3244a5c Author: Andrey V. Mashenkov <[email protected]> Authored: Tue Aug 30 13:22:29 2016 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Tue Aug 30 13:22:29 2016 +0300 ---------------------------------------------------------------------- .../processors/odbc/escape/OdbcEscapeUtils.java | 87 +++++++++++--------- .../odbc/OdbcEscapeSequenceSelfTest.java | 55 +++++++++++++ 2 files changed, 105 insertions(+), 37 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/fbbcaf43/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 27120d4..48d4296 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 @@ -69,60 +69,70 @@ public class OdbcEscapeUtils { int plainPos = startPos; int openPos = -1; + boolean insideLiteral = false; + LinkedList<OdbcEscapeParseResult> nested = null; while (curPos < text.length()) { char curChar = text.charAt(curPos); - if (curChar == '{') { - if (openPos == -1) { - // Top-level opening brace. Append previous portion and remember current position. - res.append(text, plainPos, curPos); + if (curChar == '\'') { + if (!insideLiteral) + insideLiteral = true; + else if (text.charAt(curPos - 1) != '\\') + insideLiteral = false; + } + else if (!insideLiteral) { + if (curChar == '{') { + if (openPos == -1) { + // Top-level opening brace. Append previous portion and remember current position. + res.append(text, plainPos, curPos); - openPos = curPos; - } - else { - // Nested opening brace -> perform recursion. - OdbcEscapeParseResult nestedRes = parse0(text, curPos, true); + openPos = curPos; + } + else { + // Nested opening brace -> perform recursion. + OdbcEscapeParseResult nestedRes = parse0(text, curPos, true); - if (nested == null) - nested = new LinkedList<>(); + if (nested == null) + nested = new LinkedList<>(); - nested.add(nestedRes); + nested.add(nestedRes); - curPos += nestedRes.originalLength() - 1; + curPos += nestedRes.originalLength() - 1; - plainPos = curPos + 1; + plainPos = curPos + 1; + } } - } - else if (curChar == '}') { - if (openPos == -1) - // Close without open -> exception. - throw new IgniteException("Malformed escape sequence " + - "(closing curly brace without opening curly brace): " + text); - else { - String parseRes; - - if (nested == null) - // Found sequence without nesting, process it. - parseRes = parseEscapeSequence(text, openPos, curPos + 1 - openPos); + else if (curChar == '}') { + if (openPos == -1) + // Close without open -> exception. + throw new IgniteException("Malformed escape sequence " + + "(closing curly brace without opening curly brace): " + text); else { - // Special case to process nesting. - String res0 = appendNested(text, openPos, curPos + 1, nested); + String parseRes; - nested = null; + if (nested == null) + // Found sequence without nesting, process it. + parseRes = parseEscapeSequence(text, openPos, curPos + 1 - openPos); + else { + // Special case to process nesting. + String res0 = appendNested(text, openPos, curPos + 1, nested); - parseRes = parseEscapeSequence(res0, 0, res0.length()); - } + nested = null; - if (earlyExit) - return new OdbcEscapeParseResult(startPos, curPos + 1 - startPos, parseRes); - else - res.append(parseRes); + parseRes = parseEscapeSequence(res0, 0, res0.length()); + } - openPos = -1; + if (earlyExit) + return new OdbcEscapeParseResult(startPos, curPos + 1 - startPos, parseRes); + else + res.append(parseRes); - plainPos = curPos + 1; + openPos = -1; + + plainPos = curPos + 1; + } } } @@ -132,6 +142,9 @@ public class OdbcEscapeUtils { if (openPos != -1) throw new IgniteException("Malformed escape sequence (closing curly brace missing): " + text); + if (insideLiteral) + throw new IgniteException("Malformed literal expression (closing quote missing): " + text); + if (curPos > plainPos) res.append(text, plainPos, curPos); http://git-wip-us.apache.org/repos/asf/ignite/blob/fbbcaf43/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 4887a67..3fec7d3 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 @@ -486,6 +486,61 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { } /** + * Test non-escape sequences. + */ + public void testNonEscapeSequence() throws Exception { + check("'{fn test()}'", "'{fn test()}'"); + + check("select '{fn test()}'", "select '{fn test()}'"); + + check( + "select '{fn test()}' from table;", + "select '{fn test()}' from table;" + ); + + check( + "select test('arg') from table;", + "select {fn test('arg')} from table;" + ); + + check( + "select test('{fn func()}') from table;", + "select {fn test('{fn func()}')} from table;" + ); + + check( + "'{\\'some literal\\'}'", + "'{\\'some literal\\'}'" + ); + + check( + "select '{\\'some literal\\'}'", + "select '{\\'some literal\\'}'" + ); + + check( + "select '{\\'some literal\\'}' from table;", + "select '{\\'some literal\\'}' from table;" + ); + + check( + "select '{' + func() + '}' from table;", + "select '{' + {fn func()} + '}' from table;" + ); + + check( + "select '{\\'{fn test()}\\'}' from table;", + "select '{\\'{fn test()}\\'}' from table;" + ); + + checkFail("'{fn test()}"); + + checkFail("{fn func('arg)}"); + + checkFail("{fn func(arg')}"); + } + + /** * Check parsing logic. * * @param exp Expected result.
