1 /*
2 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.sql;
27
28 import java.util.Iterator;
29 import java.util.NoSuchElementException;
30 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
31
32 /**
33 * <P>An exception that provides information on a database access
34 * error or other errors.
35 *
36 * <P>Each <code>SQLException</code> provides several kinds of information:
37 * <UL>
38 * <LI> a string describing the error. This is used as the Java Exception
39 * message, available via the method <code>getMesasge</code>.
40 * <LI> a "SQLstate" string, which follows either the XOPEN SQLstate conventions
41 * or the SQL:2003 conventions.
42 * The values of the SQLState string are described in the appropriate spec.
43 * The <code>DatabaseMetaData</code> method <code>getSQLStateType</code>
44 * can be used to discover whether the driver returns the XOPEN type or
45 * the SQL:2003 type.
46 * <LI> an integer error code that is specific to each vendor. Normally this will
47 * be the actual error code returned by the underlying database.
48 * <LI> a chain to a next Exception. This can be used to provide additional
49 * error information.
50 * <LI> the causal relationship, if any for this <code>SQLException</code>.
51 * </UL>
52 */
53 public class SQLException extends java.lang.Exception
54 implements Iterable<Throwable> {
55
56 /**
57 * Constructs a <code>SQLException</code> object with a given
58 * <code>reason</code>, <code>SQLState</code> and
59 * <code>vendorCode</code>.
60 *
61 * The <code>cause</code> is not initialized, and may subsequently be
62 * initialized by a call to the
63 * {@link Throwable#initCause(java.lang.Throwable)} method.
64 * <p>
65 * @param reason a description of the exception
66 * @param SQLState an XOPEN or SQL:2003 code identifying the exception
67 * @param vendorCode a database vendor-specific exception code
68 */
69 public SQLException(String reason, String SQLState, int vendorCode) {
70 super(reason);
71 this.SQLState = SQLState;
72 this.vendorCode = vendorCode;
73 if (!(this instanceof SQLWarning)) {
74 if (DriverManager.getLogWriter() != null) {
75 DriverManager.println("SQLState(" + SQLState +
76 ") vendor code(" + vendorCode + ")");
77 printStackTrace(DriverManager.getLogWriter());
78 }
79 }
80 }
81
82
83 /**
84 * Constructs a <code>SQLException</code> object with a given
85 * <code>reason</code> and <code>SQLState</code>.
86 *
87 * The <code>cause</code> is not initialized, and may subsequently be
88 * initialized by a call to the
89 * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
90 * is initialized to 0.
91 * <p>
92 * @param reason a description of the exception
93 * @param SQLState an XOPEN or SQL:2003 code identifying the exception
94 */
95 public SQLException(String reason, String SQLState) {
96 super(reason);
97 this.SQLState = SQLState;
98 this.vendorCode = 0;
99 if (!(this instanceof SQLWarning)) {
100 if (DriverManager.getLogWriter() != null) {
101 printStackTrace(DriverManager.getLogWriter());
102 DriverManager.println("SQLException: SQLState(" + SQLState + ")");
103 }
104 }
105 }
106
107 /**
108 * Constructs a <code>SQLException</code> object with a given
109 * <code>reason</code>. The <code>SQLState</code> is initialized to
110 * <code>null</code> and the vender code is initialized to 0.
111 *
112 * The <code>cause</code> is not initialized, and may subsequently be
113 * initialized by a call to the
114 * {@link Throwable#initCause(java.lang.Throwable)} method.
115 * <p>
116 * @param reason a description of the exception
117 */
118 public SQLException(String reason) {
119 super(reason);
120 this.SQLState = null;
121 this.vendorCode = 0;
122 if (!(this instanceof SQLWarning)) {
123 if (DriverManager.getLogWriter() != null) {
124 printStackTrace(DriverManager.getLogWriter());
125 }
126 }
127 }
128
129 /**
130 * Constructs a <code>SQLException</code> object.
131 * The <code>reason</code>, <code>SQLState</code> are initialized
132 * to <code>null</code> and the vendor code is initialized to 0.
133 *
134 * The <code>cause</code> is not initialized, and may subsequently be
135 * initialized by a call to the
136 * {@link Throwable#initCause(java.lang.Throwable)} method.
137 * <p>
138 */
139 public SQLException() {
140 super();
141 this.SQLState = null;
142 this.vendorCode = 0;
143 if (!(this instanceof SQLWarning)) {
144 if (DriverManager.getLogWriter() != null) {
145 printStackTrace(DriverManager.getLogWriter());
146 }
147 }
148 }
149
150 /**
151 * Constructs a <code>SQLException</code> object with a given
152 * <code>cause</code>.
153 * The <code>SQLState</code> is initialized
154 * to <code>null</code> and the vendor code is initialized to 0.
155 * The <code>reason</code> is initialized to <code>null</code> if
156 * <code>cause==null</code> or to <code>cause.toString()</code> if
157 * <code>cause!=null</code>.
158 * <p>
159 * @param cause the underlying reason for this <code>SQLException</code>
160 * (which is saved for later retrieval by the <code>getCause()</code> method);
161 * may be null indicating the cause is non-existent or unknown.
162 * @since 1.6
163 */
164 public SQLException(Throwable cause) {
165 super(cause);
166
167 if (!(this instanceof SQLWarning)) {
168 if (DriverManager.getLogWriter() != null) {
169 printStackTrace(DriverManager.getLogWriter());
170 }
171 }
172 }
173
174 /**
175 * Constructs a <code>SQLException</code> object with a given
176 * <code>reason</code> and <code>cause</code>.
177 * The <code>SQLState</code> is initialized to <code>null</code>
178 * and the vendor code is initialized to 0.
179 * <p>
180 * @param reason a description of the exception.
181 * @param cause the underlying reason for this <code>SQLException</code>
182 * (which is saved for later retrieval by the <code>getCause()</code> method);
183 * may be null indicating the cause is non-existent or unknown.
184 * @since 1.6
185 */
186 public SQLException(String reason, Throwable cause) {
187 super(reason,cause);
188
189 if (!(this instanceof SQLWarning)) {
190 if (DriverManager.getLogWriter() != null) {
191 printStackTrace(DriverManager.getLogWriter());
192 }
193 }
194 }
195
196 /**
197 * Constructs a <code>SQLException</code> object with a given
198 * <code>reason</code>, <code>SQLState</code> and <code>cause</code>.
199 * The vendor code is initialized to 0.
200 * <p>
201 * @param reason a description of the exception.
202 * @param sqlState an XOPEN or SQL:2003 code identifying the exception
203 * @param cause the underlying reason for this <code>SQLException</code>
204 * (which is saved for later retrieval by the
205 * <code>getCause()</code> method); may be null indicating
206 * the cause is non-existent or unknown.
207 * @since 1.6
208 */
209 public SQLException(String reason, String sqlState, Throwable cause) {
210 super(reason,cause);
211
212 this.SQLState = sqlState;
213 this.vendorCode = 0;
214 if (!(this instanceof SQLWarning)) {
215 if (DriverManager.getLogWriter() != null) {
216 printStackTrace(DriverManager.getLogWriter());
217 DriverManager.println("SQLState(" + SQLState + ")");
218 }
219 }
220 }
221
222 /**
223 * Constructs a <code>SQLException</code> object with a given
224 * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
225 * and <code>cause</code>.
226 * <p>
227 * @param reason a description of the exception
228 * @param sqlState an XOPEN or SQL:2003 code identifying the exception
229 * @param vendorCode a database vendor-specific exception code
230 * @param cause the underlying reason for this <code>SQLException</code>
231 * (which is saved for later retrieval by the <code>getCause()</code> method);
232 * may be null indicating the cause is non-existent or unknown.
233 * @since 1.6
234 */
235 public SQLException(String reason, String sqlState, int vendorCode, Throwable cause) {
236 super(reason,cause);
237
238 this.SQLState = sqlState;
239 this.vendorCode = vendorCode;
240 if (!(this instanceof SQLWarning)) {
241 if (DriverManager.getLogWriter() != null) {
242 DriverManager.println("SQLState(" + SQLState +
243 ") vendor code(" + vendorCode + ")");
244 printStackTrace(DriverManager.getLogWriter());
245 }
246 }
247 }
248
249 /**
250 * Retrieves the SQLState for this <code>SQLException</code> object.
251 *
252 * @return the SQLState value
253 */
254 public String getSQLState() {
255 return (SQLState);
256 }
257
258 /**
259 * Retrieves the vendor-specific exception code
260 * for this <code>SQLException</code> object.
261 *
262 * @return the vendor's error code
263 */
264 public int getErrorCode() {
265 return (vendorCode);
266 }
267
268 /**
269 * Retrieves the exception chained to this
270 * <code>SQLException</code> object by setNextException(SQLException ex).
271 *
272 * @return the next <code>SQLException</code> object in the chain;
273 * <code>null</code> if there are none
274 * @see #setNextException
275 */
276 public SQLException getNextException() {
277 return (next);
278 }
279
280 /**
281 * Adds an <code>SQLException</code> object to the end of the chain.
282 *
283 * @param ex the new exception that will be added to the end of
284 * the <code>SQLException</code> chain
285 * @see #getNextException
286 */
287 public void setNextException(SQLException ex) {
288
289 SQLException current = this;
290 for(;;) {
291 SQLException next=current.next;
292 if (next != null) {
293 current = next;
294 continue;
295 }
296
297 if (nextUpdater.compareAndSet(current,null,ex)) {
298 return;
299 }
300 current=current.next;
301 }
302 }
303
304 /**
305 * Returns an iterator over the chained SQLExceptions. The iterator will
306 * be used to iterate over each SQLException and its underlying cause
307 * (if any).
308 *
309 * @return an iterator over the chained SQLExceptions and causes in the proper
310 * order
311 *
312 * @since 1.6
313 */
314 public Iterator<Throwable> iterator() {
315
316 return new Iterator<Throwable>() {
317
318 SQLException firstException = SQLException.this;
319 SQLException nextException = firstException.getNextException();
320 Throwable cause = firstException.getCause();
321
322 public boolean hasNext() {
323 if(firstException != null || nextException != null || cause != null)
324 return true;
325 return false;
326 }
327
328 public Throwable next() {
329 Throwable throwable = null;
330 if(firstException != null){
331 throwable = firstException;
332 firstException = null;
333 }
334 else if(cause != null){
335 throwable = cause;
336 cause = cause.getCause();
337 }
338 else if(nextException != null){
339 throwable = nextException;
340 cause = nextException.getCause();
341 nextException = nextException.getNextException();
342 }
343 else
344 throw new NoSuchElementException();
345 return throwable;
346 }
347
348 public void remove() {
349 throw new UnsupportedOperationException();
350 }
351
352 };
353
354 }
355
356 /**
357 * @serial
358 */
359 private String SQLState;
360
361 /**
362 * @serial
363 */
364 private int vendorCode;
365
366 /**
367 * @serial
368 */
369 private volatile SQLException next;
370
371 private static final AtomicReferenceFieldUpdater<SQLException,SQLException> nextUpdater =
372 AtomicReferenceFieldUpdater.newUpdater(SQLException.class,SQLException.class,"next");
373
374 private static final long serialVersionUID = 2135244094396331484L;
375 }