001    /*
002    // $Id: //open/mondrian/src/main/mondrian/rolap/agg/DrillThroughQuerySpec.java#14 $
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) 2005-2008 Julian Hyde
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    
011    package mondrian.rolap.agg;
012    
013    import mondrian.olap.Util;
014    import mondrian.olap.MondrianDef;
015    import mondrian.rolap.RolapStar;
016    import mondrian.rolap.StarColumnPredicate;
017    import mondrian.rolap.sql.SqlQuery;
018    import java.util.ArrayList;
019    import java.util.List;
020    import java.util.HashSet;
021    import java.util.Set;
022    
023    /**
024     * Provides the information necessary to generate SQL for a drill-through
025     * request.
026     *
027     * @author jhyde
028     * @author Richard M. Emberson
029     * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/DrillThroughQuerySpec.java#14 $
030     */
031    class DrillThroughQuerySpec extends AbstractQuerySpec {
032        private final CellRequest request;
033        private final List<String> columnNames;
034        private final int maxColumnNameLength;
035    
036        public DrillThroughQuerySpec(CellRequest request, boolean countOnly) {
037            super(request.getMeasure().getStar(), countOnly);
038            this.request = request;
039            int tmpMaxColumnNameLength =
040                getStar().getSqlQueryDialect().getMaxColumnNameLength();
041            if (tmpMaxColumnNameLength == 0) {
042                // From java.sql.DatabaseMetaData: "a result of zero means that
043                // there is no limit or the limit is not known"
044                maxColumnNameLength = Integer.MAX_VALUE;
045            } else {
046                maxColumnNameLength = tmpMaxColumnNameLength;
047            }
048            this.columnNames = computeDistinctColumnNames();
049        }
050    
051        private List<String> computeDistinctColumnNames() {
052            final List<String> columnNames = new ArrayList<String>();
053            final Set<String> columnNameSet = new HashSet<String>();
054    
055            final RolapStar.Column[] columns = getColumns();
056            for (RolapStar.Column column : columns) {
057                addColumnName(column, columnNames, columnNameSet);
058            }
059    
060            addColumnName(request.getMeasure(), columnNames, columnNameSet);
061    
062            return columnNames;
063        }
064    
065        private void addColumnName(
066            final RolapStar.Column column,
067            final List<String> columnNames,
068            final Set<String> columnNameSet)
069        {
070            String columnName = column.getName();
071            if (columnName != null) {
072                // nothing
073            } else if (column.getExpression() instanceof MondrianDef.Column) {
074                columnName = ((MondrianDef.Column) column.getExpression()).name;
075            } else {
076                columnName = "c" + Integer.toString(columnNames.size());
077            }
078            // Register the column name, and if it's not unique, append numeric
079            // suffixes until it is. Also make sure that it is within the
080            // range allowed by this SQL dialect.
081            String originalColumnName = columnName;
082            if (columnName.length() > maxColumnNameLength) {
083                columnName = columnName.substring(0, maxColumnNameLength);
084            }
085            for (int j = 0; !columnNameSet.add(columnName); j++) {
086                final String suffix = "_" + Integer.toString(j);
087                columnName = originalColumnName;
088                if (originalColumnName.length() + suffix.length()
089                    > maxColumnNameLength) {
090                    columnName =
091                        originalColumnName.substring(
092                            0, maxColumnNameLength - suffix.length());
093                }
094                columnName += suffix;
095            }
096            columnNames.add(columnName);
097        }
098    
099        public int getMeasureCount() {
100            return 1;
101        }
102    
103        public RolapStar.Measure getMeasure(final int i) {
104            Util.assertTrue(i == 0);
105            return request.getMeasure();
106        }
107    
108        public String getMeasureAlias(final int i) {
109            Util.assertTrue(i == 0);
110            return columnNames.get(columnNames.size() - 1);
111        }
112    
113        public RolapStar.Column[] getColumns() {
114            return request.getConstrainedColumns();
115        }
116    
117        public String getColumnAlias(final int i) {
118            return columnNames.get(i);
119        }
120    
121        public StarColumnPredicate getColumnPredicate(final int i) {
122            final StarColumnPredicate constr = request.getValueList().get(i);
123            return (constr == null)
124                ? LiteralStarPredicate.TRUE
125                : constr;
126        }
127    
128        public String generateSqlQuery() {
129            SqlQuery sqlQuery = newSqlQuery();
130            nonDistinctGenerateSql(sqlQuery);
131            return sqlQuery.toString();
132        }
133    
134        protected void addMeasure(final int i, final SqlQuery sqlQuery) {
135            RolapStar.Measure measure = getMeasure(i);
136    
137            Util.assertTrue(measure.getTable() == getStar().getFactTable());
138            measure.getTable().addToFrom(sqlQuery, false, true);
139    
140            String expr = measure.generateExprString(sqlQuery);
141            sqlQuery.addSelect(expr, getMeasureAlias(i));
142        }
143    
144        protected boolean isAggregate() {
145            return false;
146        }
147    
148        protected boolean isOrdered() {
149            return true;
150        }
151    }
152    
153    // End DrillThroughQuerySpec.java