Skip to content

feat(metrics): add MEDIAN/STDDEV_SAMP/VAR_SAMP as system-wide aggregates - #42895

Merged
rusackas merged 9 commits into
masterfrom
sip/median-stddev-variance-aggregates
Aug 21, 2026
Merged

feat(metrics): add MEDIAN/STDDEV_SAMP/VAR_SAMP as system-wide aggregates#42895
rusackas merged 9 commits into
masterfrom
sip/median-stddev-variance-aggregates

Conversation

@rusackas

@rusackas rusackas commented Aug 7, 2026

Copy link
Copy Markdown
Member

SUMMARY

This now has a working implementation alongside docs/sip/median-stddev-variance-aggregates.md, so reviewers (and PMC members this gets shared with) have a concrete design to react to rather than just a description of one. Still opened as a draft: the point is to pressure-test the framing and scope before this goes up for a formal SIP vote, not to pre-empt that discussion.

Prompted by a report that Pivot Table lost several aggregation options somewhere along the way. Short version: most of what looked missing (Count Unique Values, Count/Average/Max/Min, "as fraction of" display) already has an equivalent today, see the doc for specifics. MEDIAN, STDDEV_SAMP (Sample Standard Deviation), and VAR_SAMP (Sample Variance) are genuinely gone, system-wide, not just Pivot Table, since #41184 (SIP-216) deliberately removed the old pivot-only "Aggregation function" control as the mechanism behind our long-standing wrong-totals bug. Not purely hypothetical either: the MCP chart-creation service already advertised STDDEV/VAR as valid aggregates that never matched any real Superset aggregate name, so MCP-built charts using them always errored at query time — fixed here too, normalized to the real names.

What's implemented:

  • MEDIAN/STDDEV_SAMP/VAR_SAMP added to the system-wide Aggregate type and the metric-picker dropdown (every chart type, not a Pivot-Table-specific control).
  • A new BaseEngineSpec.get_extended_aggregation_func extensibility point (mirrors supports_grouping_sets/_time_grain_expressions, both from feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [SIP-216] #41184) — engines opt in only once verified, unsupported engines get a clear "not supported on this database" error instead of unverified SQL.
  • Enabled for Postgres, MySQL (STDDEV_SAMP/VAR_SAMP only, no native MEDIAN), DuckDB, and Redshift (inherits Postgres, not separately verified) — each verified against a live instance, not just documentation (see commit message / SIP doc for the exact per-engine findings, including a real MySQL landmine: its VARIANCE() is population variance, not sample).
  • Zero Pivot-Table-specific code: these aggregates fall outside ADDITIVE_AGGREGATES automatically, so totals/subtotals already route through the correct DB-rollup path SIP-216 introduced — same mechanism that already makes AVG/COUNT_DISTINCT correct today.
  • MCP's STDDEV/VAR shorthand normalized to STDDEV_SAMP/VAR_SAMP.

Explicitly out of scope, per the doc: First/Last (no unambiguous SQL meaning as a plain aggregate without an explicit ordering) and List Unique Values (dialect + unbounded-payload questions) — flagged as candidate follow-up SIPs.

TESTING INSTRUCTIONS

Backend: pytest tests/unit_tests/db_engine_specs/test_base.py tests/unit_tests/db_engine_specs/test_postgres.py tests/unit_tests/db_engine_specs/test_mysql.py tests/unit_tests/db_engine_specs/test_duckdb.py tests/unit_tests/db_engine_specs/test_redshift.py tests/unit_tests/models/helpers_test.py tests/unit_tests/mcp_service/

Frontend: npx jest plugins/plugin-chart-pivot-table/test/plugin/utilities.test.ts (confirms the new aggregates are automatically treated as non-additive, with no pivot-table code changes).

Manually: on a Postgres-backed dataset, create a chart with a MEDIAN/STDDEV_SAMP/VAR_SAMP metric; on a SQLite-backed one, confirm the same aggregate now returns a clear "not supported on this database" error rather than a generic one.

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration
  • Introduces new feature or API
  • Removes existing feature or API

@github-actions github-actions Bot added preset-io doc Namespace | Anything related to documentation labels Aug 7, 2026
@netlify

netlify Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 1dbf3f1
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a8807531956a40008c5c5ea
😎 Deploy Preview https://deploy-preview-42895--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pull-request-size pull-request-size Bot added size/XL and removed size/L labels Aug 7, 2026
@rusackas rusackas changed the title docs(sip): propose system-wide MEDIAN/STDDEV_SAMP/VAR_SAMP metric aggregates feat(metrics): add MEDIAN/STDDEV_SAMP/VAR_SAMP as system-wide aggregates Aug 7, 2026
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.04878% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.84%. Comparing base (f7d505e) to head (1dbf3f1).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
superset/models/helpers.py 0.00% 7 Missing ⚠️
superset/connectors/sqla/models.py 14.28% 5 Missing and 1 partial ⚠️
superset/mcp_service/chart/chart_utils.py 0.00% 2 Missing ⚠️
superset/db_engine_specs/base.py 75.00% 1 Missing ⚠️
.../mcp_service/chart/validation/dataset_validator.py 0.00% 1 Missing ⚠️
...rvice/chart/validation/runtime/format_validator.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master   #42895   +/-   ##
=======================================
  Coverage   66.84%   66.84%           
=======================================
  Files        2876     2876           
  Lines      164066   164129   +63     
  Branches    37863    37872    +9     
=======================================
+ Hits       109666   109713   +47     
- Misses      52226    52240   +14     
- Partials     2174     2176    +2     
Flag Coverage Δ
hive 38.13% <72.97%> (+0.03%) ⬆️
javascript 74.12% <100.00%> (+<0.01%) ⬆️
mysql 57.83% <75.67%> (+0.01%) ⬆️
postgres 57.86% <75.67%> (+<0.01%) ⬆️
presto 40.07% <72.97%> (+0.02%) ⬆️
python 59.30% <75.67%> (+<0.01%) ⬆️
sqlite 57.55% <75.67%> (+0.01%) ⬆️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@rusackas
rusackas marked this pull request as ready for review August 8, 2026 04:21
@rusackas
rusackas requested a review from sadpandajoe August 8, 2026 04:21
@dosubot dosubot Bot added change:backend Requires changing the backend change:frontend Requires changing the frontend data:connect:duckdb Related to a specific database data:connect:mysql Related to MySQL data:connect:postgres Related to Postgres data:connect:redshift Related to Redshift explore:metrics Related to metrics of Explore viz:charts:pivot Related to the Pivot Table charts labels Aug 8, 2026
@rusackas
rusackas force-pushed the sip/median-stddev-variance-aggregates branch from 8305f5e to f02ef22 Compare August 8, 2026 05:20
Comment thread superset/db_engine_specs/base.py
Comment thread superset/models/helpers.py
Comment thread superset/mcp_service/chart/validation/runtime/format_validator.py Outdated
Comment thread superset/utils/core.py
@bito-code-review

bito-code-review Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #ecf60a

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset/mcp_service/chart/prompts/create_chart_guided.py - 1
    • Incomplete aggregate list · Line 139-142
      The documentation update correctly replaces ambiguous `STDDEV/VAR` with `STDDEV_SAMP/VAR_SAMP`. However, `PERCENTILE` is a valid aggregate in `schemas.py:796` and `chart_utils.py:616` but is missing from this list. Users guided by this prompt won't know PERCENTILE is available.
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset/mcp_service/chart/validation/runtime/format_validator.py - 1
Review Details
  • Files reviewed - 22 · Commit Range: c7fd626..f02ef22
    • superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/utilities.test.ts
    • superset-frontend/src/explore/constants.ts
    • superset/connectors/sqla/models.py
    • superset/db_engine_specs/base.py
    • superset/db_engine_specs/duckdb.py
    • superset/db_engine_specs/mysql.py
    • superset/db_engine_specs/postgres.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/prompts/create_chart_guided.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/validation/dataset_validator.py
    • superset/mcp_service/chart/validation/runtime/format_validator.py
    • superset/models/helpers.py
    • superset/utils/core.py
    • tests/unit_tests/db_engine_specs/test_base.py
    • tests/unit_tests/db_engine_specs/test_duckdb.py
    • tests/unit_tests/db_engine_specs/test_mysql.py
    • tests/unit_tests/db_engine_specs/test_postgres.py
    • tests/unit_tests/db_engine_specs/test_redshift.py
    • tests/unit_tests/mcp_service/chart/test_chart_utils.py
    • tests/unit_tests/models/helpers_test.py
  • Files skipped - 2
    • UPDATING.md - Reason: Filter setting
    • docs/sip/median-stddev-variance-aggregates.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #2c7e2a

Actionable Suggestions - 0
Additional Suggestions - 1
  • superset/mcp_service/chart/validation/runtime/format_validator.py - 1
    • Missing test coverage for MEDIAN · Line 220-227
      The addition of "MEDIAN" to the statistical measures format list is correct. MEDIAN produces a decimal value similar to AVG and other sample statistics, so applying `,.2f` (two decimal places) is semantically appropriate. The change maintains consistency with the existing pattern used for STDDEV_SAMP, VAR_SAMP, and related aggregates.
Review Details
  • Files reviewed - 15 · Commit Range: f02ef22..cefee1b
    • superset/db_engine_specs/cockroachdb.py
    • superset/db_engine_specs/doris.py
    • superset/db_engine_specs/greenplum.py
    • superset/db_engine_specs/hana.py
    • superset/db_engine_specs/hologres.py
    • superset/db_engine_specs/netezza.py
    • superset/db_engine_specs/oceanbase.py
    • superset/db_engine_specs/risingwave.py
    • superset/db_engine_specs/snowflake.py
    • superset/db_engine_specs/starrocks.py
    • superset/db_engine_specs/vertica.py
    • superset/db_engine_specs/yugabytedb.py
    • superset/mcp_service/chart/validation/runtime/format_validator.py
    • superset/utils/core.py
    • tests/unit_tests/db_engine_specs/test_extended_aggregations_unverified.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #a559ba

Actionable Suggestions - 0
Additional Suggestions - 2
  • tests/unit_tests/db_engine_specs/test_mysql.py - 2
    • Inline import instead of module-level · Line 412-412
      Move inline import to module level. The file already has module-level imports at lines 41-48; inline imports at function scope create inconsistency and should be consolidated per project import conventions.
    • Inline import instead of module-level · Line 437-437
      Move inline import to module level for consistency with other imports in this file.
Review Details
  • Files reviewed - 39 · Commit Range: 6658c30..dbf96b2
    • superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/utilities.test.ts
    • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
    • superset-frontend/src/explore/constants.ts
    • superset/connectors/sqla/models.py
    • superset/db_engine_specs/base.py
    • superset/db_engine_specs/cockroachdb.py
    • superset/db_engine_specs/doris.py
    • superset/db_engine_specs/duckdb.py
    • superset/db_engine_specs/greenplum.py
    • superset/db_engine_specs/hana.py
    • superset/db_engine_specs/hologres.py
    • superset/db_engine_specs/mysql.py
    • superset/db_engine_specs/netezza.py
    • superset/db_engine_specs/oceanbase.py
    • superset/db_engine_specs/postgres.py
    • superset/db_engine_specs/risingwave.py
    • superset/db_engine_specs/snowflake.py
    • superset/db_engine_specs/starrocks.py
    • superset/db_engine_specs/vertica.py
    • superset/db_engine_specs/yugabytedb.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/prompts/create_chart_guided.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/validation/dataset_validator.py
    • superset/mcp_service/chart/validation/runtime/format_validator.py
    • superset/models/helpers.py
    • superset/utils/core.py
    • tests/unit_tests/db_engine_specs/test_aurora.py
    • tests/unit_tests/db_engine_specs/test_base.py
    • tests/unit_tests/db_engine_specs/test_duckdb.py
    • tests/unit_tests/db_engine_specs/test_extended_aggregations_unverified.py
    • tests/unit_tests/db_engine_specs/test_mariadb.py
    • tests/unit_tests/db_engine_specs/test_mysql.py
    • tests/unit_tests/db_engine_specs/test_postgres.py
    • tests/unit_tests/db_engine_specs/test_redshift.py
    • tests/unit_tests/db_engine_specs/test_timescaledb.py
    • tests/unit_tests/mcp_service/chart/test_chart_utils.py
    • tests/unit_tests/models/helpers_test.py
  • Files skipped - 2
    • UPDATING.md - Reason: Filter setting
    • docs/sip/median-stddev-variance-aggregates.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@rusackas
rusackas force-pushed the sip/median-stddev-variance-aggregates branch from dbf96b2 to b616214 Compare August 19, 2026 21:48
Comment thread tests/unit_tests/models/helpers_test.py
Comment thread tests/unit_tests/db_engine_specs/test_duckdb.py
Comment thread superset/utils/core.py Outdated
@bito-code-review

bito-code-review Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #7cb282

Actionable Suggestions - 0
Additional Suggestions - 1
  • tests/unit_tests/db_engine_specs/test_redshift.py - 1
    • Incomplete SQL compilation verification · Line 102-103
      STDDEV_SAMP/VAR_SAMP assertions only verify that the function is not None (line 103), but do not verify the compiled SQL output. Compare with test_postgres.py lines 509-511 which expects `"stddev_samp(sales)"` and `"var_samp(sales)"`. This gap means if the SQLAlchemy expression ever changes, this test would not catch the regression.
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • tests/unit_tests/models/helpers_test.py - 1
Review Details
  • Files reviewed - 39 · Commit Range: f9ee90b..b616214
    • superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/utilities.test.ts
    • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
    • superset-frontend/src/explore/constants.ts
    • superset/connectors/sqla/models.py
    • superset/db_engine_specs/base.py
    • superset/db_engine_specs/cockroachdb.py
    • superset/db_engine_specs/doris.py
    • superset/db_engine_specs/duckdb.py
    • superset/db_engine_specs/greenplum.py
    • superset/db_engine_specs/hana.py
    • superset/db_engine_specs/hologres.py
    • superset/db_engine_specs/mysql.py
    • superset/db_engine_specs/netezza.py
    • superset/db_engine_specs/oceanbase.py
    • superset/db_engine_specs/postgres.py
    • superset/db_engine_specs/risingwave.py
    • superset/db_engine_specs/snowflake.py
    • superset/db_engine_specs/starrocks.py
    • superset/db_engine_specs/vertica.py
    • superset/db_engine_specs/yugabytedb.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/prompts/create_chart_guided.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/validation/dataset_validator.py
    • superset/mcp_service/chart/validation/runtime/format_validator.py
    • superset/models/helpers.py
    • superset/utils/core.py
    • tests/unit_tests/db_engine_specs/test_aurora.py
    • tests/unit_tests/db_engine_specs/test_base.py
    • tests/unit_tests/db_engine_specs/test_duckdb.py
    • tests/unit_tests/db_engine_specs/test_extended_aggregations_unverified.py
    • tests/unit_tests/db_engine_specs/test_mariadb.py
    • tests/unit_tests/db_engine_specs/test_mysql.py
    • tests/unit_tests/db_engine_specs/test_postgres.py
    • tests/unit_tests/db_engine_specs/test_redshift.py
    • tests/unit_tests/db_engine_specs/test_timescaledb.py
    • tests/unit_tests/mcp_service/chart/test_chart_utils.py
    • tests/unit_tests/models/helpers_test.py
  • Files skipped - 2
    • UPDATING.md - Reason: Filter setting
    • docs/sip/median-stddev-variance-aggregates.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✖︎ Failed

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@bito-code-review

bito-code-review Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #341b33

Actionable Suggestions - 0
Review Details
  • Files reviewed - 4 · Commit Range: b616214..2beb0ff
    • superset/utils/core.py
    • tests/unit_tests/db_engine_specs/test_duckdb.py
    • tests/unit_tests/models/helpers_test.py
    • tests/unit_tests/utils/map_type_tests.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread superset/db_engine_specs/postgres.py
Comment thread superset/utils/core.py
Comment thread superset-frontend/src/explore/constants.ts
Comment thread superset-frontend/src/explore/constants.ts
@bito-code-review

bito-code-review Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #8955f7

Actionable Suggestions - 0
Review Details
  • Files reviewed - 8 · Commit Range: 2beb0ff..3c640b8
    • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.test.ts
    • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.ts
    • superset-frontend/src/explore/constants.ts
    • superset/charts/schemas.py
    • superset/db_engine_specs/postgres.py
    • superset/db_engine_specs/redshift.py
    • tests/unit_tests/charts/test_schemas.py
    • tests/unit_tests/db_engine_specs/test_redshift.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✖︎ Failed

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

claude and others added 9 commits August 21, 2026 00:47
…regates [DRAFT/SIP]

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tes [DRAFT/SIP]

Implements the proposal in docs/sip/median-stddev-variance-aggregates.md:
MEDIAN, STDDEV_SAMP, and VAR_SAMP are now selectable anywhere a metric
aggregate is chosen, not just Pivot Table. Support is opt-in per engine
via a new BaseEngineSpec.get_extended_aggregation_func hook (mirroring
supports_grouping_sets/_time_grain_expressions), verified against live
Postgres/MySQL/DuckDB instances before being enabled; unsupported engines
raise a clear error instead of emitting unverified SQL. No pivot-table-
specific code needed: these aggregates fall outside ADDITIVE_AGGREGATES
automatically, so totals/subtotals already route through the correct
DB-rollup path SIP-216 (#41184) introduced.

Also fixes a live bug this surfaced: the MCP chart-creation service
advertised STDDEV/VAR as valid aggregates that never matched any real
Superset aggregate name, so MCP-built charts using them always errored
at query time. Now normalized to STDDEV_SAMP/VAR_SAMP.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… decided

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
MEDIAN/STDDEV_SAMP/VAR_SAMP were only verified against live Postgres,
MySQL, DuckDB, and Redshift instances, but `_extended_aggregations`
lived on `PostgresBaseEngineSpec`/`PostgresEngineSpec`/`MySQLEngineSpec`,
so every other subclass (Vertica, Netezza, HANA, Snowflake, CockroachDB,
Greenplum, RisingWave, YugabyteDB, Hologres, Doris, StarRocks, OceanBase)
silently inherited unverified aggregate SQL instead of the intended
"not supported on this database" error. Each now explicitly overrides
`_extended_aggregations` to `{}` until someone verifies it live.

Also fixes two smaller gaps the same review surfaced: MEDIAN was missing
from the MCP chart format validator's numeric-format branch, and
`get_metric_type_from_column`/`METRIC_MAP_TYPE` didn't recognize
STDDEV_SAMP/VAR_SAMP, so an all-null result column for either aggregate
fell back to STRING instead of NUMERIC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ones

Postgres/MySQL-compatible engine specs (MariaDB, Aurora MySQL/Postgres,
TimescaleDB) also inherit the new MEDIAN/STDDEV_SAMP/VAR_SAMP support
via their parent spec class, same as Redshift; the entry previously
only named the four directly-verified engines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MariaDB, Aurora MySQL/PostgreSQL (and their Data API variants), and
TimescaleDB subclass MySQLEngineSpec/PostgresBaseEngineSpec without
resetting _extended_aggregations, unlike the unverified appliance/
distributed-engine specs (CockroachDB, Greenplum, HANA). These are
wire- and SQL-compatible forks running the same query engine, so
keep them inheriting -- matching the existing Redshift precedent --
and add the same explicit test coverage plus a doc comment so the
intent is no longer just implicit.

Also add human-readable dropdown labels for STDDEV_SAMP/VAR_SAMP in
the metric aggregate picker, instead of showing the raw enum value.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- parametrize the Postgres extended-aggregate test over MEDIAN,
  STDDEV_SAMP, and VAR_SAMP instead of asserting only MEDIAN
- add a live in-process DuckDB execution test for the three
  aggregates, alongside the existing compile-only test whose
  docstring overclaimed live verification
- make get_metric_type_from_column's aggregate regex case- and
  whitespace-insensitive so saved expressions like stddev_samp(x)
  or STDDEV_SAMP (x) are still recognized

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…trip/Redshift

- ChartDataAdhocMetricSchema's aggregate enum now includes
  EXTENDED_METRIC_AGGREGATES, so Swagger/generated clients accept
  MEDIAN/STDDEV_SAMP/VAR_SAMP requests the compiler already handles.
- Custom SQL tab now prefills MEDIAN as the portable
  PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY col) instead of the raw
  MEDIAN(col) that PostgreSQL would reject; the display label keeps the
  concise MEDIAN(col) form.
- sqlaAutoGeneratedMetricRegex recognizes MEDIAN/STDDEV_SAMP/VAR_SAMP so
  they round-trip between Simple and Custom SQL like the original six.
- Redshift now emits its native MEDIAN(x) function instead of inheriting
  Postgres's PERCENTILE_CONT WITHIN GROUP spelling, sidestepping
  Redshift's restriction on multiple sort-based aggregates with
  different ORDER BY expressions in one query.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rusackas
rusackas force-pushed the sip/median-stddev-variance-aggregates branch from 3c640b8 to 1dbf3f1 Compare August 21, 2026 08:07

@sha174n sha174n left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from a query-construction standpoint. The aggregate names from metric config are resolved purely as lookup keys into the per-engine function map (the emitted SQL comes from hardcoded sa.func callables), and the opt-in-per-engine model means an aggregate that isn't verified for an engine surfaces an explicit QueryObjectValidationError rather than emitting an expression the engine might compute differently. MEDIAN handling looks correct per engine. One non-blocking follow-up: the Custom SQL prefill for MEDIAN emits the Postgres PERCENTILE_CONT ... WITHIN GROUP spelling, which won't round-trip cleanly on engines expecting native MEDIAN(col) - fine as a later refinement.

@sha174n sha174n left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from a query-construction standpoint. Aggregate names from metric config resolve purely as lookup keys into the per-engine function map (emitted SQL comes from hardcoded sa.func callables), and the opt-in-per-engine model means an unverified aggregate surfaces an explicit QueryObjectValidationError rather than a silently-different expression. MEDIAN handling looks correct per engine. Non-blocking: the Custom SQL prefill for MEDIAN emits the Postgres PERCENTILE_CONT ... WITHIN GROUP spelling, which won't round-trip cleanly on engines expecting native MEDIAN(col).

@sha174n sha174n left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - aggregate names resolve as lookup keys into per-engine hardcoded sa.func callables (no injection), and unverified aggregates raise QueryObjectValidationError rather than emitting a silently-different expression. MEDIAN correct per engine.

@sha174n sha174n left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - aggregate names resolve as lookup keys into per-engine hardcoded sa.func callables (no injection), and an unverified aggregate raises QueryObjectValidationError rather than emitting a silently-different expression. MEDIAN handling correct per engine.

@sha174n

sha174n commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

One non-blocking follow-up: the Custom SQL prefill for MEDIAN emits the Postgres PERCENTILE_CONT(0.5) WITHIN GROUP spelling (AdhocMetric.ts), so a user who switches a Simple MEDIAN metric to Custom SQL and saves gets an expression that DuckDB/Redshift (which use native MEDIAN(col)) may reject. Fine as a later refinement since Custom SQL is a raw-expression escape hatch, just flagging the cross-engine round-trip wart.

@rusackas

Copy link
Copy Markdown
Member Author

@sha174n checked this against duckdb directly and PERCENTILE_CONT(0.5) WITHIN GROUP runs fine there, alone or combined with a native MEDIAN() call in the same query. Redshift's restriction (see the comment in redshift.py) is specifically about combining two differently-ordered sort-based aggregates, not the syntax itself being rejected, so it'd only bite if someone converts one MEDIAN metric to Custom SQL while a second Simple MEDIAN on a different column stays in the same chart. Narrow enough that I'm leaving the prefill as-is.

@rusackas
rusackas merged commit 05842a6 into master Aug 21, 2026
80 checks passed
@rusackas
rusackas deleted the sip/median-stddev-variance-aggregates branch August 21, 2026 11:15

@bito-code-review bito-code-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Agent Run #adf52b

Actionable Suggestions - 1
  • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.ts - 1
Additional Suggestions - 1
  • superset/db_engine_specs/snowflake.py - 1
    • Missing test for _extended_aggregations override · Line 91-94
      The `SnowflakeEngineSpec._extended_aggregations` override is not covered by any test. The test file has 43 references to `SnowflakeEngineSpec` yet 0 references to `_extended_aggregations` or `get_extended_aggregation_func`. A test should assert that `get_extended_aggregation_func('MEDIAN')` returns `None` to guard against accidental re-enablement as the class evolves.
Review Details
  • Files reviewed - 45 · Commit Range: 67af985..1dbf3f1
    • superset-frontend/packages/superset-ui-core/src/query/types/Metric.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/utilities.test.ts
    • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.test.ts
    • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetric.ts
    • superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
    • superset-frontend/src/explore/constants.ts
    • superset/charts/schemas.py
    • superset/connectors/sqla/models.py
    • superset/db_engine_specs/base.py
    • superset/db_engine_specs/cockroachdb.py
    • superset/db_engine_specs/doris.py
    • superset/db_engine_specs/duckdb.py
    • superset/db_engine_specs/greenplum.py
    • superset/db_engine_specs/hana.py
    • superset/db_engine_specs/hologres.py
    • superset/db_engine_specs/mysql.py
    • superset/db_engine_specs/netezza.py
    • superset/db_engine_specs/oceanbase.py
    • superset/db_engine_specs/postgres.py
    • superset/db_engine_specs/redshift.py
    • superset/db_engine_specs/risingwave.py
    • superset/db_engine_specs/snowflake.py
    • superset/db_engine_specs/starrocks.py
    • superset/db_engine_specs/vertica.py
    • superset/db_engine_specs/yugabytedb.py
    • superset/mcp_service/chart/chart_utils.py
    • superset/mcp_service/chart/prompts/create_chart_guided.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/chart/validation/dataset_validator.py
    • superset/mcp_service/chart/validation/runtime/format_validator.py
    • superset/models/helpers.py
    • superset/utils/core.py
    • tests/unit_tests/charts/test_schemas.py
    • tests/unit_tests/db_engine_specs/test_aurora.py
    • tests/unit_tests/db_engine_specs/test_base.py
    • tests/unit_tests/db_engine_specs/test_duckdb.py
    • tests/unit_tests/db_engine_specs/test_extended_aggregations_unverified.py
    • tests/unit_tests/db_engine_specs/test_mariadb.py
    • tests/unit_tests/db_engine_specs/test_mysql.py
    • tests/unit_tests/db_engine_specs/test_postgres.py
    • tests/unit_tests/db_engine_specs/test_redshift.py
    • tests/unit_tests/db_engine_specs/test_timescaledb.py
    • tests/unit_tests/mcp_service/chart/test_chart_utils.py
    • tests/unit_tests/models/helpers_test.py
    • tests/unit_tests/utils/map_type_tests.py
  • Files skipped - 2
    • UPDATING.md - Reason: Filter setting
    • docs/sip/median-stddev-variance-aggregates.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers an incremental AI Review.

  • /review full - Manually triggers a full AI Review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment on lines +162 to +168
if (
params.transformCountDistinct &&
aggregate === AGGREGATES.MEDIAN &&
/^\(.*\)$/.test(column)
) {
return `PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ${column.slice(1, -1)})`;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong SQL for non-Postgres engines

The MEDIAN→PERCENTILE_CONT transformation at lines 162-168 applies unconditionally to ALL database engines, including DuckDB, Snowflake, BigQuery, Redshift, Oracle, T-SQL, Databricks, and Spark — all of which have a native MEDIAN(x) function per SIP documentation and engine specs. This generates incorrect SQL for those engines. The backend's _extended_aggregations map (postgres.py line 211, duckdb.py line 214) already handles engine-specific MEDIAN translation correctly at query execution time; the frontend rewrite bypasses this and overrides it with a Postgres-only form.

Code Review Run #adf52b


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:backend Requires changing the backend change:frontend Requires changing the frontend data:connect:duckdb Related to a specific database data:connect:mysql Related to MySQL data:connect:postgres Related to Postgres data:connect:redshift Related to Redshift doc Namespace | Anything related to documentation explore:metrics Related to metrics of Explore packages plugins preset-io size/XXL viz:charts:pivot Related to the Pivot Table charts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants