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