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


##########
superset/common/query_context_processor.py:
##########
@@ -252,9 +254,54 @@ def get_query_result(self, query_object: QueryObject) -> 
QueryResult:
         This method delegates to the datasource's get_query_result method,
         which handles query execution, normalization, time offsets, and
         post-processing.
+
+        When the query requests rollup ``grouping_sets`` but the engine does 
not
+        support native ``GROUPING SETS``, fall back to one query per level and
+        concatenate the results with ``GROUPING()``-equivalent markers, so the
+        combined result matches the shape the native path produces (SIP.md,
+        phase 3b). Engines that support it run the single native query.
         """
+        if query_object.grouping_sets and not self._supports_grouping_sets():
+            return self._grouping_sets_fallback(query_object)
         return self._qc_datasource.get_query_result(query_object)
 
+    def _supports_grouping_sets(self) -> bool:
+        engine_spec = getattr(self._qc_datasource, "db_engine_spec", None)
+        return bool(engine_spec and engine_spec.supports_grouping_sets)
+
+    def _grouping_sets_fallback(self, query_object: QueryObject) -> 
QueryResult:
+        """
+        Emulate a GROUPING SETS query on engines without native support: run 
one
+        query per rollup level and concatenate, tagging each level's rows with
+        the same per-column markers the native path emits.
+        """
+        levels = query_object.grouping_sets
+        all_labels = get_column_names_from_columns(query_object.columns)
+        label_to_column = dict(zip(all_labels, query_object.columns, 
strict=False))

Review Comment:
   **Suggestion:** The fallback builds `label_to_column` by zipping a filtered 
label list with the unfiltered `query_object.columns` list, which misaligns 
entries whenever any non-physical/adhoc column is present. That can map a label 
to the wrong column object and generate incorrect grouping SQL. Build the 
mapping from the original columns and their actual labels in the same pass 
(without dropping entries first) so each label always points to its correct 
column definition. [incorrect variable usage]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Grouping_sets fallback groups by wrong columns on SQLite.
   - ⚠️ Pivot/Table non-additive totals incorrect on fallback engines.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Build a Chart Data payload similar to
   `TestGroupingSetsRollup.test_grouping_sets_returns_all_levels` in
   `tests/integration_tests/non_additive_totals_tests.py:12-32`, but set
   `queries[0]["columns"]` to include an adhoc SQL column dict first and a 
physical column
   second (e.g. `columns = [{"expressionType": "SQL", "sqlExpression": "...", 
"label":
   "adhoc_col"}, "state"]`), and define `grouping_sets` levels that reference 
both labels
   (e.g. `[["adhoc_col", "state"], ["adhoc_col"], []]`).
   
   2. Send this payload to `ChartDataQueryContextSchema().load(...)` (see
   `superset/charts/schemas.py:32-42` and
   `tests/integration_tests/non_additive_totals_tests.py:81-84`), which 
constructs a
   `QueryContext` and its first `QueryObject` via `QueryObjectFactory.create`
   (`superset/common/query_object_factory.py:52-95`). The resulting 
`QueryObject.columns`
   list preserves the adhoc + physical ordering 
(`superset/common/query_object.py:114-162`).
   
   3. Run the query against a datasource whose 
`db_engine_spec.supports_grouping_sets` is
   false (e.g. SQLite, referenced in the docstring at
   `tests/integration_tests/non_additive_totals_tests.py:4-10`).
   `QueryContext.get_query_result()` 
(`superset/common/query_context.py:134-135`) delegates
   to `QueryContextProcessor.get_query_result()`
   (`superset/common/query_context_processor.py:250-266`), which detects
   `query_object.grouping_sets` and calls `_grouping_sets_fallback()` when 
native grouping
   sets are unsupported.
   
   4. In `_grouping_sets_fallback()` 
(`superset/common/query_context_processor.py:272-281`),
   `get_column_names_from_columns(query_object.columns)` from
   `superset/utils/core.py:1699-1707` drops adhoc columns, producing a shorter 
`all_labels`
   list. `dict(zip(all_labels, query_object.columns, strict=False))` then pairs 
each physical
   label with the first N entries of the full `columns` list, so when an adhoc 
appears before
   a later physical column the label maps to the wrong `Column` object. 
Subsequent per-level
   subqueries built from `label_to_column` group by mis-mapped columns, 
yielding rollup
   results and grouping markers that no longer correspond to the intended 
dimensions.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=b5b0140dab1c4ec2a832d9b48829d409&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=b5b0140dab1c4ec2a832d9b48829d409&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/common/query_context_processor.py
   **Line:** 279:280
   **Comment:**
        *Incorrect Variable Usage: The fallback builds `label_to_column` by 
zipping a filtered label list with the unfiltered `query_object.columns` list, 
which misaligns entries whenever any non-physical/adhoc column is present. That 
can map a label to the wrong column object and generate incorrect grouping SQL. 
Build the mapping from the original columns and their actual labels in the same 
pass (without dropping entries first) so each label always points to its 
correct column definition.
   
   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%2F41184&comment_hash=27e913088b389ae6e646cd1e83646c7f18305447e930343c9fba97c4efcccbfb&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41184&comment_hash=27e913088b389ae6e646cd1e83646c7f18305447e930343c9fba97c4efcccbfb&reaction=dislike'>👎</a>



##########
superset/common/query_context_processor.py:
##########
@@ -252,9 +254,54 @@ def get_query_result(self, query_object: QueryObject) -> 
QueryResult:
         This method delegates to the datasource's get_query_result method,
         which handles query execution, normalization, time offsets, and
         post-processing.
+
+        When the query requests rollup ``grouping_sets`` but the engine does 
not
+        support native ``GROUPING SETS``, fall back to one query per level and
+        concatenate the results with ``GROUPING()``-equivalent markers, so the
+        combined result matches the shape the native path produces (SIP.md,
+        phase 3b). Engines that support it run the single native query.
         """
+        if query_object.grouping_sets and not self._supports_grouping_sets():
+            return self._grouping_sets_fallback(query_object)
         return self._qc_datasource.get_query_result(query_object)
 
+    def _supports_grouping_sets(self) -> bool:
+        engine_spec = getattr(self._qc_datasource, "db_engine_spec", None)
+        return bool(engine_spec and engine_spec.supports_grouping_sets)
+
+    def _grouping_sets_fallback(self, query_object: QueryObject) -> 
QueryResult:
+        """
+        Emulate a GROUPING SETS query on engines without native support: run 
one
+        query per rollup level and concatenate, tagging each level's rows with
+        the same per-column markers the native path emits.
+        """
+        levels = query_object.grouping_sets
+        all_labels = get_column_names_from_columns(query_object.columns)
+        label_to_column = dict(zip(all_labels, query_object.columns, 
strict=False))
+
+        frames: list[pd.DataFrame] = []
+        result: QueryResult | None = None
+        for level in levels:
+            level_labels = set(level)
+            sub_query = copy.copy(query_object)
+            sub_query.grouping_sets = []
+            sub_query.columns = [
+                label_to_column[label] for label in all_labels if label in 
level_labels
+            ]

Review Comment:
   **Suggestion:** This fallback only keeps columns found in `all_labels`, but 
`all_labels` is built from physical columns only; adhoc groupby columns 
(including pivot temporal BASE_AXIS columns sent as adhoc SQL columns) are 
dropped from every fallback subquery. On engines without native grouping sets, 
those dimensions are silently omitted, so subtotals/grand totals are computed 
at the wrong granularity. Include adhoc-labeled groupby columns when selecting 
each level so fallback results match native behavior. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Adhoc groupby dimensions dropped from fallback rollup queries.
   - ⚠️ Totals computed at coarser-than-intended granularity levels.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure a chart payload for the `api/v1/chart/data` endpoint that uses
   `grouping_sets` with both physical and adhoc groupby dimensions, e.g. for a
   pivot-table-like query: `columns = [{"expressionType": "SQL", 
"sqlExpression":
   "DATE_TRUNC('month', dttm)", "label": "month"}, "state"]` and `grouping_sets 
= [["month",
   "state"], ["month"], []]`, following the grouping-sets schema documented in
   `superset/charts/schemas.py:32-42`.
   
   2. Load this payload via `ChartDataQueryContextSchema().load(payload)` 
(patterned after
   `_result_df` in 
`tests/integration_tests/non_additive_totals_tests.py:78-85`), which
   creates a `QueryContext` and `QueryObject`. The `QueryObject.columns` list 
contains both
   the adhoc SQL column and the physical `state` column
   (`superset/common/query_object.py:114-162`).
   
   3. Execute the query on a database engine where 
`db_engine_spec.supports_grouping_sets` is
   false (e.g. SQLite, noted in 
`tests/integration_tests/non_additive_totals_tests.py:4-10`).
   `QueryContext.get_query_result()` 
(`superset/common/query_context.py:134-135`) invokes
   `QueryContextProcessor.get_query_result()`
   (`superset/common/query_context_processor.py:250-266`), which detects 
`grouping_sets` and
   routes to `_grouping_sets_fallback()` for non-supporting engines.
   
   4. In `_grouping_sets_fallback()` 
(`superset/common/query_context_processor.py:272-290`),
   `all_labels = get_column_names_from_columns(query_object.columns)` calls the 
helper
   defined in `superset/utils/core.py:1699-1707`, which expressly ignores adhoc 
columns. The
   per-level column selection `sub_query.columns = [label_to_column[label] for 
label in
   all_labels if label in level_labels]` therefore only ever includes physical 
labels from
   `all_labels`: adhoc groupby dimensions present in 
`query_object.grouping_sets` are never
   added to `sub_query.columns`. On fallback engines, rollup queries run at a 
reduced
   grouping granularity (e.g. grouped only by `state` instead of `[month, 
state]`), so
   subtotals and grand totals for non-additive metrics are computed over the 
wrong dimension
   set compared to the native GROUPING SETS path.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=33eb2f9e225647bbbcf800dafc731b9d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=33eb2f9e225647bbbcf800dafc731b9d&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/common/query_context_processor.py
   **Line:** 288:290
   **Comment:**
        *Logic Error: This fallback only keeps columns found in `all_labels`, 
but `all_labels` is built from physical columns only; adhoc groupby columns 
(including pivot temporal BASE_AXIS columns sent as adhoc SQL columns) are 
dropped from every fallback subquery. On engines without native grouping sets, 
those dimensions are silently omitted, so subtotals/grand totals are computed 
at the wrong granularity. Include adhoc-labeled groupby columns when selecting 
each level so fallback results match native behavior.
   
   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%2F41184&comment_hash=62efd414b0b8c10bb055ea396a7a9695fd4aa167766521755e9f8f5891017404&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41184&comment_hash=62efd414b0b8c10bb055ea396a7a9695fd4aa167766521755e9f8f5891017404&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