• SQL血缘解析原理


    根据sql解析获取到表到表, 字段到字段间的关系,即血缘关系。实际上这是从sql文本获取到数据流的过程。
    大致步骤如下:

    1.sql文本进行词法分析
    2.sql语法分析获取到AST抽象语法树
    3.访问AST抽象语法树根据语法结构推测出数据的流向,例如create as select from 这种结构,数据就是从from的表流向select出来的ResultSet中间结果集最后流程create的表中, 字段可以使用字段名进行匹配,如果可以连接到元数据库是可以查询到表和字段的,如果仅仅根据sql文本分析,那么一般只能根据select中的字段名结合语法进行猜测。

    一般来说,步骤1,2比较底层会有很多工具为我们完成, 像antlr(开源语法分析器),druid(基于antlr),使用这些工具可以直接从sql获取到AST语法树, 然后我们直接进入第3个步骤遍历语法树获取自己想要的信息即可。比如在解析create table A as select * from table B; 后判断出语句为create from句式,从语法树中获取create的表A和from的表B,这样表级别的血缘关系就获取到了。

    下面以antlr为例对这三个步骤进行详细的说明:

    1. sql文本进行Lexer词法分析
      词法分析是将sql文本字符序列转换为单词(Token)序列的过程。
      进行词法分析的程序或者函数叫作词法分析器(Lexical analyzer,简称Lexer),也叫扫描器(Scanner)。
      比如,sql中的关键字select, from, table等,antlr根据一个规则g4文件去识别这些关键字。
      g4文件是antlr生成词法解析规则和语法解析规则的基础。该文件是我们自定义的,文件名后缀需要是.g4。g4文件描述了Token及Token间语法。antlr根据g4文件的描述先进行词法解析,将字符串解析为单词(Token)序列。
      借个图做个示例:
      在这里插入图片描述

    2. sql语法分析parse获取到AST抽象语法树
      语法分析器根据g4文件描述的规则将收到的Tokens组织起来,并转换成为目标语言语法定义所允许的序列,并组装为AST抽象语法树结构。
      例如下面的sql可以被解析为下图中的ast语法树。
      create table stu_tj row format delimited as SELECT b.id,b.name FROM (select oldId id ,name from stu WHERE id =‘2’) b ;
      在这里插入图片描述

    3. 访问AST抽象语法树根据语法结构推测出数据的流向。
      语法树中包含了sql的全部信息, 可以从中获取到所需信息。但是,访问代码并不好写,因为语法树中封装的对象类型很多,不同的类型需要不同的访问方式,一般使用visitor访问者模式进行访问。大部分的业务代码就在这里访问sql解析后的AST语法树(Abstract Syntax Tree),然后获取源表和目标表之间的对应关系,即所谓血缘关系。

    例如create as select from 这种结构,数据就是从from的表流向select出来的ResultSet中间结果集最后流程create的表中, 字段可以使用字段名结合语法进行匹配推理。

    在这里插入图片描述
    druid提供了visitor接口访问AST语法树,需要借用visitor设计模式,调用accept方法即可访问AST语法树,注意accept方法是调用入参对象的接口方法。druid已实现的visitor功能不够全,无法处理别名等一些需求,需要自己实现visitor。可以直接继承

    SQLASTVisitorAdapter 也可以根据不同数据库类型继承不同的visitor。
    // 自定义访问者 继承SQLASTVisitorAdapter
    class SQLCustomedVisitor extends SQLASTVisitorAdapter { 
    protected boolean hasLimit = false; 
    @Override 
    public boolean visit(SQLLimit x) { 
    System.out.println(x.getRowCount()); 
    hasLimit = true; 
    return false; 
    } 
    public boolean isHasLimit() { return hasLimit; } 
    }
    
    不同数据库类型继承不同的visitor 
    https://github.com/alibaba/druid/wiki/SQL_Parser_Demo_visitor
    public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlASTVisitor {
    
        public MySqlSchemaStatVisitor() {
            super (JdbcConstants.MYSQL);
        }
    
        public boolean visit(SQLSelectStatement x) {
            if (repository != null
                    && x.getParent() == null) {
                repository.resolve(x);
            }
    
            return true;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    参考

    https://www.jianshu.com/p/21f2afca65e8
    https://baike.baidu.com/item/antlr/9368750
    https://zhuanlan.zhihu.com/p/121545985
    https://github.com/alibaba/druid/wiki/SQL_Parser_Demo_visitor
    https://github.com/alibaba/druid/wiki/SQL-Parser
    https://blog.csdn.net/shy_snow/article/details/133373567

  • 相关阅读:
    广东的介绍
    如何获取ABAP的程序事件顺序的调用堆栈
    工信部教考中心:什么是《研发效能(DevOps)工程师》认证,拿到证书之后有什么作用!(上篇)丨IDCF
    工厂模式(初学)
    塑钢门窗三位焊接机中工位设计
    [南京大学]-[软件分析]课程学习笔记(二)-IR
    【AGV机器人智能取物】企业都能用得起的WMS/RFID系统立体智能仓库
    卡牌游戏类型定制开发微信卡牌小程序游戏
    SpringBoot 使用 Feign 无废话 All-in-one 指南
    【C】退出break,return,exit,goto
  • 原文地址:https://blog.csdn.net/shy_snow/article/details/133373567