美文网首页
sharding-sphere之语法解析器

sharding-sphere之语法解析器

作者: 一滴水的坚持 | 来源:发表于2018-06-11 11:27 被阅读0次

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

    SQLParser.png
    可以看到,不同的sql有不同的处理解析器去解析,解析完成之后,会将SQL解析成SQLStatement,看一下SQLParser的定义:
    public interface SQLParser {
       SQLStatement parse();
    }
    
    方法名 说明
    SQLType getType() 获取SQL类型,有DDL,DML,DQL,DAL,TCL
    Tables getTables(); 获取表集合
    Conditions getConditions(); 获取条件
    List<SQLToken> getSqlTokens(); 获取所有的SQLToken
    int getParametersIndex() 获取参数位置
    void setParametersIndex(int parametersIndex) 重置参数位置
    int increaseParametersIndex() 增加参数位置

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

    SQLClauseParser.png
    SQLStatement对象是个超类,具体实现类有很多。按照不同的语句,返回不同的SQLStatement
    SQLStatement.png
    api如下:
    方法名 说明
    SQLType getType() 获取SQL类型,有DDL,DML,DQL,DAL,TCL
    Tables getTables(); 获取表集合
    Conditions getConditions(); 获取条件
    List<SQLToken> 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<SQLStatement> 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语句解析的过程如下图:


    语法解析器.png

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

    相关文章

      网友评论

          本文标题:sharding-sphere之语法解析器

          本文链接:https://www.haomeiwen.com/subject/jqzxeftx.html