001    /*
002    // $Id: //open/mondrian/src/main/mondrian/rolap/agg/AggQuerySpec.java#18 $
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) 2002-2002 Kana Software, Inc.
007    // Copyright (C) 2002-2008 Julian Hyde and others
008    // All Rights Reserved.
009    // You must accept the terms of that agreement to use this software.
010    //
011    // jhyde, 21 March, 2002
012    */
013    package mondrian.rolap.agg;
014    
015    import mondrian.rolap.RolapStar;
016    import mondrian.rolap.StarColumnPredicate;
017    import mondrian.rolap.aggmatcher.AggStar;
018    import mondrian.rolap.sql.SqlQuery;
019    
020    import org.apache.log4j.Logger;
021    
022    import java.util.ArrayList;
023    import java.util.List;
024    
025    /**
026     * An AggStar's version of the {@link QuerySpec}. <p/>
027     *
028     * When/if the {@link AggStar} code is merged into {@link RolapStar}
029     * (or RolapStar is merged into AggStar}, then this, indeed, can implement the
030     * {@link QuerySpec} interface.
031     *
032     * @author Richard M. Emberson
033     * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/AggQuerySpec.java#18 $
034     */
035    class AggQuerySpec {
036        private static final Logger LOGGER = Logger.getLogger(AggQuerySpec.class);
037    
038        private final AggStar aggStar;
039        private final Segment[] segments;
040        private final boolean rollup;
041        private final GroupingSetsList groupingSetsList;
042    
043        AggQuerySpec(
044            final AggStar aggStar,
045            final boolean rollup, GroupingSetsList groupingSetsList) {
046            this.aggStar = aggStar;
047            this.segments = groupingSetsList.getDefaultSegments();
048            this.rollup = rollup;
049            this.groupingSetsList = groupingSetsList;
050        }
051    
052        protected SqlQuery newSqlQuery() {
053            return getStar().getSqlQuery();
054        }
055    
056        public RolapStar getStar() {
057            return aggStar.getStar();
058        }
059    
060        public int getMeasureCount() {
061            return segments.length;
062        }
063    
064        public AggStar.FactTable.Column getMeasureAsColumn(final int i) {
065            int bitPos = segments[i].measure.getBitPosition();
066            return aggStar.lookupColumn(bitPos);
067        }
068    
069        public String getMeasureAlias(final int i) {
070            return "m" + Integer.toString(i);
071        }
072    
073        public int getColumnCount() {
074            return segments[0].aggregation.getColumns().length;
075        }
076    
077        public AggStar.Table.Column getColumn(final int i) {
078            RolapStar.Column[] columns = segments[0].aggregation.getColumns();
079            int bitPos = columns[i].getBitPosition();
080            AggStar.Table.Column column = aggStar.lookupColumn(bitPos);
081    
082            // this should never happen
083            if (column == null) {
084                LOGGER.error("column null for bitPos=" + bitPos);
085            }
086            return column;
087        }
088    
089        public String getColumnAlias(final int i) {
090            return "c" + Integer.toString(i);
091        }
092    
093        /**
094         * Returns the predicate on the <code>i</code>th column.
095         *
096         * <p>If the column is unconstrained, returns
097         * {@link LiteralStarPredicate}(true).
098         *
099         * @param i Column ordinal
100         * @return Constraint on column
101         */
102        public StarColumnPredicate getPredicate(int i) {
103            return segments[0].axes[i].getPredicate();
104        }
105    
106        public String generateSqlQuery() {
107            SqlQuery sqlQuery = newSqlQuery();
108            generateSql(sqlQuery);
109            return sqlQuery.toString();
110        }
111    
112        private void addGroupingSets(SqlQuery sqlQuery) {
113            List<RolapStar.Column[]> groupingSetsColumns =
114                groupingSetsList.getGroupingSetsColumns();
115            for (RolapStar.Column[] groupingSetColumns : groupingSetsColumns) {
116                ArrayList<String> groupingColumnsExpr = new ArrayList<String>();
117    
118                for (RolapStar.Column aColumnArr : groupingSetColumns) {
119                    groupingColumnsExpr.add(findColumnExpr(aColumnArr, sqlQuery));
120                }
121                sqlQuery.addGroupingSet(groupingColumnsExpr);
122            }
123        }
124    
125        private String findColumnExpr(RolapStar.Column columnj, SqlQuery sqlQuery) {
126            AggStar.Table.Column column =
127                aggStar.lookupColumn(columnj.getBitPosition());
128            return column.generateExprString(sqlQuery);
129        }
130    
131        protected void addMeasure(final int i, final SqlQuery query) {
132            AggStar.FactTable.Measure column =
133                    (AggStar.FactTable.Measure) getMeasureAsColumn(i);
134    
135            column.getTable().addToFrom(query, false, true);
136            String alias = getMeasureAlias(i);
137    
138            String expr;
139            if (rollup) {
140                expr = column.generateRollupString(query);
141            } else {
142                expr = column.generateExprString(query);
143            }
144            query.addSelect(expr, alias);
145        }
146    
147        protected void generateSql(final SqlQuery sqlQuery) {
148            // add constraining dimensions
149            int columnCnt = getColumnCount();
150            for (int i = 0; i < columnCnt; i++) {
151                AggStar.Table.Column column = getColumn(i);
152                AggStar.Table table = column.getTable();
153                table.addToFrom(sqlQuery, false, true);
154    
155                String expr = column.generateExprString(sqlQuery);
156    
157                StarColumnPredicate predicate = getPredicate(i);
158                final String where = RolapStar.Column.createInExpr(
159                    expr,
160                    predicate,
161                    column.getDatatype(),
162                    sqlQuery);
163                if (!where.equals("true")) {
164                    sqlQuery.addWhere(where);
165                }
166    
167                // some DB2 (AS400) versions throw an error, if a column alias is
168                // there and *not* used in a subsequent order by/group by
169                if (sqlQuery.getDialect().isAS400()) {
170                    sqlQuery.addSelect(expr, null);
171                } else {
172                    sqlQuery.addSelect(expr, getColumnAlias(i));
173                }
174    
175                if (rollup) {
176                    sqlQuery.addGroupBy(expr);
177                }
178            }
179    
180            // Add measures.
181            // This can also add non-shared local dimension columns, which are
182            // not measures.
183            for (int i = 0, count = getMeasureCount(); i < count; i++) {
184                addMeasure(i, sqlQuery);
185            }
186            addGroupingSets(sqlQuery);
187            addGroupingFunction(sqlQuery);
188        }
189    
190        private void addGroupingFunction(SqlQuery sqlQuery) {
191            List<RolapStar.Column> list = groupingSetsList.getRollupColumns();
192            for (RolapStar.Column column : list) {
193                sqlQuery.addGroupingFunction(findColumnExpr(column, sqlQuery));
194            }
195        }
196    }
197    
198    // End AggQuerySpec.java