diff --git a/common/src/main/java/com/tencent/supersonic/common/jsqlparser/FieldAliasReplaceWithBackticksVisitor.java b/common/src/main/java/com/tencent/supersonic/common/jsqlparser/FieldAliasReplaceWithBackticksVisitor.java new file mode 100644 index 000000000..151d77331 --- /dev/null +++ b/common/src/main/java/com/tencent/supersonic/common/jsqlparser/FieldAliasReplaceWithBackticksVisitor.java @@ -0,0 +1,33 @@ +package com.tencent.supersonic.common.jsqlparser; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.select.SelectItem; +import net.sf.jsqlparser.statement.select.SelectItemVisitorAdapter; +import org.apache.commons.lang3.StringUtils; + +public class FieldAliasReplaceWithBackticksVisitor extends SelectItemVisitorAdapter { + + @Override + public void visit(SelectItem selectExpressionItem) { + Alias alias = selectExpressionItem.getAlias(); + if (alias == null) { + return; + } + String aliasName = alias.getName(); + String replaceValue = addBackticks(aliasName); + if (StringUtils.isBlank(replaceValue)) { + return; + } + alias.setName(replaceValue); + } + + private String addBackticks(String aliasName) { + if (StringUtils.isBlank(aliasName)) { + return ""; + } + if (aliasName.startsWith("`") && aliasName.endsWith("`")) { + return ""; + } + return "`" + aliasName + "`"; + } +} diff --git a/common/src/main/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelper.java b/common/src/main/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelper.java index 0a5f7f562..aa09cc847 100644 --- a/common/src/main/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelper.java +++ b/common/src/main/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelper.java @@ -486,6 +486,19 @@ public static String replaceAliasFieldName(String sql, Map field return selectStatement.toString(); } + public static String replaceAliasWithBackticks(String sql) { + Select selectStatement = SqlSelectHelper.getSelect(sql); + if (!(selectStatement instanceof PlainSelect)) { + return sql; + } + PlainSelect plainSelect = (PlainSelect) selectStatement; + FieldAliasReplaceWithBackticksVisitor visitor = new FieldAliasReplaceWithBackticksVisitor(); + for (SelectItem selectItem : plainSelect.getSelectItems()) { + selectItem.accept(visitor); + } + return selectStatement.toString(); + } + public static String replaceAlias(String sql) { Select selectStatement = SqlSelectHelper.getSelect(sql); if (!(selectStatement instanceof PlainSelect)) { diff --git a/common/src/test/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelperTest.java b/common/src/test/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelperTest.java index 16557d7cc..515557a97 100644 --- a/common/src/test/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelperTest.java +++ b/common/src/test/java/com/tencent/supersonic/common/jsqlparser/SqlReplaceHelperTest.java @@ -302,6 +302,26 @@ void testReplaceAlias() { replaceSql); } + @Test + void testReplaceAliasWithBackticks() { + String sql = "SELECT 部门, SUM(访问次数) AS 总访问次数 FROM 超音数 WHERE " + + "datediff('day', 数据日期, '2023-09-05') <= 3 GROUP BY 部门 ORDER BY 总访问次数 DESC LIMIT 10"; + String replaceSql = SqlReplaceHelper.replaceAliasWithBackticks(sql); + System.out.println(replaceSql); + Assert.assertEquals("SELECT 部门, SUM(访问次数) AS `总访问次数` FROM 超音数 WHERE " + + "datediff('day', 数据日期, '2023-09-05') <= 3 GROUP BY 部门 ORDER BY 总访问次数 DESC LIMIT 10", + replaceSql); + + sql = "select 部门, sum(访问次数) as 访问次数 from 超音数 where " + + "(datediff('day', 数据日期, '2023-09-05') <= 3) and 数据日期 = '2023-10-10' " + + "group by 部门 order by 访问次数 desc limit 10"; + replaceSql = SqlReplaceHelper.replaceAliasWithBackticks(sql); + System.out.println(replaceSql); + Assert.assertEquals("SELECT 部门, sum(访问次数) AS `访问次数` FROM 超音数 WHERE (datediff('day', 数据日期, " + + "'2023-09-05') <= 3) AND 数据日期 = '2023-10-10' GROUP BY 部门 ORDER BY 访问次数 DESC LIMIT 10", + replaceSql); + } + @Test void testReplaceAliasFieldName() { Map map = new HashMap<>(); diff --git a/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/SqlQueryParser.java b/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/SqlQueryParser.java index e4c523c23..540af5180 100644 --- a/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/SqlQueryParser.java +++ b/headless/core/src/main/java/com/tencent/supersonic/headless/core/translator/parser/SqlQueryParser.java @@ -68,6 +68,8 @@ public void parse(QueryStatement queryStatement) throws Exception { ontologyQuery.setAggOption(sqlQueryAggOption); convertNameToBizName(queryStatement); + // Solve the problem of SQL execution error when alias is Chinese + aliasesWithBackticks(queryStatement); rewriteOrderBy(queryStatement); // fill sqlQuery @@ -88,6 +90,12 @@ public void parse(QueryStatement queryStatement) throws Exception { log.info("parse sqlQuery [{}] ", sqlQuery); } + private void aliasesWithBackticks(QueryStatement queryStatement) { + String sql = queryStatement.getSqlQuery().getSql(); + sql = SqlReplaceHelper.replaceAliasWithBackticks(sql); + queryStatement.getSqlQuery().setSql(sql); + } + private AggOption getAggOption(String sql, Set metricSchemas) { if (SqlSelectFunctionHelper.hasAggregateFunction(sql)) { return AggOption.AGGREGATION;