mirror of
https://github.com/tencentmusic/supersonic.git
synced 2026-04-30 04:54:25 +08:00
Compare commits
6 Commits
738093bc88
...
9c10089707
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c10089707 | ||
|
|
0e6050e8ce | ||
|
|
61685d31f3 | ||
|
|
e0dc3fbf1a | ||
|
|
efddf4cacf | ||
|
|
732222ab98 |
@@ -26,6 +26,16 @@ public class SqlDialectFactory {
|
|||||||
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
|
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
|
||||||
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
||||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
|
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
|
||||||
|
public static final Context PRESTO_CONTEXT =
|
||||||
|
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.PRESTO)
|
||||||
|
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
|
||||||
|
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
||||||
|
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
|
||||||
|
public static final Context KYUUBI_CONTEXT =
|
||||||
|
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.BIG_QUERY)
|
||||||
|
.withLiteralQuoteString("'").withIdentifierQuoteString("`")
|
||||||
|
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
||||||
|
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(false);
|
||||||
private static Map<EngineType, SemanticSqlDialect> sqlDialectMap;
|
private static Map<EngineType, SemanticSqlDialect> sqlDialectMap;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -35,6 +45,10 @@ public class SqlDialectFactory {
|
|||||||
sqlDialectMap.put(EngineType.H2, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
sqlDialectMap.put(EngineType.H2, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
||||||
sqlDialectMap.put(EngineType.POSTGRESQL, new SemanticSqlDialect(POSTGRESQL_CONTEXT));
|
sqlDialectMap.put(EngineType.POSTGRESQL, new SemanticSqlDialect(POSTGRESQL_CONTEXT));
|
||||||
sqlDialectMap.put(EngineType.HANADB, new SemanticSqlDialect(HANADB_CONTEXT));
|
sqlDialectMap.put(EngineType.HANADB, new SemanticSqlDialect(HANADB_CONTEXT));
|
||||||
|
sqlDialectMap.put(EngineType.STARROCKS, new SemanticSqlDialect(DEFAULT_CONTEXT));
|
||||||
|
sqlDialectMap.put(EngineType.KYUUBI, new SemanticSqlDialect(KYUUBI_CONTEXT));
|
||||||
|
sqlDialectMap.put(EngineType.PRESTO, new SemanticSqlDialect(PRESTO_CONTEXT));
|
||||||
|
sqlDialectMap.put(EngineType.TRINO, new SemanticSqlDialect(PRESTO_CONTEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SemanticSqlDialect getSqlDialect(EngineType engineType) {
|
public static SemanticSqlDialect getSqlDialect(EngineType engineType) {
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ public class FiledFilterReplaceVisitor extends ExpressionVisitorAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExpressionList<?> leftFunctionParams = leftFunction.getParameters();
|
ExpressionList<?> leftFunctionParams = leftFunction.getParameters();
|
||||||
if (CollectionUtils.isEmpty(leftFunctionParams)) {
|
if (CollectionUtils.isEmpty(leftFunctionParams)
|
||||||
|
|| !(leftFunctionParams.get(0) instanceof Column)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ public class ModelDetail {
|
|||||||
|
|
||||||
private String tableQuery;
|
private String tableQuery;
|
||||||
|
|
||||||
|
private String filterSql;
|
||||||
|
|
||||||
private List<Identify> identifiers = Lists.newArrayList();
|
private List<Identify> identifiers = Lists.newArrayList();
|
||||||
|
|
||||||
private List<Dimension> dimensions = Lists.newArrayList();
|
private List<Dimension> dimensions = Lists.newArrayList();
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ public class ModelBuildReq {
|
|||||||
|
|
||||||
private String sql;
|
private String sql;
|
||||||
|
|
||||||
|
private String filterSql;
|
||||||
|
|
||||||
private String catalog;
|
private String catalog;
|
||||||
|
|
||||||
private String db;
|
private String db;
|
||||||
|
|||||||
@@ -50,19 +50,19 @@ public class SqlQueryParser implements QueryParser {
|
|||||||
queryFields.removeAll(queryAliases);
|
queryFields.removeAll(queryAliases);
|
||||||
Ontology ontology = queryStatement.getOntology();
|
Ontology ontology = queryStatement.getOntology();
|
||||||
OntologyQuery ontologyQuery = buildOntologyQuery(ontology, queryFields);
|
OntologyQuery ontologyQuery = buildOntologyQuery(ontology, queryFields);
|
||||||
// check if there are fields not matched with any metric or dimension
|
// // check if there are fields not matched with any metric or dimension
|
||||||
if (queryFields.size() > ontologyQuery.getMetrics().size()
|
// if (queryFields.size() > ontologyQuery.getMetrics().size()
|
||||||
+ ontologyQuery.getDimensions().size()) {
|
// + ontologyQuery.getDimensions().size()) {
|
||||||
List<String> semanticFields = Lists.newArrayList();
|
// List<String> semanticFields = Lists.newArrayList();
|
||||||
ontologyQuery.getMetrics().forEach(m -> semanticFields.add(m.getName()));
|
// ontologyQuery.getMetrics().forEach(m -> semanticFields.add(m.getName()));
|
||||||
ontologyQuery.getDimensions().forEach(d -> semanticFields.add(d.getName()));
|
// ontologyQuery.getDimensions().forEach(d -> semanticFields.add(d.getName()));
|
||||||
String errMsg =
|
// String errMsg =
|
||||||
String.format("Querying columns[%s] not matched with semantic fields[%s].",
|
// String.format("Querying columns[%s] not matched with semantic fields[%s].",
|
||||||
queryFields, semanticFields);
|
// queryFields, semanticFields);
|
||||||
queryStatement.setErrMsg(errMsg);
|
// queryStatement.setErrMsg(errMsg);
|
||||||
queryStatement.setStatus(QueryState.INVALID);
|
// queryStatement.setStatus(QueryState.INVALID);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
queryStatement.setOntologyQuery(ontologyQuery);
|
queryStatement.setOntologyQuery(ontologyQuery);
|
||||||
|
|
||||||
AggOption sqlQueryAggOption = getAggOption(sqlQuery.getSql(), ontologyQuery.getMetrics());
|
AggOption sqlQueryAggOption = getAggOption(sqlQuery.getSql(), ontologyQuery.getMetrics());
|
||||||
|
|||||||
@@ -40,11 +40,23 @@ public class DataModelNode extends SemanticNode {
|
|||||||
.equalsIgnoreCase(EngineType.POSTGRESQL.getName())) {
|
.equalsIgnoreCase(EngineType.POSTGRESQL.getName())) {
|
||||||
String fullTableName = String.join(".public.",
|
String fullTableName = String.join(".public.",
|
||||||
dataModel.getModelDetail().getTableQuery().split("\\."));
|
dataModel.getModelDetail().getTableQuery().split("\\."));
|
||||||
sqlTable = "select * from " + fullTableName;
|
sqlTable = "SELECT * FROM " + fullTableName;
|
||||||
} else {
|
} else {
|
||||||
sqlTable = "select * from " + dataModel.getModelDetail().getTableQuery();
|
sqlTable = "SELECT * FROM " + dataModel.getModelDetail().getTableQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String filterSql = dataModel.getFilterSql();
|
||||||
|
String filterSql = dataModel.getModelDetail().getFilterSql();
|
||||||
|
if (filterSql != null && !filterSql.isEmpty()) {
|
||||||
|
boolean sqlContainWhere = sqlTable.toUpperCase().matches("(?s).*\\bWHERE\\b.*");
|
||||||
|
if (sqlContainWhere) {
|
||||||
|
sqlTable = String.format("%s AND %s", sqlTable, filterSql);
|
||||||
|
} else {
|
||||||
|
sqlTable = String.format("%s WHERE %s", sqlTable, filterSql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sqlTable.isEmpty()) {
|
if (sqlTable.isEmpty()) {
|
||||||
throw new Exception("DataModelNode build error [tableSqlNode not found]");
|
throw new Exception("DataModelNode build error [tableSqlNode not found]");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ public abstract class SemanticNode {
|
|||||||
scope.getValidator().getCatalogReader().getRootSchema(), engineType);
|
scope.getValidator().getCatalogReader().getRootSchema(), engineType);
|
||||||
if (Configuration.getSqlAdvisor(sqlValidatorWithHints, engineType).getReservedAndKeyWords()
|
if (Configuration.getSqlAdvisor(sqlValidatorWithHints, engineType).getReservedAndKeyWords()
|
||||||
.contains(expression.toUpperCase())) {
|
.contains(expression.toUpperCase())) {
|
||||||
if (engineType == EngineType.HANADB) {
|
if (engineType == EngineType.HANADB || engineType == EngineType.PRESTO
|
||||||
|
|| engineType == EngineType.TRINO) {
|
||||||
expression = String.format("\"%s\"", expression);
|
expression = String.format("\"%s\"", expression);
|
||||||
} else {
|
} else {
|
||||||
expression = String.format("`%s`", expression);
|
expression = String.format("`%s`", expression);
|
||||||
@@ -166,9 +167,9 @@ public abstract class SemanticNode {
|
|||||||
if (sqlNode instanceof SqlBasicCall) {
|
if (sqlNode instanceof SqlBasicCall) {
|
||||||
SqlBasicCall sqlBasicCall = (SqlBasicCall) sqlNode;
|
SqlBasicCall sqlBasicCall = (SqlBasicCall) sqlNode;
|
||||||
if (sqlBasicCall.getOperator().getKind().equals(SqlKind.AS)) {
|
if (sqlBasicCall.getOperator().getKind().equals(SqlKind.AS)) {
|
||||||
if (sqlBasicCall.getOperandList().get(0) instanceof SqlSelect) {
|
SqlNode innerQuery = sqlBasicCall.getOperandList().get(0);
|
||||||
SqlSelect table = (SqlSelect) sqlBasicCall.getOperandList().get(0);
|
if (innerQuery instanceof SqlCall) {
|
||||||
return table;
|
return innerQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,13 @@ public class SqlBuilder {
|
|||||||
SqlNode parserNode = tableView.build();
|
SqlNode parserNode = tableView.build();
|
||||||
DatabaseResp database = queryStatement.getOntology().getDatabase();
|
DatabaseResp database = queryStatement.getOntology().getDatabase();
|
||||||
EngineType engineType = EngineType.fromString(database.getType());
|
EngineType engineType = EngineType.fromString(database.getType());
|
||||||
|
try {
|
||||||
parserNode = optimizeParseNode(parserNode, engineType);
|
parserNode = optimizeParseNode(parserNode, engineType);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// failure in optimization phase doesn't affect the query result,
|
||||||
|
// just ignore it
|
||||||
|
log.error("optimizeParseNode error", e);
|
||||||
|
}
|
||||||
return SemanticNode.getSql(parserNode, engineType);
|
return SemanticNode.getSql(parserNode, engineType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public class ModelYamlManager {
|
|||||||
} else {
|
} else {
|
||||||
dataModelYamlTpl.setTableQuery(modelDetail.getTableQuery());
|
dataModelYamlTpl.setTableQuery(modelDetail.getTableQuery());
|
||||||
}
|
}
|
||||||
|
dataModelYamlTpl.setFilterSql(modelDetail.getFilterSql());
|
||||||
dataModelYamlTpl.setFields(modelResp.getModelDetail().getFields());
|
dataModelYamlTpl.setFields(modelResp.getModelDetail().getFields());
|
||||||
dataModelYamlTpl.setId(modelResp.getId());
|
dataModelYamlTpl.setId(modelResp.getId());
|
||||||
return dataModelYamlTpl;
|
return dataModelYamlTpl;
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ public class SemanticSchemaManager {
|
|||||||
modelDetail.setDbType(d.getType());
|
modelDetail.setDbType(d.getType());
|
||||||
modelDetail.setSqlQuery(d.getSqlQuery());
|
modelDetail.setSqlQuery(d.getSqlQuery());
|
||||||
modelDetail.setTableQuery(d.getTableQuery());
|
modelDetail.setTableQuery(d.getTableQuery());
|
||||||
|
modelDetail.setFilterSql(d.getFilterSql());
|
||||||
modelDetail.getIdentifiers().addAll(getIdentify(d.getIdentifiers()));
|
modelDetail.getIdentifiers().addAll(getIdentify(d.getIdentifiers()));
|
||||||
modelDetail.getMeasures().addAll(getMeasureParams(d.getMeasures()));
|
modelDetail.getMeasures().addAll(getMeasureParams(d.getMeasures()));
|
||||||
modelDetail.getDimensions().addAll(getDimensions(d.getDimensions()));
|
modelDetail.getDimensions().addAll(getDimensions(d.getDimensions()));
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ public class DataModelYamlTpl {
|
|||||||
|
|
||||||
private String tableQuery;
|
private String tableQuery;
|
||||||
|
|
||||||
|
private String filterSql;
|
||||||
|
|
||||||
private List<IdentifyYamlTpl> identifiers;
|
private List<IdentifyYamlTpl> identifiers;
|
||||||
|
|
||||||
private List<DimensionYamlTpl> dimensions;
|
private List<DimensionYamlTpl> dimensions;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.tencent.supersonic.common.pojo.QueryColumn;
|
import com.tencent.supersonic.common.pojo.QueryColumn;
|
||||||
import com.tencent.supersonic.common.pojo.User;
|
import com.tencent.supersonic.common.pojo.User;
|
||||||
|
import com.tencent.supersonic.common.pojo.enums.AuthType;
|
||||||
import com.tencent.supersonic.common.pojo.enums.EngineType;
|
import com.tencent.supersonic.common.pojo.enums.EngineType;
|
||||||
import com.tencent.supersonic.headless.api.pojo.DBColumn;
|
import com.tencent.supersonic.headless.api.pojo.DBColumn;
|
||||||
import com.tencent.supersonic.headless.api.pojo.enums.DataType;
|
import com.tencent.supersonic.headless.api.pojo.enums.DataType;
|
||||||
@@ -79,8 +80,9 @@ public class DatabaseServiceImpl extends ServiceImpl<DatabaseDOMapper, DatabaseD
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DatabaseResp> getDatabaseList(User user) {
|
public List<DatabaseResp> getDatabaseList(User user) {
|
||||||
List<DatabaseResp> databaseResps =
|
List<DatabaseResp> databaseResps = list().stream().map(DatabaseConverter::convert)
|
||||||
list().stream().map(DatabaseConverter::convert).collect(Collectors.toList());
|
.filter(database -> filterByAuth(database, user, AuthType.VIEWER))
|
||||||
|
.collect(Collectors.toList());
|
||||||
fillPermission(databaseResps, user);
|
fillPermission(databaseResps, user);
|
||||||
return databaseResps;
|
return databaseResps;
|
||||||
}
|
}
|
||||||
@@ -100,6 +102,43 @@ public class DatabaseServiceImpl extends ServiceImpl<DatabaseDOMapper, DatabaseD
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean filterByAuth(DatabaseResp database, User user, AuthType authType) {
|
||||||
|
if (user.isSuperAdmin() || user.getName().equals(database.getCreatedBy())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
authType = authType == null ? AuthType.VIEWER : authType;
|
||||||
|
switch (authType) {
|
||||||
|
case ADMIN:
|
||||||
|
return checkAdminPermission(user, database);
|
||||||
|
case VIEWER:
|
||||||
|
default:
|
||||||
|
return checkViewPermission(user, database);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkAdminPermission(User user, DatabaseResp database) {
|
||||||
|
List<String> admins = database.getAdmins();
|
||||||
|
if (user.isSuperAdmin()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (admins.contains(user.getName()) || database.getCreatedBy().equals(user.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkViewPermission(User user, DatabaseResp database) {
|
||||||
|
if (checkAdminPermission(user, database)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
List<String> viewers = database.getViewers();
|
||||||
|
|
||||||
|
if (viewers.contains(user.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteDatabase(Long databaseId) {
|
public void deleteDatabase(Long databaseId) {
|
||||||
ModelFilter modelFilter = new ModelFilter();
|
ModelFilter modelFilter = new ModelFilter();
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ public class ModelConverter {
|
|||||||
modelDetail.setQueryType(ModelDefineType.TABLE_QUERY.getName());
|
modelDetail.setQueryType(ModelDefineType.TABLE_QUERY.getName());
|
||||||
modelDetail.setTableQuery(String.format("%s.%s", modelBuildReq.getDb(), tableName));
|
modelDetail.setTableQuery(String.format("%s.%s", modelBuildReq.getDb(), tableName));
|
||||||
}
|
}
|
||||||
|
modelDetail.setFilterSql(modelBuildReq.getFilterSql());
|
||||||
for (ColumnSchema columnSchema : modelSchema.getColumnSchemas()) {
|
for (ColumnSchema columnSchema : modelSchema.getColumnSchemas()) {
|
||||||
FieldType fieldType = columnSchema.getFiledType();
|
FieldType fieldType = columnSchema.getFiledType();
|
||||||
if (getIdentifyType(fieldType) != null) {
|
if (getIdentifyType(fieldType) != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user