語法解析器,根據(jù)不同類型的語句有不同的語法解析器去解析成成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() | 獲取參數(shù)位置 |
void setParametersIndex(int parametersIndex) | 重置參數(shù)位置 |
int increaseParametersIndex() | 增加參數(shù)位置 |
除了語法解析器SQLParser,還有SQL從句解析器SQLClauseParser,SQL別名解析器AliasExpressionParser,表達(dá)式解析器BasicExpressionParser涛菠。
如下圖:
SQLClauseParser.png
SQLStatement對象是個超類莉御,具體實(shí)現(xiàn)類有很多。按照不同的語句俗冻,返回不同的SQLStatement礁叔。
SQLStatement.png
api如下:
方法名 | 說明 |
---|---|
SQLType getType() | 獲取SQL類型,有DDL迄薄,DML琅关,DQL,DAL讥蔽,TCL |
Tables getTables(); | 獲取表集合 |
Conditions getConditions(); | 獲取條件 |
List<SQLToken> getSqlTokens(); | 獲取所有的SQLToken |
int getParametersIndex() | 獲取參數(shù)位置 |
void setParametersIndex(int parametersIndex) | 重置參數(shù)位置 |
int increaseParametersIndex() | 增加參數(shù)位置 |
不同的語句涣易,ddl画机,dml,tcl等新症,有不同的語法解析器SQLParser去解析步氏,Sharding-sphere如何根據(jù)不同的SQL去選擇不同的SQLParser?
這里和詞法分析器一樣账劲,同樣是使用工廠模式戳护,按照不同類型的SQL選擇不同的語法解析器金抡。根據(jù)數(shù)據(jù)庫類型瀑焦,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語句為例顷级,看一下如何通過數(shù)據(jù)庫類型選擇不同的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,根據(jù)SQL語句類型(DML凫乖,DDL)等路由到不同的方法,根據(jù)具體類型(Insert弓颈,update)等找到對應(yīng)的工廠模式帽芽,按照不同的數(shù)據(jù)庫類型返回具體的語法解析器SQLParser。
一條sql在執(zhí)行的時候翔冀,如何知道是什么類型的語句导街??
詞法分析器Lexer在解析Sql的時候纤子,第一個分詞就是SQL的具體類型(select,update)搬瑰,所以在執(zhí)行sql的時候,首先調(diào)用詞法分析器解析第一個分詞控硼,獲取語句類型泽论,然后選擇具體的語法解析器解析。和分詞器引擎一樣象颖,SQL語句解析器也有自己的解析引擎SQLParsingEngine
public final class SQLParsingEngine {
//數(shù)據(jù)庫類型
private final DatabaseType dbType;
//sql
private final String sql;
//分片規(guī)則
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();
}
//詞法解析器佩厚,根據(jù)不同的sql,獲取不同的詞法解析引擎
LexerEngine lexerEngine = LexerEngineFactory.newInstance(dbType, sql);
//解析第一個分詞说订,第一個分詞能區(qū)分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語句的流程毯辅。