Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 78761200B7C for ; Thu, 8 Sep 2016 17:40:48 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 773FC160AD0; Thu, 8 Sep 2016 15:40:48 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 6D76F160ADC for ; Thu, 8 Sep 2016 17:40:46 +0200 (CEST) Received: (qmail 81706 invoked by uid 500); 8 Sep 2016 15:40:45 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 80707 invoked by uid 99); 8 Sep 2016 15:40:44 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 08 Sep 2016 15:40:44 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 19DCFE03CE; Thu, 8 Sep 2016 15:40:44 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: sboikov@apache.org To: commits@ignite.apache.org Date: Thu, 08 Sep 2016 15:41:12 -0000 Message-Id: In-Reply-To: <1b11fdb4ca024595b5ebcd8933780c53@git.apache.org> References: <1b11fdb4ca024595b5ebcd8933780c53@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [30/50] [abbrv] ignite git commit: IGNITE-3742: ODBC: Added support for OUTER JOIN escape sequence. This closes #1000. archived-at: Thu, 08 Sep 2016 15:40:48 -0000 IGNITE-3742: ODBC: Added support for OUTER JOIN escape sequence. This closes #1000. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/3244a5c9 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/3244a5c9 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/3244a5c9 Branch: refs/heads/ignite-961 Commit: 3244a5c9dabf6d4fcaa32a661cc0adc6f8ea30de Parents: f9ff97c Author: Andrey V. Mashenkov Authored: Tue Aug 30 11:49:11 2016 +0300 Committer: vozerov-gridgain Committed: Tue Aug 30 11:49:11 2016 +0300 ---------------------------------------------------------------------- .../processors/odbc/escape/OdbcEscapeUtils.java | 32 +++--- .../odbc/OdbcEscapeSequenceSelfTest.java | 109 ++++++++++++++++++- 2 files changed, 122 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/3244a5c9/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 a4b89c3..27120d4 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 @@ -105,14 +105,14 @@ public class OdbcEscapeUtils { if (nested == null) // Found sequence without nesting, process it. - parseRes = parseExpression(text, openPos, curPos + 1 - openPos); + parseRes = parseEscapeSequence(text, openPos, curPos + 1 - openPos); else { // Special case to process nesting. String res0 = appendNested(text, openPos, curPos + 1, nested); nested = null; - parseRes = parseExpression(res0, 0, res0.length()); + parseRes = parseEscapeSequence(res0, 0, res0.length()); } if (earlyExit) @@ -139,14 +139,14 @@ public class OdbcEscapeUtils { } /** - * Parse concrete expression. + * Parse escape sequence: {escape_sequence}. * * @param text Text. * @param startPos Start position within text. * @param len Length. * @return Result. */ - private static String parseExpression(String text, int startPos, int len) { + private static String parseEscapeSequence(String text, int startPos, int len) { assert validSubstring(text, startPos, len); char firstChar = text.charAt(startPos); @@ -228,7 +228,7 @@ public class OdbcEscapeUtils { } /** - * Parse standard token. + * Parse standard expression: {TOKEN expression} * * @param text Text. * @param startPos Start position. @@ -245,10 +245,13 @@ public class OdbcEscapeUtils { switch (token.type()) { case SCALAR_FUNCTION: - return parseScalarExpression(text, startPos0, len0); + return parseExpression(text, startPos0, len0); + + case GUID: { + String res = parseExpression(text, startPos0, len0, token.type(), GUID_PATTERN); - case GUID: - return parseExpression(text, startPos0, len0, token.type(), GUID_PATTERN); + return "CAST(" + res + " AS UUID)"; + } case DATE: return parseExpression(text, startPos0, len0, token.type(), DATE_PATTERN); @@ -259,6 +262,9 @@ public class OdbcEscapeUtils { case TIMESTAMP: return parseExpression(text, startPos0, len0, token.type(), TIMESTAMP_PATTERN); + case OUTER_JOIN: + return parseExpression(text, startPos0, len0); + default: throw new IgniteException("Unsupported escape sequence token [text=" + substring(text, startPos, len) + ", token=" + token.type().body() + ']'); @@ -266,19 +272,19 @@ public class OdbcEscapeUtils { } /** - * Parse scalar function expression. + * Parse simple expression. * * @param text Text. * @param startPos Start position. * @param len Length. * @return Parsed expression. */ - private static String parseScalarExpression(String text, int startPos, int len) { + private static String parseExpression(String text, int startPos, int len) { return substring(text, startPos, len).trim(); } /** - * Parse concrete expression. + * Parse expression and validate against ODBC specification with regex pattern. * * @param text Text. * @param startPos Start position. @@ -286,12 +292,12 @@ public class OdbcEscapeUtils { * @return Parsed expression. */ private static String parseExpression(String text, int startPos, int len, OdbcEscapeType type, Pattern pattern) { - String val = substring(text, startPos, len).trim(); + String val = parseExpression(text, startPos, len); if (!pattern.matcher(val).matches()) throw new IgniteException("Invalid " + type + " escape sequence: " + substring(text, startPos, len)); - return "CAST(" + val + " AS UUID)"; + return val; } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/3244a5c9/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 1aa90fd..4887a67 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 @@ -167,17 +167,17 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { */ public void testGuidEscapeSequence() { check( - "'12345678-9abc-def0-1234-123456789abc'", + "CAST('12345678-9abc-def0-1234-123456789abc' AS UUID)", "{guid '12345678-9abc-def0-1234-123456789abc'}" ); check( - "select '12345678-9abc-def0-1234-123456789abc' from SomeTable;", + "select CAST('12345678-9abc-def0-1234-123456789abc' AS UUID) from SomeTable;", "select {guid '12345678-9abc-def0-1234-123456789abc'} from SomeTable;" ); check( - "select '12345678-9abc-def0-1234-123456789abc'", + "select CAST('12345678-9abc-def0-1234-123456789abc' AS UUID)", "select {guid '12345678-9abc-def0-1234-123456789abc'}" ); } @@ -212,17 +212,17 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { */ public void testGuidEscapeSequenceWithWhitespaces() throws Exception { check( - "'12345678-9abc-def0-1234-123456789abc'", + "CAST('12345678-9abc-def0-1234-123456789abc' AS UUID)", "{ guid '12345678-9abc-def0-1234-123456789abc'}" ); check( - "'12345678-9abc-def0-1234-123456789abc'", + "CAST('12345678-9abc-def0-1234-123456789abc' AS UUID)", "{ guid '12345678-9abc-def0-1234-123456789abc'}" ); check( - "'12345678-9abc-def0-1234-123456789abc'", + "CAST('12345678-9abc-def0-1234-123456789abc' AS UUID)", "{ \n guid\n'12345678-9abc-def0-1234-123456789abc'}" ); } @@ -388,6 +388,103 @@ public class OdbcEscapeSequenceSelfTest extends GridCommonAbstractTest { checkFail("select {}ts '2016-08-26 13:15:08'} from table;"); } + + /** + * Test escape sequence series. + */ + public void testOuterJoinFunction() throws Exception { + check( + "t OUTER JOIN t2 ON t.id=t2.id", + "{oj t OUTER JOIN t2 ON t.id=t2.id}" + ); + + check( + "select * from t OUTER JOIN t2 ON t.id=t2.id", + "select * from {oj t OUTER JOIN t2 ON t.id=t2.id}" + ); + + check( + "select * from t OUTER JOIN t2 ON t.id=t2.id ORDER BY t2.id", + "select * from {oj t OUTER JOIN t2 ON t.id=t2.id} ORDER BY t2.id" + ); + } + + /** + * Test simple nested escape sequences. Depth = 2. + */ + public void testNestedOuterJoin() throws Exception { + check( + "t OUTER JOIN (t2 OUTER JOIN t3 ON t2.id=t3.id) ON t.id=t2.id", + "{oj t OUTER JOIN ({oj t2 OUTER JOIN t3 ON t2.id=t3.id}) ON t.id=t2.id}" + ); + + check( + "select * from t OUTER JOIN (t2 OUTER JOIN t3 ON t2.id=t3.id) ON t.id=t2.id", + "select * from {oj t OUTER JOIN ({oj t2 OUTER JOIN t3 ON t2.id=t3.id}) ON t.id=t2.id}" + ); + + check( + "select * from t OUTER JOIN (t2 OUTER JOIN t3 ON t2.id=t3.id) ON t.id=t2.id ORDER BY t2.id", + "select * from {oj t OUTER JOIN ({oj t2 OUTER JOIN t3 ON t2.id=t3.id}) ON t.id=t2.id} ORDER BY t2.id" + ); + } + + /** + * Test nested escape sequences. Depth > 2. + */ + public void testDeepNestedOuterJoin() { + check( + "t OUTER JOIN (t2 OUTER JOIN (t3 OUTER JOIN t4 ON t3.id=t4.id) ON t2.id=t3.id) ON t.id=t2.id", + "{oj t OUTER JOIN ({oj t2 OUTER JOIN ({oj t3 OUTER JOIN t4 ON t3.id=t4.id}) ON t2.id=t3.id}) ON t.id=t2.id}" + ); + + check( + "select * from " + + "t OUTER JOIN (t2 OUTER JOIN (t3 OUTER JOIN t4 ON t3.id=t4.id) ON t2.id=t3.id) ON t.id=t2.id", + "select * from " + + "{oj t OUTER JOIN ({oj t2 OUTER JOIN ({oj t3 OUTER JOIN t4 ON t3.id=t4.id}) ON t2.id=t3.id})" + + " ON t.id=t2.id}" + ); + + check( + "select * from t OUTER JOIN (t2 OUTER JOIN (t3 OUTER JOIN t4 ON t3.id=t4.id) " + + "ON t2.id=t3.id) ON t.id=t2.id ORDER BY t4.id", + "select * from {oj t OUTER JOIN ({oj t2 OUTER JOIN ({oj t3 OUTER JOIN t4 ON t3.id=t4.id}) " + + "ON t2.id=t3.id}) ON t.id=t2.id} ORDER BY t4.id" + ); + } + + /** + * Test invalid escape sequence. + */ + public void testFailedOnInvalidOuterJoinSequence() { + checkFail("{ojt OUTER JOIN t2 ON t.id=t2.id}"); + + checkFail("select {oj t OUTER JOIN ({oj t2 OUTER JOIN t3 ON t2.id=t3.id) ON t.id=t2.id} from SomeTable;"); + + checkFail("select oj t OUTER JOIN t2 ON t.id=t2.id} from SomeTable;"); + } + + /** + * Test escape sequences with additional whitespace characters + */ + public void testOuterJoinSequenceWithWhitespaces() throws Exception { + check( + "t OUTER JOIN t2 ON t.id=t2.id", + "{ oj t OUTER JOIN t2 ON t.id=t2.id}" + ); + + check( + "t OUTER JOIN t2 ON t.id=t2.id", + "{ oj t OUTER JOIN t2 ON t.id=t2.id}" + ); + + check( + "t OUTER JOIN t2 ON t.id=t2.id", + " \n { oj\nt OUTER JOIN t2 ON t.id=t2.id}" + ); + } + /** * Check parsing logic. *