4 Commits

Author SHA1 Message Date
beat4ocean
fb71ed3dc1 Merge 738093bc88 into f764236657 2025-03-05 16:50:12 +08:00
jerryjzhang
f764236657 (improvement)(headless)Optimize compatibility and robustness in ontology query translation.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-05 16:48:40 +08:00
zyclove
efddf4cacf fix: https://github.com/tencentmusic/supersonic/issues/2132 (#2137) 2025-03-05 14:54:16 +08:00
jerryjzhang
732222ab98 (fix)(headless)Fix database permission check.
(fix)(headless)Fix database permission check.
2025-03-05 14:39:53 +08:00
4 changed files with 67 additions and 7 deletions

View File

@@ -26,6 +26,16 @@ public class SqlDialectFactory {
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
.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;
static {
@@ -35,6 +45,10 @@ public class SqlDialectFactory {
sqlDialectMap.put(EngineType.H2, new SemanticSqlDialect(DEFAULT_CONTEXT));
sqlDialectMap.put(EngineType.POSTGRESQL, new SemanticSqlDialect(POSTGRESQL_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) {

View File

@@ -78,7 +78,8 @@ public abstract class SemanticNode {
scope.getValidator().getCatalogReader().getRootSchema(), engineType);
if (Configuration.getSqlAdvisor(sqlValidatorWithHints, engineType).getReservedAndKeyWords()
.contains(expression.toUpperCase())) {
if (engineType == EngineType.HANADB) {
if (engineType == EngineType.HANADB || engineType == EngineType.PRESTO
|| engineType == EngineType.TRINO) {
expression = String.format("\"%s\"", expression);
} else {
expression = String.format("`%s`", expression);
@@ -166,9 +167,9 @@ public abstract class SemanticNode {
if (sqlNode instanceof SqlBasicCall) {
SqlBasicCall sqlBasicCall = (SqlBasicCall) sqlNode;
if (sqlBasicCall.getOperator().getKind().equals(SqlKind.AS)) {
if (sqlBasicCall.getOperandList().get(0) instanceof SqlSelect) {
SqlSelect table = (SqlSelect) sqlBasicCall.getOperandList().get(0);
return table;
SqlNode innerQuery = sqlBasicCall.getOperandList().get(0);
if (innerQuery instanceof SqlCall) {
return innerQuery;
}
}
}

View File

@@ -69,7 +69,13 @@ public class SqlBuilder {
SqlNode parserNode = tableView.build();
DatabaseResp database = queryStatement.getOntology().getDatabase();
EngineType engineType = EngineType.fromString(database.getType());
parserNode = optimizeParseNode(parserNode, engineType);
try {
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);
}

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.tencent.supersonic.common.pojo.QueryColumn;
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.headless.api.pojo.DBColumn;
import com.tencent.supersonic.headless.api.pojo.enums.DataType;
@@ -79,8 +80,9 @@ public class DatabaseServiceImpl extends ServiceImpl<DatabaseDOMapper, DatabaseD
@Override
public List<DatabaseResp> getDatabaseList(User user) {
List<DatabaseResp> databaseResps =
list().stream().map(DatabaseConverter::convert).collect(Collectors.toList());
List<DatabaseResp> databaseResps = list().stream().map(DatabaseConverter::convert)
.filter(database -> filterByAuth(database, user, AuthType.VIEWER))
.collect(Collectors.toList());
fillPermission(databaseResps, user);
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
public void deleteDatabase(Long databaseId) {
ModelFilter modelFilter = new ModelFilter();