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


##########
superset/common/query_context_processor.py:
##########
@@ -252,9 +256,60 @@ 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: BaseEngineSpec | None = 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: list[list[str]] = query_object.grouping_sets
+        # Use the same label derivation as the native path (physical column 
name
+        # or adhoc column label) so both column kinds are represented and each
+        # label maps back to its own column, in the same order as the source
+        # list.
+        all_labels = [get_column_name(col) for col in query_object.columns]
+        label_to_column = dict(zip(all_labels, query_object.columns, 
strict=True))
+
+        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:** The fallback reuses the original query object (including 
`row_limit`) for every rollup level. That applies the limit independently per 
level, which can truncate subtotal/grand-total rows and produce different 
results than the native GROUPING SETS path (which explicitly skips per-level 
limiting). Clear `row_limit` on each fallback subquery and, if needed, enforce 
any final cap only once on the concatenated result. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   ❌ Pivot/pivot-table rollup totals incorrect on non-supporting engines.
   ⚠️ Grouping-sets rollup results inconsistent across database backends.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure a pivot/table Chart Data payload with a grouping_sets rollup on 
a dataset
   backed by an engine without native GROUPING SETS support
   (SqliteEngineSpec.supports_grouping_sets is False, verified in
   tests/unit_tests/db_engine_specs/test_grouping_sets_capability.py:39). Use a 
payload
   similar to TestGroupingSetsRollup in
   tests/integration_tests/non_additive_totals_tests.py:230-249, but targeting 
such an engine
   and with a finite row_limit (for example 100).
   
   2. The ChartData API parses this payload via 
ChartDataQueryContextSchema().load(payload)
   as in tests/integration_tests/non_additive_totals_tests.py:42-45, producing 
a QueryContext
   whose first QueryObject has columns ["gender", "state"], a non-additive 
metric,
   grouping_sets levels, and row_limit set to the requested value.
   
   3. When QueryContext.get_query_result(query_context.queries[0]) is called
   (tests/integration_tests/non_additive_totals_tests.py:299-2), it delegates to
   QueryContextProcessor.get_query_result(query_object) in
   superset/common/query_context_processor.py:33-49. Because
   datasource.db_engine_spec.supports_grouping_sets is False, 
_supports_grouping_sets()
   (lines 51-55) returns False and _grouping_sets_fallback(query_object) (lines 
57-92) is
   invoked.
   
   4. Inside _grouping_sets_fallback, the loop over levels at
   superset/common/query_context_processor.py:73-80 creates sub_query =
   copy.copy(query_object), leaves sub_query.row_limit unchanged, and calls
   self._qc_datasource.get_query_result(sub_query) for each level. This applies 
the same
   row_limit independently to every level, truncating each per-level DataFrame 
before
   concatenation at line 91. The combined result.df therefore omits rows that 
would be
   present if the GROUPING SETS path fetched all rows once and applied any 
limit only on the
   final combined result, yielding incorrect subtotals/grand totals on engines 
using the
   fallback.
   ```
   </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=3a51977983a74a1c9ef6c6c365e0c1df&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=3a51977983a74a1c9ef6c6c365e0c1df&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:** 294:298
   **Comment:**
        *Logic Error: The fallback reuses the original query object (including 
`row_limit`) for every rollup level. That applies the limit independently per 
level, which can truncate subtotal/grand-total rows and produce different 
results than the native GROUPING SETS path (which explicitly skips per-level 
limiting). Clear `row_limit` on each fallback subquery and, if needed, enforce 
any final cap only once on the concatenated result.
   
   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=6478106458fb985c103eac66d2af066b06ec84f9e2d6fe063e2891882902af20&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41184&comment_hash=6478106458fb985c103eac66d2af066b06ec84f9e2d6fe063e2891882902af20&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