通过使用SQLancer,CnosDB技术团队不仅找到并修正产品查询的逻辑错误;并且帮助上游项目构建更稳定的查询引擎;CnosDB也成为了首个产品支持SQLancer的云原生时序数据库。
1.CnosDB已支持SQLancer
充分、全面的测试是保障数据库管理系统正确性的关键,查找逻辑错误是构建可靠的数据库的重要组成部分。CnosDB不光关注性能的极致释放,也同样关心结果的正确性和可重复性。
SQLancer,全称为Synthesized Query Lancer,该工具是一款针对数据库管理系统DBMS的自动化安全测试工具。该工具可以帮助广大研究人员轻松识别应用程序实现中的逻辑漏洞。我们这里所指的逻辑漏洞,即能够导致DBMS获取错误结果集的安全漏洞(比如说忽略数据记录等等)。SQLancer的工作是强调数据库系统返回不一致或不合逻辑的结果。它用Java编写,已经支持多款数据库,包括SQLite、MySQL、PostgreSQL、ClickHouse等。
近期CnosDB团队及开源社区为 CnosDB 实现了 SQLancer 所支持的 TLP、NoREC 两种测试方案,并合并到上游的 main 分支之中,成为首个支持SQLancer的云原生时序数据库。
2.CnosDB实现SQLancer
SQLancer的CnosDB实现目前使用的是Restful API,并根据CnosDB提供的数据类型生成SQL表达式,能生成聚合查询,关联查询的SQL。表达式包括算术运算和支持的大部分函数。接下来我们会讲解SQLancer的执行步骤和SQLancer的具体检测方法。
2.1.SQLancer 的执行步骤
SQLancer的主要执行步骤有以下五个阶段,分别是:
1.通过连接器,连接CnosDB。
2.在CnosDB中创建数据库。
3.在CnosDB中创建几张表。
4.往CnosDB表中插入数据,插入的数据是常量,往往是一些边界数据。比如最大的整数,负数,还有各种奇怪的UTF8字符串。
5.执行所选择的检测方法。
2.2CnosDB支持SQLancer的检测方法
CnosDB现阶段支持TLP检测和NoREC检测两种方法。
2.2.1TLP 检测方法
TLP是Ternary Logic Partitioning的缩写,TLP 是一种在数字电路设计中使用的技术,其中信号可以被分配到三个状态之一:1,0,或者未定义(X)。这种技术可以用于表示不确定性或不完整性,并且可以有助于缩小电路的实现复杂度。在数据库查询之中,就是将一个 Query 分成了三个 Query,执行结果分别为 TRUE,FALSE 和 NULL,然后再将这三个 Query 的结果合并,并且保证结果为 TRUE。通过这种方式,再跟原始的结果对比,发现是否不一致。
TLP的步骤如下:
1.从数据库中随机选择几张表;在选出的表中,随机选择几列。
2.生成一个基本的不带 WHERE 子句的 SQL 语句,并生成 WHERE 子句。
3.根据生成的 WHERE 子句,在基本 SQL 语句上添加 IS TRUE、IS FALSE、IS NULL 的谓词,合成三个 SQL 语句。
4.通过 UNION 将三个 SQL 语句合并为一个。
5.执行基本 SQL 语句和 UNION 后的 SQL 语句。
6.对结果行数进行比对,如果出现行数不同的情况,则说明出现异常。
2.2.2NoREC 检测方法
NoREC是Non-Optimizing Reference Engine Construction的缩写,是一种不进行优化的引擎构建方法。这种方法的目的是提供一种简单的、不受优化限制的参考实现,以便在其他优化的引擎和算法中进行对比。这种方法通常没有考虑性能和效率,并且只是为了证明概念的正确性。NoREC的检测就是将一条优化的 Query,强制变成非优化的方式,然后对比查询结果,如果两种执行方式不一致,那就是有 bug了。
NoREC的步骤如下:
1.生成一个 SELCT COUNT(*) FROM table WHERE expr 的格式的SQL。
2.再生成一个 SELECT SUM (cnt)FROM (SELECT CAST (expr AS BIGINT) cnt FROM table)
3.执行后比对结果值,如果值不相同,说明出现异常。
但因为CnosDB是时序数据库,对Count(*)的优化规则,只会扫描第一个Field列。所以我们不是用COUNT(*)生成SQL,而是COUNT第一个FIELD。
3.SQLancer的成果
通过实现SQLancer,CnosDB技术团队及社区伙伴发现并处理15处潜在的逻辑错误Bug,进一步保障了 CnosDB 执行的正确性。这里的Bug,有CnosDB自身的Bug,也有查询引擎DataFusion的Bug。截止到2023年2月1日找到的Bug如下:
1.https://github.com/cnosdb/cnosdb/issues/852
2.https://github.com/cnosdb/cnosdb/issues/784
3.https://github.com/apache/arrow-datafusion/issues/4401
4.https://github.com/cnosdb/cnosdb/issues/830
5.https://github.com/apache/arrow-datafusion/issues/4843(该bug发现前已被datafusion修复)
6.https://github.com/apache/arrow-datafusion/issues/4947
7.https://github.com/apache/arrow-datafusion/issues/3778
8.https://github.com/apache/arrow-datafusion/issues/4075
9.https://github.com/cnosdb/cnosdb/issues/782
10.https://github.com/cnosdb/cnosdb/issues/807
11.https://github.com/apache/arrow-datafusion/issues/4339
12.https://github.com/apache/arrow-datafusion/issues/4297
13.https://github.com/apache/arrow-datafusion/issues/4080
14.https://github.com/apache/arrow-datafusion/issues/3832
15.https://github.com/apache/arrow-datafusion/issues/3830
16.https://github.com/apache/arrow-datafusion/issues/4452
4.未支持PQS的原因
除了所介绍的TPL和NoREC,SQLancer还提供了PQS的检测方法。PQS的全称是Pivoted Query Synthesis,用逻辑方法生成新的查询(通常是SQL查询)以解决特定的问题。它通过对已有的查询进行变换和合成,以找到更优的查询,并使用特定的评估函数来评估其质量。
PQS的主要流程如下:
生成随机的表格并向其中插入数据。
1.从数据库中随机选择一行数据。
2.根据该行数据随机构建一个表达式。
3.执行该表达式,如果结果不为 TRUE,则调整为 TRUE。
4.将该表达式放入 WHERE 或 JOIN 中。
5.执行该查询语句。
6.检查最新的结果是否仍包含先前的那行数据,如果不包含,则表示存在问题。
目前CnosDB还未支持PQS,原因如下:
1.由于CnosDB的时序数据库的存储引擎特性,目前并不存储NULL值,也没有相应的NULL标记。
2.在读取一行数据时,如果该列不存在任何值,则以NULL值补充,以满足查询引擎的需求。
3.CnosDB的Tag可以被视为一种特殊的索引,与Field存储方式不同,相同的TagSet(即一组Tag键值对)不需要在每一行都进行存储。
4.对于CnosDB,具有相同时间戳和TagSet的数据行会进行合并去重。
5.CnosDB目前不支持表之间的交叉连接。
因为以上原因,支持PQS在检测错误中变得无足轻重了。但通过系统的不断迭代和升级,CnosDB开发团队及社区也会重新评估支持PQS的可能性。
5.结语
以上就是CnosDB支持SQLancer的全部内容了,欢迎热爱数据库及数据库测试的小伙伴们关注我们微信公众号、B站视频号以及加入我们的社区,我们将及时更新最近技术动态与技术内幕,并期待与大家深入交流。
作者
Harbour,哈老师。热爱技术的创业码农,HIT计算机🧮+广告学📢学士,CMU计算机编译方向博士肄业,现潜心钻研时序⌛️数据库与📒数据库教育领域。
参考文献
1.Finding Bugs in Database Systems via Query Partitioning, https://www.manuelrigger.at/preprints/TLP.pdf
2.Detecting Optimization Bugs in Database Engines via Non-Optimizing Reference Engine Construction,https://www.manuelrigger.at/preprints/NoREC.pdf
3.Testing Database Engines via Pivoted Query Synthesis,https://arxiv.org/abs/2001.04174
4.SQLancer GitHub,https://github.com/sqlancer/sqlancer