sadpandajoe commented on code in PR #45793:
URL: https://github.com/apache/superset/pull/45793#discussion_r4393778828


##########
superset/db_engine_specs/clickhouse.py:
##########
@@ -72,6 +73,16 @@ class ClickHouseQueryStoppedBeforeDispatchError(Exception):
     """
 
 
+class AggregateFunctionState(types.UserDefinedType):
+    cache_ok = True
+
+    def get_col_spec(self, **kw: Any) -> str:
+        return "AggregateFunction"
+
+    def column_expression(self, colexpr: ColumnElement) -> ColumnElement:
+        return func.finalizeAggregation(colexpr)

Review Comment:
   This hook applies to every column that carries this type, including 
calculated columns: `TableColumn.get_sqla_col()` passes the mapped type to 
`literal_column(expression, type_=...)` too. A dataset column that kept the 
reflected `AGGREGATEFUNCTION` type and already uses `finalizeAggregation(rtt)` 
as its expression (a natural workaround for this bug) would now compile to 
`finalizeAggregation((finalizeAggregation(rtt)))`, and ClickHouse rejects the 
outer call because its argument is no longer an aggregate state. Should 
explicit-expression columns skip the wrapper, or is there another way to keep 
those datasets working?



##########
tests/unit_tests/db_engine_specs/test_clickhouse.py:
##########
@@ -1107,3 +1114,107 @@ def 
test_legacy_clickhouse_engine_spec_has_no_cancel_support() -> None:
     cursor_mock = Mock()
     assert spec.get_cancel_query_id(cursor_mock, Query()) is None
     assert spec.cancel_query(cursor_mock, Query(), "123") is False
+
+
[email protected](
+    "native_type",
+    [
+        "AggregateFunction(quantileTiming, UInt16)",
+        "AggregateFunction(uniqHLL12, String)",
+        "AGGREGATEFUNCTION",
+    ],
+)
+def test_aggregate_function_column_spec(native_type: str) -> None:
+    from superset.db_engine_specs.clickhouse import (  # noqa: N813
+        AggregateFunctionState,
+        ClickHouseConnectEngineSpec as spec,
+    )
+
+    assert_column_spec(
+        spec,
+        native_type,
+        AggregateFunctionState,
+        None,
+        GenericDataType.NUMERIC,
+        False,
+    )
+    assert AggregateFunctionState().compile() == "AggregateFunction"
+
+
+def test_select_star_finalizes_aggregate_function_columns() -> None:
+    from clickhouse_connect.cc_sqlalchemy.datatypes.base import 
sqla_type_from_name
+    from clickhouse_connect.cc_sqlalchemy.dialect import ClickHouseDialect
+
+    from superset.db_engine_specs.clickhouse import (  # noqa: N813
+        ClickHouseConnectEngineSpec as spec,
+    )
+    from superset.sql.parse import Table
+    from superset.superset_typing import ResultSetColumnType
+
+    dialect = ClickHouseDialect()
+    database = Mock()
+    database.compile_sqla_query = lambda query, catalog, schema: str(
+        query.compile(dialect=dialect, compile_kwargs={"literal_binds": True})
+    )
+    cols: list[ResultSetColumnType] = [
+        {
+            "name": name,
+            "column_name": name,
+            "type": sqla_type_from_name(native_type),
+            "is_dttm": False,
+        }
+        for name, native_type in [
+            ("rows", "SimpleAggregateFunction(sum, UInt64)"),
+            ("rtt", "AggregateFunction(quantileTiming, UInt16)"),
+        ]
+    ]
+
+    sql = spec.select_star(
+        database=database,
+        table=Table("t"),
+        dialect=dialect,
+        limit=10,
+        show_cols=True,
+        indent=False,
+        latest_partition=False,
+        cols=cols,
+    )
+
+    assert sql == (
+        "SELECT `rows`, finalizeAggregation(`rtt`) AS `rtt` \nFROM `t`\n LIMIT 
10"
+    )
+
+
+def test_dataset_query_finalizes_aggregate_function_columns(
+    app_context: None,
+) -> None:
+    from superset.connectors.sqla.models import SqlaTable, TableColumn
+    from superset.models.core import Database
+
+    table = SqlaTable(
+        database=Database(
+            database_name="ch", 
sqlalchemy_uri="clickhousedb://localhost/default"
+        ),
+        schema="default",
+        table_name="t",
+        columns=[
+            TableColumn(column_name="ts", type="DATETIME", is_dttm=True),
+            TableColumn(column_name="rtt", type="AGGREGATEFUNCTION"),
+        ],
+    )
+
+    sqlaq = table.get_sqla_query(
+        columns=["ts", "rtt"],
+        metrics=None,

Review Comment:
   The description says finalization applies only in the SELECT list, and that 
existing merge-style metrics keep working, but the dataset test passes 
`metrics=None` and orders by the plain `ts` column. If the wrapper ever leaked 
into a `uniqMerge(rtt)` metric argument, or into a filter or `ORDER BY` on 
`rtt`, it would feed a scalar where ClickHouse needs a state and nothing here 
would fail. Could you add a compiled-query case that includes a merge metric 
over `rtt` plus a filter and an `ORDER BY rtt`, asserting `finalizeAggregation` 
shows up only in the projection (or not at all for the metric)?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to