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