背景
SQL解析是ShardingSphere中,处理sql第一步
sql解析引擎
ShardingSphere的一个sql解析引擎:SQL解析引擎,这里我们进入SQLParserEngine类,看下SQL解析引擎的实现。org.apache.shardingsphere.sql.parser.SQLParserEngine
public final class SQLParserEngine {
private final String databaseTypeName;
private final SQLParseResultCache cache = new SQLParseResultCache();
…
/**
* Parse SQL.
*
* @param sql SQL
* @param useCache use cache or not
* @return SQL statement
*/
public SQLStatement parse(final String sql, final boolean useCache) {
ParsingHook parsingHook = new SPIParsingHook();// SQL解析hook
parsingHook.start(sql);
try {
SQLStatement result = parse0(sql, useCache);
parsingHook.finishSuccess(result);
return result;
// CHECKSTYLE:OFF
} catch (final Exception ex) {
// CHECKSTYLE:ON
parsingHook.finishFailure(ex);
throw ex;
}
}
private SQLStatement parse0(final String sql, final boolean useCache) {
if (useCache) {
Optional<SQLStatement> cachedSQLStatement = cache.getSQLStatement(sql);
if (cachedSQLStatement.isPresent()) {// 如果缓存中有该SQL的解析结果,则直接复用
return cachedSQLStatement.get();
}
}
ParseTree parseTree = new SQLParserExecutor(databaseTypeName, sql).execute().getRootNode();// 1. 解析SQL生成AST,ParseTree是antlr对应的解析树接口
SQLStatement result = (SQLStatement) ParseTreeVisitorFactory.newInstance(databaseTypeName, VisitorRule.valueOf(parseTree.getClass())).visit(parseTree);//2. 通过访问者模式,将antlr的解析树转化为SQLStatement
if (useCache) {
cache.put(sql, result);
}
return result;
}
内部通过调用SQLParserExecutor.execute()方法,获取解析树ParseASTNode
然后通过ParseTreeVisitor访问解析树,生成SQLStatement
SQLParserExecutor
public final class SQLParserExecutor {
private final String databaseTypeName;
private final String sql;
/**
* Execute to parse SQL.
*
* @return AST node
*/
public ParseASTNode execute() {
ParseASTNode result = towPhaseParse();
if (result.getRootNode() instanceof ErrorNode) {
throw new SQLParsingException(String.format("Unsupported SQL of `%s`", sql));
}
return result;
}
private ParseASTNode towPhaseParse() {//名称可能拼错了,可能是two towPhaseParse?
SQLParser sqlParser = SQLParserFactory.newInstance(databaseTypeName, sql);//创建该类型数据库对应的SQL解析器
try {
((Parser) sqlParser).setErrorHandler(new BailErrorStrategy());
((Parser) sqlParser).getInterpreter().setPredictionMode(PredictionMode.SLL);
return (ParseASTNode) sqlParser.parse();
} catch (final ParseCancellationException ex) {
((Parser) sqlParser).reset();
((Parser) sqlParser).setErrorHandler(new DefaultErrorStrategy());
((Parser) sqlParser).getInterpreter().setPredictionMode(PredictionMode.LL);
return (ParseASTNode) sqlParser.parse();
}
}
ParseTreeVisitorFactory
/**
* Parse tree visitor factory.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ParseTreeVisitorFactory {
/**
* New instance of SQL visitor.
*
* @param databaseTypeName name of database type
* @param visitorRule visitor rule
* @return parse tree visitor
*/
public static ParseTreeVisitor newInstance(final String databaseTypeName, final VisitorRule visitorRule) {
for (SQLParserConfiguration each : NewInstanceServiceLoader.newServiceInstances(SQLParserConfiguration.class)) {
if (each.getDatabaseTypeName().equals(databaseTypeName)) {
return createParseTreeVisitor(each, visitorRule.getType());
}
}
throw new UnsupportedOperationException(String.format("Cannot support database type '%s'", databaseTypeName));
}
@SneakyThrows
private static ParseTreeVisitor createParseTreeVisitor(final SQLParserConfiguration configuration, final SQLStatementType type) {
SQLVisitorFacade visitorFacade = configuration.getVisitorFacadeClass().getConstructor().newInstance();
switch (type) {
case DML:
return (ParseTreeVisitor) visitorFacade.getDMLVisitorClass().getConstructor().newInstance();
case DDL:
return (ParseTreeVisitor) visitorFacade.getDDLVisitorClass().getConstructor().newInstance();
case TCL:
return (ParseTreeVisitor) visitorFacade.getTCLVisitorClass().getConstructor().newInstance();
case DCL:
return (ParseTreeVisitor) visitorFacade.getDCLVisitorClass().getConstructor().newInstance();
case DAL:
return (ParseTreeVisitor) visitorFacade.getDALVisitorClass().getConstructor().newInstance();
case RL:
return (ParseTreeVisitor) visitorFacade.getRLVisitorClass().getConstructor().newInstance();
default:
throw new SQLParsingException("Can not support SQL statement type: `%s`", type);
}
}
}
调用SQLParserExecutor和ParseTreeVisitorFactory时,已经使用antlr类