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) 2005-2005 Julian Hyde 008// Copyright (C) 2005-2013 Pentaho 009// All Rights Reserved. 010*/ 011package mondrian.rolap.agg; 012 013import mondrian.olap.MondrianDef; 014import mondrian.olap.Util; 015import mondrian.rolap.*; 016import mondrian.rolap.sql.SqlQuery; 017import mondrian.util.Pair; 018 019import java.util.*; 020 021/** 022 * Provides the information necessary to generate SQL for a drill-through 023 * request. 024 * 025 * @author jhyde 026 * @author Richard M. Emberson 027 */ 028class DrillThroughQuerySpec extends AbstractQuerySpec { 029 private final DrillThroughCellRequest request; 030 private final List<StarPredicate> listOfStarPredicates; 031 private final List<String> columnNames; 032 private final int maxColumnNameLength; 033 034 public DrillThroughQuerySpec( 035 DrillThroughCellRequest request, 036 StarPredicate starPredicateSlicer, 037 boolean countOnly) 038 { 039 super(request.getMeasure().getStar(), countOnly); 040 this.request = request; 041 if (starPredicateSlicer != null) { 042 this.listOfStarPredicates = 043 Collections.singletonList(starPredicateSlicer); 044 } else { 045 this.listOfStarPredicates = Collections.emptyList(); 046 } 047 int tmpMaxColumnNameLength = 048 getStar().getSqlQueryDialect().getMaxColumnNameLength(); 049 if (tmpMaxColumnNameLength == 0) { 050 // From java.sql.DatabaseMetaData: "a result of zero means that 051 // there is no limit or the limit is not known" 052 maxColumnNameLength = Integer.MAX_VALUE; 053 } else { 054 maxColumnNameLength = tmpMaxColumnNameLength; 055 } 056 this.columnNames = computeDistinctColumnNames(); 057 } 058 059 private List<String> computeDistinctColumnNames() { 060 final List<String> columnNames = new ArrayList<String>(); 061 final Set<String> columnNameSet = new HashSet<String>(); 062 063 final RolapStar.Column[] columns = getColumns(); 064 for (RolapStar.Column column : columns) { 065 addColumnName(column, columnNames, columnNameSet); 066 } 067 068 addColumnName(request.getMeasure(), columnNames, columnNameSet); 069 070 return columnNames; 071 } 072 073 private void addColumnName( 074 final RolapStar.Column column, 075 final List<String> columnNames, 076 final Set<String> columnNameSet) 077 { 078 String columnName = makeAlias(column, columnNames, columnNameSet); 079 columnNames.add(columnName); 080 } 081 082 private String makeAlias( 083 final RolapStar.Column column, 084 final List<String> columnNames, 085 final Set<String> columnNameSet) 086 { 087 String columnName = column.getName(); 088 if (columnName != null) { 089 // nothing 090 } else if (column.getExpression() instanceof MondrianDef.Column) { 091 columnName = ((MondrianDef.Column) column.getExpression()).name; 092 } else { 093 columnName = "c" + Integer.toString(columnNames.size()); 094 } 095 // Register the column name, and if it's not unique, append numeric 096 // suffixes until it is. Also make sure that it is within the 097 // range allowed by this SQL dialect. 098 String originalColumnName = columnName; 099 if (columnName.length() > maxColumnNameLength) { 100 columnName = columnName.substring(0, maxColumnNameLength); 101 } 102 for (int j = 0; !columnNameSet.add(columnName); j++) { 103 final String suffix = "_" + Integer.toString(j); 104 columnName = originalColumnName; 105 if (originalColumnName.length() + suffix.length() 106 > maxColumnNameLength) 107 { 108 columnName = 109 originalColumnName.substring( 110 0, maxColumnNameLength - suffix.length()); 111 } 112 columnName += suffix; 113 } 114 115 return columnName; 116 } 117 118 @Override 119 protected boolean isPartOfSelect(RolapStar.Column col) { 120 return request.includeInSelect(col); 121 } 122 123 @Override 124 protected boolean isPartOfSelect(RolapStar.Measure measure) { 125 return request.includeInSelect(measure); 126 } 127 128 public int getMeasureCount() { 129 return request.getDrillThroughMeasures().size() > 0 130 ? request.getDrillThroughMeasures().size() 131 : 1; 132 } 133 134 public RolapStar.Measure getMeasure(final int i) { 135 return request.getDrillThroughMeasures().size() > 0 136 ? request.getDrillThroughMeasures().get(i) 137 : request.getMeasure(); 138 } 139 140 public String getMeasureAlias(final int i) { 141 return request.getDrillThroughMeasures().size() > 0 142 ? request.getDrillThroughMeasures().get(i).getName() 143 : columnNames.get(columnNames.size() - 1); 144 } 145 146 public RolapStar.Column[] getColumns() { 147 return request.getConstrainedColumns(); 148 } 149 150 public String getColumnAlias(final int i) { 151 return columnNames.get(i); 152 } 153 154 public StarColumnPredicate getColumnPredicate(final int i) { 155 final StarColumnPredicate constr = request.getValueAt(i); 156 return (constr == null) 157 ? LiteralStarPredicate.TRUE 158 : constr; 159 } 160 161 public Pair<String, List<SqlStatement.Type>> generateSqlQuery() { 162 SqlQuery sqlQuery = newSqlQuery(); 163 nonDistinctGenerateSql(sqlQuery); 164 return sqlQuery.toSqlAndTypes(); 165 } 166 167 protected void addMeasure(final int i, final SqlQuery sqlQuery) { 168 RolapStar.Measure measure = getMeasure(i); 169 170 if (!isPartOfSelect(measure)) { 171 return; 172 } 173 174 Util.assertTrue(measure.getTable() == getStar().getFactTable()); 175 measure.getTable().addToFrom(sqlQuery, false, true); 176 177 if (!countOnly) { 178 String expr = measure.generateExprString(sqlQuery); 179 sqlQuery.addSelect(expr, null, getMeasureAlias(i)); 180 } 181 } 182 183 protected boolean isAggregate() { 184 return false; 185 } 186 187 protected boolean isOrdered() { 188 return true; 189 } 190 191 protected List<StarPredicate> getPredicateList() { 192 return listOfStarPredicates; 193 } 194 195 protected void extraPredicates(SqlQuery sqlQuery) { 196 super.extraPredicates(sqlQuery); 197 198 if (countOnly) { 199 return; 200 } 201 // generate the select list 202 final Set<String> columnNameSet = new HashSet<String>(); 203 columnNameSet.addAll(columnNames); 204 205 List<StarPredicate> predicateList = getPredicateList(); 206 for (StarPredicate predicate : predicateList) { 207 for (RolapStar.Column column 208 : predicate.getConstrainedColumnList()) 209 { 210 sqlQuery.addSelect( 211 column.generateExprString(sqlQuery), 212 column.getInternalType(), 213 makeAlias(column, columnNames, columnNameSet)); 214 } 215 } 216 } 217} 218 219// End DrillThroughQuerySpec.java