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