Druid SQL ASTシステムの概要:
一、全体アーキテクチャ概要
Druid SQL解析は主に3つの層で構成されています: ソースコード文字列 → 字句解析(Lexer) → 構文解析(Parser) → AST抽象構文木 → Visitorによる走査/修正/SQL生成
完全な処理フロー:
SQLテキスト
↓
Lexer 字句解析(Tokenに分解)
↓
Parser 構文解析(TokenをASTノードに構築)
↓
SQLStatement / SQLExprで完全なAST木を形成
↓
VisitorパターンによるASTの走査、抽出、修正
↓
ASTからSQLテキストを再生成
Druidの核心的な位置づけ:データベースを跨ぎ、解析可能、走査可能、書き換え可能、フォーマット可能な SQL AST エンジン
二、主要コンポーネントの概要
1. 主要トップレベルクラス(必須)
| コンポーネント | 役割 |
|---|---|
DbType |
データベース方言:MySQL/Oracle/PG/SQLServer |
SQLUtils |
ツールエントリーポイント:フォーマット、解析、SQL生成、式の作成 |
SQLLexer |
字句解析器:SQLをTokenに分解 |
SQLParser |
構文解析器:TokenをAST木に構築 |
SQLStatement |
ASTトップレベルのステートメントノード(各SQLに対応) |
SQLExpr |
AST式ノード(where、case、関数、フィールド、定数) |
SQLObject |
全ASTノードの**ルート親クラス** |
SchemaStatVisitor |
組み込みVisitor:テーブル、フィールド、操作タイプ、条件の抽出 |
SQLASTVisitor |
カスタムAST走査/修正の親クラス |
SQLCreateTableStatement/SQLSelectStatement |
各種具体的なステートメントのAST実装クラス |
三、第一層:字句解析 Lexer(SQLLexer)
1. 職務
- SQL文字列全体をTokenトークンに分割
- キーワード、テーブル名、フィールド名、定数、記号、文字列、数字を認識
- 空白、改行、コメントをフィルタリング
2. Tokenタイプの例
- キーワード:
SELECT、FROM、WHERE、AND - 識別子:
user、id、username - 記号:
=、>、<、,、(、) - リテラル:
123、'張三'、3.14
3. 処理フロー
SQL文字ストリーム → Lexer → Tokenストリーム → Parserに渡す
4. 特徴
- 方言認識:異なるデータベースではキーワードが異なり、Lexerは
DbTypeに適応 - コメント、空白文字の自動無視
四、第二層:構文解析 Parser(SQLParser)
1. 職務
データベース構文規則に従い、Tokenを順次読み取り、再帰的にAST構文木を構築します。
2. 細分化されたParser実装
Druidはデータベースごとに専用Parserを分割しています:
MySqlParserOracleParserSQLServerParserPostgreSqlParserDb2Parser
3. 解析結果
- 単一SQL → 1つの
SQLStatement - 複数SQL →
List<SQLStatement>
4. 解析例外
構文エラーは直接ParserExceptionをスローし、SQL構文検証に利用できます。
五、第三層:AST抽象構文木の核心システム(最重要)
1. ASTトップレベル親クラス構造
すべてのノードは以下を継承します:
SQLObject
├─ SQLStatement // 完全なSQLステートメントノード
└─ SQLExpr // 式ノード(条件、関数、値、フィールド)
2. SQLStatementステートメントシステム(完全なSQL)
完全なSQLステートメントを表し、一般的な実装:
| ステートメントクラス | 対応SQL |
|---|---|
SQLSelectStatement |
SELECTクエリ |
SQLInsertStatement |
INSERT挿入 |
SQLUpdateStatement |
UPDATE更新 |
SQLDeleteStatement |
DELETE削除 |
SQLCreateTableStatement |
CREATE TABLE |
SQLAlterTableStatement |
ALTERテーブル構造 |
SQLDropTableStatement |
DROP TABLE |
構造例(SELECT):
SQLSelectStatement
├─ SQLSelectQueryBlock // クエリ本体
│ ├─ selectList クエリフィールドリスト
│ ├─ from テーブル/関連テーブル
│ ├─ where 条件句
│ ├─ groupBy グループ化
│ ├─ having グループ条件
│ └─ orderBy ソート
└─ ... その他の句
3. SQLExpr式システム(条件、フィールド、値)
すべての条件、フィールド、定数、関数、演算はSQLExprに属します
一般的な実装クラス:
SQLIdentifierExpr:フィールド名、テーブル名(例:id、username)SQLNumberExpr:数字定数(例:18、100)SQLCharExpr:文字列定数(例:'張三')SQLBinaryOpExpr:二項演算(例:a = b、age > 18)SQLInExpr:IN式SQLBetweenExpr:BETWEEN範囲SQLMethodInvokeExpr:関数(例:count()、sum())SQLCaseExpr:case when式
WHERE条件の実体はSQLExpr二分木であり、AND/ORを介して継続的にネストされます。
4. その他の一般的なASTノード
SQLTableSource:from後のテーブル、関連テーブルSQLJoinTableSource:JOIN関連SQLOrderByExpr:ソートフィールドSQLGroupByExpr:グループ化フィールドSQLColumnDefinition:テーブル作成フィールド定義
六、第四層:Visitorアクセスシステム(ASTの走査と修正)
1. 設計パターン
Visitorパターン:ASTノードは固定で、Visitorがすべてのノードを走査し、木構造を変更せずに以下の操作が可能:
- テーブル名、フィールドの抽出
- すべての条件の走査 WHERE条件の動的追加 テーブル名、フィールド名の置換 SQLマスキング、監査、権限書き換え
2. 主要Visitorクラス
SQLASTVisitorカスタムVisitorはこれを継承し、visitXxxメソッドをオーバーライドして対応ASTノードをインターセプトします。SchemaStatVisitor(組み込み常用) Druidが標準で提供し、直接使用可能:
- すべてのテーブル名を取得
- すべてのフィールドを取得
- SQL操作タイプSELECT/INSERT/UPDATEを取得
- WHERE条件、関連関係を取得
3. 走査フロー
AST木ルートノード → accept(visitor) → 自動的にすべての子ノードを再帰的に走査 → Visitor対応メソッドのコールバック
七、第五層:ASTからのSQL逆生成とフォーマット
1. 処理フロー
修正されたAST木 → toString / SQLUtils.toSQLStringを呼び出す → SQLテキストを再結合
2. フォーマット機能
SQLUtils.formatの内部:
- ASTを走査
- インデント、大文字小文字、改行規則に従って再レイアウト
- カスタムFormatOptionをサポート
八、完全な解析プロセスのデモンストレーション(上記アーキテクチャに対応)
String query = "select id,name from users where age > 18";
// 1. 方言を指定
DbType databaseType = DbType.mysql;
// 2. 字句+構文解析 → ASTを生成
List<SQLStatement> statementList = SQLUtils.parseStatements(query, databaseType);
SQLSelectStatement selectStatement = (SQLSelectStatement) statementList.get(0);
// 3. Visitorでテーブルとフィールドを抽出
SchemaStatVisitor extractor = SQLUtils.createSchemaStatVisitor(databaseType);
selectStatement.accept(extractor);
// 4. 解析結果を取得
System.out.println("テーブル:" + extractor.getTables());
System.out.println("フィールド:" + extractor.getColumns());
// 5. ASTからフォーマットされたSQLを再生成
String formattedSql = SQLUtils.toSQLString(selectStatement, databaseType);
System.out.println(formattedSql);
完全なプロセス:Lexer → Parser → AST → Visitor → SQL生成 全フロー。
九、Druid ASTの主要応用シナリオ(下位層の原理対応)
- マルチテナントへの自動テナントID追加
ASTを走査し、WHEREノードを見つけて
tenant_id = ?条件を追加 - シャーディング時の動的テーブル名置換
SQLTableSourceノードを走査し、テーブル名をシャーディング接尾辞に置換 - SQL監査における高リスク検出 ASTを解析し、DROP/ALTER/DELETE全テーブル無whereを検出
- データ権限の行レベルフィルタリング SELECTステートメントをインターセプトし、部署、データ範囲条件を動的に結合
- SQLフォーマット、構文検証 ASTに基づき再レイアウト、解析例外で構文の正当性を判断
- 汎用マッパー、動的SQL生成 手動でSQLSelectStatement + SQLExprを組み合わせてSQLを構築
十、システムの核心的まとめ(一言で覚える)
- Lexer:SQLをTokenに分割
- Parser:TokenでAST構文木を構築
- AST:SQLStatement(ステートメント) + SQLExpr(式) の2大システム
- Visitor:VisitorパターンでASTを走査、抽出、修正
- 最後に:ASTからSQLを逆生成 + フォーマット
全体のシステムは字句 → 構文 → AST木 → 走査 → 逆生成という標準的なコンパイラ原理のプロセスです。