0


【SQL解析】- Druid SQL AST 01

什么是AST

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

大数据领域比如Hive,Spark,Presto等提供sql api的计算框架都用了Antlr进行sql解析(因为其比较简单,只需要写好对应的类似正则的文件,就可以生成对应的词法语法工具,以及遍历的访问入口),而Druid则自己实现了这个过程。其实这个过程无法就是词法分析(打标签),语法适配(上下文关系),按照SQL的语法以及层次构建对应的AST数据结构。

在这里插入图片描述
构建AST的过程其实非常类似 我们做一些领域内的NER命名实体识别技术实现过程。。

2. 在Druid SQL Parser中有哪些AST节点类型

在Druid中,AST节点类型主要包括SQLObject、SQLExpr、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 {}

2.1. 常用的SQLExpr有哪些

这个非常多,部分例子如下:

  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. }

2.2. 常用的SQLStatemment

最常用的Statement当然是SELECT/UPDATE/DELETE/INSERT,他们分别是

  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. }

2.3 SQLTableSource

常见的SQLTableSource包括SQLExprTableSource、SQLJoinTableSource、SQLSubqueryTableSource、SQLWithSubqueryClause.Entry

  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. }

2.4. SQLSelect & SQLSelectQuery

SQLSelectStatement包含一个SQLSelect,SQLSelect包含一个SQLSelectQuery,都是组成的关系。SQLSelectQuery有主要的两个派生类,分别是SQLSelectQueryBlock和SQLUnionQuery。

  1. class SQLSelect extends SQLObjectImpl {
  2. SQLWithSubqueryClause withSubQuery;
  3. SQLSelectQuery query;
  4. }
  5. interface SQLSelectQuery extends SQLObject {}
  6. class SQLSelectQueryBlock implements SQLSelectQuery {
  7. List<SQLSelectItem> selectList;
  8. SQLTableSource from;
  9. SQLExprTableSource into;
  10. SQLExpr where;
  11. SQLSelectGroupByClause groupBy;
  12. SQLOrderBy orderBy;
  13. SQLLimit limit;
  14. }
  15. class SQLUnionQuery implements SQLSelectQuery {
  16. SQLSelectQuery left;
  17. SQLSelectQuery right;
  18. SQLUnionOperator operator; // UNION/UNION_ALL/MINUS/INTERSECT
  19. }

2.5. SQLCreateTableStatement

建表语句包含了一系列方法,用于方便各种操作

  1. public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLStatement, SQLCreateStatement {
  2. SQLExprTableSource tableSource;
  3. List<SQLTableElement> tableElementList;
  4. Select select;
  5. // 忽略大小写的查找SQLCreateTableStatement中的SQLColumnDefinition
  6. public SQLColumnDefinition findColumn(String columName) {}
  7. // 忽略大小写的查找SQLCreateTableStatement中的column关联的索引
  8. public SQLTableElement findIndex(String columnName) {}
  9. // 是否外键依赖另外一个表
  10. public boolean isReferenced(String tableName) {}
  11. }

3. 怎样产生AST

3.1. 通过SQLUtils产生List

  1. import com.alibaba.druid.util.JdbcConstants;
  2. String dbType = JdbcConstants.MYSQL;
  3. List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dbType);

3.2. 通过SQLUtils产生SQLExpr

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

4. 怎样打印AST节点

4.1. 通过SQLUtils工具类打印节点

  1. package com.alibaba.druid.sql;
  2. public class SQLUtils {
  3. // 可以将SQLExpr/SQLStatement打印为String类型
  4. static String toSQLString(SQLObject sqlObj, String dbType);
  5. // 可以将一个&lt;SQLStatement&gt;打印为String类型
  6. static String toSQLString(List<SQLStatement> statementList, String dbType);
  7. }

5. 如何自定义遍历AST节点

所有的AST节点都支持Visitor模式,需要自定义遍历逻辑,可以实现相应的ASTVisitorAdapter派生类,比如 https://github.com/alibaba/druid/wiki/SQL_Parser_Demo_visitor

标签: sql 大数据 数据库

本文转载自: https://blog.csdn.net/qq_31557939/article/details/126025442
版权归原作者 Pushkin. 所有, 如有侵权,请联系我们删除。

“【SQL解析】- Druid SQL AST 01”的评论:

还没有评论