You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2016/10/24 02:40:17 UTC
[6/9] kylin git commit: KYLIN-2108 refactor massageSql(),
disable KeywordDefaultDirtyHack by default
KYLIN-2108 refactor massageSql(), disable KeywordDefaultDirtyHack by default
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/c9216b18
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/c9216b18
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/c9216b18
Branch: refs/heads/yang21-hbase1.x
Commit: c9216b180eae37fbffea453028ee9bb8c72bc03c
Parents: cec8b9e
Author: Li Yang <li...@apache.org>
Authored: Thu Oct 20 15:08:14 2016 +0800
Committer: Li Yang <li...@apache.org>
Committed: Thu Oct 20 15:08:28 2016 +0800
----------------------------------------------------------------------
.../apache/kylin/common/KylinConfigBase.java | 4 +
.../test_case_data/localmeta/kylin.properties | 2 +
.../apache/kylin/rest/service/QueryService.java | 3 +-
.../rest/util/KeywordDefaultDirtyHack.java | 34 +++
.../org/apache/kylin/rest/util/QueryUtil.java | 231 ++++++++-----------
.../kylin/rest/util/TableauInterceptor.java | 115 +++++++++
.../apache/kylin/rest/util/QueryUtilTest.java | 30 ++-
7 files changed, 274 insertions(+), 145 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kylin/blob/c9216b18/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
----------------------------------------------------------------------
diff --git a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
index 79ee084..5d92aef 100644
--- a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
+++ b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
@@ -504,6 +504,10 @@ abstract public class KylinConfigBase implements Serializable {
public boolean getBadQueryPersistentEnabled() {
return Boolean.parseBoolean(getOptional("kylin.query.badquery.persistent.enable", "true"));
}
+
+ public String[] getQueryTransformers() {
+ return getOptionalStringArray("kylin.query.transformers", new String[0]);
+ }
public int getCachedDictMaxEntrySize() {
return Integer.parseInt(getOptional("kylin.dict.cache.max.entry", "3000"));
http://git-wip-us.apache.org/repos/asf/kylin/blob/c9216b18/examples/test_case_data/localmeta/kylin.properties
----------------------------------------------------------------------
diff --git a/examples/test_case_data/localmeta/kylin.properties b/examples/test_case_data/localmeta/kylin.properties
index 50dd0b6..d727fe8 100644
--- a/examples/test_case_data/localmeta/kylin.properties
+++ b/examples/test_case_data/localmeta/kylin.properties
@@ -75,6 +75,8 @@ kylin.job.yarn.app.rest.check.interval.seconds=10
### QUERY ###
+kylin.query.transformers=org.apache.kylin.rest.util.KeywordDefaultDirtyHack
+
### SECURITY ###
# Spring security profile, options: testing, ldap, saml
http://git-wip-us.apache.org/repos/asf/kylin/blob/c9216b18/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
index 8303cee..918bdf1 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
@@ -68,6 +68,7 @@ import org.apache.kylin.rest.request.SQLRequest;
import org.apache.kylin.rest.response.SQLResponse;
import org.apache.kylin.rest.util.QueryUtil;
import org.apache.kylin.rest.util.Serializer;
+import org.apache.kylin.rest.util.TableauInterceptor;
import org.apache.kylin.storage.hbase.HBaseConnection;
import org.apache.kylin.storage.hybrid.HybridInstance;
import org.slf4j.Logger;
@@ -299,7 +300,7 @@ public class QueryService extends BasicService {
userInfo += grantedAuthority.getAuthority();
}
- SQLResponse fakeResponse = QueryUtil.tableauIntercept(sqlRequest.getSql());
+ SQLResponse fakeResponse = TableauInterceptor.tableauIntercept(sqlRequest.getSql());
if (null != fakeResponse) {
logger.debug("Return fake response, is exception? " + fakeResponse.getIsException());
return fakeResponse;
http://git-wip-us.apache.org/repos/asf/kylin/blob/c9216b18/server-base/src/main/java/org/apache/kylin/rest/util/KeywordDefaultDirtyHack.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/KeywordDefaultDirtyHack.java b/server-base/src/main/java/org/apache/kylin/rest/util/KeywordDefaultDirtyHack.java
new file mode 100644
index 0000000..8d8d971
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/util/KeywordDefaultDirtyHack.java
@@ -0,0 +1,34 @@
+/*
+ * 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.rest.util;
+
+import org.apache.kylin.rest.util.QueryUtil.IQueryTransformer;
+
+public class KeywordDefaultDirtyHack implements IQueryTransformer {
+
+ @Override
+ public String transform(String sql) {
+ // KYLIN-2108, DEFAULT is hive default database, but a sql keyword too, needs quote
+ sql = sql.replace("DEFAULT.", "\"DEFAULT\".");
+ sql = sql.replace("default.", "\"default\".");
+
+ return sql;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/c9216b18/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java b/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java
index cc9d32e..66619fe 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java
@@ -18,87 +18,28 @@
package org.apache.kylin.rest.util;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.kylin.rest.model.SelectedColumnMeta;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.ClassUtil;
import org.apache.kylin.rest.request.SQLRequest;
-import org.apache.kylin.rest.response.SQLResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.Lists;
+
/**
*/
public class QueryUtil {
protected static final Logger logger = LoggerFactory.getLogger(QueryUtil.class);
- private static final String S0 = "\\s*";
- private static final String S1 = "\\s";
- private static final String SM = "\\s+";
- private static final Pattern PTN_GROUP_BY = Pattern.compile(S1 + "GROUP" + SM + "BY" + S1, Pattern.CASE_INSENSITIVE);
- private static final Pattern PTN_HAVING_COUNT_GREATER_THAN_ZERO = Pattern.compile(S1 + "HAVING" + SM + "[(]?" + S0 + "COUNT" + S0 + "[(]" + S0 + "1" + S0 + "[)]" + S0 + ">" + S0 + "0" + S0 + "[)]?", Pattern.CASE_INSENSITIVE);
- private static final Pattern PTN_SUM_1 = Pattern.compile(S1 + "SUM" + S0 + "[(]" + S0 + "[1]" + S0 + "[)]" + S1, Pattern.CASE_INSENSITIVE);
- private static final Pattern PTN_INTERVAL = Pattern.compile("interval" + SM + "(floor\\()([\\d\\.]+)(\\))" + SM + "(second|minute|hour|day|month|year)", Pattern.CASE_INSENSITIVE);
- private static final Pattern PTN_CONCAT = Pattern.compile("concat\\(.+?\\)");//non-greedy
-
- // private static final Pattern PTN_HAVING_ESCAPE_FUNCTION =
- // Pattern.compile("\\{fn" + "(" + S0 + ")" + "\\}",
- // Pattern.CASE_INSENSITIVE);
- private static final Pattern PTN_HAVING_ESCAPE_FUNCTION = Pattern.compile("\\{fn" + "(.*?)" + "\\}", Pattern.CASE_INSENSITIVE);
-
- private static String[] tableauTestQueries = new String[] { "SELECT 1", //
- "CREATE LOCAL TEMPORARY TABLE \"XTableau_B_Connect\" ( \"COL\" INTEGER ) ON COMMIT PRESERVE ROWS", //
- "DROP TABLE \"XTableau_B_Connect\"", //
- "SELECT \"COL\" FROM (SELECT 1 AS \"COL\") AS \"SUBQUERY\"", //
- "SELECT TOP 1 \"COL\" FROM (SELECT 1 AS \"COL\") AS \"CHECKTOP\"", "SELECT \"COL\" FROM (SELECT 1 AS \"COL\") AS \"CHECKTOP\" LIMIT 1", //
- "SELECT \"SUBCOL\" AS \"COL\" FROM ( SELECT 1 AS \"SUBCOL\" ) \"SUBQUERY\" GROUP BY 1", "SELECT \"SUBCOL\" AS \"COL\" FROM ( SELECT 1 AS \"SUBCOL\" ) \"SUBQUERY\" GROUP BY 2", "INSERT INTO \"XTableau_C_Connect\" SELECT * FROM (SELECT 1 AS COL) AS CHECKTEMP LIMIT 1", "DROP TABLE \"XTableau_C_Connect\"", "INSERT INTO \"XTableau_B_Connect\" SELECT * FROM (SELECT 1 AS COL) AS CHECKTEMP LIMIT 1" };
-
- private static SQLResponse temp = new SQLResponse(new LinkedList<SelectedColumnMeta>() {
- private static final long serialVersionUID = -8086728462624901359L;
-
- {
- add(new SelectedColumnMeta(false, false, true, false, 2, true, 11, "COL", "COL", "", "", "", 10, 0, 4, "int4", false, true, false));
- }
- }, new LinkedList<List<String>>() {
- private static final long serialVersionUID = -470083340592928073L;
-
- {
- add(new LinkedList<String>() {
- private static final long serialVersionUID = -3673192785838230054L;
-
- {
- add("1");
- }
- });
- }
- }, 0, false, null);
-
- private static SQLResponse[] fakeResponses = new SQLResponse[] { temp, new SQLResponse(null, null, 0, false, null), //
- new SQLResponse(null, null, 0, false, null), //
- temp, //
- new SQLResponse(null, null, 0, true, "near 1 syntax error"), //
- temp, //
- new SQLResponse(null, null, 0, true, "group by 1????"), //
- new SQLResponse(null, null, 0, true, "group by 2????"), //
- new SQLResponse(null, null, 0, true, "XTableau_C_Connect not exist"), //
- new SQLResponse(null, null, 0, true, "XTableau_C_Connect not exist"), new SQLResponse(null, null, 0, true, "XTableau_B_Connect not exist"), };
-
- private static ArrayList<HashSet<String>> tableauTestQueriesInToken = new ArrayList<HashSet<String>>();
-
- static {
- for (String q : tableauTestQueries) {
- HashSet<String> temp = new HashSet<String>();
- for (String token : q.split("[\r\n\t \\(\\)]")) {
- temp.add(token);
- }
- temp.add("");
- tableauTestQueriesInToken.add(temp);
- }
+ private static List<IQueryTransformer> queryTransformers;
+
+ public interface IQueryTransformer {
+ String transform(String sql);
}
public static String massageSql(SQLRequest sqlRequest) {
@@ -106,10 +47,6 @@ public class QueryUtil {
sql = sql.trim();
sql = sql.replace("\r", " ").replace("\n", System.getProperty("line.separator"));
- // KYLIN-2108, DEFAULT is hive default database, but a Calcite keyword too, needs quote
- sql = sql.replace("DEFAULT.", "\"DEFAULT\".");
- sql = sql.replace("default.", "\"default\".");
-
while (sql.endsWith(";"))
sql = sql.substring(0, sql.length() - 1);
@@ -123,78 +60,103 @@ public class QueryUtil {
sql += ("\nOFFSET " + offset);
}
- return healSickSql(sql);
- }
-
- // correct sick / invalid SQL
- private static String healSickSql(String sql) {
- Matcher m;
-
- // Case fn{ EXTRACT(...) }
- // Use non-greedy regrex matching to remove escape functions
- while (true) {
- m = PTN_HAVING_ESCAPE_FUNCTION.matcher(sql);
- if (!m.find())
- break;
- sql = sql.substring(0, m.start()) + m.group(1) + sql.substring(m.end());
+ // customizable SQL transformation
+ if (queryTransformers == null) {
+ initQueryTransformers();
}
-
- // Case: HAVING COUNT(1)>0 without Group By
- // Tableau generates: SELECT SUM(1) AS "COL" FROM "VAC_SW" HAVING
- // COUNT(1)>0
- m = PTN_HAVING_COUNT_GREATER_THAN_ZERO.matcher(sql);
- if (m.find() && PTN_GROUP_BY.matcher(sql).find() == false) {
- sql = sql.substring(0, m.start()) + " " + sql.substring(m.end());
+ for (IQueryTransformer t : queryTransformers) {
+ sql = t.transform(sql);
}
+ return sql;
+ }
- // Case: SUM(1)
- // Replace it with COUNT(1)
- while (true) {
- m = PTN_SUM_1.matcher(sql);
- if (!m.find())
- break;
- sql = sql.substring(0, m.start()) + " COUNT(1) " + sql.substring(m.end());
+ private static void initQueryTransformers() {
+ List<IQueryTransformer> transformers = Lists.newArrayList();
+ transformers.add(new DefaultQueryTransformer());
+
+ String[] classes = KylinConfig.getInstanceFromEnv().getQueryTransformers();
+ for (String clz : classes) {
+ try {
+ IQueryTransformer t = (IQueryTransformer) ClassUtil.newInstance(clz);
+ transformers.add(t);
+ } catch (Exception e) {
+ logger.error("Failed to init query transformer", e);
+ }
}
+ queryTransformers = transformers;
+ }
- // ( date '2001-09-28' + interval floor(1) day ) generated by cognos
- // calcite only recognizes date '2001-09-28' + interval '1' day
- while (true) {
- m = PTN_INTERVAL.matcher(sql);
- if (!m.find())
- break;
+ // correct sick / invalid SQL
+ private static class DefaultQueryTransformer implements IQueryTransformer {
+
+ private static final String S0 = "\\s*";
+ private static final String S1 = "\\s";
+ private static final String SM = "\\s+";
+ private static final Pattern PTN_GROUP_BY = Pattern.compile(S1 + "GROUP" + SM + "BY" + S1, Pattern.CASE_INSENSITIVE);
+ private static final Pattern PTN_HAVING_COUNT_GREATER_THAN_ZERO = Pattern.compile(S1 + "HAVING" + SM + "[(]?" + S0 + "COUNT" + S0 + "[(]" + S0 + "1" + S0 + "[)]" + S0 + ">" + S0 + "0" + S0 + "[)]?", Pattern.CASE_INSENSITIVE);
+ private static final Pattern PTN_SUM_1 = Pattern.compile(S1 + "SUM" + S0 + "[(]" + S0 + "[1]" + S0 + "[)]" + S1, Pattern.CASE_INSENSITIVE);
+ private static final Pattern PTN_INTERVAL = Pattern.compile("interval" + SM + "(floor\\()([\\d\\.]+)(\\))" + SM + "(second|minute|hour|day|month|year)", Pattern.CASE_INSENSITIVE);
+ private static final Pattern PTN_CONCAT = Pattern.compile("concat\\(.+?\\)");//non-greedy
+ private static final Pattern PTN_HAVING_ESCAPE_FUNCTION = Pattern.compile("\\{fn" + "(.*?)" + "\\}", Pattern.CASE_INSENSITIVE);
+
+ @Override
+ public String transform(String sql) {
+ Matcher m;
+
+ // Case fn{ EXTRACT(...) }
+ // Use non-greedy regrex matching to remove escape functions
+ while (true) {
+ m = PTN_HAVING_ESCAPE_FUNCTION.matcher(sql);
+ if (!m.find())
+ break;
+ sql = sql.substring(0, m.start()) + m.group(1) + sql.substring(m.end());
+ }
- int value = (int) Math.floor(Double.valueOf(m.group(2)));
- sql = sql.substring(0, m.start(1)) + "'" + value + "'" + sql.substring(m.end(3));
- }
+ // Case: HAVING COUNT(1)>0 without Group By
+ // Tableau generates: SELECT SUM(1) AS "COL" FROM "VAC_SW" HAVING
+ // COUNT(1)>0
+ m = PTN_HAVING_COUNT_GREATER_THAN_ZERO.matcher(sql);
+ if (m.find() && PTN_GROUP_BY.matcher(sql).find() == false) {
+ sql = sql.substring(0, m.start()) + " " + sql.substring(m.end());
+ }
- //according to https://issues.apache.org/jira/browse/CALCITE-1375,
- //{fn concat('a','b')} will succeed but concat('a','b') will fail
- StringBuilder sb = new StringBuilder();
- while (true) {
- m = PTN_CONCAT.matcher(sql);
- if (!m.find())
- break;
+ // Case: SUM(1)
+ // Replace it with COUNT(1)
+ while (true) {
+ m = PTN_SUM_1.matcher(sql);
+ if (!m.find())
+ break;
+ sql = sql.substring(0, m.start()) + " COUNT(1) " + sql.substring(m.end());
+ }
- sb.append(sql.substring(0, m.start()) + "{fn " + m.group(0) + " }");
- sql = sql.substring(m.end());
- }
- String temp = sb.toString() + sql;
- sql = "".equals(temp) ? sql : temp;
+ // ( date '2001-09-28' + interval floor(1) day ) generated by cognos
+ // calcite only recognizes date '2001-09-28' + interval '1' day
+ while (true) {
+ m = PTN_INTERVAL.matcher(sql);
+ if (!m.find())
+ break;
- return sql;
- }
+ int value = (int) Math.floor(Double.valueOf(m.group(2)));
+ sql = sql.substring(0, m.start(1)) + "'" + value + "'" + sql.substring(m.end(3));
+ }
- public static SQLResponse tableauIntercept(String sql) {
+ //according to https://issues.apache.org/jira/browse/CALCITE-1375,
+ //{fn concat('a','b')} will succeed but concat('a','b') will fail
+ StringBuilder sb = new StringBuilder();
+ while (true) {
+ m = PTN_CONCAT.matcher(sql);
+ if (!m.find())
+ break;
- String[] tokens = sql.split("[\r\n\t \\(\\)]");
- for (int i = 0; i < tableauTestQueries.length; ++i) {
- if (isTokenWiseEqual(tokens, tableauTestQueriesInToken.get(i))) {
- logger.info("Hit fake response " + i);
- return fakeResponses[i];
+ sb.append(sql.substring(0, m.start()) + "{fn " + m.group(0) + " }");
+ sql = sql.substring(m.end());
}
- }
+ String temp = sb.toString() + sql;
+ sql = "".equals(temp) ? sql : temp;
- return null;
+ return sql;
+ }
+
}
public static String makeErrorMsgUserFriendly(Throwable e) {
@@ -230,13 +192,4 @@ public class QueryUtil {
}
}
- private static boolean isTokenWiseEqual(String[] tokens, HashSet<String> tokenSet) {
- for (String token : tokens) {
- if (!tokenSet.contains(token)) {
- return false;
- }
- }
- return true;
- }
-
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/c9216b18/server-base/src/main/java/org/apache/kylin/rest/util/TableauInterceptor.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/TableauInterceptor.java b/server-base/src/main/java/org/apache/kylin/rest/util/TableauInterceptor.java
new file mode 100644
index 0000000..afe91e1
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/util/TableauInterceptor.java
@@ -0,0 +1,115 @@
+/*
+ * 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.rest.util;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.kylin.rest.model.SelectedColumnMeta;
+import org.apache.kylin.rest.response.SQLResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TableauInterceptor {
+
+ protected static final Logger logger = LoggerFactory.getLogger(TableauInterceptor.class);
+
+ private static String[] tableauTestQueries = new String[] { "SELECT 1", //
+ "CREATE LOCAL TEMPORARY TABLE \"XTableau_B_Connect\" ( \"COL\" INTEGER ) ON COMMIT PRESERVE ROWS", //
+ "DROP TABLE \"XTableau_B_Connect\"", //
+ "SELECT \"COL\" FROM (SELECT 1 AS \"COL\") AS \"SUBQUERY\"", //
+ "SELECT TOP 1 \"COL\" FROM (SELECT 1 AS \"COL\") AS \"CHECKTOP\"", //
+ "SELECT \"COL\" FROM (SELECT 1 AS \"COL\") AS \"CHECKTOP\" LIMIT 1", //
+ "SELECT \"SUBCOL\" AS \"COL\" FROM ( SELECT 1 AS \"SUBCOL\" ) \"SUBQUERY\" GROUP BY 1", //
+ "SELECT \"SUBCOL\" AS \"COL\" FROM ( SELECT 1 AS \"SUBCOL\" ) \"SUBQUERY\" GROUP BY 2", //
+ "INSERT INTO \"XTableau_C_Connect\" SELECT * FROM (SELECT 1 AS COL) AS CHECKTEMP LIMIT 1", //
+ "DROP TABLE \"XTableau_C_Connect\"", //
+ "INSERT INTO \"XTableau_B_Connect\" SELECT * FROM (SELECT 1 AS COL) AS CHECKTEMP LIMIT 1" };
+
+ private static SQLResponse temp = new SQLResponse(new LinkedList<SelectedColumnMeta>() {
+ private static final long serialVersionUID = -8086728462624901359L;
+
+ {
+ add(new SelectedColumnMeta(false, false, true, false, 2, true, 11, "COL", "COL", "", "", "", 10, 0, 4, "int4", false, true, false));
+ }
+ }, new LinkedList<List<String>>() {
+ private static final long serialVersionUID = -470083340592928073L;
+
+ {
+ add(new LinkedList<String>() {
+ private static final long serialVersionUID = -3673192785838230054L;
+
+ {
+ add("1");
+ }
+ });
+ }
+ }, 0, false, null);
+
+ private static SQLResponse[] fakeResponses = new SQLResponse[] { temp, //
+ new SQLResponse(null, null, 0, false, null), //
+ new SQLResponse(null, null, 0, false, null), //
+ temp, //
+ new SQLResponse(null, null, 0, true, "near 1 syntax error"), //
+ temp, //
+ new SQLResponse(null, null, 0, true, "group by 1????"), //
+ new SQLResponse(null, null, 0, true, "group by 2????"), //
+ new SQLResponse(null, null, 0, true, "XTableau_C_Connect not exist"), //
+ new SQLResponse(null, null, 0, true, "XTableau_C_Connect not exist"), //
+ new SQLResponse(null, null, 0, true, "XTableau_B_Connect not exist"), };
+
+ private static ArrayList<HashSet<String>> tableauTestQueriesInToken = new ArrayList<HashSet<String>>();
+
+ static {
+ for (String q : tableauTestQueries) {
+ HashSet<String> temp = new HashSet<String>();
+ for (String token : q.split("[\r\n\t \\(\\)]")) {
+ temp.add(token);
+ }
+ temp.add("");
+ tableauTestQueriesInToken.add(temp);
+ }
+ }
+
+ public static SQLResponse tableauIntercept(String sql) {
+
+ String[] tokens = sql.split("[\r\n\t \\(\\)]");
+ for (int i = 0; i < tableauTestQueries.length; ++i) {
+ if (isTokenWiseEqual(tokens, tableauTestQueriesInToken.get(i))) {
+ logger.info("Hit fake response " + i);
+ return fakeResponses[i];
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isTokenWiseEqual(String[] tokens, HashSet<String> tokenSet) {
+ for (String token : tokens) {
+ if (!tokenSet.contains(token)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/c9216b18/server-base/src/test/java/org/apache/kylin/rest/util/QueryUtilTest.java
----------------------------------------------------------------------
diff --git a/server-base/src/test/java/org/apache/kylin/rest/util/QueryUtilTest.java b/server-base/src/test/java/org/apache/kylin/rest/util/QueryUtilTest.java
index 9305410..c00cd3f 100644
--- a/server-base/src/test/java/org/apache/kylin/rest/util/QueryUtilTest.java
+++ b/server-base/src/test/java/org/apache/kylin/rest/util/QueryUtilTest.java
@@ -18,13 +18,27 @@
package org.apache.kylin.rest.util;
+import org.apache.kylin.common.util.LocalFileMetadataTestCase;
import org.apache.kylin.rest.request.SQLRequest;
+import org.junit.After;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
-public class QueryUtilTest {
+public class QueryUtilTest extends LocalFileMetadataTestCase {
+
+ @Before
+ public void setUp() throws Exception {
+ this.createTestMetadata();
+ }
+
+ @After
+ public void after() throws Exception {
+ this.cleanupTestMetadata();
+ }
+
@Test
- public void testHealInterval() {
+ public void testMassageSql() {
{
SQLRequest sqlRequest = new SQLRequest();
sqlRequest.setSql("select ( date '2001-09-28' + interval floor(1.2) day) from test_kylin_fact");
@@ -37,15 +51,21 @@ public class QueryUtilTest {
String s = QueryUtil.massageSql(sqlRequest);
Assert.assertEquals("select ( date '2001-09-28' + interval '2' month) from test_kylin_fact group by ( date '2001-09-28' + interval '2' month)", s);
}
+ {
+ SQLRequest sqlRequest = new SQLRequest();
+ sqlRequest.setSql("select concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") ()");
+ String s = QueryUtil.massageSql(sqlRequest);
+ Assert.assertEquals("select {fn concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") } {fn concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") } ()", s);
+ }
}
@Test
- public void testHealConcat() {
+ public void testKeywordDefaultDirtyHack() {
{
SQLRequest sqlRequest = new SQLRequest();
- sqlRequest.setSql("select concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") ()");
+ sqlRequest.setSql("select * from DEFAULT.TEST_KYLIN_FACT");
String s = QueryUtil.massageSql(sqlRequest);
- Assert.assertEquals("select {fn concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") } {fn concat(\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\",\"TEST_KYLIN_FACT\".\"LSTG_FORMAT_NAME\") } ()", s);
+ Assert.assertEquals("select * from \"DEFAULT\".TEST_KYLIN_FACT", s);
}
}
}