IGNITE-3745: ODBC: Implemented date/time/timestamp escape sequence parsing. This closes #991.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/92f18bf3 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/92f18bf3 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/92f18bf3 Branch: refs/heads/master Commit: 92f18bf353cc8c3821c6500ce9f1cd397a7cf17c Parents: 87a1928 Author: Andrey V. Mashenkov <[email protected]> Authored: Fri Aug 26 15:31:30 2016 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Fri Aug 26 15:31:30 2016 +0300 ---------------------------------------------------------------------- .../processors/odbc/escape/OdbcEscapeUtils.java | 30 ++- .../odbc/OdbcEscapeSequenceSelfTest.java | 191 +++++++++++++++++-- 2 files changed, 203 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/92f18bf3/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 83ec9d8..4c1deb6 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 @@ -26,10 +26,17 @@ import java.util.regex.Pattern; * ODBC escape sequence parse. */ public class OdbcEscapeUtils { + /** Odbc date regexp pattern: '2016-08-23' */ + private static final Pattern DATE_PATTERN = Pattern.compile("^'\\d{4}-\\d{2}-\\d{2}'$"); - /** - * GUID regexp pattern: '12345678-9abc-def0-1234-123456789abc' - */ + /** Odbc time regexp pattern: '14:33:44' */ + private static final Pattern TIME_PATTERN = Pattern.compile("^'\\d{2}:\\d{2}:\\d{2}'$"); + + /** Odbc timestamp regexp pattern: '2016-08-23 14:33:44.12345' */ + private static final Pattern TIMESTAMP_PATTERN = + Pattern.compile("^'\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}(\\.\\d+)?'$"); + + /** GUID regexp pattern: '12345678-9abc-def0-1234-123456789abc' */ private static final Pattern GUID_PATTERN = Pattern.compile("^'\\p{XDigit}{8}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{4}-\\p{XDigit}{12}'$"); @@ -241,7 +248,16 @@ public class OdbcEscapeUtils { return parseScalarExpression(text, startPos0, len0); case GUID: - return parseGuidExpression(text, startPos0, len0); + return parseExpression(text, startPos0, len0, token.type(), GUID_PATTERN); + + case DATE: + return parseExpression(text, startPos0, len0, token.type(), DATE_PATTERN); + + case TIME: + return parseExpression(text, startPos0, len0, token.type(), TIME_PATTERN); + + case TIMESTAMP: + return parseExpression(text, startPos0, len0, token.type(), TIMESTAMP_PATTERN); default: throw new IgniteException("Unsupported escape sequence token [text=" + @@ -269,11 +285,11 @@ public class OdbcEscapeUtils { * @param len Length. * @return Parsed expression. */ - private static String parseGuidExpression(String text, int startPos, int len) { + private static String parseExpression(String text, int startPos, int len, OdbcEscapeType type, Pattern pattern) { String val = substring(text, startPos, len).trim(); - if (!GUID_PATTERN.matcher(val).matches()) - throw new IgniteException("Invalid GUID escape sequence: " + substring(text, startPos, len)); + if (!pattern.matcher(val).matches()) + throw new IgniteException("Invalid " + type + " escape sequence: " + substring(text, startPos, len)); return val; } http://git-wip-us.apache.org/repos/asf/ignite/blob/92f18bf3/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 7225c1a..1aa90fd 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 @@ -142,12 +142,14 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { * Test invalid escape sequence. */ public void testFailedOnInvalidFunctionSequence() { + checkFail("{fnfunc1()}"); + checkFail("select {fn func1(field1, {fn func2(field2), field3)} from SomeTable;"); checkFail("select {fn func1(field1, fn func2(field2)}, field3)} from SomeTable;"); } - /** + /** * Test escape sequences with additional whitespace characters */ public void testFunctionEscapeSequenceWithWhitespaces() throws Exception { @@ -155,7 +157,7 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { check("func1()", "{ fn func1()}"); - check("func1()", "{ \n fn func1()}"); + check("func1()", "{ \n fn\nfunc1()}"); checkFail("{ \n func1()}"); } @@ -178,6 +180,21 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { "select '12345678-9abc-def0-1234-123456789abc'", "select {guid '12345678-9abc-def0-1234-123456789abc'}" ); + } + + /** + * Test invalid escape sequence. + */ + public void testFailedOnInvalidGuidSequence() { + checkFail("select {guid'12345678-9abc-def0-1234-123456789abc'}"); + + checkFail("select {guid 12345678-9abc-def0-1234-123456789abc'}"); + + checkFail("select {guid '12345678-9abc-def0-1234-123456789abc}"); + + checkFail("select {guid '12345678-9abc-def0-1234-123456789abc' from SomeTable;"); + + checkFail("select guid '12345678-9abc-def0-1234-123456789abc'} from SomeTable;"); checkFail("select {guid '1234567-1234-1234-1234-123456789abc'}"); @@ -191,15 +208,6 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { } /** - * Test invalid escape sequence. - */ - public void testFailedOnInvalidGuidSequence() { - checkFail("select {guid '12345678-9abc-def0-1234-123456789abc' from SomeTable;"); - - checkFail("select guid '12345678-9abc-def0-1234-123456789abc'} from SomeTable;"); - } - - /** * Test escape sequences with additional whitespace characters */ public void testGuidEscapeSequenceWithWhitespaces() throws Exception { @@ -220,6 +228,167 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { } /** + * Test date escape sequences + */ + public void testDateEscapeSequence() throws Exception { + check( + "'2016-08-26'", + "{d '2016-08-26'}" + ); + + check( + "select '2016-08-26'", + "select {d '2016-08-26'}" + ); + + check( + "select '2016-08-26' from table;", + "select {d '2016-08-26'} from table;" + ); + } + + /** + * Test date escape sequences with additional whitespace characters + */ + public void testDateEscapeSequenceWithWhitespaces() throws Exception { + check("'2016-08-26'", "{ d '2016-08-26'}"); + + check("'2016-08-26'", "{ d '2016-08-26'}"); + + check("'2016-08-26'", "{ \n d\n'2016-08-26'}"); + } + + /** + * Test invalid escape sequence. + */ + public void testFailedOnInvalidDateSequence() { + checkFail("{d'2016-08-26'}"); + + checkFail("{d 2016-08-26'}"); + + checkFail("{d '2016-08-26}"); + + checkFail("{d '16-08-26'}"); + + checkFail("{d '2016/08/02'}"); + + checkFail("select {d '2016-08-26' from table;"); + + checkFail("select {}d '2016-08-26'} from table;"); + } + + /** + * Test date escape sequences + */ + public void testTimeEscapeSequence() throws Exception { + check("'13:15:08'", "{t '13:15:08'}"); + + check("select '13:15:08'", "select {t '13:15:08'}"); + + check("select '13:15:08' from table;", "select {t '13:15:08'} from table;" + ); + } + + /** + * Test date escape sequences with additional whitespace characters + */ + public void testTimeEscapeSequenceWithWhitespaces() throws Exception { + check("'13:15:08'", "{ t '13:15:08'}"); + + check("'13:15:08'", "{ t '13:15:08'}"); + + check("'13:15:08'", "{ \n t\n'13:15:08'}"); + } + + /** + * Test invalid escape sequence. + */ + public void testFailedOnInvalidTimeSequence() { + checkFail("{t'13:15:08'}"); + + checkFail("{t 13:15:08'}"); + + checkFail("{t '13:15:08}"); + + checkFail("{t '13 15:08'}"); + + checkFail("{t '3:15:08'}"); + + checkFail("select {t '13:15:08' from table;"); + + checkFail("select {}t '13:15:08'} from table;"); + } + + /** + * Test timestamp escape sequences + */ + public void testTimestampEscapeSequence() throws Exception { + check( + "'2016-08-26 13:15:08'", + "{ts '2016-08-26 13:15:08'}" + ); + + check( + "'2016-08-26 13:15:08.123456'", + "{ts '2016-08-26 13:15:08.123456'}" + ); + + check( + "select '2016-08-26 13:15:08'", + "select {ts '2016-08-26 13:15:08'}" + ); + + check( + "select '2016-08-26 13:15:08' from table;", + "select {ts '2016-08-26 13:15:08'} from table;" + ); + } + + /** + * Test timestamp escape sequences with additional whitespace characters + */ + public void testTimestampEscapeSequenceWithWhitespaces() throws Exception { + check("'2016-08-26 13:15:08'", + "{ ts '2016-08-26 13:15:08'}" + ); + + check("'2016-08-26 13:15:08'", + "{ ts '2016-08-26 13:15:08'}" + ); + + check("'2016-08-26 13:15:08'", + "{ \n ts\n'2016-08-26 13:15:08'}" + ); + } + + /** + * Test invalid escape sequence. + */ + public void testFailedOnInvalidTimestampSequence() { + checkFail("{ts '2016-08-26 13:15:08,12345'}"); + + checkFail("{ts'2016-08-26 13:15:08'}"); + + checkFail("{ts 2016-08-26 13:15:08'}"); + + checkFail("{ts '2016-08-26 13:15:08}"); + + checkFail("{ts '16-08-26 13:15:08'}"); + + checkFail("{ts '2016-08-26 3:25:08'}"); + + checkFail("{ts '2016-08 26 03:25:08'}"); + + checkFail("{ts '2016-08-26 03 25:08'}"); + + checkFail("{t s '2016-08-26 13:15:08''}"); + + checkFail("select {ts '2016-08-26 13:15:08' from table;"); + + checkFail("select {}ts '2016-08-26 13:15:08'} from table;"); + } + + /** * Check parsing logic. * * @param exp Expected result.
