test(sql): reproduce sanitize_clause mutating user aggregation SQL (#36113)

Add a failing regression test for #36113. `sanitize_clause` round-trips a
user-authored clause through SQLGlot's dialect generator and returns the
re-rendered SQL. The Postgres dialect (borrowed by several engines) rewrites
`ROUND(AVG(x), n)` to `ROUND(CAST(AVG(x) AS DECIMAL), n)` at generation time;
on engines whose unqualified DECIMAL defaults to scale 0 the injected cast
rounds the aggregate before the explicit ROUND, producing wrong values.

The test asserts the clause is returned unchanged and currently fails for
postgresql/cockroachdb/netezza/hana.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Claude Code
2026-06-16 11:35:05 -07:00
committed by Evan
parent b4dfeef2fd
commit ee0a93771f

View File

@@ -3208,6 +3208,31 @@ def test_sanitize_clause(sql: str, expected: str | Exception, engine: str) -> No
sanitize_clause(sql, engine)
@pytest.mark.parametrize(
"engine",
["postgresql", "redshift", "cockroachdb", "netezza", "hana", "base", "mysql"],
)
def test_sanitize_clause_preserves_aggregation_semantics(engine: str) -> None:
"""
Regression test for https://github.com/apache/superset/issues/36113.
`sanitize_clause` must not silently rewrite a user-authored expression. The
Postgres SQLGlot dialect (which several engines borrow) rewrites
``ROUND(AVG(x), n)`` to ``ROUND(CAST(AVG(x) AS DECIMAL), n)`` at generation
time. On engines whose unqualified ``DECIMAL`` defaults to scale 0 (e.g.
Redshift, Netezza) the injected cast rounds the aggregate to an integer
*before* the explicit ``ROUND``, producing wrong results.
The clause must be returned unchanged regardless of the engine dialect.
"""
clause = "ROUND(AVG(col), 4)"
sanitized = sanitize_clause(clause, engine)
assert "CAST" not in sanitized.upper(), (
f"sanitize_clause injected a cast for engine {engine!r}: {sanitized!r}"
)
assert sanitized == clause
@pytest.mark.parametrize(
"engine",
[