001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2007-2011 Pentaho and others 008// All Rights Reserved. 009*/ 010package mondrian.rolap.agg; 011 012import mondrian.rolap.*; 013 014import java.util.*; 015 016/** 017 * Class for using GROUP BY GROUPING SETS sql query. 018 * 019 * <p>For example, suppose we have the 3 grouping sets (a, b, c), (a, b) and 020 * (b, c).<ul> 021 * <li>detailed grouping set -> (a, b, c) 022 * <li>rolled-up grouping sets -> (a, b), (b, c) 023 * <li>rollup columns -> c, a (c for (a, b) and a for (b, c)) 024 * <li>rollup columns bitkey -><br/> 025 * (a, b, c) grouping set represented as 0, 0, 0<br/> 026 * (a, b) grouping set represented as 0, 0, 1<br/> 027 * (b, c) grouping set represented as 1, 0, 0 028 * </ul> 029 * 030 * @author Thiyagu 031 * @since 24 May 2007 032 */ 033final class GroupingSetsList { 034 035 private final List<RolapStar.Column> rollupColumns; 036 private final List<RolapStar.Column[]> groupingSetsColumns; 037 private final boolean useGroupingSet; 038 039 private final List<BitKey> rollupColumnsBitKeyList; 040 041 /** 042 * Maps column index to grouping function index. 043 */ 044 private final int[] columnIndexToGroupingIndexMap; 045 046 private final List<GroupingSet> groupingSets; 047 private final int groupingBitKeyIndex; 048 049 /** 050 * Creates a GroupingSetsList. 051 * 052 * <p>First element of the groupingSets list should be the detailed 053 * grouping set (default grouping set), followed by grouping sets which can 054 * be rolled-up. 055 * 056 * @param groupingSets List of groups of columns 057 */ 058 public GroupingSetsList(List<GroupingSet> groupingSets) { 059 this.groupingSets = groupingSets; 060 this.useGroupingSet = groupingSets.size() > 1; 061 if (useGroupingSet) { 062 this.groupingSetsColumns = getGroupingColumnsList(groupingSets); 063 this.rollupColumns = findRollupColumns(); 064 065 int arity = getDefaultColumns().length; 066 int segmentLength = getDefaultSegments().size(); 067 this.groupingBitKeyIndex = arity + segmentLength; 068 } else { 069 this.groupingSetsColumns = Collections.emptyList(); 070 this.rollupColumns = Collections.emptyList(); 071 this.groupingBitKeyIndex = -1; 072 } 073 this.columnIndexToGroupingIndexMap = loadRollupIndex(); 074 this.rollupColumnsBitKeyList = loadGroupingColumnBitKeys(); 075 } 076 077 List<RolapStar.Column[]> getGroupingColumnsList( 078 List<GroupingSet> groupingSets) 079 { 080 List<RolapStar.Column[]> groupingColumns = 081 new ArrayList<RolapStar.Column[]>(); 082 for (GroupingSet aggBatchDetail : groupingSets) { 083 groupingColumns.add( 084 aggBatchDetail.segment0.getColumns()); 085 } 086 return groupingColumns; 087 } 088 089 public int getGroupingBitKeyIndex() { 090 return groupingBitKeyIndex; 091 } 092 093 public List<RolapStar.Column> getRollupColumns() { 094 return rollupColumns; 095 } 096 097 public List<RolapStar.Column[]> getGroupingSetsColumns() { 098 return groupingSetsColumns; 099 } 100 101 public List<BitKey> getRollupColumnsBitKeyList() { 102 return rollupColumnsBitKeyList; 103 } 104 105 private List<BitKey> loadGroupingColumnBitKeys() { 106 if (!useGroupingSet) { 107 return Collections.singletonList(BitKey.EMPTY); 108 } 109 final List<BitKey> rollupColumnsBitKeyList = new ArrayList<BitKey>(); 110 final int bitKeyLength = getDefaultColumns().length; 111 for (RolapStar.Column[] groupingSetColumns : groupingSetsColumns) { 112 BitKey groupingColumnsBitKey = 113 BitKey.Factory.makeBitKey(bitKeyLength); 114 Set<RolapStar.Column> columns = 115 new HashSet<RolapStar.Column>( 116 Arrays.asList(groupingSetColumns)); 117 int bitPosition = 0; 118 for (RolapStar.Column rollupColumn : rollupColumns) { 119 if (!columns.contains(rollupColumn)) { 120 groupingColumnsBitKey.set(bitPosition); 121 } 122 bitPosition++; 123 } 124 rollupColumnsBitKeyList.add(groupingColumnsBitKey); 125 } 126 return rollupColumnsBitKeyList; 127 } 128 129 private int[] loadRollupIndex() { 130 if (!useGroupingSet) { 131 return new int[0]; 132 } 133 RolapStar.Column[] detailedColumns = getDefaultColumns(); 134 int[] columnIndexToGroupingIndexMap = new int[detailedColumns.length]; 135 for (int columnIndex = 0; columnIndex < detailedColumns.length; 136 columnIndex++) 137 { 138 int rollupIndex = 139 rollupColumns.indexOf(detailedColumns[columnIndex]); 140 columnIndexToGroupingIndexMap[columnIndex] = rollupIndex; 141 } 142 return columnIndexToGroupingIndexMap; 143 } 144 145 private List<RolapStar.Column> findRollupColumns() { 146 Set<RolapStar.Column> rollupSet = new TreeSet<RolapStar.Column>( 147 RolapStar.ColumnComparator.instance); 148 for (RolapStar.Column[] groupingSetColumn : groupingSetsColumns) { 149 Set<RolapStar.Column> summaryColumns = 150 new HashSet<RolapStar.Column>( 151 Arrays.asList(groupingSetColumn)); 152 for (RolapStar.Column column : getDefaultColumns()) { 153 if (!summaryColumns.contains(column)) { 154 rollupSet.add(column); 155 } 156 } 157 } 158 return new ArrayList<RolapStar.Column>(rollupSet); 159 } 160 161 public boolean useGroupingSets() { 162 return useGroupingSet; 163 } 164 165 public int findGroupingFunctionIndex(int columnIndex) { 166 return columnIndexToGroupingIndexMap[columnIndex]; 167 } 168 169 public SegmentAxis[] getDefaultAxes() { 170 return getDefaultGroupingSet().getAxes(); 171 } 172 173 public StarColumnPredicate[] getDefaultPredicates() { 174 return getDefaultGroupingSet().getPredicates(); 175 } 176 177 protected GroupingSet getDefaultGroupingSet() { 178 return groupingSets.get(0); 179 } 180 181 public RolapStar.Column[] getDefaultColumns() { 182 return getDefaultGroupingSet().segment0.getColumns(); 183 } 184 185 public List<Segment> getDefaultSegments() { 186 return getDefaultGroupingSet().getSegments(); 187 } 188 189 public BitKey getDefaultLevelBitKey() { 190 return getDefaultGroupingSet().getLevelBitKey(); 191 } 192 193 public BitKey getDefaultMeasureBitKey() { 194 return getDefaultGroupingSet().getMeasureBitKey(); 195 } 196 197 public RolapStar getStar() { 198 return getDefaultGroupingSet().segment0.getStar(); 199 } 200 201 public List<GroupingSet> getGroupingSets() { 202 return groupingSets; 203 } 204 205 public List<GroupingSet> getRollupGroupingSets() { 206 return groupingSets.subList(1, groupingSets.size()); 207 } 208 209 /** 210 * Collection of {@link mondrian.rolap.agg.SegmentDataset} that have the 211 * same dimensionality and identical axis values. A cohort contains 212 * corresponding cell values for set of measures. 213 */ 214 static class Cohort 215 { 216 final List<SegmentDataset> segmentDatasetList; 217 final SegmentAxis[] axes; 218 // workspace 219 final int[] pos; 220 221 Cohort( 222 List<SegmentDataset> segmentDatasetList, 223 SegmentAxis[] axes) 224 { 225 this.segmentDatasetList = segmentDatasetList; 226 this.axes = axes; 227 this.pos = new int[axes.length]; 228 } 229 } 230} 231 232// End GroupingSetsList.java