Copilot commented on code in PR #18662:
URL: https://github.com/apache/pinot/pull/18662#discussion_r3385847359


##########
pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java:
##########
@@ -114,6 +114,26 @@ public static QueryContext getQueryContext(PinotQuery 
pinotQuery) {
       }
     }
 
+    /// GROUP BY GROUPING SETS / ROLLUP / CUBE: the wire carries one 
membership bitmask per set over
+    /// groupByExpressions (the union of all grouping columns). Decode each 
mask into the sorted list of
+    /// participating column indexes; a mask of 0 yields the empty 
(grand-total) set (). Null when this is a
+    /// plain GROUP BY query.
+    List<int[]> groupingSets = null;
+    List<Integer> groupingSetMasks = pinotQuery.getGroupingSetMasks();
+    if (groupingSetMasks != null) {
+      groupingSets = new ArrayList<>(groupingSetMasks.size());
+      for (int mask : groupingSetMasks) {
+        int[] indexes = new int[Integer.bitCount(mask)];
+        int idx = 0;
+        for (int bit = 0; bit < Integer.SIZE && idx < indexes.length; bit++) {
+          if ((mask & (1 << bit)) != 0) {
+            indexes[idx++] = bit;
+          }
+        }
+        groupingSets.add(indexes);
+      }
+    }

Review Comment:
   `groupingSetMasks` is decoded into column indexes without validating that 
the mask only references existing GROUP BY union columns. A 
malformed/mismatched request (e.g. mask with a bit >= groupByList.size()) will 
later cause out-of-bounds access when building grouping sets (and can crash the 
broker/server). It’s safer to validate masks against the union size during 
QueryContext conversion (and optionally ignore the special case where the union 
is empty).



##########
pinot-common/src/main/java/org/apache/pinot/sql/parsers/CalciteSqlParser.java:
##########
@@ -690,6 +724,172 @@ private static List<Expression> 
convertSelectList(SqlNodeList selectList) {
     return selectExpr;
   }
 
+  /// Converts the GROUP BY clause into {@link PinotQuery#groupByList} and 
(when grouping constructs are
+  /// present) {@link PinotQuery#groupingSets}.
+  ///
+  /// For a plain GROUP BY (no ROLLUP / CUBE / GROUPING SETS) this behaves 
exactly like
+  /// {@link #convertSelectList} and leaves {@code groupingSets} unset, so 
non-grouping-set queries are
+  /// unchanged. When grouping constructs are present, the grouping elements 
are cross-multiplied into the
+  /// canonical, de-duplicated list of grouping sets (standard SQL semantics, 
e.g.
+  /// {@code GROUP BY a, ROLLUP(b, c)} produces {@code {a,b,c}, {a,b}, {a}}); 
the ordered, de-duplicated
+  /// union of all participating columns is stored as {@code groupByList}, and 
each grouping set is stored
+  /// as the sorted list of indexes into that union (an empty list = the 
grand-total set {@code ()}).

Review Comment:
   The doc comment for `setGroupByListAndGroupingSets` refers to 
`PinotQuery#groupingSets` and describes per-set values as “sorted list of 
indexes”, but the implementation actually populates 
`PinotQuery#groupingSetMasks` (bitmask per set). Updating the comment avoids 
misleading future maintainers.



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