1 /*
2  * Copyright (c) 1996, 2014, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * 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>getMessage</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  * @since 1.1
54  */

55 public class SQLException extends java.lang.Exception
56                           implements Iterable<Throwable> {
57
58     /**
59      *  Constructs a <code>SQLException</code> object with a given
60      * <code>reason</code>, <code>SQLState</code>  and
61      * <code>vendorCode</code>.
62      *
63      * The <code>cause</code> is not initialized, and may subsequently be
64      * initialized by a call to the
65      * {@link Throwable#initCause(java.lang.Throwable)} method.
66      *
67      * @param reason a description of the exception
68      * @param SQLState an XOPEN or SQL:2003 code identifying the exception
69      * @param vendorCode a database vendor-specific exception code
70      */

71     public SQLException(String reason, String SQLState, int vendorCode) {
72         super(reason);
73         this.SQLState = SQLState;
74         this.vendorCode = vendorCode;
75         if (!(this instanceof SQLWarning)) {
76             if (DriverManager.getLogWriter() != null) {
77                 DriverManager.println("SQLState(" + SQLState +
78                                                 ") vendor code(" + vendorCode + ")");
79                 printStackTrace(DriverManager.getLogWriter());
80             }
81         }
82     }
83
84
85     /**
86      * Constructs a <code>SQLException</code> object with a given
87      * <code>reason</code> and <code>SQLState</code>.
88      *
89      * The <code>cause</code> is not initialized, and may subsequently be
90      * initialized by a call to the
91      * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
92      * is initialized to 0.
93      *
94      * @param reason a description of the exception
95      * @param SQLState an XOPEN or SQL:2003 code identifying the exception
96      */

97     public SQLException(String reason, String SQLState) {
98         super(reason);
99         this.SQLState = SQLState;
100         this.vendorCode = 0;
101         if (!(this instanceof SQLWarning)) {
102             if (DriverManager.getLogWriter() != null) {
103                 printStackTrace(DriverManager.getLogWriter());
104                 DriverManager.println("SQLException: SQLState(" + SQLState + ")");
105             }
106         }
107     }
108
109     /**
110      *  Constructs a <code>SQLException</code> object with a given
111      * <code>reason</code>. The  <code>SQLState</code>  is initialized to
112      * <code>null</code> and the vendor code is initialized to 0.
113      *
114      * The <code>cause</code> is not initialized, and may subsequently be
115      * initialized by a call to the
116      * {@link Throwable#initCause(java.lang.Throwable)} method.
117      *
118      * @param reason a description of the exception
119      */

120     public SQLException(String reason) {
121         super(reason);
122         this.SQLState = null;
123         this.vendorCode = 0;
124         if (!(this instanceof SQLWarning)) {
125             if (DriverManager.getLogWriter() != null) {
126                 printStackTrace(DriverManager.getLogWriter());
127             }
128         }
129     }
130
131     /**
132      * Constructs a <code>SQLException</code> object.
133      * The <code>reason</code>, <code>SQLState</code> are initialized
134      * to <code>null</code> and the vendor code is initialized to 0.
135      *
136      * The <code>cause</code> is not initialized, and may subsequently be
137      * initialized by a call to the
138      * {@link Throwable#initCause(java.lang.Throwable)} method.
139      *
140      */

141     public SQLException() {
142         super();
143         this.SQLState = null;
144         this.vendorCode = 0;
145         if (!(this instanceof SQLWarning)) {
146             if (DriverManager.getLogWriter() != null) {
147                 printStackTrace(DriverManager.getLogWriter());
148             }
149         }
150     }
151
152     /**
153      *  Constructs a <code>SQLException</code> object with a given
154      * <code>cause</code>.
155      * The <code>SQLState</code> is initialized
156      * to <code>null</code> and the vendor code is initialized to 0.
157      * The <code>reason</code>  is initialized to <code>null</code> if
158      * <code>cause==null</code> or to <code>cause.toString()</code> if
159      * <code>cause!=null</code>.
160      *
161      * @param cause the underlying reason for this <code>SQLException</code>
162      * (which is saved for later retrieval by the <code>getCause()</code> method);
163      * may be null indicating the cause is non-existent or unknown.
164      * @since 1.6
165      */

166     public SQLException(Throwable cause) {
167         super(cause);
168
169         if (!(this instanceof SQLWarning)) {
170             if (DriverManager.getLogWriter() != null) {
171                 printStackTrace(DriverManager.getLogWriter());
172             }
173         }
174     }
175
176     /**
177      * Constructs a <code>SQLException</code> object with a given
178      * <code>reason</code> and  <code>cause</code>.
179      * The <code>SQLState</code> is  initialized to <code>null</code>
180      * and the vendor code is initialized to 0.
181      *
182      * @param reason a description of the exception.
183      * @param cause the underlying reason for this <code>SQLException</code>
184      * (which is saved for later retrieval by the <code>getCause()</code> method);
185      * may be null indicating the cause is non-existent or unknown.
186      * @since 1.6
187      */

188     public SQLException(String reason, Throwable cause) {
189         super(reason,cause);
190
191         if (!(this instanceof SQLWarning)) {
192             if (DriverManager.getLogWriter() != null) {
193                     printStackTrace(DriverManager.getLogWriter());
194             }
195         }
196     }
197
198     /**
199      * Constructs a <code>SQLException</code> object with a given
200      * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
201      * The vendor code is initialized to 0.
202      *
203      * @param reason a description of the exception.
204      * @param sqlState an XOPEN or SQL:2003 code identifying the exception
205      * @param cause the underlying reason for this <code>SQLException</code>
206      * (which is saved for later retrieval by the
207      * <code>getCause()</code> method); may be null indicating
208      *     the cause is non-existent or unknown.
209      * @since 1.6
210      */

211     public SQLException(String reason, String sqlState, Throwable cause) {
212         super(reason,cause);
213
214         this.SQLState = sqlState;
215         this.vendorCode = 0;
216         if (!(this instanceof SQLWarning)) {
217             if (DriverManager.getLogWriter() != null) {
218                 printStackTrace(DriverManager.getLogWriter());
219                 DriverManager.println("SQLState(" + SQLState + ")");
220             }
221         }
222     }
223
224     /**
225      * Constructs a <code>SQLException</code> object with a given
226      * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
227      * and  <code>cause</code>.
228      *
229      * @param reason a description of the exception
230      * @param sqlState an XOPEN or SQL:2003 code identifying the exception
231      * @param vendorCode a database vendor-specific exception code
232      * @param cause the underlying reason for this <code>SQLException</code>
233      * (which is saved for later retrieval by the <code>getCause()</code> method);
234      * may be null indicating the cause is non-existent or unknown.
235      * @since 1.6
236      */

237     public SQLException(String reason, String sqlState, int vendorCode, Throwable cause) {
238         super(reason,cause);
239
240         this.SQLState = sqlState;
241         this.vendorCode = vendorCode;
242         if (!(this instanceof SQLWarning)) {
243             if (DriverManager.getLogWriter() != null) {
244                 DriverManager.println("SQLState(" + SQLState +
245                                                 ") vendor code(" + vendorCode + ")");
246                 printStackTrace(DriverManager.getLogWriter());
247             }
248         }
249     }
250
251     /**
252      * Retrieves the SQLState for this <code>SQLException</code> object.
253      *
254      * @return the SQLState value
255      */

256     public String getSQLState() {
257         return (SQLState);
258     }
259
260     /**
261      * Retrieves the vendor-specific exception code
262      * for this <code>SQLException</code> object.
263      *
264      * @return the vendor's error code
265      */

266     public int getErrorCode() {
267         return (vendorCode);
268     }
269
270     /**
271      * Retrieves the exception chained to this
272      * <code>SQLException</code> object by setNextException(SQLException ex).
273      *
274      * @return the next <code>SQLException</code> object in the chain;
275      *         <code>null</code> if there are none
276      * @see #setNextException
277      */

278     public SQLException getNextException() {
279         return (next);
280     }
281
282     /**
283      * Adds an <code>SQLException</code> object to the end of the chain.
284      *
285      * @param ex the new exception that will be added to the end of
286      *            the <code>SQLException</code> chain
287      * @see #getNextException
288      */

289     public void setNextException(SQLException ex) {
290
291         SQLException current = this;
292         for(;;) {
293             SQLException next=current.next;
294             if (next != null) {
295                 current = next;
296                 continue;
297             }
298
299             if (nextUpdater.compareAndSet(current,null,ex)) {
300                 return;
301             }
302             current=current.next;
303         }
304     }
305
306     /**
307      * Returns an iterator over the chained SQLExceptions.  The iterator will
308      * be used to iterate over each SQLException and its underlying cause
309      * (if any).
310      *
311      * @return an iterator over the chained SQLExceptions and causes in the proper
312      * order
313      *
314      * @since 1.6
315      */

316     public Iterator<Throwable> iterator() {
317
318        return new Iterator<Throwable>() {
319
320            SQLException firstException = SQLException.this;
321            SQLException nextException = firstException.getNextException();
322            Throwable cause = firstException.getCause();
323
324            public boolean hasNext() {
325                if(firstException != null || nextException != null || cause != null)
326                    return true;
327                return false;
328            }
329
330            public Throwable next() {
331                Throwable throwable = null;
332                if(firstException != null){
333                    throwable = firstException;
334                    firstException = null;
335                }
336                else if(cause != null){
337                    throwable = cause;
338                    cause = cause.getCause();
339                }
340                else if(nextException != null){
341                    throwable = nextException;
342                    cause = nextException.getCause();
343                    nextException = nextException.getNextException();
344                }
345                else
346                    throw new NoSuchElementException();
347                return throwable;
348            }
349
350            public void remove() {
351                throw new UnsupportedOperationException();
352            }
353
354        };
355
356     }
357
358     /**
359          * @serial
360          */

361     private String SQLState;
362
363         /**
364          * @serial
365          */

366     private int vendorCode;
367
368         /**
369          * @serial
370          */

371     private volatile SQLException next;
372
373     private static final AtomicReferenceFieldUpdater<SQLException,SQLException> nextUpdater =
374             AtomicReferenceFieldUpdater.newUpdater(SQLException.class,SQLException.class,"next");
375
376     private static final long serialVersionUID = 2135244094396331484L;
377 }
378