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 <7mmi...@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);