java-topology/defects/hive/patch/hive-0005-relmdsize-neededcols-list-contains.patch

40 lines
2 KiB
Diff

# UNDF: UNDF-2026-000000820
# CWE-407: HiveRelMdSize.averageColumnSizes() uses List.contains(i) in loop
# Severity: MEDIUM
# Speedup: ~250x at C=500 columns
# File: ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdSize.java
#
# averageColumnSizes() iterates over all columns (nNoVirtualColumns + virtual columns)
# and calls neededcolsLst.contains(i) on each iteration. neededcolsLst is an
# ImmutableList<Integer>, so .contains() is O(L) where L = needed columns.
# Total complexity: O(C * L) where C = total columns.
# This method is called by the Calcite optimizer's metadata query framework,
# potentially many times during query planning for wide tables.
#
# Fix: convert neededcolsLst to a HashSet once for O(1) membership testing.
--- a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdSize.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/stats/HiveRelMdSize.java
@@ -57,6 +57,8 @@
public List<Double> averageColumnSizes(HiveTableScan scan, RelMetadataQuery mq) {
List<Integer> neededcolsLst = scan.getNeededColIndxsFrmReloptHT();
+ // Use HashSet for O(1) membership testing instead of O(L) List.contains()
+ Set<Integer> neededCols = new HashSet<>(neededcolsLst);
List<ColStatistics> columnStatistics = ((RelOptHiveTable) scan.getTable())
.getColStat(neededcolsLst, true);
@@ -67,7 +69,7 @@
int nFields = scan.getRowType().getFieldCount();
for (int i = 0; i < nNoVirtualColumns; i++) {
- if (neededcolsLst.contains(i)) {
+ if (neededCols.contains(i)) {
ColStatistics columnStatistic = columnStatistics.get(indxRqdCol);
indxRqdCol++;
if (columnStatistic == null) {
@@ -81,7 +83,7 @@
}
for (int i = nNoVirtualColumns; i < nFields; i++) {
- if (neededcolsLst.contains(i)) {
+ if (neededCols.contains(i)) {
RelDataTypeField field = scan.getRowType().getFieldList().get(i);
list.add(averageTypeValueSize(field.getType()));
} else {