SQLreduce: Reduce las consultas SQL verbosas a ejemplos de tamaño mínimo
SQLsmith ha demostrado ser una herramienta eficaz para detectar errores en diferentes áreas del servidor PostgreSQL y en otros productos, incluyendo los errores de seguridad: desde errores en el ejecutor hasta las violaciones de acceso en implementaciones de métodos de tipos e índices.
Sin embargo, las consultas aleatorias generadas por SQLsmith que provocan algún error suelen ser muy extensas y con mucho ruido, lo cual no contribuye a generar el error. Hasta ahora, ha sido necesario realizar una inspección manual de la consulta y un tedioso proceso de edición para reducir el ejemplo a un reproductor mínimo que los desarrolladores puedan utilizar para solucionar el problema.
Este problema se soluciona con SQLreduce, el cual utiliza como entrada una consulta SQL arbitraria que se ejecuta en un servidor PostgreSQL. Se aplican varios pasos de simplificación, comprobando después de cada uno de ellos que la consulta simplificada siga provocando el mismo error en PostgreSQL. El resultado final es una consulta SQL que presenta una complejidad mínima.
SQLreduce reduce eficazmente las consultas desde los reportes de error originales de SQLsmith a consultas equivalentes a las reducidas manualmente.
Encontrarán más detalles sobre su funcionamiento en un artículo de blog.
Ejemplo
En 2018, SQLsmith encontró una violación de acceso en PostgreSQL ejecutando la revisión 039eb6e92f de Git. El reproductor de entonces era una enorme consulta de 40 líneas y 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 puede reducir eficazmente ese monstruo a tan solo esto:
SELECT pg_catalog.stddev(NULL) OVER () AS c5 FROM public.mlparted3 AS ref_0
Disponibilidad
SQLreduce es una herramienta de código abierto con licencia MIT. El código fuente se encuentra en GitHub: https://github.com/credativ/sqlreduce
Los paquetes de Debian/Ubuntu para sqlreduce se distribuyen en apt.postgresql.org.
SQLreduce es un producto de código abierto de credativ GmbH.