1.什么是AST

AST是abstract syntax tree的缩写,也就是抽象语法树.和所有的Parser一样,Druid Parser会生成一个抽象语法树。

2.常用的节点类型

在Druid中,AST节点类型主要包括SQLObject,SQLExpr,SQLStatement三种抽象类型。
其中SQLExpr主要针对的是sql表达式。
SQLStatement主要是语句级别的。

  1. package com.alibaba.druid.sql.ast;
  2. interface SQLObject {}
  3. interface SQLExpr extends SQLObject {}
  4. interface SQLStatement extends SQLObject {}
  5. interface SQLTableSource extends SQLObject {}
  6. class SQLSelect extends SQLObject {}
  7. class SQLSelectQueryBlock extends SQLObject {}

常用的SQLExpr

image.png

  1. package com.alibaba.druid.sql.ast.expr;
  2. // SQLName是一种的SQLExpr的Expr,包括SQLIdentifierExpr、SQLPropertyExpr等
  3. public interface SQLName extends SQLExpr {}
  4. // 例如 ID = 3 这里的ID是一个SQLIdentifierExpr
  5. class SQLIdentifierExpr implements SQLExpr, SQLName {
  6. String name;
  7. }
  8. // 例如 A.ID = 3 这里的A.ID是一个SQLPropertyExpr
  9. class SQLPropertyExpr implements SQLExpr, SQLName {
  10. SQLExpr owner;
  11. String name;
  12. }
  13. // 例如 ID = 3 这是一个SQLBinaryOpExpr
  14. // left是ID (SQLIdentifierExpr)
  15. // right是3 (SQLIntegerExpr)
  16. class SQLBinaryOpExpr implements SQLExpr {
  17. SQLExpr left;
  18. SQLExpr right;
  19. SQLBinaryOperator operator;
  20. }
  21. // 例如 select * from where id = ?,这里的?是一个SQLVariantRefExpr,name是'?'
  22. class SQLVariantRefExpr extends SQLExprImpl {
  23. String name;
  24. }
  25. // 例如 ID = 3 这里的3是一个SQLIntegerExpr
  26. public class SQLIntegerExpr extends SQLNumericLiteralExpr implements SQLValuableExpr {
  27. Number number;
  28. // 所有实现了SQLValuableExpr接口的SQLExpr都可以直接调用这个方法求值
  29. @Override
  30. public Object getValue() {
  31. return this.number;
  32. }
  33. }
  34. // 例如 NAME = 'jobs' 这里的'jobs'是一个SQLCharExpr
  35. public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr{
  36. String text;
  37. }

常用的SQLStatemment

语句方面就是我门常用的增删改查了。
`image.png

  1. package com.alibaba.druid.sql.ast.statement;
  2. class SQLSelectStatement implements SQLStatement {
  3. SQLSelect select;
  4. }
  5. class SQLUpdateStatement implements SQLStatement {
  6. SQLExprTableSource tableSource;
  7. List<SQLUpdateSetItem> items;
  8. SQLExpr where;
  9. }
  10. class SQLDeleteStatement implements SQLStatement {
  11. SQLTableSource tableSource;
  12. SQLExpr where;
  13. }
  14. class SQLInsertStatement implements SQLStatement {
  15. SQLExprTableSource tableSource;
  16. List<SQLExpr> columns;
  17. SQLSelect query;
  18. }

SQLTableSource

常见的SQLTableSource包括SQLExprTableSource、SQLJoinTableSource、SQLSubqueryTableSource、SQLWithSubqueryClause.Entr
image.png

  1. class SQLTableSourceImpl extends SQLObjectImpl implements SQLTableSource {
  2. String alias;
  3. }
  4. // 例如 select * from emp where i = 3,这里的from emp是一个SQLExprTableSource
  5. // 其中expr是一个name=emp的SQLIdentifierExpr
  6. class SQLExprTableSource extends SQLTableSourceImpl {
  7. SQLExpr expr;
  8. }
  9. // 例如 select * from emp e inner join org o on e.org_id = o.id
  10. // 其中left 'emp e' 是一个SQLExprTableSource,right 'org o'也是一个SQLExprTableSource
  11. // condition 'e.org_id = o.id'是一个SQLBinaryOpExpr
  12. class SQLJoinTableSource extends SQLTableSourceImpl {
  13. SQLTableSource left;
  14. SQLTableSource right;
  15. JoinType joinType; // INNER_JOIN/CROSS_JOIN/LEFT_OUTER_JOIN/RIGHT_OUTER_JOIN/...
  16. SQLExpr condition;
  17. }
  18. // 例如 select * from (select * from temp) a,这里第一层from(...)是一个SQLSubqueryTableSource
  19. SQLSubqueryTableSource extends SQLTableSourceImpl {
  20. SQLSelect select;
  21. }
  22. /*
  23. 例如
  24. WITH RECURSIVE ancestors AS (
  25. SELECT *
  26. FROM org
  27. UNION
  28. SELECT f.*
  29. FROM org f, ancestors a
  30. WHERE f.id = a.parent_id
  31. )
  32. SELECT *
  33. FROM ancestors;
  34. 这里的ancestors AS (...) 是一个SQLWithSubqueryClause.Entry
  35. */
  36. class SQLWithSubqueryClause {
  37. static class Entry extends SQLTableSourceImpl {
  38. SQLSelect subQuery;
  39. }
  40. }

SQLSelect & SQLSelectQuery

class SQLSelect extends SQLObjectImpl { 
    SQLWithSubqueryClause withSubQuery;
    SQLSelectQuery query;
}

interface SQLSelectQuery extends SQLObject {}

class SQLSelectQueryBlock implements SQLSelectQuery {
    List<SQLSelectItem> selectList;
    SQLTableSource from;
    SQLExprTableSource into;
    SQLExpr where;
    SQLSelectGroupByClause groupBy;
    SQLOrderBy orderBy;
    SQLLimit limit;
}

class SQLUnionQuery implements SQLSelectQuery {
    SQLSelectQuery left;
    SQLSelectQuery right;
    SQLUnionOperator operator; // UNION/UNION_ALL/MINUS/INTERSECT
}

SQLCreateTableStatement

public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLStatement, SQLCreateStatement {
    SQLExprTableSource tableSource;
    List<SQLTableElement> tableElementList;
    Select select;

    // 忽略大小写的查找SQLCreateTableStatement中的SQLColumnDefinition
    public SQLColumnDefinition findColumn(String columName) {}

    // 忽略大小写的查找SQLCreateTableStatement中的column关联的索引
    public SQLTableElement findIndex(String columnName) {}

    // 是否外键依赖另外一个表
    public boolean isReferenced(String tableName) {}
}

产生AST

通过SQLUtils产生List

import com.alibaba.druid.util.JdbcConstants;

String dbType = JdbcConstants.MYSQL;
List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dbType);

通过SQLStatement我们可以解析一些建表语句这里以建表语句为列子

//循环遍历表元素
for(SQLStatement st:statementList){
    if(st instanceof MySqlCreateTableStatement )//判断是不是建表语句的元素
    {
        MySqlCreateTableStatement stb = (MySqlCreateTableStatement)st;//转换类型
        for(SQLTableElement te:stb.getTableElementList()){  
            if(te instanceof SQLColumnDefinition){ //判定是否是列元素
                        te.getDataType().getName();//读取字段类型
                        te.getName();//读取字段名
                        te.getComment();//读取字段描述
            }else if(te instanceof MySqlPrimaryKey) //如果是主键通过遍历的方法提取出来。
                                       for (SQLExpr expr : primaryKey.getColumns()) {
                                if (expr instanceof SQLIdentifierExpr) {
                                    primaryKeyNames.add(((SQLIdentifierExpr) expr).getSimpleName().replace("`", ""));
                                }
                            }

        }
    }
}

通过SQLUtils产生SQLExpr

String dbType = JdbcConstants.MYSQL;
SQLExpr expr = SQLUtils.toSQLExpr("id=3", dbType);