sharding-sphere之语法解析器

语法解析器,根据不同类型的语句有不同的语法解析器去解析成成SQLStatement,SQL解析器的类图我用脑图画出来如下:

sharding-sphere之语法解析器_第1张图片
SQLParser.png

可以看到,不同的sql有不同的处理解析器去解析,解析完成之后,会将SQL解析成 SQLStatement,看一下 SQLParser的定义:

public interface SQLParser {
   SQLStatement parse();
}
方法名 说明
SQLType getType() 获取SQL类型,有DDL,DML,DQL,DAL,TCL
Tables getTables(); 获取表集合
Conditions getConditions(); 获取条件
List getSqlTokens(); 获取所有的SQLToken
int getParametersIndex() 获取参数位置
void setParametersIndex(int parametersIndex) 重置参数位置
int increaseParametersIndex() 增加参数位置

除了语法解析器SQLParser,还有SQL从句解析器SQLClauseParser,SQL别名解析器AliasExpressionParser,表达式解析器BasicExpressionParser
如下图:

sharding-sphere之语法解析器_第2张图片
SQLClauseParser.png

SQLStatement对象是个超类,具体实现类有很多。按照不同的语句,返回不同的 SQLStatement
sharding-sphere之语法解析器_第3张图片
SQLStatement.png

api如下:

方法名 说明
SQLType getType() 获取SQL类型,有DDL,DML,DQL,DAL,TCL
Tables getTables(); 获取表集合
Conditions getConditions(); 获取条件
List getSqlTokens(); 获取所有的SQLToken
int getParametersIndex() 获取参数位置
void setParametersIndex(int parametersIndex) 重置参数位置
int increaseParametersIndex() 增加参数位置

不同的语句,ddldmltcl等,有不同的语法解析器SQLParser去解析,Sharding-sphere如何根据不同的SQL去选择不同的SQLParser

这里和词法分析器一样,同样是使用工厂模式,按照不同类型的SQL选择不同的语法解析器。根据数据库类型,DB类型分词解析器获取语法解析器。

public final class SQLParserFactory {
    public static SQLParser newInstance(final DatabaseType dbType, final TokenType tokenType, final ShardingRule shardingRule, final LexerEngine lexerEngine, final ShardingMetaData shardingMetaData) {
        //如果是DQL语句 select语句
        if (isDQL(tokenType)) {
            return getDQLParser(dbType, shardingRule, lexerEngine, shardingMetaData);
        }
        //DML语句 insert,update,delete语句
        if (isDML(tokenType)) {
            return getDMLParser(dbType, tokenType, shardingRule, lexerEngine, shardingMetaData);
        }
        //DDL语句 create,alter,drop,TRUNCATE语句
        if (isDDL(tokenType)) {
            return getDDLParser(dbType, tokenType, shardingRule, lexerEngine);
        }
        //TCL语句 set,commit,rollBack,savePoint,begin语句
        if (isTCL(tokenType)) {
            return getTCLParser(dbType, shardingRule, lexerEngine);
        }
        //DAL语句,use,desc,describe,show语句
        if (isDAL(tokenType)) {
            return getDALParser(dbType, (Keyword) tokenType, shardingRule, lexerEngine);
        }
        throw new SQLParsingUnsupportedException(tokenType);
    }
}

这里以insert语句为例,看一下如何通过数据库类型选择不同的SQLParser

private static SQLParser getDMLParser(
        final DatabaseType dbType, final TokenType tokenType, final ShardingRule shardingRule, final LexerEngine lexerEngine, final ShardingMetaData shardingMetaData) {
    switch ((DefaultKeyword) tokenType) {
        case INSERT:
             //如果Insert语句
            return InsertParserFactory.newInstance(dbType, shardingRule, lexerEngine, shardingMetaData);
        case UPDATE:
            return UpdateParserFactory.newInstance(dbType, shardingRule, lexerEngine);
        case DELETE:
            return DeleteParserFactory.newInstance(dbType, shardingRule, lexerEngine);
        default:
            throw new SQLParsingUnsupportedException(tokenType);
    }
}
public final class InsertParserFactory {
    public static AbstractInsertParser newInstance(final DatabaseType dbType, final ShardingRule shardingRule, final LexerEngine lexerEngine, final ShardingMetaData shardingMetaData) {
        switch (dbType) {
            case H2:
            case MySQL:
                return new MySQLInsertParser(shardingRule, lexerEngine, shardingMetaData);
            case Oracle:
                return new OracleInsertParser(shardingRule, lexerEngine, shardingMetaData);
            case SQLServer:
                return new SQLServerInsertParser(shardingRule, lexerEngine, shardingMetaData);
            case PostgreSQL:
                return new PostgreSQLInsertParser(shardingRule, lexerEngine, shardingMetaData);
            default:
                throw new UnsupportedOperationException(String.format("Cannot support database [%s].", dbType));
        }
    }
}

能够看到,通过多个Factory,根据SQL语句类型(DML,DDL)等路由到不同的方法,根据具体类型(Insert,update)等找到对应的工厂模式,按照不同的数据库类型返回具体的语法解析器SQLParser

一条sql在执行的时候,如何知道是什么类型的语句??

词法分析器Lexer在解析Sql的时候,第一个分词就是SQL的具体类型(select,update),所以在执行sql的时候,首先调用词法分析器解析第一个分词,获取语句类型,然后选择具体的语法解析器解析。和分词器引擎一样,SQL语句解析器也有自己的解析引擎SQLParsingEngine

public final class SQLParsingEngine {
    //数据库类型
    private final DatabaseType dbType;    
    //sql
    private final String sql;   
    //分片规则
    private final ShardingRule shardingRule;
    private final ShardingMetaData shardingMetaData;
    
    public SQLStatement parse(final boolean useCache) {
        //是否从缓存中获取
        Optional cachedSQLStatement = getSQLStatementFromCache(useCache);
        if (cachedSQLStatement.isPresent()) {
            return cachedSQLStatement.get();
        }
        //词法解析器,根据不同的sql,获取不同的词法解析引擎
        LexerEngine lexerEngine = LexerEngineFactory.newInstance(dbType, sql);
        //解析第一个分词,第一个分词能区分sql类型
        lexerEngine.nextToken();
        //不同的sql解析器去做解析,完成解析工作,返回SQLStatement
        SQLStatement result = SQLParserFactory.newInstance(dbType, lexerEngine.getCurrentToken().getType(), shardingRule, lexerEngine, shardingMetaData).parse();
        if (useCache) {
            ParsingResultCache.getInstance().put(sql, result);
        }
        return result;
    }
}

所以sql语句解析的过程如下图:


sharding-sphere之语法解析器_第4张图片
语法解析器.png

终于把sql语法解析器的流程梳理清楚了。
下一篇,分析insert语句的流程。

你可能感兴趣的:(sharding-sphere之语法解析器)