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