codeant-ai-for-open-source[bot] commented on code in PR #39865:
URL: https://github.com/apache/superset/pull/39865#discussion_r3198274865


##########
superset/mcp_service/chart/tool/get_chart_sql.py:
##########
@@ -162,6 +177,44 @@ def _resolve_engine(
         return "base"
 
 
+def _build_single_query_dict(
+    form_data: dict[str, Any],
+    columns: list[Any],
+    metrics: list[Any],
+) -> dict[str, Any]:
+    """Build one query entry for QueryContextFactory from form_data fields."""
+    qd: dict[str, Any] = {"columns": columns, "metrics": metrics}
+    if time_range := form_data.get("time_range"):
+        qd["time_range"] = time_range
+    if filters := form_data.get("filters"):
+        qd["filters"] = filters
+    if (row_limit := form_data.get("row_limit")) is not None:
+        qd["row_limit"] = row_limit

Review Comment:
   **Suggestion:** Query dict construction always reads `row_limit` and never 
supports `row_limit_b`, so the secondary `mixed_timeseries` query cannot honor 
its own row limit. This causes incorrect SQL LIMIT behavior for query B. Use 
the secondary-specific limit when building the secondary query. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Secondary series row limits ignored in get_chart_sql output.
   - ⚠️ SQL preview shows incorrect LIMIT for mixed_timeseries B.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure a `mixed_timeseries` chart whose Explore form_data contains 
both `row_limit`
   and a different `row_limit_b` (per-series secondary row limit). Example 
persisted
   configuration appears in 
`superset/examples/featured_charts/charts/Mixed.yaml:80-81` where
   both `row_limit` and `row_limit_b` are defined.
   
   2. Use the MCP `get_chart_sql` tool for this chart in a context that goes 
through the
   form_data fallback, e.g. request SQL for an unsaved Explore state via 
`form_data_key` so
   `_handle_unsaved_chart_sql` 
(`superset/mcp_service/chart/tool/get_chart_sql.py:24-56`)
   loads the cached form_data and calls `_sql_from_form_data(form_data, 
chart=None)` at lines
   39-56.
   
   3. `_sql_from_form_data` invokes `_build_query_context_from_form_data` 
(lines 218-305),
   which builds the primary query via `_build_single_query_dict(form_data, 
groupby, metrics)`
   and the secondary mixed_timeseries query via 
`_build_mixed_timeseries_secondary` (lines
   196-215). Inside `_build_mixed_timeseries_secondary`, the secondary query 
dict is
   constructed with `qd = _build_single_query_dict(form_data, groupby_b, 
metrics_b)` at line
   212.
   
   4. `_build_single_query_dict` (lines 180-193) always reads `row_limit` from
   `form_data.get("row_limit")` and, if set, assigns `qd["row_limit"] = 
row_limit` (lines
   191-192). There is no handling of `row_limit_b`, so both the primary query 
and secondary
   query use the same `row_limit` value. When `ChartDataCommand` executes this 
`QueryContext`
   (`_sql_from_form_data` lines 44-49), the generated SQL for series B uses the 
primary row
   limit instead of the configured `row_limit_b`, making the SQL preview 
inconsistent with
   the chart configuration.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20superset%2Fmcp_service%2Fchart%2Ftool%2Fget_chart_sql.py%0A%2A%2ALine%3A%2A%2A%20191%3A192%0A%2A%2AComment%3A%2A%2A%0A%09%2ALogic%20Error%3A%20Query%20dict%20construction%20always%20reads%20%60row_limit%60%20and%20never%20supports%20%60row_limit_b%60%2C%20so%20the%20secondary%20%60mixed_timeseries%60%20query%20cannot%20honor%20its%20own%20row%20limit.%20This%20causes%20incorrect%20SQL%20LIMIT%20behavior%20for%20query%20B.%20Use%20the%20secondary-specific%20limit%20when%20building%20the%20secondary%20query.%0A%0AValidate%20the%20correctness%20of%20the%20flagged%20issue.%20If%20correct%2C%20How%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%
 
20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%20implement%20a%20minimal%20fix%0A)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20superset%2Fmcp_service%2Fchart%2Ftool%2Fget_chart_sql.py%0A%2A%2ALine%3A%2A%2A%20191%3A192%0A%2A%2AComment%3A%2A%2A%0A%09%2ALogic%20Error%3A%20Query%20dict%20construction%20always%20reads%20%60row_limit%60%20and%20never%20supports%20%60row_limit_b%60%2C%20so%20the%20secondary%20%60mixed_timeseries%60%20query%20cannot%20honor%20its%20own%20row%20limit.%20This%20causes%20incorrect%20SQL%20LIMIT%20behavior%20for%20query%20B.%20Use%20the%20secondary-specific%20limit%20when%20building%20the%20secondary%20query.%0A%0AValidate%20the%20correctness%20of%20the%20flagged%20issue.%20If%20correct%2C%20How%20can%20I%20
 
resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%20implement%20a%20minimal%20fix%0A)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/chart/tool/get_chart_sql.py
   **Line:** 191:192
   **Comment:**
        *Logic Error: Query dict construction always reads `row_limit` and 
never supports `row_limit_b`, so the secondary `mixed_timeseries` query cannot 
honor its own row limit. This causes incorrect SQL LIMIT behavior for query B. 
Use the secondary-specific limit when building the secondary query.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39865&comment_hash=13ee868e08f3c4c1c9d8e6726c08e07901fb90457a1bc8ee935fd7125496e994&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39865&comment_hash=13ee868e08f3c4c1c9d8e6726c08e07901fb90457a1bc8ee935fd7125496e994&reaction=dislike'>👎</a>



##########
superset/mcp_service/chart/tool/get_chart_sql.py:
##########
@@ -162,6 +177,44 @@ def _resolve_engine(
         return "base"
 
 
+def _build_single_query_dict(
+    form_data: dict[str, Any],
+    columns: list[Any],
+    metrics: list[Any],
+) -> dict[str, Any]:
+    """Build one query entry for QueryContextFactory from form_data fields."""
+    qd: dict[str, Any] = {"columns": columns, "metrics": metrics}
+    if time_range := form_data.get("time_range"):
+        qd["time_range"] = time_range
+    if filters := form_data.get("filters"):
+        qd["filters"] = filters
+    if (row_limit := form_data.get("row_limit")) is not None:
+        qd["row_limit"] = row_limit
+    return qd
+
+
+def _build_mixed_timeseries_secondary(
+    form_data: dict[str, Any],
+    x_axis_col: str | None,
+) -> dict[str, Any]:
+    """Build the secondary query dict for the ``mixed_timeseries`` viz type.
+
+    ``mixed_timeseries`` has two independent series layers; the secondary
+    layer uses ``metrics_b`` / ``groupby_b`` instead of the primary fields.
+    If ``time_range_b`` is set it overrides the primary ``time_range`` for
+    the secondary query.
+    """
+    metrics_b: list[Any] = list(form_data.get("metrics_b") or [])
+    raw_b = form_data.get("groupby_b") or []
+    groupby_b: list[Any] = [raw_b] if isinstance(raw_b, str) else list(raw_b)
+    if x_axis_col and x_axis_col not in groupby_b:
+        groupby_b = [x_axis_col] + groupby_b
+    qd = _build_single_query_dict(form_data, groupby_b, metrics_b)

Review Comment:
   **Suggestion:** The secondary query for `mixed_timeseries` is built from the 
original `form_data` without translating `_b` controls to base keys, so 
secondary-only filters (for example `adhoc_filters_b` after preprocessing) are 
never applied. This makes query B SQL use primary filter state and can return 
incorrect results. Build a secondary form-data view (equivalent to 
`retainFormDataSuffix(..., "_b")`) before constructing query B. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ get_chart_sql misrepresents mixed_timeseries secondary series filters.
   - ⚠️ Unsaved mixed_timeseries SQL omits secondary adhoc_filters_b.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Create or edit a `mixed_timeseries` chart in Explore so its form_data (as 
stored in
   `Slice.params` / cached via `GetFormDataCommand`) contains both primary and 
secondary
   series, including `metrics`, `groupby`, `metrics_b`, `groupby_b`, and a 
secondary-only
   adhoc filter in `adhoc_filters_b`. This matches how mixed charts are 
migrated/built in
   `superset/migrations/shared/migrate_viz/processors.py:17-28` where 
`adhoc_filters_b` is
   populated from `adhoc_filters`.
   
   2. From an MCP client, request SQL for this chart using only `form_data_key` 
(unsaved
   state), triggering `_handle_unsaved_chart_sql` at
   `superset/mcp_service/chart/tool/get_chart_sql.py:24-56`, which loads the 
cached form_data
   and calls `_sql_from_form_data(form_data, chart=None)` at lines 39-56.
   
   3. `_sql_from_form_data` calls `_build_query_context_from_form_data` (lines 
218-305).
   Inside that function, adhoc filters are preprocessed by 
`merge_extra_filters` and
   `split_adhoc_filters_into_base_filters` at lines 250-263, but
   `split_adhoc_filters_into_base_filters` (`superset/utils/core.py:1387-1400`) 
only reads
   the `adhoc_filters` key, never `adhoc_filters_b`, so secondary-only adhoc 
filters remain
   unprocessed on `form_data` and are not converted into 
`filters`/`where`/`having`.
   
   4. Still in `_build_query_context_from_form_data`, the secondary query dict 
for
   mixed_timeseries is built by `_build_mixed_timeseries_secondary` (lines 
196-215), which
   calls `qd = _build_single_query_dict(form_data, groupby_b, metrics_b)` at 
line 212.
   `_build_single_query_dict` (lines 180-193) pulls `filters` and `time_range` 
from the
   shared `form_data`, so the secondary query's `qd["filters"]` is based only 
on primary
   `adhoc_filters` that were split into base filters, while `adhoc_filters_b` 
is never
   applied. When `ChartDataCommand` later runs on this `QueryContext` 
(`_sql_from_form_data`
   lines 44-49), the rendered SQL for query B ignores its intended 
secondary-only filters.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20superset%2Fmcp_service%2Fchart%2Ftool%2Fget_chart_sql.py%0A%2A%2ALine%3A%2A%2A%20212%3A212%0A%2A%2AComment%3A%2A%2A%0A%09%2ALogic%20Error%3A%20The%20secondary%20query%20for%20%60mixed_timeseries%60%20is%20built%20from%20the%20original%20%60form_data%60%20without%20translating%20%60_b%60%20controls%20to%20base%20keys%2C%20so%20secondary-only%20filters%20%28for%20example%20%60adhoc_filters_b%60%20after%20preprocessing%29%20are%20never%20applied.%20This%20makes%20query%20B%20SQL%20use%20primary%20filter%20state%20and%20can%20return%20incorrect%20results.%20Build%20a%20secondary%20form-data%20view%20%28equivalent%20to%20%60retainFormDataSuffix%28...%2C%20%22_b%22%29%60%29%20before%20constructing%20query%20B.%0A%0AValidate%20the%20correctness%20of%20the%20flagged%20issue.%20If%20correct%2C%20How%20can%20I%20resolve%20this%3F%20If%2
 
0you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%20implement%20a%20minimal%20fix%0A)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0A%0A%2A%2APath%3A%2A%2A%20superset%2Fmcp_service%2Fchart%2Ftool%2Fget_chart_sql.py%0A%2A%2ALine%3A%2A%2A%20212%3A212%0A%2A%2AComment%3A%2A%2A%0A%09%2ALogic%20Error%3A%20The%20secondary%20query%20for%20%60mixed_timeseries%60%20is%20built%20from%20the%20original%20%60form_data%60%20without%20translating%20%60_b%60%20controls%20to%20base%20keys%2C%20so%20secondary-only%20filters%20%28for%20example%20%60adhoc_filters_b%60%20after%20prep
 
rocessing%29%20are%20never%20applied.%20This%20makes%20query%20B%20SQL%20use%20primary%20filter%20state%20and%20can%20return%20incorrect%20results.%20Build%20a%20secondary%20form-data%20view%20%28equivalent%20to%20%60retainFormDataSuffix%28...%2C%20%22_b%22%29%60%29%20before%20constructing%20query%20B.%0A%0AValidate%20the%20correctness%20of%20the%20flagged%20issue.%20If%20correct%2C%20How%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20implement%20it%20and%20please%20make%20it%20concise.%0AOnce%20fix%20is%20implemented%2C%20also%20check%20other%20comments%20on%20the%20same%20PR%2C%20and%20ask%20user%20if%20the%20user%20wants%20to%20fix%20the%20rest%20of%20the%20comments%20as%20well.%20if%20said%20yes%2C%20then%20fetch%20all%20the%20comments%20validate%20the%20correctness%20and%20implement%20a%20minimal%20fix%0A)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/chart/tool/get_chart_sql.py
   **Line:** 212:212
   **Comment:**
        *Logic Error: The secondary query for `mixed_timeseries` is built from 
the original `form_data` without translating `_b` controls to base keys, so 
secondary-only filters (for example `adhoc_filters_b` after preprocessing) are 
never applied. This makes query B SQL use primary filter state and can return 
incorrect results. Build a secondary form-data view (equivalent to 
`retainFormDataSuffix(..., "_b")`) before constructing query B.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39865&comment_hash=8ad0b3b2c094b5d4c8307afd2dda001c0919cbca58cb0e31946c74fb6b36321b&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39865&comment_hash=8ad0b3b2c094b5d4c8307afd2dda001c0919cbca58cb0e31946c74fb6b36321b&reaction=dislike'>👎</a>



-- 
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