
解析ast操作
解析语句相对简单,wiki上直接有示例,如:
String dbType = JdbcConstants.MYSQL;
List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dbType);
SQLUtils的parseStatements方法会把你传入的SQL语句给解析成SQLStatement对象集合,每一个SQLStatement代表一条完整的SQL语句,如:
SELECT id FROM user WHERE status = 1
多个SQLStatement如:
SELECT id FROM user WHERE status = 1;
SELECT id FROM order WHERE create_time > '2018-01-01'
一般上我们只处理一条语句。
ast的结构(继承实现关系)
SQL类型四种结构实现(SQLStatement)
SQLStatement表示一条SQL语句,我们知道常见的SQL语句有CRUD四种操作,所以SQLStatement会有四种主要实现类,如:
class SQLSelectStatement implements SQLStatement {
SQLSelect select;
}
class SQLUpdateStatement implements SQLStatement {
SQLExprTableSource tableSource;
List<SQLUpdateSetItem> items;
SQLExpr where;
}
class SQLDeleteStatement implements SQLStatement {
SQLTableSource tableSource;
SQLExpr where;
}
class SQLInsertStatement implements SQLStatement {
SQLExprTableSource tableSource;
List<SQLExpr> columns;
SQLSelect query;
}
这里我们以SQLSelectStatement来说明,ast既然是SQL的语法结构表示。
我们先看一下ast和SQL 增删改查语法的主要对应结构如下:

可替换SQL组件类(SQLReplaceable接口实现)
**介绍:**SQLReplaceable 接口允许你把一个 SQL 表达式或者对象替换成另外一个,这在 SQL 解析、优化以及转换的过程中很有用。借助这个接口,你可以对 SQL 语句里的特定部分进行修改或者替换,从而实现自定义的 SQL 处理逻辑。
**实际应用:**例如 SQLLimit 是用于限制查询结果数量的组件,SQLOrderBy 是用于对查询结果进行排序的组件。
小组件节点SQLSelectItem、SQLSelectGroupByClause、SQLOrderBy、SQLLimit:

表数据源类(SQLTableSource)
**介绍:**在 SQL 查询中,SQLTableSource 实现类通常会定义数据的出处,可能是数据库中的物理表、视图,或者是经过特殊处理后的虚拟表等。例如,一个实现 SQLTableSource 用于从 MySQL 数据库表获取数据的类,可以命名为 MySQLSQLTableDataSource 。
**实际应用:**SQLTableSource这个节点,它有着常见的实现SQLExprTableSource(from的表)、SQLJoinTableSource(join的表)、SQLSubqueryTableSource(子查询的表):

class SQLTableSourceImpl extends SQLObjectImpl implements SQLTableSource {
String alias;
}
// 例如 select * from emp where i = 3,这里的from emp是一个SQLExprTableSource
// 其中expr是一个name=emp的SQLIdentifierExpr
class SQLExprTableSource extends SQLTableSourceImpl {
SQLExpr expr;
}
// 例如 select * from emp e inner join org o on e.org_id = o.id
// 其中left 'emp e' 是一个SQLExprTableSource,right 'org o'也是一个SQLExprTableSource
// condition 'e.org_id = o.id'是一个SQLBinaryOpExpr
class SQLJoinTableSource extends SQLTableSourceImpl {
SQLTableSource left;
SQLTableSource right;
JoinType joinType; // INNER_JOIN/CROSS_JOIN/LEFT_OUTER_JOIN/RIGHT_OUTER_JOIN/...
SQLExpr condition;
}
// 例如 select * from (select * from temp) a,这里第一层from(...)是一个SQLSubqueryTableSource
SQLSubqueryTableSource extends SQLTableSourceImpl {
SQLSelect select;
}
另外SQLExpr出现的地方也比较多,比如where语句,join条件,SQLSelectItem中等,因此,也需要细化了解一下,如
表达式实现类(SQLExpr)
**介绍:**SQLExpr 代表着 SQL 语句里的表达式,它是构成 SQL 查询的基础单元。这些表达式可以是常量、变量、函数调用、列引用等,能用来描述数据的筛选条件、计算逻辑等。
实际应用:实现 SQLExpr 接口的类就是用于表示和处理各种 SQL 表达式的类。SQLExpr出现的地方也比较多,比如where语句,join条件,SQLSelectItem中等,因此,也需要细化了解一下:

// SQLName是一种的SQLExpr的Expr,包括SQLIdentifierExpr、SQLPropertyExpr等
public interface SQLName extends SQLExpr {}
// 例如 ID = 3 这里的ID是一个SQLIdentifierExpr
class SQLIdentifierExpr implements SQLExpr, SQLName {
String name;
}
// 例如 A.ID = 3 这里的A.ID是一个SQLPropertyExpr
class SQLPropertyExpr implements SQLExpr, SQLName {
SQLExpr owner;
String name;
}
// 例如 ID = 3 这是一个SQLBinaryOpExpr
// left是ID (SQLIdentifierExpr)
// right是3 (SQLIntegerExpr)
class SQLBinaryOpExpr implements SQLExpr {
SQLExpr left;
SQLExpr right;
SQLBinaryOperator operator;
}
// 例如 select * from where id = ?,这里的?是一个SQLVariantRefExpr,name是'?'
class SQLVariantRefExpr extends SQLExprImpl {
String name;
}
// 例如 ID = 3 这里的3是一个SQLIntegerExpr
public class SQLIntegerExpr extends SQLNumericLiteralExpr implements SQLValuableExpr {
Number number;
// 所有实现了SQLValuableExpr接口的SQLExpr都可以直接调用这个方法求值
@Override
public Object getValue() {
return this.number;
}
}
// 例如 NAME = 'jobs' 这里的'jobs'是一个SQLCharExpr
public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr{
String text;
}
// SQLMethodInvokeExpr 是 SQLExpr 接口的实现类,专门用来解析和表示 SQL 中的函数调用
public class SQLMethodInvokeExpr extends SQLExprImpl {
private String methodName; // 方法名,如 "COUNT", "SUBSTR"
private SQLExpr owner; // 方法所有者(用于类似 o.method() 的调用)
private List<SQLExpr> parameters; // 参数列表
private boolean distinct; // 是否包含 DISTINCT 关键字
private boolean trim; // 是否 TRIM 函数特有属性
// ... 其他属性和方法
}
// 用于表示 SQL 聚合函数(Aggregate Function)。它继承自 SQLMethodInvokeExpr,专门处理聚合操作,如 COUNT(), SUM(), AVG(), MAX(), MIN() 等。
public class SQLAggregateExpr extends SQLMethodInvokeExpr implements Serializable, SQLReplaceable {
提示信息接口(SQLHint)
**介绍:**SQLHint 接口在 Druid 的 SQL 解析和处理体系中,代表着 SQL 提示信息。SQL 提示是一种给数据库查询优化器提供额外信息的方式,能够指导优化器以特定的方式执行查询,比如指定使用某个索引、调整查询的执行计划等。实现 SQLHint 接口的类就是用来表示和处理这些 SQL 提示信息的类。

查询实现接口(SQLSelectQuery)
**含义:**SQLSelectQuery 接口主要用于表示 SQL 中的 SELECT 查询语句。实现该接口的类承担着构建、解析和处理完整 SELECT 查询逻辑的任务。因此,称它们为 “SQL 查询语句类” 能突出其核心作用是代表完整的 SQL 查询语句。
**作用体现:**这些类可以包含查询的各个部分,如 SELECT 子句(指定要返回的列)、FROM 子句(指定数据源)、WHERE 子句(指定筛选条件)、GROUP BY 子句(分组)、ORDER BY 子句(排序)等。例如,一个实现类可能会将这些子句组合起来,形成一个完整的 SELECT 查询语句。

深入解析Statement(组成结构)
顶层抽象类

SelectStatement
SelectStatement实现类
所处的位置为:

class SQLSelectStatement implements SQLStatement {
SQLSelect select;
}
SQLSelect

public class SQLSelect extends SQLObjectImpl implements SQLDbTypedObject {
// 见上章节【可替换SQL组件类(SQLReplaceable接口实现)】
protected SQLWithSubqueryClause withSubQuery;
protected SQLOrderBy orderBy;
protected SQLLimit limit;
// 见章节【SQLSelectQuery】
protected SQLSelectQuery query;
protected List<SQLHint> hints;
protected SQLObject restriction;
protected boolean forBrowse;
protected List<String> forXmlOptions;
// 见章节 表达式实现类(SQLExpr)
protected SQLExpr xmlPath;
protected SQLExpr rowCount;
protected SQLExpr offset;
private SQLHint headHint;
SQLSelectQuery

SQLSelect包含一个SQLSelectQuery,都是组成的关系。
public class SQLSelect extends SQLObjectImpl implements SQLDbTypedObject {
// sql中的子查询
protected SQLWithSubqueryClause withSubQuery;
// 主要select构成组成 【SQLSelectQueryBlock、SQLUnionQuery】
protected SQLSelectQuery query;
protected SQLOrderBy orderBy;
protected SQLLimit limit;
protected List<SQLHint> hints;
protected SQLObject restriction;
protected boolean forBrowse;
protected List<String> forXmlOptions;
protected SQLExpr xmlPath;
protected SQLExpr rowCount;
protected SQLExpr offset;
private SQLHint headHint;
SQLSelectQuery有主要的两个派生类,分别是SQLSelectQueryBlock和SQLUnionQuery。
interface SQLSelectQuery extends SQLObject {}
// 具体select查询条件其中组成
class SQLSelectQueryBlock implements SQLSelectQuery {
// 字段内容
List<SQLSelectItem> selectList;
// 表来源 各种情况:SQLExprTableSource、SQLJoinTableSource、SQLSubqueryTableSource
SQLTableSource from;
// where条件
SQLExpr where;
// group by
SQLSelectGroupByClause groupBy;
SQLOrderBy orderBy;
SQLLimit limit;
}
// 由SQLSelectQuery组成
class SQLUnionQuery implements SQLSelectQuery {
SQLSelectQuery left;
SQLSelectQuery right;
SQLUnionOperator operator; // UNION/UNION_ALL/MINUS/INTERSECT
}
针对解析到的node树进行处理模板操作
关于不同结构之间血缘如何计算(简单记录)
// 单表 如:from table1 或者 from table1 as t1
// 子查询表 如:from (select xxx, xxx from table 1)
CREATE TABLE new_table AS
select col3, col4 from (
select col1 as col3, col2 as col4, col5 from table2
)as table3

// 场景3:join表 如:from table1 left|inner|right join table2 on table1.id = table2.id
CREATE TABLE new_table AS
SELECT col1 as cc1, col2 as cc2 FROM table1
union
-- left join
select col1, col2 from table4 as t4
left join table5 t4 on t1.col1 = t2.col1
// 另一个例子
CREATE TABLE new_table AS
select col1, col2 from table4 as t4
left join table5 t4 on t1.col1 = t2.col1


复杂sql结合例子
复杂结合例子:
CREATE TABLE
new_table AS
SELECT col1 as cc1, col2 as cc2 FROM table1
union
select
col3,
col4
from
(
select
t4.col1 as col3,
t5.col2 as col4
from
table4 as t4
left join table5 t5 on t4.col3 = t5.col3
) as tt

select类型:SqlSelectQueryBlock、SqlUnionQuery
tableSource类型:SQLSubqueryTableSource、SQLExprTableSource、SQLJoinTableSource
步骤一:确认目标表的字段
创建的表结构以第一组的sql为准:
CREATE TABLE
new_table AS
SELECT col1 as cc1, col2 as cc2 FROM table1
union
select
得到的一组目标写入字段为:
真实字段 别名字段 真实表名
col1 cc1 new_table
col2 cc2 new_table
步骤二:union右边的(带子查询、left join)
关注下面这部分:
union
select
col3,
col4
from
(
// 内部1️⃣
select
t4.col1 as col3,
t5.col2 as col4
from
table4 as t4
left join table5 t5 on t4.col3 = t5.col3
) as tt
以select开头作为一组,关注拿到的是该select 所拿到的selectItem字段:
如先看内部1️⃣:
select
t4.col1 as col3,
t5.col2 as col4
from
table4 as t4
left join table5 t5 on t4.col3 = t5.col3
# 涉及到 join 关联
# 关于真实表名如何获取到:需要去单独去针对该selectsql匹配到表及别名预先获取到
# 1、首先为查询到select的字段:
# 关于select字段
真实字段 别名字段 真实表名
col1 col3 t4
col2 col4 t5
# 关于from来源表为这种SQLExprTableSource情况,直接进行匹配
真实表名 表别名字段
table4 t4
table5 t5
# 2、借助select的字段去匹配from、left join的场景实现替换逻辑
# 由于t4与表别名字段t4匹配,则表字段记录的真实表名替换为相应的真实表名
真实字段 别名字段 真实表名
col1 col3 table4
col2 col4 table5
在看外部2️⃣,如下:
select
col3 as col5,
col4 as col6
from
(
// 内部1️⃣已替换
真实字段 别名字段 真实表名
col1 col3 table4
col2 col4 table5
) as tt
此时select的字段为col3、col4
逻辑应该是拿其col3匹配1️⃣中的中的字段(先别名、无别名再真实字段),匹配得到了则取相应table名字。
tt的col3匹配到1️⃣如下:
真实字段 别名字段 真实表名
col1 col3 table4
// 中间过程
// 1、tt的真实字段col3尝试匹配内部1️⃣中的别名
// 1.1、匹配成功一致
// 1.1.1、判断tt自身这个字段是否有别名,有的话则将col5填充别名字段到表中
// 1.1.2、如果tt自身没有别名,则不动
// 1.2、匹配失败:则该字段舍弃,抛出异常记录(sql有问题了)
// 按照规则会走到1.1.1替换后如下得到一组字段记录
真实字段 别名字段 真实表名
col1 col5 table4
tt的col4匹配1️⃣如下:
真实字段 别名字段 真实表名
col2 col4 table5
// 中间过程如上所述
// 同样按照规则走的是1.1.1 替换后如下
真实字段 别名字段 真实表名
col2 col6 table5
最终外部2转换得到的一组字段为:
真实字段 别名字段 真实表名
col1 col5 table4
col2 col6 table5
步骤三:union左边的
SELECT col1 as cc1, col2 as cc2 FROM table1
union
参考步骤二:
真实字段 别名字段 真实表名
col1 cc1 table1
col2 cc2 table1
合并去看
目标表:
真实字段 别名字段 表名
col1 cc1 new_table
col2 cc2 new_table
union左:
真实字段 别名字段 真实表名
col1 cc1 table1
col2 cc2 table1
union右:
真实字段 别名字段 真实表名
col1 col5 table4
col2 col6 table5
血缘去匹配过程为:
union有几个就匹配几次,这里有两个就匹配两次 组成两组血缘
注意注意!!! 该过程与步骤2、3的追溯过程不一样
第一组:目标字段 & union左
# 目标字段
真实字段 别名字段 真实表名
col1 cc1 new_table
col2 cc2 new_table
# union左sql字段
真实字段 别名字段 真实表名
col1 cc1 table1
col2 cc2 table1
匹配过程:
1、应该是一一对应的过程,而不是追溯寻找的过程。
2、例如【目标字段】第一行对应下面【union左sql字段】第一行,【目标字段】第二行对应下面【union左sql字段】第二行,各自只取真实的即可

来源表 来源字段 目标表 目标字段
table1 col1 new_table cc1
table1 col2 new_table cc2
3、关于select查询表有join连接逻辑(也要产生血缘)
# 目标字段
真实字段 别名字段 真实表名
col1 cc1 new_table
col2 cc2 new_table
# 涉及到 join 关联
真实字段 真实表名(需要去匹配到) 表别名字段
col3 table4 t4
col3 table5 t5
产生4条血缘规则(每一个目标真实表及字段映射join关联的真实表及字段):
来源表 来源字段 目标表 目标字段
table4 col3 new_table cc1
table5 col3 new_table cc2
第二组:目标血缘 & union右
datablau血缘问题记录
问题1:复杂sql加上on条件之后血缘解析有问题
无问题:
CREATE TABLE
new_table AS
SELECT col1 as cc1, col2 as cc2 FROM table1
union
select
col3,
col4
from
(
select
t4.col1 as col3,
t5.col2 as col4
from
table4 as t4
left join table5 t5 on t4.col1 = t5.col1
) as tt

有问题:修改on条件之后,影响new_table中的字段为col3、col3
// left join table5 t5 on t4.col1 = t5.col1
CREATE TABLE
new_table AS
SELECT col1 as cc1, col2 as cc2 FROM table1
union
select
col3,
col4
from
(
select
t4.col1 as col3,
t5.col2 as col4
from
table4 as t4
left join table5 t5 on t4.col3 = t5.col3
) as tt

问题2:union on问题
CREATE TABLE new_table AS
SELECT col1, col2 FROM table1
UNION
SELECT col3, col4 FROM table2;

问题描述:错误的将目标表中的字段作为了col3、col4。
整理者:长路 时间:2025.3.21
评论区请在客户端页面查看