You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by xx...@apache.org on 2021/06/03 02:01:38 UTC

[kylin] branch master updated: KYLIN-4995 fix query exception when the query statement contains a single left parenthesis

This is an automated email from the ASF dual-hosted git repository.

xxyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kylin.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e63c34  KYLIN-4995 fix query exception when the query statement contains a single left parenthesis
4e63c34 is described below

commit 4e63c34b11496a1b79cb7ad4a1ce7b29c99a492d
Author: 7mming7 <7m...@gmail.com>
AuthorDate: Wed May 26 19:13:27 2021 +0800

    KYLIN-4995 fix query exception when the query statement contains a single left parenthesis
---
 .../kylin/metadata/model/tool/CalciteParser.java   |   7 ++
 .../source/adhocquery/HivePushDownConverter.java   |  12 +-
 .../apache/kylin/model/tool/CalciteParserTest.java | 126 +++++++++++++++++++++
 .../adhocquery/HivePushDownConverterTest.java      |   7 ++
 4 files changed, 148 insertions(+), 4 deletions(-)

diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java b/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java
index fe602c7..d31800c 100644
--- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/tool/CalciteParser.java
@@ -160,9 +160,16 @@ public class CalciteParser {
     private static Pair<Integer, Integer> getPosWithBracketsCompletion(String inputSql, int left, int right) {
         int leftBracketNum = 0;
         int rightBracketNum = 0;
+        boolean constantFlag = false;
         String substring = inputSql.substring(left, right);
         for (int i = 0; i < substring.length(); i++) {
             char temp = substring.charAt(i);
+            if (temp == '\'') {
+                constantFlag = !constantFlag;
+            }
+            if (constantFlag) {
+                continue;
+            }
             if (temp == '(') {
                 leftBracketNum++;
             }
diff --git a/core-metadata/src/main/java/org/apache/kylin/source/adhocquery/HivePushDownConverter.java b/core-metadata/src/main/java/org/apache/kylin/source/adhocquery/HivePushDownConverter.java
index 9db5a99..fcbf80a 100644
--- a/core-metadata/src/main/java/org/apache/kylin/source/adhocquery/HivePushDownConverter.java
+++ b/core-metadata/src/main/java/org/apache/kylin/source/adhocquery/HivePushDownConverter.java
@@ -6,9 +6,9 @@
  * 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.
@@ -228,15 +228,19 @@ public class HivePushDownConverter implements IPushDownConverter {
         if (sql.length() > 1) {
             Stack<Integer> lStack = new Stack<>();
             boolean inStrVal = false;
+            boolean constantFlag = false;
             for (int i = 0; i < sql.length(); i++) {
                 switch (sql.charAt(i)) {
+                case '\'':
+                    constantFlag = !constantFlag;
+                    break;
                 case '(':
-                    if (!inStrVal) {
+                    if (!inStrVal && !constantFlag) {
                         lStack.push(i);
                     }
                     break;
                 case ')':
-                    if (!inStrVal && !lStack.empty()) {
+                    if (!inStrVal && !lStack.empty() && !constantFlag) {
                         result.put(lStack.pop(), i);
                     }
                     break;
diff --git a/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java b/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java
new file mode 100644
index 0000000..a775606
--- /dev/null
+++ b/core-metadata/src/test/java/org/apache/kylin/model/tool/CalciteParserTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.kylin.model.tool;
+
+import com.google.common.base.Preconditions;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlSelect;
+import org.apache.calcite.sql.parser.SqlParseException;
+import org.apache.kylin.common.util.Pair;
+import org.apache.kylin.metadata.model.tool.CalciteParser;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class CalciteParserTest {
+
+    @Rule
+    public final ExpectedException exception = ExpectedException.none();
+
+    @Test
+    public void testNoTableNameExists() throws SqlParseException {
+        String expr1 = "a + b";
+        assertEquals("x.a + x.b", CalciteParser.insertAliasInExpr(expr1, "x"));
+
+        String expr2 = "a + year(b)";
+        assertEquals("x.a + year(x.b)", CalciteParser.insertAliasInExpr(expr2, "x"));
+
+        String expr3 = "a + hiveudf(b)";
+        assertEquals("x.a + hiveudf(x.b)", CalciteParser.insertAliasInExpr(expr3, "x"));
+    }
+
+    @Test
+    public void testTableNameExists1() throws SqlParseException {
+        String expr1 = "a + x.b";
+
+        exception.expect(IllegalArgumentException.class);
+        exception.expectMessage("SqlIdentifier X.B contains DB/Table name");
+        CalciteParser.insertAliasInExpr(expr1, "x");
+    }
+
+    @Test
+    public void testTableNameExists2() throws SqlParseException {
+        String expr1 = "a + year(x.b)";
+
+        exception.expect(IllegalArgumentException.class);
+        exception.expectMessage("SqlIdentifier X.B contains DB/Table name");
+        CalciteParser.insertAliasInExpr(expr1, "x");
+    }
+
+    @Test
+    public void testTableNameExists3() throws SqlParseException {
+        String expr1 = "a + hiveudf(x.b)";
+
+        exception.expect(IllegalArgumentException.class);
+        exception.expectMessage("SqlIdentifier X.B contains DB/Table name");
+        CalciteParser.insertAliasInExpr(expr1, "x");
+    }
+
+    @Test
+    public void testCaseWhen() {
+        String expr = "(CASE LSTG_FORMAT_NAME  WHEN 'Auction' THEN 'x'  WHEN 'y' THEN '222' ELSE 'z' END)";
+        String alias = "TEST_KYLIN_FACT";
+        String s = CalciteParser.insertAliasInExpr(expr, alias);
+        System.out.println(s);
+        assertEquals(
+                "(CASE TEST_KYLIN_FACT.LSTG_FORMAT_NAME  WHEN 'Auction' THEN 'x'  WHEN 'y' THEN '222' ELSE 'z' END)",
+                s);
+    }
+
+    @Test
+    public void testPos() throws SqlParseException {
+        String[] sqls = new String[]{"select \n a \n + \n b \n from t", //
+                "select\na\n+\nb\nfrom t", //
+                "select \r\n a \r\n + \r\n b \r\n from t", //
+                "select\r\na\r\n+\r\nb\r\nfrom t"};
+
+        for (String sql : sqls) {
+            SqlNode parse = ((SqlSelect) CalciteParser.parse(sql)).getSelectList().get(0);
+            Pair<Integer, Integer> replacePos = CalciteParser.getReplacePos(parse, sql);
+            String substring = sql.substring(replacePos.getFirst(), replacePos.getSecond());
+            Preconditions.checkArgument(substring.startsWith("a"));
+            Preconditions.checkArgument(substring.endsWith("b"));
+        }
+
+    }
+
+    @Test
+    public void testPosWithBracketsInConstant() throws SqlParseException {
+        String[] sqls = new String[]{"select '(   a + b) * (c+ d     ' from t", };
+        for (String sql : sqls) {
+            SqlNode parse = ((SqlSelect) CalciteParser.parse(sql)).getSelectList().get(0);
+            Pair<Integer, Integer> replacePos = CalciteParser.getReplacePos(parse, sql);
+            String substring = sql.substring(replacePos.getFirst(), replacePos.getSecond());
+            Preconditions.checkArgument(substring.startsWith("'"));
+        }
+    }
+
+    @Test
+    public void testRowExpression() {
+        String sql = "SELECT 'LO_LINENUMBER', 'LO_SUPPKEY' FROM \"SSB\".\"P_LINEORDER\" WHERE ROW('LO_ORDERKEY', 'LO_CUSTKEY') IN (ROW(123, 234), ROW(321, 432)) GROUP BY 'LO_LINENUMBER', 'LO_SUPPKEY'";
+        try {
+            CalciteParser.parse(sql);
+        } catch (SqlParseException e) {
+            fail("can't parse row construction");
+        }
+    }
+}
\ No newline at end of file
diff --git a/core-metadata/src/test/java/org/apache/kylin/source/adhocquery/HivePushDownConverterTest.java b/core-metadata/src/test/java/org/apache/kylin/source/adhocquery/HivePushDownConverterTest.java
index b374a60..63faf33 100644
--- a/core-metadata/src/test/java/org/apache/kylin/source/adhocquery/HivePushDownConverterTest.java
+++ b/core-metadata/src/test/java/org/apache/kylin/source/adhocquery/HivePushDownConverterTest.java
@@ -31,6 +31,13 @@ public class HivePushDownConverterTest extends TestCase {
     }
 
     @Test
+    public void testStringReplace1() {
+        String originString = "select * from (select '(aaaa' from P_LINEORDER) ";
+        String replacedString = HivePushDownConverter.subqueryReplace(originString);
+        assertEquals("select * from (select '(aaaa' from P_LINEORDER) ", replacedString);
+    }
+
+    @Test
     public void testExtractReplace() {
         String originString = "ignore EXTRACT(YEAR FROM KYLIN_CAL_DT.CAL_DT) ignore";
         String replacedString = HivePushDownConverter.extractReplace(originString);