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) 2007-2011 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.olap4j;
011
012import mondrian.olap.Exp;
013import mondrian.olap.Util;
014import mondrian.rolap.RolapCell;
015import mondrian.rolap.SqlStatement;
016
017import org.apache.log4j.Logger;
018
019import org.olap4j.*;
020import org.olap4j.metadata.Property;
021
022import java.sql.ResultSet;
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.List;
026
027/**
028 * Implementation of {@link Cell}
029 * for the Mondrian OLAP engine.
030 *
031 * @author jhyde
032 * @since May 24, 2007
033 */
034class MondrianOlap4jCell implements Cell {
035    private final int[] coordinates;
036    private final MondrianOlap4jCellSet olap4jCellSet;
037    final RolapCell cell;
038
039    /**
040     * Creates a MondrianOlap4jCell.
041     *
042     * @param coordinates Coordinates
043     * @param olap4jCellSet Cell set
044     * @param cell Cell in native Mondrian representation
045     */
046    MondrianOlap4jCell(
047        int[] coordinates,
048        MondrianOlap4jCellSet olap4jCellSet,
049        RolapCell cell)
050    {
051        assert coordinates != null;
052        assert olap4jCellSet != null;
053        assert cell != null;
054        this.coordinates = coordinates;
055        this.olap4jCellSet = olap4jCellSet;
056        this.cell = cell;
057    }
058
059    public CellSet getCellSet() {
060        return olap4jCellSet;
061    }
062
063    public int getOrdinal() {
064        return (Integer) cell.getPropertyValue(
065            mondrian.olap.Property.CELL_ORDINAL.name);
066    }
067
068    public List<Integer> getCoordinateList() {
069        ArrayList<Integer> list = new ArrayList<Integer>(coordinates.length);
070        for (int coordinate : coordinates) {
071            list.add(coordinate);
072        }
073        return list;
074    }
075
076    public Object getPropertyValue(Property property) {
077        // We assume that mondrian properties have the same name as olap4j
078        // properties.
079        return cell.getPropertyValue(property.getName());
080    }
081
082    public boolean isEmpty() {
083        // FIXME
084        return cell.isNull();
085    }
086
087    public boolean isError() {
088        return cell.isError();
089    }
090
091    public boolean isNull() {
092        return cell.isNull();
093    }
094
095    public double getDoubleValue() throws OlapException {
096        Object o = cell.getValue();
097        if (o instanceof Number) {
098            Number number = (Number) o;
099            return number.doubleValue();
100        }
101        throw olap4jCellSet.olap4jStatement.olap4jConnection.helper
102            .createException(this, "not a number");
103    }
104
105    public String getErrorText() {
106        Object o = cell.getValue();
107        if (o instanceof Throwable) {
108            return ((Throwable) o).getMessage();
109        } else {
110            return null;
111        }
112    }
113
114    public Object getValue() {
115        return cell.getValue();
116    }
117
118    public String getFormattedValue() {
119        return cell.getFormattedValue();
120    }
121
122    public ResultSet drillThrough() throws OlapException {
123        return drillThroughInternal(
124            -1,
125            -1,
126            new ArrayList<Exp>(),
127            false,
128            null,
129            null);
130    }
131
132    /**
133     * Executes drill-through on this cell.
134     *
135     * <p>Not a part of the public API. Package-protected because this method
136     * also implements the DRILLTHROUGH statement.
137     *
138     * @param maxRowCount Maximum number of rows to retrieve, <= 0 if unlimited
139     * @param firstRowOrdinal Ordinal of row to skip to (1-based), or 0 to
140     *   start from beginning
141     * @param fields            List of fields to return, expressed as MDX
142     *                          expressions.
143     * @param extendedContext   If true, add non-constraining columns to the
144     *                          query for levels below each current member.
145     *                          This additional context makes the drill-through
146     *                          queries easier for humans to understand.
147     * @param logger Logger. If not null and debug is enabled, log SQL here
148     * @param rowCountSlot Slot into which the number of fact rows is written
149     * @return Result set
150     * @throws OlapException on error
151     */
152    ResultSet drillThroughInternal(
153        int maxRowCount,
154        int firstRowOrdinal,
155        List<Exp> fields,
156        boolean extendedContext,
157        Logger logger,
158        int[] rowCountSlot)
159        throws OlapException
160    {
161        if (!cell.canDrillThrough()) {
162            return null;
163        }
164        if (rowCountSlot != null) {
165            rowCountSlot[0] = cell.getDrillThroughCount();
166        }
167        final SqlStatement sqlStmt =
168            cell.drillThroughInternal(
169                maxRowCount, firstRowOrdinal, fields, extendedContext,
170                logger);
171        return sqlStmt.getWrappedResultSet();
172    }
173
174    public void setValue(
175        Object newValue,
176        AllocationPolicy allocationPolicy,
177        Object... allocationArgs)
178        throws OlapException
179    {
180        Scenario scenario =
181            olap4jCellSet.olap4jStatement.olap4jConnection.getScenario();
182        cell.setValue(scenario, newValue, allocationPolicy, allocationArgs);
183    }
184}
185
186// End MondrianOlap4jCell.java