当前位置: 首页 > article >正文

SQL血缘解析

Druid 作为使用率特别高的的数据库连接池工具,在具备完善的连接池管理功能外,同时Druid 的 SQL解析功能可以用来防止 SQL注入等安全风险。通过对 SQL 语句进行解析和检查,Druid 可以识别并阻止潜在的恶意 SQL 语句执行,黑名单(阻止特定的 SQL 语句执行)、白名单(仅允许特定的 SQL 语句执行)等功能,从而提升数据库的安全性。

可以利用 Druid 的 SQL 解析结果,进行进一步的二次解析和组合,从而形成脚本的血缘关系和影响关系
在这里插入图片描述

测试访问地址:http://43.139.19.48:8888/#/
Gitee:https://gitee.com/javalxy/sql-lineage-show

前置知识

AST抽象语法树

官方文档链接:Druid_SQL_AST · alibaba/druid Wiki · GitHub

抽象语法树(AST, Abstract Syntax Tree) 是编程语言解析和编译过程中产生的一种树状数据结构,它表示源代码的语法结构。AST 抽象出代码的语法特征,同时剔除不必要的语法细节,提供了程序结构的抽象表示。

SQLTableSource

常见的SQLTableSource包括SQLExprTableSource、SQLJoinTableSource、SQLSubqueryTableSource、SQLUnionQuery

主要为表的关联类型,针对与不同的SQL,分支处理。

if (tableSource instanceof SQLExprTableSource) {
   
    SQLExpr sqlExpr = ((SQLExprTableSource) tableSource).getExpr();
    processTableExpression(tableName, sqlExpr);
} else if (tableSource instanceof SQLSubqueryTableSource) {
   
    List<SQLSelectItem> selectList = queryBlock.getSelectList();
    selectList.forEach(item -> processTableExpression(tableName, item.getExpr()));
} else if (tableSource instanceof SQLUnionQuery) {
   
    SQLUnionQuery sqlUnionQuery = (SQLUnionQuery) tableSource;
    List<SQLSelectQuery> relations = sqlUnionQuery.getRelations();

    for (SQLSelectQuery relation : relations) {
   
        if (relation instanceof SQLSelectQueryBlock) {
   
            SQLTableSource nestedTableSource = ((SQLSelectQueryBlock) relation).getFrom();

            if (nestedTableSource instanceof SQLExprTableSource) {
   
                SQLExpr sqlExpr = ((SQLExprTableSource) nestedTableSource).getExpr();
                processTableExpression(tableName, sqlExpr);
            }
        }
    }
}

SQLSelect & SQLSelectQuery

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

此对象是一个查询主体,其主要的关联关系就是查询的关系。这种关系由查询字段衍生出来,涵盖了查询字段、关系字段、函数、组成等(也就是可解析的字段类型,后文会详细说明,即:SQLExpr)。除此之外,还有表关系(如上文提到的 SQLTableSource)、分组关系等。这些关系共同构成了 SQL 语句的结构和逻辑。此对象也可看做是解析的中流砥柱,很多向下的衍生关系也都通过此封装。

if (sqlSelectQuery instanceof SQLSelectQueryBlock) {
   
    disposeSelectQuery((SQLSelectQueryBlock) sqlSelectQuery, sqlItems, fieldModels);
} else if (sqlSelectQuery instanceof SQLUnionQuery) {
   
    disposeSQLUnionQuery((SQLUnionQuery) sqlSelectQuery, sqlItems, fieldModels);
}

SQLExpr

解析代码中大约 80% 的内容可能都围绕着 SQLExpr 进行。在所有的 SQLExpr 子对象中,通常存在多层次的继承关系。因此,无论表达式多么复杂,都可以通过递归层层向下,找到基本类型进行处理。这种处理方式相当繁琐,因为需要针对每种类型进行细致的拆解和处理。对于几种基本类型,可以直接进行处理;但对于聚合函数或二元操作这样的复杂类型,则需要逐层拆解,获取其下层类型后再判断并处理,如此反复,直至解析到基本类型为止,形成一个完整的闭环。

目前已处理类型如下:

SQLAggregateExpr、SQLBinaryOpExpr、SQLPropertyExpr、SQLMethodInvokeExpr、SQLAllColumnExpr、SQLIdentifierExpr、SQLCaseExpr、SQLInListExpr、SQLCastExpr、SQLBetweenExpr、SQLQueryExpr、SQLCharExpr、SQLNullExpr、SQLIntegerExpr、SQLNumberExpr

其中也存在无法处理的情况,如常量类型,All类型(*),需要其他逻辑支持。

if (sqlExpr instanceof SQLAggregateExpr) {
   
    // 处理聚合函数表达式
    dispose((SQLAggregateExpr) sqlExpr, itemFieldModels);
} else if (sqlExpr instanceof SQLBinaryOpExpr) {
   
    // 处理二元操作表达式
    dispose((SQLBinaryOpExpr) sqlExpr, itemFieldModels);
} else if (sqlExpr instanceof SQLPropertyExpr) {
   
    // 处理属性表达式
    dispose((SQLPropertyExpr) sqlExpr, itemFieldModels);
} else if (sqlExpr instanceof SQLMethodInvokeExpr) {
   
    // 处理方法调用表达式
    dispose((SQLMethodInvokeExpr) sqlExpr, itemFieldModels);
} else if (sqlExpr instanceof SQLAllColumnExpr) {
   
    // 处理所有列(*)表达式
    dispose((SQLAllColumnExpr) sqlExpr, itemFieldModels);
} else if (sqlExpr instanceof SQLIdentifierExpr) {
   
    // 处理标识符表达式
    dispose((SQLIdentifierExpr) sqlExpr, itemFieldModels);
}
// 略...

示例

此示例和druid解析无关系。

SELECT name, age FROM users WHERE age > 18;

对应的 AST

这个 SQL 查询的 AST(抽象语法树)可以表示如下:

SelectStatement
 ├── SelectClause
 │   ├── Column (name)
 │   └── Column (age)
 ├── FromClause
 │   └── Table (users)
 └── WhereClause
     └── BinaryExpression (>)
         ├── Column (age)
         └── Literal (18)

一条正确的 SQL 语句可以通过抽象语法树(AST)进行概括(通常使用 ANTLR 作为底层支持,排除 g4 模板解析失败的情况)。对于较复杂的语句,如关联查询、子查询和函数处理等,这些语句基本上是层层嵌套的。理论上,通过支持各种类型的解析后,可以使用递归方式遍历整个抽象语法树,从而完整地获取字段结构并进行二次处理。

二次处理Druid AST抽象语法树

使用Druid解析SQL

List

http://www.kler.cn/a/446745.html

相关文章:

  • 合并比对学习资料
  • Linux 使用的小细节
  • 二叉搜索树Ⅲ【东北大学oj数据结构8-3】C++
  • html 中 表格和表单的关系与区别
  • 谷歌浏览器的扩展市场使用指南
  • STM32MP1linux根文件系统目录作用
  • ubuntu镜像开荒ssh
  • [数据结构] 链表
  • 【Linux开发工具】版本控制器git
  • Vivado - 远程调试 + 远程综合实现 + vmWare网络配置 + NFS 文件共享 + 使用 VIO 核
  • 如何看待Java面试造火箭工作拧螺丝?
  • 怎么将pdf中的某一个提取出来?介绍几种提取PDF中页面的方法
  • 数据结构与算法学习笔记----Prim算法
  • 复盘:“辩论赛”复盘
  • 容联云孔淼:金融数智化深水区,从数字化工具到业务变革提效
  • 驾考科目一考什么?
  • 感受野如何计算?
  • vtie项目中使用到了TailwindCSS,如何打包成一个单独的CSS文件(优化、压缩)
  • 阿里云OSS批量导出下载地址 OSS批量导出 OSS导出清单
  • 应用端sql慢查询监控分析
  • git全教程(长期更新)
  • Leetcode分隔链表
  • 急!急!急!电脑丢失msvcr100.dll怎么办?电脑“缺失msvcr100.dll”要怎么解决?
  • 使用计算机创建一个虚拟世界
  • 【P2P】【Go】采用go语言实现udp hole punching 打洞 传输速度测试 ping测试
  • 《XML》教案 第1章 学习XML基础