1 /* 2 * Copyright (c) 1996, 2006, 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>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 */ SQLException(String reason, String SQLState, int vendorCode)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 */ SQLException(String reason, String SQLState)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 */ SQLException(String reason)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 */ SQLException()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 */ SQLException(Throwable cause)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 */ SQLException(String reason, Throwable cause)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 */ SQLException(String reason, String sqlState, Throwable cause)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 */ SQLException(String reason, String sqlState, int vendorCode, Throwable cause)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 */ getSQLState()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 */ getErrorCode()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 */ getNextException()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 */ setNextException(SQLException ex)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 */ iterator()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 } 376