fix(sql): preserve multi-arg DISTINCT in sanitize_clause and format (#39340)

This commit is contained in:
Jean Dupuis
2026-06-19 21:02:50 +01:00
committed by GitHub
parent f1504611fd
commit b2e5f80db2
2 changed files with 103 additions and 11 deletions

View File

@@ -3153,6 +3153,48 @@ def test_is_valid_cvas(sql: str, engine: str, expected: bool) -> None:
("col1 = 1) AND (col2 = 2", QueryClauseValidationException, "base"),
("(col1 = 1)) AND ((col2 = 2)", QueryClauseValidationException, "base"),
("TRUE; SELECT 1", QueryClauseValidationException, "base"),
# Regression test for https://github.com/apache/superset/issues/39223:
# dialects with `MULTI_ARG_DISTINCT=False` (Postgres, Presto, Trino,
# DuckDB) must not rewrite user-defined multi-argument DISTINCT
# aggregates into row-expression null guards. Dremio is included
# below as a defensive regression guard even though its generator
# does not currently set `MULTI_ARG_DISTINCT=False`.
(
"DISTINCT_AVG(DISTINCT report_id, time_to_accept / 86400)",
"DISTINCT_AVG(DISTINCT report_id, time_to_accept / 86400)",
"postgresql",
),
(
"DISTINCT_SUM(DISTINCT report_id, total_bounty_reward_amount)",
"DISTINCT_SUM(DISTINCT report_id, total_bounty_reward_amount)",
"postgresql",
),
(
"DISTINCT_AVG(DISTINCT k, v)",
"DISTINCT_AVG(DISTINCT k, v)",
"presto",
),
(
"DISTINCT_AVG(DISTINCT k, v)",
"DISTINCT_AVG(DISTINCT k, v)",
"trino",
),
(
"DISTINCT_AVG(DISTINCT k, v)",
"DISTINCT_AVG(DISTINCT k, v)",
"duckdb",
),
(
"DISTINCT_AVG(DISTINCT k, v)",
"DISTINCT_AVG(DISTINCT k, v)",
"dremio",
),
# Single-argument DISTINCT must still round-trip cleanly.
(
"COUNT(DISTINCT x)",
"COUNT(DISTINCT x)",
"postgresql",
),
],
)
def test_sanitize_clause(sql: str, expected: str | Exception, engine: str) -> None:
@@ -3166,6 +3208,30 @@ def test_sanitize_clause(sql: str, expected: str | Exception, engine: str) -> No
sanitize_clause(sql, engine)
@pytest.mark.parametrize(
"engine",
[
"postgresql",
"presto",
"trino",
"duckdb",
"dremio",
],
)
def test_sqlstatement_format_preserves_multi_arg_distinct(engine: str) -> None:
"""
Regression guard for https://github.com/apache/superset/issues/39223:
``SQLStatement.format()`` must not rewrite user-defined multi-argument
DISTINCT aggregates into row-expression null guards. This is the SQL Lab /
executor path; the metric-expression path is covered by
``test_sanitize_clause``.
"""
sql = "SELECT DISTINCT_AVG(DISTINCT a, b) FROM t"
formatted = SQLScript(sql, engine).format()
assert "DISTINCT_AVG(DISTINCT a, b)" in formatted
assert "CASE WHEN" not in formatted
@pytest.mark.parametrize(
"engine",
[