游乐游手机版
首页/数据库/文章详情

SQL生成工具全面解读与使用指南

时间:2026-06-14 07:02
要测试一个 Parser 和其他数据库的兼容性,SQL 生成工具是个不错的选择。核心思路很简单:解析 YACC 语法文件里的产生式,自动生成 SQL 语句,然后扔给目标数据库去执行,看结果是否匹配。这样一来,兼容性好不好,一跑便知。 01 工具使用 语法文件预处理 预处理的目的,是把语法文件里无关紧

要测试一个 Parser 和其他数据库的兼容性,SQL 生成工具是个不错的选择。核心思路很简单:解析 YACC 语法文件里的产生式,自动生成 SQL 语句,然后扔给目标数据库去执行,看结果是否匹配。这样一来,兼容性好不好,一跑便知。

一文解读SQL生成工具

01 工具使用

语法文件预处理

预处理的目的,是把语法文件里无关紧要的部分剔除干净,只留下各个语句的产生式。具体操作上,可以用 bison -v sql.y 命令获取语法规则(不带 Action),然后再从生成的文件中删掉终结符列表、非终结符列表、状态转换表这些冗余信息。下面是一个示例:

生成的 sql.output 文件内容中,我们只保留“语法”这一节。注意,保留的这一节还需要把序号去掉。

为了方便,整个预处理流程已经封装在 preprocess.sh 脚本里,处理后的文件可以直接喂给工具。最终生成的 .output 文件就是预处理后的语法文件。

SQL 语句生成

拿到干净的语法文件后,就可以用它来生成 SQL 了。工具支持以下参数:

  • -b:指定语法文件,必选。语法文件就是上面 preprocess.sh 处理后的那个。
  • -n:指定待生成的产生式名称,必选。
  • -R:随机生成模式,可选,默认是枚举模式。
  • -o:指定生成 SQL 语句的保存文件,可选,默认是 report.csv
  • -N:限制生成 SQL 条数,可选,默认不限制。

02 工具实现

整个工具由两个 package 组成:yacc_parsersql_generator,分别负责 Token 解析和 SQL 生成。

产生式的表示方法

type SeqInfo struct {
    Items []string
}

type Production struct {
    Head  string    // 产生式头部
    Alter []SeqInfo // 产生式 body
}

Token 解析

Tokenize 函数将读取的语法文件中的字符 Token 化,每次调用返回一个 Token。这个函数只处理了简单的分隔符和引号,并没有实现标准词法分析器的正则匹配,够用就行。

Parse 函数会调用 Tokenize,每拿到一个 Token 后,根据当前状态和 Token 类型,将一连串 Token 组装成 Production 结构。

SQL 生成

SQL 生成有两种模式:枚举和随机。

1、枚举

枚举模式的实现思路是:用一个链表来保存待 resolve 的 Token。每次从链表头取一个 Token,并自增该 Token 出现的次数;然后根据每个子表达式中 Token 在记录中间出现次数是否大于指定次数,筛选出可以继续推导的子表达式。

同时,用两个数组分别记录当前所取的子表达式下标(choice)和当前最大子表达式下标(max),这样下次自增 choice 就能取下一条表达式。

筛选之后,选择 choice 位置的产生式右部子表达式,将其全部 Token 插入链表头部。接着判断头部是否为 literalkeyword:如果是,就取出来放入 SQL 数组;如果不是,就继续循环处理链表。

当处理到当前产生式的末尾时(判断条件是 choice > max),就会尝试“进位”——把记录的当前所取位置数组的最后一位自增。举个例子:max 数组是 [1, 2, 1, 3],choice 数组是 [0, 0, 0, 3],进位后 choice 变成 [0, 0, 1, 0],表示最后一个位置已经遍历完,现在将倒数第二位自增,最后一位置零,然后继续下一轮排列组合。

生成过程通过递归实现。比如下面这条产生式,处理逻辑如图所示:

show_tables_stmt: SHOW TABLES FROM name '.' name with_comment
                | SHOW TABLES FROM name with_comment
                | SHOW TABLES with_comment
with_comment: WITH COMMENT
            | %empty
name: IDENT

根据记录的 choice 值,选择产生式的第 choice 条子表达式,反复推导直到生成一条完整的 SQL。然后对 choice 数组进位,继续下一轮选择。

2、随机

随机生成模式与枚举模式大同小异,区别在于它不会顺序遍历产生式 body 列表中的每个 Token,而是随机挑一个 Token 来组成 SQL,其余逻辑基本一致。

来源:https://www.jb51.net/database/358926uv9.htm
上一篇DataX、Airbyte等六大主流数据同步工具对比 下一篇ClickHouse数据库监控运维:指标、工具、策略与故障处理
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Redis 7.0增量AOF重写RDB前导码配置详解
数据库 · 2026-07-02

Redis 7.0增量AOF重写RDB前导码配置详解

先说一个几乎所有人都踩过的典型误区:很多人把 aof-use-rdb-preamble yes 当作开启“增量重写”的开关。实际上,这个配置只干了一件事——让重写后的 AOF 文件头部带上 RDB 快照。它解决的是加载速度问题,跟“增量重写”本身的概念压根不是一回事。真正的增量重写,依赖的是 Red

在Python Tornado异步框架中安全执行SQL命令的方法与最佳实践
数据库 · 2026-07-02

在Python Tornado异步框架中安全执行SQL命令的方法与最佳实践

直接在Tornado里用SQLAlchemy同步执行SQL,结果就是阻塞IOLoop,所谓“异步框架里写同步数据库代码”,等于白搭。安全执行的关键不是“怎么写SQL”,而是“怎么不卡住事件循环”。 为什么不能在RequestHandler里直接调用session execute() 因为sessio

利用SQL触发器实现在INSERT数据时自动同步到审计表
数据库 · 2026-07-02

利用SQL触发器实现在INSERT数据时自动同步到审计表

先说结论:可以用触发器把 INSERT 数据同步到审计表,但必须用 AFTER INSERT,并且审计表的字段顺序、类型、字符集得和源表严格一致。否则,轻则写入错位、数据截断,重则直接报错、丢数据。下面把这些坑一个一个掰开说。 能,但必须用 AFTER INSERT,且审计表字段顺序、类型、字符集要

如何用SQL编写按不同工作日统计员工出勤率
数据库 · 2026-07-02

如何用SQL编写按不同工作日统计员工出勤率

在实际业务中,统计不同工作日的出勤率是HR系统里的高频需求。如果直接按日期函数分组,很容易掉进语言环境、索引失效或分母口径的坑里。下面就来拆解具体的实现要点。 必须用 CASE WHEN 将日期映射为固定 weekday 标签(如 Mon )再分组,避免语言环境导致的分组断裂;需过滤 DOW IN

Spring Boot 3动态拼接SQL为何引发严重安全漏洞
数据库 · 2026-07-02

Spring Boot 3动态拼接SQL为何引发严重安全漏洞

SQL注入漏洞的核心成因,本质上是因为用户输入直接参与了SQL语句的字符串拼接,而未采用参数化绑定机制。在MyBatis中使用${}、QueryWrapper中调用apply()与last()、JPA的@Query注解进行拼接等操作,都会绕过PreparedStatement的安全防护。动态字段必须