001/*
002// Licensed to Julian Hyde under one or more contributor license
003// agreements. See the NOTICE file distributed with this work for
004// additional information regarding copyright ownership.
005//
006// Julian Hyde licenses this file to you under the Apache License,
007// Version 2.0 (the "License"); you may not use this file except in
008// compliance with the License. You may obtain a copy of the License at:
009//
010// http://www.apache.org/licenses/LICENSE-2.0
011//
012// Unless required by applicable law or agreed to in writing, software
013// distributed under the License is distributed on an "AS IS" BASIS,
014// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015// See the License for the specific language governing permissions and
016// limitations under the License.
017*/
018package org.olap4j;
019
020import java.sql.*;
021
022/**
023 * <p>An exception describing an error accessing an OLAP database.</p>
024 *
025 * <p>Since olap4j extends JDBC, it is natural that <code>OlapException</code>
026 * should extend JDBC's {@link SQLException}. The implementation by an olap4j
027 * driver of a JDBC method which is declared to throw a SQLException may, if the
028 * driver chooses, throw instead an OlapException.</p>
029 *
030 * <p>OlapException provides some additional information to help an OLAP client
031 * identify the location of the error. This information is
032 *
033 * @author jhyde
034 * @since Oct 23, 2006
035 */
036public class OlapException extends SQLException {
037    private Region region;
038    private Object context;
039
040    /**
041     * Constructs an <code>OlapException</code> object with a given
042     * <code>reason</code>, <code>SQLState</code>  and
043     * <code>vendorCode</code>.
044     *
045     * @param reason a description of the exception
046     * @param sqlState an XOPEN or SQL 99 code identifying the exception
047     * @param vendorCode a database vendor-specific exception code
048     */
049    public OlapException(String reason, String sqlState, int vendorCode) {
050        super(reason, sqlState, vendorCode);
051    }
052
053    /**
054     * Constructs an <code>OlapException</code> object with the given reason and
055     * SQLState; the <code>vendorCode</code> field defaults to 0.
056     *
057     * @param reason a description of the exception
058     * @param sqlState an XOPEN or SQL 99 code identifying the exception
059     */
060    public OlapException(String reason, String sqlState) {
061        super(reason, sqlState);
062    }
063
064    /**
065     * Constructs an <code>OlapException</code> object with a reason;
066     * the <code>sqlState</code> field defaults to <code>null</code>, and
067     * the <code>vendorCode</code> field defaults to 0.
068     *
069     * @param reason a description of the exception
070     */
071    public OlapException(String reason) {
072        super(reason);
073    }
074
075    /**
076     * Constructs an <code>OlapException</code> object;
077     * the <code>reason</code> field defaults to null,
078     * the <code>sqlState</code> field defaults to <code>null</code>, and
079     * the <code>vendorCode</code> field defaults to 0.
080     */
081    public OlapException() {
082        super();
083    }
084
085    /**
086     * Constructs an <code>OlapException</code> object with a given
087     * <code>cause</code>.
088     * The <code>SQLState</code> is initialized
089     * to <code>null</code> and the vendor code is initialized to 0.
090     * The <code>reason</code>  is initialized to <code>null</code> if
091     * <code>cause==null</code> or to <code>cause.toString()</code> if
092     * <code>cause!=null</code>.
093     * <p>
094     * @param cause the underlying reason for this <code>OlapException</code>
095     * (which is saved for later retrieval by the <code>getCause()</code>
096     * method); may be null indicating the cause is non-existent or unknown.
097     */
098    public OlapException(Throwable cause) {
099        super();
100        initCause(cause);
101    }
102
103    /**
104     * Constructs an <code>OlapException</code> object with a given
105     * <code>reason</code> and <code>cause</code>.
106     *
107     * @param  reason the detail message (which is saved for later retrieval
108     *         by the {@link #getMessage()} method).
109     * @param  cause the cause (which is saved for later retrieval by the
110     *         {@link #getCause()} method).  (A <tt>null</tt> value is
111     *         permitted, and indicates that the cause is nonexistent or
112     *         unknown.)
113     */
114    public OlapException(String reason, Throwable cause) {
115        // Cannot call super(reason, cause) because
116        // SQLException(String, Throwable) only exists from JDK 1.6.
117        super(reason);
118        initCause(cause);
119    }
120
121    /**
122     * Constructs an <code>OlapException</code> object with a given
123     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
124     * The vendor code is initialized to 0.
125     *
126     * @param reason a description of the exception.
127     * @param sqlState an XOPEN or SQL:2003 code identifying the exception
128     * @param cause the underlying reason for this <code>OlapException</code>
129     * (which is saved for later retrieval by the
130     * <code>getCause()</code> method); may be null indicating
131     *     the cause is non-existent or unknown.
132     */
133    public OlapException(String reason, String sqlState, Throwable cause) {
134        // Cannot call SQLException(String, String, Throwable); it only
135        // exists from JDK 1.6
136        super(reason, sqlState);
137        initCause(cause);
138    }
139
140    /**
141     * Constructs an <code>OlapException</code> object with a given
142     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
143     * and  <code>cause</code>.
144     *
145     * @param reason a description of the exception
146     * @param sqlState an XOPEN or SQL:2003 code identifying the exception
147     * @param vendorCode a database vendor-specific exception code
148     * @param cause the underlying reason for this <code>OlapException</code>
149     * (which is saved for later retrieval by the <code>getCause()</code>
150     * method);
151     * may be null indicating the cause is non-existent or unknown.
152     */
153    public OlapException(
154        String reason,
155        String sqlState,
156        int vendorCode,
157        Throwable cause)
158    {
159        // Cannot call SQLException(String, String, int, Throwable); it only
160        // exists from JDK 1.6
161        super(reason, sqlState, vendorCode);
162        initCause(cause);
163    }
164
165    /**
166     * Sets the textual region where the exception occurred.
167     *
168     * @param region Textual region
169     */
170    public void setRegion(Region region) {
171        this.region = region;
172    }
173
174    /**
175     * Returns the textual region where the exception occurred, or null if no
176     * region can be identified.
177     *
178     * @return Region where the exception occurred
179     */
180    public Region getRegion() {
181        return region;
182    }
183
184    /**
185     * Sets the context where the exception occurred.
186     *
187     * @param context Context where the exception occurred
188     * @throws IllegalArgumentException If context is not a {@link Cell}
189     *   or a {@link Position}
190     */
191    public void setContext(Object context) {
192        if (!(context instanceof Cell)
193            && !(context instanceof Position))
194        {
195            throw new IllegalArgumentException(
196                "expected Cell or Position");
197        }
198        this.context = context;
199    }
200
201    /**
202     * Returns the context where the exception occurred.
203     * Typically a {@link Cell} or a {@link Position}, or null.
204     *
205     * @return context where the exception occurred, or null
206     */
207    public Object getContext() {
208        return context;
209    }
210
211    /**
212     * Description of the position of a syntax or validation error in the source
213     * MDX string.
214     *
215     * <p>Row and column positions are 1-based and inclusive. For example,
216     * in</p>
217     *
218     * <blockquote>
219     * <pre>
220     * SELECT { [Measures].MEMBERS } ON COLUMNS,
221     *    { } ON ROWS
222     * FROM [Sales]
223     * </pre>
224     * </blockquote>
225     *
226     * <p>the <code>SELECT</code> keyword occupies positions (1, 1) through
227     * (1, 6), and would have a <code>Region(startLine=1, startColumn=1,
228     * endColumn=1, endLine=6)</code>.</p>
229     */
230    public static final class Region {
231        public final int startLine;
232        public final int startColumn;
233        public final int endLine;
234        public final int endColumn;
235
236        protected Region(
237            int startLine,
238            int startColumn,
239            int endLine,
240            int endColumn)
241        {
242            this.startLine = startLine;
243            this.startColumn = startColumn;
244            this.endColumn = endLine;
245            this.endLine = endColumn;
246        }
247
248        public String toString() {
249            if (startLine == endColumn && startColumn == endLine) {
250                return "line " + startLine + ", column " + startColumn;
251            } else {
252                return "line " + startLine + ", column " + startColumn
253                    + " through line " + endLine + ", column " + endColumn;
254            }
255        }
256    }
257}
258
259// End OlapException.java