天天看點

ShardingSphere的SQL解析ShardingSphere的SQL解析

ShardingSphere的SQL解析

本篇文章源碼基于4.0.1版本

ShardingSphere的分片引擎從解析引擎到路由引擎到改寫引擎到執行引擎再到歸并引擎,一步一步對分片操作進行處理,我們這篇文章先從解析引擎開始,深入分析一下Sql的解析引擎處理流程。

解析Sql的入口

SQLParseEngine這個類是sql解析引擎對應的類,通過看它的parse()方法,我們知道sql解析的過程就是建構SQLStatement對象的過程,方法中調用了SQLParseKernel來建立對象,然後調用它的parse()方法來完成。是以我們把重心放在這個方法上

解析Sql

SQLParseKernel的parse()方法:

public SQLStatement parse() {
    SQLAST ast = parserEngine.parse();
    Collection<SQLSegment> sqlSegments = extractorEngine.extract(ast);
    Map<ParserRuleContext, Integer> parameterMarkerIndexes = ast.getParameterMarkerIndexes();
    return fillerEngine.fill(sqlSegments, parameterMarkerIndexes.size(), ast.getSqlStatementRule());
}
           
  1. 将原始SQL通過解析器解析為抽象文法樹
  2. 使用提取器根據提取規則提取Sql片段結合
  3. 使用填充器根據填充規則填充Sql片段生成SQL解析後的結果并傳回

下面将具體看一下這三步

1. 将 SQL 解析為抽象文法樹

這一塊是對應的SQLParserEngine的parse()方法,這個方法的主要邏輯是利用工廠類SQLParserFactory來建立Sql解析器執行個體,由于不同的資料庫對應的SQL解析器也不相同,是以這一塊的邏輯也是利用了Java的SPI機制來建立配置的SQLParserEntry執行個體對象,根據不同的資料庫類型選擇不同的Sql解析器,最終會生成SQLAST對象,也就是SQL 的抽象文法樹。

2. 提取Sql片段

這一步對應的是SQLSegmentsExtractorEngine的extract()方法,傳回的是所有的Sql片段的集合。

周遊抽象文法樹中的Sql片段的提取器,提取器分為兩種類型,一種是單節點的Sql片段提取器,這時候就直接擷取Sql片段,放入集合中就可以了,另一種是樹狀節點的Sql片段提取線,這時候就需要周遊這棵樹,将結果放入集合中。看!資料結構之樹的周遊用到了吧,以後别說資料結構沒用了。。

3. 填充Sql片段,生成解析結果

public SQLStatement fill(final Collection<SQLSegment> sqlSegments, final int parameterMarkerCount, final SQLStatementRule rule) {
    SQLStatement result = rule.getSqlStatementClass().newInstance();
    Preconditions.checkArgument(result instanceof AbstractSQLStatement, "%s must extends AbstractSQLStatement", result.getClass().getName());
    ((AbstractSQLStatement) result).setParametersCount(parameterMarkerCount);
    result.getAllSQLSegments().addAll(sqlSegments);
    for (SQLSegment each : sqlSegments) {
        Optional<SQLSegmentFiller> filler = parseRuleRegistry.findSQLSegmentFiller(databaseTypeName, each.getClass());
        if (filler.isPresent()) {
            filler.get().fill(each, result);
        }
    }
    return result;
}
           
  1. 擷取SQLStatement對象,對SQLStatement進行合法性進行校驗
  2. 設定結果的參數的個數
  3. 将上一步中的SQL片段集合添加到結果對象中
  4. 周遊Sql片段,根據資料庫類型和Sql片段找到Sql片段過濾器,利用Sql片段過濾器來填充Sql片段
  5. 最後傳回解析後的SQLStatement

總結

❤️ 感謝大家

  1. 歡迎關注我❤️,點贊👍🏻,評論🤤,轉發🙏
  2. 有不當之處歡迎批評指正。