暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

用SQLancer在Postgres的Citus扩展中挖掘逻辑错误

原创 CiciLee 2022-07-10
1810

不管查询有多复杂,许多人都依赖数据库为SQL查询返回正确的结果。您可能会毫无疑问地信任它——因为您知道关系数据库是建立在经过验证的数学基础之上的,而且无论如何没有实际的方法来手动验证SQL查询输出。

由于数据库的SQL逻辑实现可能会有一些错误,数据库开发人员应用广泛的测试方法来避免这种缺陷。例如,GitHub上的Citus开源repo中与自动化测试相关的行数是数据库代码行的两倍多。然而,检查所有可能的SQL查询的正确性是具有挑战性的,因为缺乏一个“基本事实”来比较它们的输出,以及无限多的可能的SQL查询。

即使我们知道一个SQL查询应该给出的结果,并且我们得到了预期的结果,但这并不意味着查询和输入数据的所有可能变体的实现都是100%正确的。数据库团队面临的挑战是找到可能引入bug的微妙边缘情况。

SQL中的逻辑错误是什么?为什么它们很难被发现?

数据库中有两种主要的错误类型:

  • “引发”错误
  • 逻辑错误

“引发”错误包括语法错误、恐慌、错误和其他崩溃。引发的错误异常地终止进程或向您提供一些不希望的行为的信号,使您能够立即识别它们。为了自动检测(然后修复)引发的错误,数据库提供商广泛地使用SQL模糊工具。Fuzzing工具是随机的SQL查询生成器,它使用复杂的命令使目标数据库紧张,直到引发错误。

另一方面,逻辑错误是潜在的(或静默的)错误,它会导致数据库产生不准确的结果,而不会发出任何意外行为的迹象。逻辑错误是危险的—用户、数据库提供者和模糊工具都可能不知道从数据库获取的是不正确的结果。

图片.png
图1:“引发”错误与逻辑错误

如果我们能找到一种方法来测试数据库管理系统的SQL查询输出的有效性呢?

最近推出的开源SQLancer (synthetic Query Lancer)工具提供了一种测试数据库查询响应有效性的方法。SQLancer是一个用于检测逻辑错误的自动化数据库管理系统(DBMS)测试工具。SQLancer的测试方法通过探测数据库的自一致性(而不是与某些已知行为的一致性)来替代正确性检查中的基本事实。

虽然SQLancer仍处于研究原型阶段,但由于不同公司、组织和开发人员的高需求,它很早就发布了。我第一次了解SQLancer是在2020年6月,通过卡内基梅隆大学数据库教授Andy Pavlo组织的2020年数据库隔离讲座。

SQLancer创始人Manuel Rigger在CMU的演讲是关于在数据库管理系统中寻找逻辑错误。在Manuel Rigger的演讲中,SQLancer已经通过使用三元逻辑分区(TLP)在5个不同的SQL数据库管理系统中发现了超过175个bug。因此,三元逻辑分区成为我们Citus团队最感兴趣的SQLancer测试方法。

如果你不熟悉,Citus是Postgres的开源扩展,它将Postgres转换为分布式数据库。自从去年Citus团队被微软收购后,Citus现在可以作为Hyperscale (Citus)在微软Azure上使用,这是针对PostgreSQL的Azure数据库的内置部署选项。

在斯坦福大学的第二年暑假,我在软件工程实习期间,我在微软的Citus开源团队工作。我的项目是关于将正确性检查整合到我们的自动化测试机制中,这使我参加了关于SQLancer的CMU数据库讲座。请继续阅读,了解我们对SQLancer的兴奋之处,我是如何开发一个支持Citus扩展到Postgres的SQLancer的实现,以及我的项目的有益结果。

SQLancer在Citus上的表现(& Postgres)

在我的项目的早期阶段,SQLancer被证明在检测Citus中的逻辑错误方面非常有用,在我刚刚完成基本的Citus支持后,在运行初始SQLancer的几秒钟内就发现了第一个错误。我在第一周内就发现了第一个SQL逻辑错误。

到我在微软Postgres团队的暑期实习结束时,我们已经在Citus GitHub页面上打开了10多个由SQLancer发现的错误,其中至少有3个符合SQL逻辑错误。此外,我还能够识别出PostgreSQL中的一个错误,然后由David Rowley修复,并由Thomas munro引用——他们两人都是PostgreSQL的提交者,也是微软Postgres团队的一员。
图片.png

通过使用SQLancer的Citus实现,我们能够在3天内测试超过300万个SQL查询。虽然SQL数据库中的逻辑错误很少出现,但SQLancer工具的速度及其广泛、复杂的测试空间让我们能够检测到DBMS实现中存在的逻辑错误(或者可能在未来随着新特性的添加而引入的逻辑错误)。无论是持续集成(CI)测试的一部分,还是常规的长时间后台运行的一部分,将SQLancer整合到Citus扩展到PostgreSQL的自动化测试过程中,将显著提高用户对Citus的可靠性和稳定性。

SQLancer测试方法的技术概述:三元逻辑分区(TLP)

在SQLancer采用的三个测试工具中,我的项目主要关注三元逻辑分区(TLP)方法,该方法可用于测试WHERE、GROUP by、HAVING子句、聚合函数和DISTINCT查询。TLP比较两个语义上相同但在语法上不同但期望相等的SELECT查询的结果集。

我们来打个苹果的比方:比如说,你想“取所有的苹果”。你也可以说,你想“取所有红色的苹果”,“取所有非红色的苹果”,或者“取所有颜色未知的苹果”。这两个版本是等同的——第二个版本只是通过添加与“红色”相关的条件,并以一种让条件变得微不足道的方式将它们结合起来,从而更啰嗦地表达同一件事。
图片.png
图2所示。谓词的三元划分,由Nazli Ugur Koyluoglu手绘,灵感来自Rigger & Su的TLP论文(https://www.manuelrigger.at/preprints/TLP.pdf)

对于那些想要看到TLP如何工作的数学解释的人,而不是依赖我的苹果类比,它是这样的:

Q为原始查询。语义上等价的查询Q '是使用三元逻辑划分Q的3个查询的并集。这3个查询是通过随机生成一个布尔谓词φ,并将φ的值附加到TRUE、FALSE和NULL到Q的末尾来生成的,每一个都以WHERE或HAVING子句的形式存在。由于这3个布尔值覆盖了与谓词相关的状态的全域集合,它们的联合,Q ',必须返回与没有谓词Q的查询返回的相同的结果集,即ResultSet(Q) = ResultSet(Q ')
图片.png
图3所示。三元逻辑分区的实现步骤,灵感来自Manuel Rigger在CMU隔离2020数据库演讲上的SQLancer演讲:https://youtu.be/_LLHssTadKA

测试oracle的实现步骤如下:

1.随机生成原始查询Q,类似于模糊器生成的随机查询。继续我们的苹果类比,Q将是“取回所有苹果”。
2.随机生成布尔谓词φ。其中n对应于我们类比中的条件,’ 红色的 '。
3.使用三元逻辑分区(TLP)方法创建语义等价的查询Q '。在我们的类比中,Q '对应于命令的详细版本,即“获取红色的苹果”、“非红色的苹果”或“颜色未知的苹果”。
4.获取并比较
Q
Q '的结果集。
5.如果不匹配,报告逻辑错误。

SQLancer中的三元逻辑分区允许我们对Postgres或Citus这样的数据库本身进行测试,首先生成一个(相对)简单的和一个更复杂的SQL查询版本,然后检查增加的复杂性是否会引入逻辑错误。换句话说,SQLancer的TLP测试oracle通过将更简单的SQL查询指定为更复杂查询的预期输出的启发式,从而消除了对基本事实的需要。

虽然不能保证我们可以使用查询分区检测Postgres或Citus这样的数据库中的所有逻辑错误,但SQLancer的TLP已经被证明是成功的,它将Citus扩展到Postgres和其他数据库。

为什么要关心SQLancer发现的逻辑错误?

您可能会想,如果SQLancer正在测试开发人员通常不会提出(更不用说用户了)的超级复杂的SQL查询,那么这些SQL查询为什么重要呢?好问题。

虽然复杂的机器生成的SQL查询揭示了逻辑错误,但逻辑错误本身可能存在于影响一般行为的积分操作中。特别是对于Postgres的Citus扩展,逻辑错误的根源主要是在下推到Citus工作节点期间对SQL查询的解析和分离。

另一个强调SQLancer有用性的用例是:许多人可能使用对象关系映射器(orm)来生成SQL查询,而不是手动编写它们,这使得计算机生成的查询更有可能进入由SQLancer测试的容易出错的区域。

Citus的逻辑bug检测,一目了然

运行SQLancer来查找SQL中的逻辑错误涉及到两个不同的执行阶段:

1.准备阶段。SQLancer使用Citus支持初始化测试数据库,在数据库中创建本地、分布式和引用表,并通过随机生成的SQL命令对表执行插入、更新、删除和其他修改。
2.测试阶段。与TLP方法一致,SQLancer生成、执行并比较原始和分区SELECT查询对的输出,直到发现不匹配,即逻辑错误。图片.png
图4:由SQLancer的Citus实现生成的原始和分区查询示例对。

在上面的图4中,可以看到原始SQL查询和分区查询(3个组件的联合,其谓词分别计算为TRUE、FALSE和NULL)未能返回相同的结果集。事实证明,当在复杂的连接树中使用时,Citus在处理显式CROSS JOIN语法时存在一个bug。由于交叉连接更常用隐式形式(FROM t1, t4),这种类型的连接树在手动测试中没有出现。

我如何实现SQLancer的Citus扩展到Postgres

我通过重用和扩展现有的支持PostgreSQL的SQLancer组件来创建了SQLancer的Citus实现。

为Citus编写一个SQLancer实现,包括通过SQLancer在创建测试数据库时跨多个节点合并分片,在数据库准备阶段通过集成Citus的概念和特性(如分布式和参考表、colocation、分布键等)来扩展测试空间,在测试阶段生成的SELECT语句中配置Citus支持的不同类型的join。并调整预期的行为以反映Citus的SQL覆盖范围。
图片.png
https://twitter.com/AzureDBPostgres/status/1293663559801438208
我的项目对Postgres社区的一个潜在的积极影响是:在现有的Postgres支持基础上,将Citus支持构建到SQLancer中,这需要对Postgres支持进行重做,以准备其Java类,以便通过新的实现进行扩展。我对SQLancer Postgres实现的改进和修改,也为将来其他PostgreSQL扩展的SQLancer应用铺平了道路

特别感谢

在微软Postgres团队的暑期实习期间,我在Citus对Postgres的扩展上有一个不可思议的经历。我有机会加入Citus开源项目,并与一些非常了不起的人合作。我要感谢我的导师尼尔斯·戴克(Nils Dijk),感谢他对我的成长所做出的贡献,尤其是在受COVID-19限制的偏远环境中。我要感谢我的经理乌特库·阿兹曼,他一直鼓励我采取主动。

感谢Onder Kalaci和Marco Slot,他们对我们实施SQLancer的愿景做出了贡献,帮助我们调整了我的项目,使我的工作对Citus团队更有用。我要感谢柑橘团队全体成员对我的欢迎和不遗余力的帮助。

特别感谢SQLancer的创建者Manuel Rigger,他与我们分享了为Citus开发一个SQLancer实现的兴奋之情,以及他合作的意愿。
图片.png
https://twitter.com/sqlancer_dbms/status/1293277358783434752
图片.png
https://twitter.com/sqlancer_dbms/status/1293178256108081152

原文标题:Mining for logic bugs in the Citus extension to Postgres with SQLancer
原文作者:Nazli Ugur Koyluoglu
原文地址:https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/mining-for-logic-bugs-in-the-citus-extension-to-postgres-with/ba-p/1634393

最后修改时间:2022-07-10 22:39:42
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论