fix(mcp): database filter columns, timeseries SQL, and unsaved chart datasource name#39636
Conversation
…datasource name - Add created_by_fk and changed_by_fk to DatabaseFilter schema so list_databases supports filtering by creator/modifier - Pass time_range, adhoc_filters, and filters from form_data into the query dict in get_chart_sql so timeseries charts produce temporal SQL - Resolve datasource_name from form_data via DAO lookup for unsaved charts in get_chart_sql instead of returning null
Code Review Agent Run #6fca56Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
|
Yes, the flagged logic error is correct — adhoc_filters are added to the query payload but ignored by QueryObjectFactory.create() and QueryObject, as they don't consume the adhoc_filters kwarg. To resolve, convert adhoc_filters into query filters format using process_filters and merge with existing filters. Here's the concise fix: import process_filters, process adhoc_filters into filters, and merge before adding to query_dict. superset/mcp_service/chart/tool/get_chart_sql.py |
adhoc_filters are processed by merge_extra_filters() on form_data during query context creation. Passing them in query_dict is dead code since QueryObject.__init__ silently absorbs them via **kwargs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #39636 +/- ##
==========================================
- Coverage 64.49% 64.45% -0.04%
==========================================
Files 2565 2566 +1
Lines 133857 133952 +95
Branches 31084 31097 +13
==========================================
+ Hits 86326 86340 +14
- Misses 46036 46117 +81
Partials 1495 1495
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
The test asserted that created_by_fk should be rejected, but it is now a valid filter column. Changed the test to verify that user-directory string fields (created_by_name) are still rejected.
Code Review Agent Run #1fcc96Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
There was a problem hiding this comment.
From my reviewer agent:
Thanks for the fix — three independent bugs squashed in one tight PR. The schema fix and time_range plumbing are clean. Two concerns on _resolve_datasource_name and one on adhoc_filters.
1. _resolve_datasource_name swallows the wrong exceptions (real bug)
DatasourceDAO.get_datasource() does not return None on miss — it raises:
DatasourceNotFoundwhen the row isn't in the DBDatasourceTypeNotSupportedErrorwhen the type isn't incls.sourcesDatasourceValueIsIncorrectwhendatabase_id_or_uuidisn't a digit/uuid
All three subclass SupersetException, not ValueError/KeyError, so except (ValueError, KeyError) won't catch them. A stale/missing datasource_id in cached form_data will bubble up an exception out of get_chart_sql instead of degrading gracefully to datasource_name=None.
The unit test test_returns_none_when_datasource_not_found patches the DAO to return None, which doesn't reflect real DAO behavior — the test passes but the code path it claims to cover doesn't exist in production.
Suggested fix:
from superset.daos.exceptions import (
DatasourceNotFound,
DatasourceTypeNotSupportedError,
DatasourceValueIsIncorrect,
)
try:
datasource = DatasourceDAO.get_datasource(...)
return getattr(datasource, "name", None)
except (
ValueError,
DatasourceNotFound,
DatasourceTypeNotSupportedError,
DatasourceValueIsIncorrect,
):
return NoneAnd update the test to actually raise DatasourceNotFound rather than returning None.
2. adhoc_filters claim is incorrect
The new comment says:
adhoc_filters live in form_data and are processed by merge_extra_filters() during query context creation
That's not what happens on this code path. merge_extra_filters is called from view-layer code (views/core.py, commands/explore/get.py, viz.py, jinja_context.py) — not from ChartDataCommand → QueryContextFactory → QueryObjectFactory. Nothing in superset/common/ reads adhoc_filters off form_data.
Practical impact: a user calling get_chart_sql on a chart whose WHERE clause is expressed as adhoc_filters (the common case for explore-saved charts) will get SQL without that filter — same class of bug the PR is fixing for time_range. The bito-code-review bot called this out as well.
The standard approach is split_adhoc_filters_into_base_filters or merging adhoc filters into the filters list on the query dict before handing it to the factory. Either way, the test test_temporal_fields_passed_to_factory asserting "adhoc_filters" not in queries[0] is locking in the bug.
3. Minor: duplicated comment
The two-line note "QueryObjectFactory.create() accepts time_range as a top-level kwarg / and converts it to from_dttm/to_dttm for the QueryObject" appears verbatim above the query_dict definition AND immediately above if time_range := …. Drop one — the second placement (right above the assignment) is clearer.
What's solid
DatabaseFilterschema fix + tests — straightforward and the Literal expansion is the right call.time_rangeplumbing into the query dict — verifiedQueryObjectFactory.create()accepts it as a kwarg and converts tofrom_dttm/to_dttm.- The combined-
datasourceparsing ("123__table") mirrors the existing pattern at line 149 — good consistency. DatasourceType("table")default is safe since"table"is a valid enum value.
…filters - Catch DatasourceNotFound/DatasourceTypeNotSupportedError/ DatasourceValueIsIncorrect in _resolve_datasource_name instead of ValueError/KeyError (DAO raises these, never returns None) - Preprocess adhoc_filters via split_adhoc_filters_into_base_filters before building the query dict so WHERE clauses from explore-saved charts appear in rendered SQL - Extract _resolve_engine helper to reduce complexity of _build_query_context_from_form_data - Remove duplicate comment - Update tests to raise real DAO exceptions instead of returning None
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Code Review Agent Run #10c609Actionable Suggestions - 0Filtered by Review RulesBito filtered these suggestions based on rules created automatically for your feedback. Manage rules.
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
* fix(docs): fix 404s in documentation (apache#38974) Co-authored-by: Evan Rusackas <evan@preset.io> * chore(deps): bump baseline-browser-mapping from 2.10.21 to 2.10.23 in /docs (apache#39671) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump d3-cloud from 1.2.8 to 1.2.9 in /superset-frontend (apache#39677) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(ci): update Node.js version used in building CI image (apache#38635) * fix(explore): ensure unsaved-changes dialog renders above View SQL modal (apache#39569) Co-authored-by: yousoph <sophieyou12@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(Modal): prevent title overlapping with close button in long header titles (apache#36536) * fix(mcp): database filter columns, timeseries SQL, and unsaved chart datasource name (apache#39636) * docs(rls): adding additional rls filter documentation (apache#38829) Co-authored-by: codeant-ai-for-open-source[bot] <244253245+codeant-ai-for-open-source[bot]@users.noreply.github.com> * fix(dev): revert `react-checkbox-tree` from 2.1.0 to 1.8.0 in /superset-frontend (apache#39660) Signed-off-by: hainenber <dotronghai96@gmail.com> Co-authored-by: Evan Rusackas <evan@rusackas.com> * chore(deps-dev): bump typescript-eslint from 8.59.0 to 8.59.1 in /superset-websocket (apache#39687) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(plugin-chart-handlebars): preserve template on explore open (apache#39442) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(mcp): surface structured errors for generate_chart validation failures (apache#39484) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(table chart): fix rerender bug that continuously cleared search box (apache#39707) * fix(query-history): enable sorting by Duration column (apache#39637) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): add generic validation for guest token API (closes #8) Co-Authored-By: Chiranjeevi Balawat <cbalawat@gmail.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: hainenber <dotronghai96@gmail.com> Co-authored-by: David <39565245+dmunozv04@users.noreply.github.com> Co-authored-by: Evan Rusackas <evan@preset.io> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Đỗ Trọng Hải <41283691+hainenber@users.noreply.github.com> Co-authored-by: yousoph <sophieyou12@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: innovark <eric.graham@mailfence.com> Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com> Co-authored-by: SkinnyPigeon <e.blackledge@stuart.com> Co-authored-by: codeant-ai-for-open-source[bot] <244253245+codeant-ai-for-open-source[bot]@users.noreply.github.com> Co-authored-by: Evan Rusackas <evan@rusackas.com> Co-authored-by: Mehmet Salih Yavuz <salih.yavuz@proton.me> Co-authored-by: Sam Firke <sfirke@users.noreply.github.com> Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Chiranjeevi Balawat <cbalawat@gmail.com>
…mplexity - _extract_x_axis_col: also handle adhoc-SQL x_axis dicts (expressionType: "SQL") by returning the full dict so the SQL expression is preserved in the query context; column_name dicts (expressionType: "SIMPLE") still return the bare column name string - extract _build_single_query_dict and _build_mixed_timeseries_secondary as module-level helpers to reduce McCabe complexity of _build_query_context_from_form_data below the C901 limit - add tests for SQL-expression x_axis: _extract_x_axis_col unit tests and an integration test through _build_query_context_from_form_data - fix test docstring: regressions introduced after apache#38700, not apache#39636
SUMMARY
Fixes three MCP tool bugs:
list_databases filter columns:
DatabaseFilterschema now acceptscreated_by_fkandchanged_by_fkas valid filter columns. Previously onlydatabase_name,expose_in_sqllab, andallow_file_uploadwere allowed, causing validation errors when filtering by creator.get_chart_sql timeseries:
_build_query_context_from_form_datanow passestime_range,adhoc_filters, andfiltersfromform_datainto the query dict sent toQueryObjectFactory.create(). Previously the query dict only containedcolumnsandmetrics, so timeseries charts produced SQL with no temporal column or time range filtering.get_chart_sql unsaved chart datasource_name: Added
_resolve_datasource_name()helper that resolves datasource name viaDatasourceDAO.get_datasource()for unsaved charts (form_data_key only, no chart object). Previously returnednullbecausegetattr(None, "datasource_name", None)was called whenchart=None.BEFORE/AFTER SCREENSHOTS OR ANIMATIONS
N/A — backend-only changes to MCP tool schemas and query building logic.
TESTING INSTRUCTIONS
list_databaseswithfilters: [{"col": "created_by_fk", "opr": "eq", "value": 1}]— should succeed instead of validation error.get_chart_sqlfor a timeseries chart — SQL should include temporal column and time range WHERE clause.get_chart_sqlwith onlyform_data_key(unsaved chart) —datasource_nameshould be populated, not null.ADDITIONAL INFORMATION
created_by_fkandchanged_by_fkinDatabaseFiltertest_temporal_fields_passed_to_factoryto verifytime_range,adhoc_filters, andfiltersare in the queries dictTestResolveDatasourceNametest class covering: chart exists, unsaved chart DAO lookup, missing datasource_id, datasource not found, DAO error, combined datasource field