codeant-ai-for-open-source[bot] commented on code in PR #40907:
URL: https://github.com/apache/superset/pull/40907#discussion_r3382267178
##########
superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:
##########
@@ -62,6 +64,13 @@ export const useResultsPane = ({
const chartRowLimit = Number(queryFormData?.row_limit) || 10000;
const [rowLimit, setRowLimit] = useState(1000);
+ const [orderby, setOrderby] = useState<[string, boolean][]>([]);
+ // Server-side sort is only valid when the displayed columns map directly to
+ // the SQL result. When the query has post-processing (e.g.
pivot/cum/rolling),
+ // `orderby` + `row_limit` are applied to the raw SQL *before*
post-processing,
+ // which changes the rows that feed those operations and corrupts the result.
+ // In that case we fall back to client-side sorting of what the chart
produced.
+ const [hasPostProcessing, setHasPostProcessing] = useState(false);
Review Comment:
**Suggestion:** Initializing post-processing detection to `false`
temporarily enables server-side sorting before async detection finishes, which
can send incorrect `orderby + row_limit` requests for post-processed queries.
Start in a disabled/unknown state and enable server sort only after detection
confirms no post-processing. [incorrect condition logic]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Post-processed charts can briefly issue unsafe sorted queries.
- ⚠️ Early header clicks may show incorrect cumulative/rolling values.
- ⚠️ Behavior contradicts documented intent to disable server sort.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Configure a chart whose query uses post-processing (e.g., a cumulative or
rolling
operation) so that the backend query context includes a non-empty
`post_processing` list
alongside `orderby`, as reflected in
`tests/unit_tests/common/test_query_context_processor.py:1086-1092` (showing
`"orderby":
[("Net Amount In", False)], "post_processing": [...]` in the same query).
2. Open the Explore results data panel for that chart: `DataTablesPane`
instantiates
`useResultsPane` (`DataTablesPane.tsx:185-198`), which initializes
`hasPostProcessing` to
`false` (`useResultsPane.tsx:73`) and immediately kicks off two effects: one
that fetches
results via `getChartDataRequest` (`useResultsPane.tsx:108-147`) and one that
asynchronously detects `post_processing` by calling
`buildV1ChartDataPayload` and updating
`hasPostProcessing` based on `payload.queries[].post_processing`
(`useResultsPane.tsx:155-186`).
3. As soon as the first result set comes back, `isLoading` is set to false
and
`resultResp` is populated (`useResultsPane.tsx:130-145`), causing the hook
to return
`SingleQueryResultPane` instances (`useResultsPane.tsx:228-258`); until the
`buildV1ChartDataPayload` promise resolves and `setHasPostProcessing(true)`
runs,
`hasPostProcessing` remains `false`.
4. In that window, because `!hasPostProcessing && result.rowcount >=
effectiveRowLimit` is
true, `onServerSort={handleServerSort}` is passed down
(`useResultsPane.tsx:247-253` →
`SingleQueryResultPane.tsx:95-105` → `GridTable/index.tsx:49-65`), so
clicking a column
header sends a server-side `orderby` while `row_limit` is applied to the raw
SQL feeding
post-processing, potentially truncating or reordering the input rows for
cumulative/rolling operations and yielding incorrect post-processed values,
even though
the design comment in `useResultsPane.tsx:68-72` indicates post-processed
queries should
never be server-sorted.
```
</details>
[Fix in
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=889df2dc60fb4ff18cfb853c48673084&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
| [Fix in VSCode
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=889df2dc60fb4ff18cfb853c48673084&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(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-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
**Line:** 73:73
**Comment:**
*Incorrect Condition Logic: Initializing post-processing detection to
`false` temporarily enables server-side sorting before async detection
finishes, which can send incorrect `orderby + row_limit` requests for
post-processed queries. Start in a disabled/unknown state and enable server
sort only after detection confirms no post-processing.
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%2F40907&comment_hash=e2c9ea832abc0e76bbef4823ce53725686f6ef9727ca5b4f7b3621f6acf8f542&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40907&comment_hash=e2c9ea832abc0e76bbef4823ce53725686f6ef9727ca5b4f7b3621f6acf8f542&reaction=dislike'>👎</a>
##########
superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:
##########
@@ -74,8 +83,14 @@ export const useResultsPane = ({
const effectiveRowLimit = Math.min(rowLimit, chartRowLimit);
const cappedFormData = useMemo(
- () => ({ ...queryFormData, row_limit: effectiveRowLimit }),
- [queryFormData, effectiveRowLimit],
+ () => ({
+ ...queryFormData,
+ row_limit: effectiveRowLimit,
+ // A new `orderby` produces a new object, missing the cache below and
+ // triggering a server-side re-query in the sorted order.
+ ...(orderby.length > 0 && { orderby }),
Review Comment:
**Suggestion:** Omitting `orderby` when the sort model becomes empty makes a
"clear sort" action indistinguishable from "no explicit sort provided".
Downstream query builders then re-apply their metric-based default ordering, so
the grid can show `aria-sort="none"` while rows are still server-sorted. Keep
an explicit empty `orderby` (or track a "user sorted" flag) so clearing sort
actually clears server ordering. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ Results pane clear-sort reverts to metric default ordering.
- ⚠️ Grid header shows no sort while backend still orders.
- ⚠️ Users may misinterpret "unsorted" as raw row order.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Open the Explore view and ensure the results data panel is visible so that
`DataTablesPane` renders (entry component at
`superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx:80-90`).
2. With the "Results" tab active, `DataTablesPane` calls `useResultsPane`
(`DataTablesPane.tsx:185-198`), which builds `cappedFormData` without an
`orderby` field
when `orderby` state is empty (`useResultsPane.tsx:85-92`).
3. Because no `orderby` is provided in `cappedFormData`,
`getChartDataRequest`
(`useResultsPane.tsx:121-128`) sends form data without `orderby`, and the
backend query
builders apply their metric-based default ordering as verified by
`tests/unit_tests/mcp_service/chart/test_chart_helpers.py:860-868` (default
`orderby` from
first metric when omitted).
4. Click a grid column header to sort: `GridTable` translates the Ag-Grid
sort state into
an `orderby` array and calls `onServerSort(orderby)`
(`GridTable/index.tsx:57-64`), which
`SingleQueryResultPane` passes through (`SingleQueryResultPane.tsx:97-105`)
to
`useResultsPane.handleServerSort` (`useResultsPane.tsx:104-106`), updating
`orderby` so
the next request includes an explicit `orderby`
(`useResultsPane.tsx:85-92`); clicking the
same header again to clear the sort causes `GridTable` to send an empty `[]`,
`handleServerSort` resets `orderby` to `[]`, `cappedFormData` drops the
`orderby` field
entirely (`...(orderby.length > 0 && { orderby })` at
`useResultsPane.tsx:91`), and the
subsequent server request again uses the backend's implicit metric-based
ordering while
the grid's header shows no active sort.
```
</details>
[Fix in
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=9f595c3d60134618b21fb7952ce37b83&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
| [Fix in VSCode
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=9f595c3d60134618b21fb7952ce37b83&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(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-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
**Line:** 91:91
**Comment:**
*Logic Error: Omitting `orderby` when the sort model becomes empty
makes a "clear sort" action indistinguishable from "no explicit sort provided".
Downstream query builders then re-apply their metric-based default ordering, so
the grid can show `aria-sort="none"` while rows are still server-sorted. Keep
an explicit empty `orderby` (or track a "user sorted" flag) so clearing sort
actually clears server ordering.
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%2F40907&comment_hash=4c39a90efea2100d178bb0dce84cbea97d241e292ee1d37fec074daa026265f7&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40907&comment_hash=4c39a90efea2100d178bb0dce84cbea97d241e292ee1d37fec074daa026265f7&reaction=dislike'>👎</a>
##########
superset-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx:
##########
@@ -86,6 +101,10 @@ export const useResultsPane = ({
[cappedFormData],
);
+ const handleServerSort = useCallback((nextOrderby: [string, boolean][]) => {
+ setOrderby(nextOrderby);
+ }, []);
Review Comment:
**Suggestion:** The new server-sort path can fire multiple overlapping
requests (e.g., rapid header clicks), but there is no request sequencing or
cancellation, so a slower older response can overwrite a newer sort result. Add
a request id/AbortController guard and only apply the latest response to
prevent stale data races. [race condition]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Results pane can display rows for an old sort.
- ⚠️ Grid sort indicators may not match underlying row subset.
- ⚠️ Fast header clicks can cause confusing result "flapping."
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. In Explore, open the results data panel so `DataTablesPane` renders and
calls
`useResultsPane` (`DataTablesPane.tsx:80-90` and `185-198`), and ensure the
result set is
large enough that `result.rowcount >= effectiveRowLimit` so `onServerSort`
is wired
(`useResultsPane.tsx:82-84` and `232-255`).
2. With a non–post-processed chart (so `hasPostProcessing` is false),
`SingleQueryResultPane` passes the `onServerSort` callback from
`useResultsPane` down to
`GridTable` (`SingleQueryResultPane.tsx:49-65` and `95-105`), where Ag-Grid's
`onSortChanged` builds an `orderby` array from the current column sort state
and invokes
`onServerSort(orderby)` (`GridTable/index.tsx:49-65`).
3. Rapidly click two different column headers (or repeatedly toggle sort) so
that
`GridTable` fires multiple `onSortChanged` events in quick succession; for
each event,
`handleServerSort` in `useResultsPane` updates `orderby`
(`useResultsPane.tsx:104-106`),
which changes `cappedFormData` (`useResultsPane.tsx:85-93`) and triggers the
`useEffect`
that starts a new `getChartDataRequest` without cancelling the previous one
(`useResultsPane.tsx:108-147`).
4. If the earlier request's network response arrives after the later one
(e.g., the "old"
sort query is slower), its `.then` handler still calls `setResultResp(...)`
and
`cache.set(cappedFormData, json.result)` (`useResultsPane.tsx:130-134`), and
its
`.finally` sets `isLoading` false (`useResultsPane.tsx:143-145`),
overwriting the more
recent sort's data because there is no AbortController or request-id check
here (unlike
the guarded, abortable flow in `exploreJSON` at `chartAction.ts:221-249` and
the
stale-response dropping at `chartAction.ts:278-79`), leaving the grid
showing sort UI for
the last header clicked but row data corresponding to an earlier `orderby`.
```
</details>
[Fix in
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=cf1502d729ac4c049ac3c8974ee0075d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
| [Fix in VSCode
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=cf1502d729ac4c049ac3c8974ee0075d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(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-frontend/src/explore/components/DataTablesPane/components/useResultsPane.tsx
**Line:** 104:106
**Comment:**
*Race Condition: The new server-sort path can fire multiple overlapping
requests (e.g., rapid header clicks), but there is no request sequencing or
cancellation, so a slower older response can overwrite a newer sort result. Add
a request id/AbortController guard and only apply the latest response to
prevent stale data races.
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%2F40907&comment_hash=84f83d8241aae09041c54eb587352f338a50811b3f979a25ee2a1c9f5c854151&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40907&comment_hash=84f83d8241aae09041c54eb587352f338a50811b3f979a25ee2a1c9f5c854151&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]