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.*;
013import mondrian.util.Pair;
014
015import org.olap4j.*;
016import org.olap4j.metadata.Cube;
017import org.olap4j.metadata.Dimension;
018import org.olap4j.metadata.Hierarchy;
019import org.olap4j.metadata.Level;
020import org.olap4j.metadata.Member;
021import org.olap4j.type.*;
022import org.olap4j.type.DimensionType;
023import org.olap4j.type.LevelType;
024
025import java.io.InputStream;
026import java.io.Reader;
027import java.math.BigDecimal;
028import java.net.URL;
029import java.sql.*;
030import java.util.Calendar;
031
032/**
033 * Implementation of {@link PreparedOlapStatement}
034 * for the Mondrian OLAP engine.
035 *
036 * <p>This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs;
037 * it is instantiated using {@link Factory#newPreparedStatement}.</p>
038 *
039 * @author jhyde
040 * @since Jun 12, 2007
041 */
042abstract class MondrianOlap4jPreparedStatement
043    extends MondrianOlap4jStatement
044    implements PreparedOlapStatement, OlapParameterMetaData
045{
046    private final String mdx; // for debug
047    MondrianOlap4jCellSetMetaData cellSetMetaData;
048
049    /**
050     * Creates a MondrianOlap4jPreparedStatement.
051     *
052     * @param olap4jConnection Connection
053     * @param mdx MDX query string
054     *
055     * @throws OlapException if database error occurs
056     */
057    protected MondrianOlap4jPreparedStatement(
058        MondrianOlap4jConnection olap4jConnection,
059        String mdx)
060        throws OlapException
061    {
062        super(olap4jConnection);
063        this.mdx = mdx;
064        final Pair<Query, MondrianOlap4jCellSetMetaData> pair = parseQuery(mdx);
065        this.query = pair.left;
066        this.cellSetMetaData = pair.right;
067    }
068
069    // implement PreparedOlapStatement
070
071    public CellSet executeQuery() throws OlapException {
072        return executeOlapQueryInternal(query, cellSetMetaData);
073    }
074
075    public OlapParameterMetaData getParameterMetaData() throws OlapException {
076        return this;
077    }
078
079    public Cube getCube() {
080        return cellSetMetaData.getCube();
081    }
082
083    // implement PreparedStatement
084
085    public int executeUpdate() throws SQLException {
086        throw new UnsupportedOperationException();
087    }
088
089    public void setNull(int parameterIndex, int sqlType) throws SQLException {
090        getParameter(parameterIndex).setValue(null);
091    }
092
093    public void setBoolean(int parameterIndex, boolean x) throws SQLException {
094        getParameter(parameterIndex).setValue(x);
095    }
096
097    public void setByte(int parameterIndex, byte x) throws SQLException {
098        getParameter(parameterIndex).setValue(x);
099    }
100
101    public void setShort(int parameterIndex, short x) throws SQLException {
102        getParameter(parameterIndex).setValue(x);
103    }
104
105    public void setInt(int parameterIndex, int x) throws SQLException {
106        getParameter(parameterIndex).setValue(x);
107    }
108
109    public void setLong(int parameterIndex, long x) throws SQLException {
110        getParameter(parameterIndex).setValue(x);
111    }
112
113    public void setFloat(int parameterIndex, float x) throws SQLException {
114        getParameter(parameterIndex).setValue(x);
115    }
116
117    public void setDouble(int parameterIndex, double x) throws SQLException {
118        getParameter(parameterIndex).setValue(x);
119    }
120
121    public void setBigDecimal(
122        int parameterIndex, BigDecimal x) throws SQLException
123    {
124        getParameter(parameterIndex).setValue(x);
125    }
126
127    public void setString(int parameterIndex, String x) throws SQLException {
128        getParameter(parameterIndex).setValue(x);
129    }
130
131    public void setBytes(int parameterIndex, byte x[]) throws SQLException {
132        getParameter(parameterIndex).setValue(x);
133    }
134
135    public void setDate(int parameterIndex, Date x) throws SQLException {
136        getParameter(parameterIndex).setValue(x);
137    }
138
139    public void setTime(int parameterIndex, Time x) throws SQLException {
140        getParameter(parameterIndex).setValue(x);
141    }
142
143    public void setTimestamp(
144        int parameterIndex, Timestamp x) throws SQLException
145    {
146        getParameter(parameterIndex).setValue(x);
147    }
148
149    public void setAsciiStream(
150        int parameterIndex, InputStream x, int length) throws SQLException
151    {
152        getParameter(parameterIndex).setValue(x);
153    }
154
155    public void setUnicodeStream(
156        int parameterIndex, InputStream x, int length) throws SQLException
157    {
158        getParameter(parameterIndex).setValue(x);
159    }
160
161    public void setBinaryStream(
162        int parameterIndex, InputStream x, int length) throws SQLException
163    {
164        getParameter(parameterIndex).setValue(x);
165    }
166
167    public void clearParameters() throws SQLException {
168        throw new UnsupportedOperationException();
169    }
170
171    public void setObject(
172        int parameterIndex, Object x, int targetSqlType) throws SQLException
173    {
174        getParameter(parameterIndex).setValue(x);
175    }
176
177    public void setObject(int parameterIndex, Object x) throws SQLException {
178        final Parameter parameter = getParameter(parameterIndex);
179        if (x instanceof MondrianOlap4jMember) {
180            MondrianOlap4jMember mondrianOlap4jMember =
181                (MondrianOlap4jMember) x;
182            x = mondrianOlap4jMember.member;
183        }
184        parameter.setValue(x);
185    }
186
187    public boolean execute() throws SQLException {
188        throw new UnsupportedOperationException();
189    }
190
191    public void addBatch() throws SQLException {
192        throw new UnsupportedOperationException();
193    }
194
195    public void setCharacterStream(
196        int parameterIndex, Reader reader, int length) throws SQLException
197    {
198        throw new UnsupportedOperationException();
199    }
200
201    public void setRef(int parameterIndex, Ref x) throws SQLException {
202        throw new UnsupportedOperationException();
203    }
204
205    public void setBlob(int parameterIndex, Blob x) throws SQLException {
206        throw new UnsupportedOperationException();
207    }
208
209    public void setClob(int parameterIndex, Clob x) throws SQLException {
210        throw new UnsupportedOperationException();
211    }
212
213    public void setArray(int parameterIndex, Array x) throws SQLException {
214        throw new UnsupportedOperationException();
215    }
216
217    public CellSetMetaData getMetaData() {
218        return cellSetMetaData;
219    }
220
221    public void setDate(
222        int parameterIndex, Date x, Calendar cal) throws SQLException
223    {
224        throw new UnsupportedOperationException();
225    }
226
227    public void setTime(
228        int parameterIndex, Time x, Calendar cal) throws SQLException
229    {
230        throw new UnsupportedOperationException();
231    }
232
233    public void setTimestamp(
234        int parameterIndex, Timestamp x, Calendar cal) throws SQLException
235    {
236        throw new UnsupportedOperationException();
237    }
238
239    public void setNull(
240        int parameterIndex, int sqlType, String typeName) throws SQLException
241    {
242        throw new UnsupportedOperationException();
243    }
244
245    public void setURL(int parameterIndex, URL x) throws SQLException {
246        throw new UnsupportedOperationException();
247    }
248
249    public void setObject(
250        int parameterIndex,
251        Object x,
252        int targetSqlType,
253        int scaleOrLength) throws SQLException
254    {
255        throw new UnsupportedOperationException();
256    }
257
258    // implement OlapParameterMetaData
259
260    public String getParameterName(int param) throws OlapException {
261        Parameter paramDef = getParameter(param);
262        return paramDef.getName();
263    }
264
265    private Parameter getParameter(int param) throws OlapException {
266        final Parameter[] parameters = query.getParameters();
267        if (param < 1 || param > parameters.length) {
268            //noinspection ThrowableResultOfMethodCallIgnored
269            throw this.olap4jConnection.helper.toOlapException(
270                this.olap4jConnection.helper.createException(
271                    "parameter ordinal " + param + " out of range"));
272        }
273        return parameters[param - 1];
274    }
275
276    public Type getParameterOlapType(int param) throws OlapException {
277        Parameter paramDef = getParameter(param);
278        return olap4jConnection.toOlap4j(paramDef.getType());
279    }
280
281    public int getParameterCount() {
282        return query.getParameters().length;
283    }
284
285    public int isNullable(int param) throws SQLException {
286        return ParameterMetaData.parameterNullableUnknown;
287    }
288
289    public boolean isSigned(int param) throws SQLException {
290        final Type type = getParameterOlapType(param);
291        return type instanceof NumericType;
292    }
293
294    public int getPrecision(int param) throws SQLException {
295        final Type type = getParameterOlapType(param);
296        if (type instanceof NumericType) {
297            return 0; // precision not applicable
298        }
299        if (type instanceof StringType) {
300            return Integer.MAX_VALUE;
301        }
302        return 0;
303    }
304
305    public int getScale(int param) throws SQLException {
306        return 0; // scale not applicable
307    }
308
309    public int getParameterType(int param) throws SQLException {
310        final Type type = getParameterOlapType(param);
311        if (type instanceof NumericType) {
312            return Types.NUMERIC;
313        } else if (type instanceof StringType) {
314            return Types.VARCHAR;
315        } else if (type instanceof NullType) {
316            return Types.NULL;
317        } else {
318            return Types.OTHER;
319        }
320    }
321
322    public String getParameterTypeName(int param) throws SQLException {
323        final Type type = getParameterOlapType(param);
324        return type.toString();
325    }
326
327    public String getParameterClassName(int param) throws SQLException {
328        final Type type = getParameterOlapType(param);
329        return foo(
330            new TypeHelper<Class>() {
331                public Class booleanType(BooleanType type) {
332                    return Boolean.class;
333                }
334
335                public Class<Cube> cubeType(CubeType cubeType) {
336                    return Cube.class;
337                }
338
339                public Class<Number> decimalType(DecimalType decimalType) {
340                    return Number.class;
341                }
342
343                public Class<Dimension> dimensionType(
344                    DimensionType dimensionType)
345                {
346                    return Dimension.class;
347                }
348
349                public Class<Hierarchy> hierarchyType(
350                    HierarchyType hierarchyType)
351                {
352                    return Hierarchy.class;
353                }
354
355                public Class<Level> levelType(LevelType levelType) {
356                    return Level.class;
357                }
358
359                public Class<Member> memberType(MemberType memberType) {
360                    return Member.class;
361                }
362
363                public Class<Void> nullType(NullType nullType) {
364                    return Void.class;
365                }
366
367                public Class<Number> numericType(NumericType numericType) {
368                    return Number.class;
369                }
370
371                public Class<Iterable> setType(SetType setType) {
372                    return Iterable.class;
373                }
374
375                public Class<String> stringType(StringType stringType) {
376                    return String.class;
377                }
378
379                public Class<Member[]> tupleType(TupleType tupleType) {
380                    return Member[].class;
381                }
382
383                public Class symbolType(SymbolType symbolType) {
384                    // parameters cannot be of this type
385                    throw new UnsupportedOperationException();
386                }
387            },
388            type).getName();
389    }
390
391    public int getParameterMode(int param) throws SQLException {
392        Parameter paramDef = getParameter(param); // forces param range check
393        Util.discard(paramDef);
394        return ParameterMetaData.parameterModeIn;
395    }
396
397    public boolean isSet(int parameterIndex) throws SQLException {
398        return getParameter(parameterIndex).isSet();
399    }
400
401    public void unset(int parameterIndex) throws SQLException {
402        getParameter(parameterIndex).unsetValue();
403    }
404
405    // Helper classes
406
407    private interface TypeHelper<T> {
408        T booleanType(BooleanType type);
409        T cubeType(CubeType cubeType);
410        T decimalType(DecimalType decimalType);
411        T dimensionType(DimensionType dimensionType);
412        T hierarchyType(HierarchyType hierarchyType);
413        T levelType(LevelType levelType);
414        T memberType(MemberType memberType);
415        T nullType(NullType nullType);
416        T numericType(NumericType numericType);
417        T setType(SetType setType);
418        T stringType(StringType stringType);
419        T tupleType(TupleType tupleType);
420        T symbolType(SymbolType symbolType);
421    }
422
423    <T> T foo(TypeHelper<T> helper, Type type) {
424        if (type instanceof BooleanType) {
425            return helper.booleanType((BooleanType) type);
426        } else if (type instanceof CubeType) {
427            return helper.cubeType((CubeType) type);
428        } else if (type instanceof DecimalType) {
429            return helper.decimalType((DecimalType) type);
430        } else if (type instanceof DimensionType) {
431            return helper.dimensionType((DimensionType) type);
432        } else if (type instanceof HierarchyType) {
433            return helper.hierarchyType((HierarchyType) type);
434        } else if (type instanceof LevelType) {
435            return helper.levelType((LevelType) type);
436        } else if (type instanceof MemberType) {
437            return helper.memberType((MemberType) type);
438        } else if (type instanceof NullType) {
439            return helper.nullType((NullType) type);
440        } else if (type instanceof NumericType) {
441            return helper.numericType((NumericType) type);
442        } else if (type instanceof SetType) {
443            return helper.setType((SetType) type);
444        } else if (type instanceof StringType) {
445            return helper.stringType((StringType) type);
446        } else if (type instanceof TupleType) {
447            return helper.tupleType((TupleType) type);
448        } else if (type instanceof SymbolType) {
449            return helper.symbolType((SymbolType) type);
450        } else {
451            throw new UnsupportedOperationException();
452        }
453    }
454}
455
456// End MondrianOlap4jPreparedStatement.java