SQLSmith: Databend 如何利用随机化测试检测 Bug

作者:白 珅

Databend 研发工程师

https://github.com/b41sh

为什么需要 SQLSmith?

在数据库系统的开发和维护过程中,测试扮演着至关重要的角色。它不仅可以验证功能的正确性,还可以发现潜在的问题,确保数据库在每个变更和迭代后保持性能和稳定性。Databend 的 CI 已经支持了多种类型的测试,主要包括:

  • 单元测试(Unit Tests):用于验证代码中最小可测试单元的功能是否正常工作,主要针对函数、模块等基本功能点,确保其能够正确执行,并返回预期的结果。
  • SQL 逻辑测试(SQL Logic Tests):通过 SQL 测试用例来验证 SQL 的语法和逻辑的正确性,覆盖不同的查询场景,确保查询在各种情况下都能正常运行。
  • 性能测试(Performance Tests):测试新功能的性能变化,验证优化的有效性,防止性能回退。

这些测试能够保证系统在快速开发迭代过程中功能的正确性和稳定性,并覆盖常见的使用场景。但是它们也存在一些局限性,例如,测试中使用的 SQL 语句主要通过手工编写,通常较为简单,缺乏真实场景中会的出现复杂 SQL ,对各种边界条件和异常情况覆盖不足。

SQLSmith 是一个随机 SQL 查询生成器,它可以生成大量、多样化的 SQL 测试用例,从而在一定程度上模拟真实世界中的各种可能情况。相比于其它测试方法,SQLSmith 能够提高测试覆盖率,从而发现更多潜在的问题和 bug 。

SQLSmith 的实现

最早的 SQLSmith 灵感来自于 Csmith ,主要用于 PostgreSQL 的模糊测试。目前,已经有许多知名的开源数据库移植了各自版本的 SQLSmith 实现,如 CockroachDB、TiDB、RisingWave 等。

这些开源的 SQLSmith 实现使用不同的编程语言开发(包括 C++、Golang、Rust),支持的语法也各不相同,适用于各自的应用领域,我们无法直接使用它们来进行测试。为了完全支持 Databend 的语法和功能特点,我们必须用 Rust 构建自己的 SQLSmith 。

SQLSmith 主要包括三个部分,生成抽象语法树(AST)的 SQL Generator ,简化执行失败 SQL 的 SQL Reducer ,执行 SQL 并记录错误的 Runner 。

SQL Generator

SQL Generator 随机生成各种类型的抽象语法树(AST),主要包括如下几类:

  1. 生成多种数据类型,除了常见的基本数据类型之外,Databend 还支持了多种嵌套数据类型,包括 ArrayMapTuple 等,这些类型可以多层嵌套,组合出更复杂的数据类型。
  2. 生成 DDL 语句,创建并修改用于测试的表,包括 CREATE TABLEALTER TABLEDELETE TABLE 等。
  3. 生成 DML 语句,生成随机的测试数据执行插入和修改操作,包括 INSERTUPDATEDELETEMERGE 等。
  4. 生成 Query 语句,依次随机生成其内部的各个字段,包括 WITHSelectTargetTableReferenceSubQueryORDER ``BY 等,由于 WITH 和 SubQuery 包含嵌套的 Query,可以生成复杂的查询语句。
  5. 生成 Expression 表达式,包括 ColumnLiteralScalar FunctionAggregate Function 等,由于表达式的参数也可以是表达式,从而支持生成嵌套的表达式。

由于 AST 中的各个部分都会按照一定的概率随机生成,可以覆盖所有类型的 AST ,进而覆盖所有可能的 SQL 语句。通过递归调用生成器,我们还可以生成一些不常见的复杂嵌套语句,有利于发现一些隐藏的 bug 。同时,我们也需要适当控制嵌套的深度,避免生成过于复杂无法执行的 SQL。

SQL Reducer

由于 SQL Generator 生成的 SQL 语句可能会非常复杂,而造成 bug 的往往只是其中的一小部分,直接查看原始 SQL 不容易定位问题。有必要对原始 SQL 进行简化,得出能够复现该 bug 的最小 SQL,这样可以减少无关部分的干扰,方便用最简单的 SQL 复现 bug。

SQL Reducer 采用自顶向下的方法来简化 SQL,依次删除 AST 的不同组成部分,例如 WITHSubQueryExpression 等,如果删除后的 SQL 仍然可以复现出相同的 bug,我们就使用这个删除后的 SQL,否则就回退到原来的 SQL 。通过遍历 AST 的所有组成部分,最终可以得到一个最小可复现的 SQL 语句。

Runner

SQL Runner 使用 SQL Generator 按顺序不断循环生成用于测试的 SQL 语句,并连接 Databend 执行 SQL,如果执行成功则忽略,如果执行失败,说明可能存在 bug,继续按照以下流程进行处理:

  1. 判断是否是正常的报错,例如参数错误,语义错误等。
  2. 判断是否是已知的报错,例如一些未实现的功能,或已提 issue 的报错。
  3. 调用 SQL Reducer 进行简化生成最小可复现的 SQL 。
  4. 打印报错信息和简化后的 SQL 语句。

目前 Runner 已经集成到了 Databend 的 CI,在每次发布 Release 版本的时候都会执行,生成报错信息和 SQL 会被记录下来,用于进一步的分析。

SQLsmith 的效果

到目前为止,SQLSmith 已经在 Databend 运行了一个多月的时间,一共发现了 50 多个 bug,主要包括如下几类:

  1. 内部执行逻辑错误导致的 bug (17个)
  2. 函数或表达式参数校验错误导致的 bug (12个)
  3. 未执行正确的语义检查导致的 bug (9个)
  4. unwrap 和 unreachable 处理不当导致的 bug (7个)
  5. Parser 语法解析失败的 bug (3个)
  6. 不同类型 cast 失败的 bug (4个)
  7. Parquet 数据读写错误导致的 bug (1个)

经验总结

通过分析 SQLSmith 发现的 bug,我们总结了一些常见的问题,可以帮助我们在以后的开发过程中避免出现 bug 。

  1. 函数的参数需要校验是否合法,并考虑各种情况,主要包括以下几类:

    1. 参数类型是 String 时,注意字符串为空的情况。
    2. 参数类型是 Int 时,注意值是一个大数的情况。
    3. 参数支持任意类型时,需要考虑一些不常用的类型,例如 NullEmptyArrayBitmap 等。
    4. 参数只支持特定类型时,需要考虑其它类型能不能自动转换,或者提前检查类型并返回错误。
  2. 谨慎使用 unwrap,对于 Result 和 Option 类型的返回值,应该尽量显式的进行处理,返回值并不总是像预期的一样返回成功的结果。

  3. 开发新的功能需要了解相关 SQL 语义规则的约束条件,例如 ORDERBY 和 HAVING表达式中不允许出现 Aggregate 和 Window 函数。在 Binder 阶段进行符合语义规则的检查可以避免执行时发生错误。

  4. 重要的功能模块需要增加更多的单元测试用例,避免内部执行逻辑错误导致的 bug 。

下一步的工作

目前,SQLSmith 已经支持生成绝大部分常用的 SQL 并且能够与 CI 集成自动运行。我们计划在下一步继续完善 SQLsmith 的功能。主要包括如下几个方面:

  1. 增加更多的 SQL 语法支持,包括 Computed ColumnUnion 等。
  2. 支持更多的配置项,包括表达式的嵌套深度,查询语句的复杂度等。
  3. 完善 SQL Reducer 的功能,生成更简化的 SQL 语句。
  4. 通过改进查询执行和结果分析的方法,提高 bug 发现的效率。

SQLSmith 是一个强大的工具,它可以帮助我们发现 Databend 隐藏的 bug,提高系统的稳定性和可靠性。我们期待 SQLsmith 在未来能够发挥更大的作用。

Connect With Us

Databend 是一款开源、弹性、低成本,基于对象存储也可以做实时分析的新式数仓。期待您的关注,一起探索云原生数仓解决方案,打造新一代开源 Data Cloud。

  • Databend Website
  • GitHub Discussions
  • Twitter
  • Slack Channel

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/124190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL主从架构

1 主从架构解决了什么问题 随着业务的持续增长,单体数据库满足不了业务的需求,可能会出现负载过重,操作数据库速度变慢的情况。为了解决这个问题,数据库一般采用一主一从、一主多从的架构。 为了操作提高效率,减轻压…

sql在线练习

SQLBolt - 学习 SQL - SQL 简介https://sqlbolt.com/拿走不谢!!! UIUC什么乱七八糟的啊

探讨下前端测试的常见场景

前端测试 场景 这边指的测试是指白盒测试,用代码来测试代码。 测试有利于提升代码质量。 代码功能和需求一致。根据需求,写测试。测试通过了,则表明需求实现了。保证代码重构后,未改坏以前的功能。代码重构后,能通过…

html5怎么实现语音搜索

html5怎么实现语音搜索 谷歌的网站在他们首页发现了HTML5的新玩法——语音搜索。 注意&#xff1a; 只有webkit核心的浏览器才能使用 用法很简单 只需要在input添加属性x-webkit-speech即可&#xff0c;例子如下&#xff1a; 代码如下: <input type"text" x-…

一文告诉你样机是什么,分享几个常用的样机模板

一个项目的诞生通常需要经历头脑构思、绘制设计和最终着陆。在这个过程中&#xff0c;样机制作往往是在着陆实践之前进行的。俗话说&#xff1a;“样机使用得好&#xff0c;草稿过早”。样机设计是产品或网站最终设计的生动、静态和视觉表现。它为用户提供了一种模拟现实的方式…

信息系统项目管理师教程 第四版【第7章-项目立项管理-思维导图】

信息系统项目管理师教程 第四版【第7章-项目立项管理-思维导图】 课本里章节里所有蓝色字体的思维导图

【uniapp】短信验证码输入框

需求是短信验证码需要格子输入框 如图 网上找了一个案例改吧改吧 直接上代码 结构 <template><view class"verify-code"><!-- 输入框 --><input id"input" :value"code" class"input" :focus"isFocus"…

数据结构之树(图解)

文章目录 前言一、树是什么&#xff1f;二、树的特点三、树的相关概念四、树的表示方法&#xff08;孩子兄弟表示法&#xff09;总结 前言 在学习完线性结构&#xff0c;例如顺序表、链表、栈、队列后&#xff0c;我们要开始学习一个新的数据结构----树 一、树是什么&#xf…

小白如何在一个月写一篇论文(中文核心,SCI)

小白如何半年发3篇sci的我教你如何快速“水”一篇sci论文_哔哩哔哩_bilibili 计算机视觉&#xff0c;cv领域 半年发3篇sci的我教你如何快速“水”一篇sci论文 计算机视觉(辅导 SCI EI 核心) 微信&#xff1a;whbwqq123或主页加up 小白如何快速写出一篇论文并成功发表&…

Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二)

这是继上一篇文章 “Elasticsearch&#xff1a;使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation &#xff08;一&#xff09;” 的续篇。在这篇文章中&#xff0c;我主要来讲述 ElasticVectorSearch 的使用。 我们的设置和之前的那篇文章是一样的&#xff…

【C】C语言文件操作

1.为什么使用文件 我们前面学习结构体时&#xff0c;写通讯录的程序&#xff0c;当通讯录运行起来的时候&#xff0c;可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯录中的数据自然就不存在了&#xff0c;等下…

大彩串口屏读写文件问题

分区 本文使用的是大彩串口屏M系列的&#xff1a; 串口屏内部有三个分区&#xff0c;分别为A、B、C三个区&#xff1a; A区&#xff1a;系统区&#xff0c;存储组态工程文件 B区&#xff1a;数据区&#xff0c;存储配置信息&#xff0c;记录数据、历史曲线等 C区&#xff1a;备…

3.线性神经网络

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 知识框架No.1 线性回归基础优化算法一、线性回归1、买房案例2、买房模型简化3、线性模型4、神经网络5、损失函数6、训练数据7、参数学习8、显示解9、总结 二、 基础优化算法1、梯度下降2、学习率3、小批量随机梯度下降4、批量大小5、…

【Linux】【驱动】设备树常用 of 函数

【Linux】【驱动】设备树常用 of 函数 序常用的of函数添加我们要查找的节点的代码 of_find_node_by_path获取 compatible 属性内容的代码 of_find_property获取 reg 属性内容的代码 of_property_read_u32_array获取 status 属性内容的代码 of_property_read_string 演示代码操作…

docker+playwright

windows10 docker playwright 难点在于windows下docker的安装&#xff0c;以及官方hub被墙的困难。 wsl2 wsl2 ubuntu docker git clone https://gitee.com/lineuman/lcs_playwright.git npm install npx playwright test docker端口怎么映射到主机上面&#xff1f; 设置重…

图、深度优先(DFS)、广度优先(BFS)

图 基本介绍 表示方式 图的创建 from typing import Listclass Graph:vertex_list: List[str] [] # 存储顶点的数组edges: List[list] [] # 存储图中各条边的邻接矩阵num_edges: int 0 # 边的数总数def __init__(self, n: int):"""根据传入的顶点个数初始…

测开(性能测试---LoadRunner)

目录 一、LoadRunner的安装 二、Loadrunner的基本概念 三、开发测试脚本——VUG 3.1 脚本录制 3.2 脚本加强 四、设计场景——Controller LoadRunner是一款开源桌面应用软件&#xff0c;可用来模拟用户负载完成性能测试工作&#xff0c;LoadRunner的功能在版本不断升级的…

JWT详解解读读

&#x1f4d1;前言 本文主要是jwt解读文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&#xff1a;努力一点&#…

WebDAV之π-Disk派盘 + 读出通知

手机各种推销通知太多,如何避免那些繁琐的通知内容,做出一键就能够阅读重要通知的最佳体验,帮助您更加快速和便捷的体验到那些应用内容?推荐大家使用读出通知。 读出通知APP可以设置接收通知的app,还可以用耳机操作,操作简单,你还可以指定播报设备,还有播报的声音的设置…

数据结构 | 顺序表专题

数据结构 | 顺序表专题 文章目录 数据结构 | 顺序表专题课前准备1. 目标2. 需要的储备知识3. 数据结构相关概念 开始顺序表1、顺序表的概念及结构2、顺序表分类3、动态顺序表的实现初始化顺序表顺序表的销毁顺序表的尾插顺序表的头插检查容量顺序表的尾删打印顺序表顺序表的头删…