SQLreduce:将冗长的 SQL 查询简化为最小示例

由 credativ 于 2022-03-09 发布,现为 NetApp 开源服务
相关开源

SQLsmith 已被证明是一个有效的工具,可用于查找 PostgreSQL 服务器和其他产品中不同领域的错误,包括安全错误,范围从执行器错误到类型和索引方法实现中的段错误。

然而,SQLsmith 生成的触发某些错误的随机查询通常非常庞大,并且包含许多对错误没有贡献的噪声。到目前为止,需要手动检查查询和繁琐的编辑才能将示例简化为开发人员可以用来解决问题的最小重现程序。

这个问题由 SQLreduce 解决。SQLreduce 接受任意 SQL 查询作为输入,然后在 PostgreSQL 服务器上运行。应用各种简化步骤,在每个步骤之后检查简化的查询是否仍然触发来自 PostgreSQL 的相同错误。最终结果是具有最小复杂性的 SQL 查询。

SQLreduce 可以有效地将 SQLsmith 的原始错误报告中的查询简化为与手动简化的查询匹配的查询。

有关 其工作原理的更多详细信息,请参阅博客文章

示例

在 2018 年,SQLsmith 在运行 Git 修订版 039eb6e92f 的 PostgreSQL 中发现了一个段错误。当时的重现程序是一个巨大的 40 行、2.2kB 的查询

select case when pg_catalog.lastval() < pg_catalog.pg_stat_get_bgwriter_maxwritten_clean() then case when pg_catalog.circle_sub_pt( cast(cast(null as circle) as circle), cast((select location from public.emp limit 1 offset 13) as point)) ~ cast(nullif(case when cast(null as box) &> (select boxcol from public.brintest limit 1 offset 2) then (select f1 from public.circle_tbl limit 1 offset 4) else (select f1 from public.circle_tbl limit 1 offset 4) end, case when (select pg_catalog.max(class) from public.f_star) ~~ ref_0.c then cast(null as circle) else cast(null as circle) end ) as circle) then ref_0.a else ref_0.a end else case when pg_catalog.circle_sub_pt( cast(cast(null as circle) as circle), cast((select location from public.emp limit 1 offset 13) as point)) ~ cast(nullif(case when cast(null as box) &> (select boxcol from public.brintest limit 1 offset 2) then (select f1 from public.circle_tbl limit 1 offset 4) else (select f1 from public.circle_tbl limit 1 offset 4) end, case when (select pg_catalog.max(class) from public.f_star) ~~ ref_0.c then cast(null as circle) else cast(null as circle) end ) as circle) then ref_0.a else ref_0.a end end as c0, case when (select intervalcol from public.brintest limit 1 offset 1) >= cast(null as "interval") then case when ((select pg_catalog.max(roomno) from public.room) !~~ ref_0.c) and (cast(null as xid) <> 100) then ref_0.b else ref_0.b end else case when ((select pg_catalog.max(roomno) from public.room) !~~ ref_0.c) and (cast(null as xid) <> 100) then ref_0.b else ref_0.b end end as c1, ref_0.a as c2, (select a from public.idxpart1 limit 1 offset 5) as c3, ref_0.b as c4, pg_catalog.stddev( cast((select pg_catalog.sum(float4col) from public.brintest) as float4)) over (partition by ref_0.a,ref_0.b,ref_0.c order by ref_0.b) as c5, cast(nullif(ref_0.b, ref_0.a) as int4) as c6, ref_0.b as c7, ref_0.c as c8 from public.mlparted3 as ref_0 where true;

SQLreduce 可以有效地将那个怪物简化为这个

SELECT pg_catalog.stddev(NULL) OVER () AS c5 FROM public.mlparted3 AS ref_0

可用性

SQLreduce 是在 MIT 许可下获得许可的开源软件。源代码在 GitHub 上:https://github.com/credativ/sqlreduce

sqlreduce 的 Debian/Ubuntu 包在 apt.postgresql.org 上提供。

SQLreduce 是由 credativ GmbH 提供的开源产品。