001: /*
002: * Copyright 2003 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: SQLState.java,v 1.1 2003/10/18 19:54:01 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: import java.util.Arrays;
014:
015: /**
016: * A SQLSTATE diagnostic code.
017: * <p>
018: * SQLSTATE is a 5-character string that some JDBC drivers return in their
019: * SQLExceptions to indicate status in a vendor-independent way.
020: * SQLSTATE can contain only digits and capital letters.
021: * The first two characters of SQLSTATE indicate a class; the following three
022: * characters indicate a subclass.
023: * Class codes are unique, but subclass codes are not; the meaning of a subclass
024: * code depends on the class code that accompanies it.
025: * <p>
026: * The initial character of the class and subclass indicates the source document
027: * that defines that return condition:
028: * <ul>
029: * <li>
030: * Class codes starting with 0-4 or A-H mean that the result condition is
031: * defined in the International Standard (or, for class 'HZ', in ISO RDA).
032: * In this case, subclass codes for conditions specified in the same standard
033: * also start with 0-4 or A-H.
034: * The meaning of all other subclass codes is implementation-defined.
035: * </li>
036: * <li>
037: * Class codes starting with 5-9 or I-Z denote implementation-specific
038: * conditions.
039: * In this case, subclass codes can start with any character.
040: * The meaning of all subclass codes is implementation-defined, except that
041: * implementations may not define '000' but return '000' when there is no
042: * subclass information.
043: * </li>
044: *
045: * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a>
046: * @version $Revision: 1.1 $
047: *
048: * @see DatabaseAdapter
049: */
050:
051: public class SQLState {
052: private static final int LENGTH = 5;
053:
054: private final String value;
055:
056: /**
057: * Constructs a SQLState object from the specified SQLSTATE string.
058: *
059: * @param s
060: * A 5-character SQLSTATE string.
061: *
062: * @exception IllegalArgumentException
063: * if <var>s</var> is not a valid 5-character SQLSTATE string.
064: */
065:
066: public SQLState(String s) throws IllegalArgumentException {
067: if (s.length() != LENGTH)
068: throw new IllegalArgumentException(s);
069:
070: s = s.toUpperCase();
071:
072: for (int i = 0; i < LENGTH; ++i) {
073: if (!isValidChar(s.charAt(i)))
074: throw new IllegalArgumentException(s);
075: }
076:
077: value = s;
078: }
079:
080: private static boolean isValidChar(char c) {
081: return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
082: }
083:
084: private static boolean isStandardChar(char c) {
085: return (c >= '0' && c <= '4') || (c >= 'A' && c <= 'H');
086: }
087:
088: /**
089: * Returns the class code for this SQLSTATE.
090: * This is the first two characters.
091: */
092:
093: public final String classCode() {
094: return value.substring(0, 2);
095: }
096:
097: /**
098: * Returns the subclass code for this SQLSTATE.
099: * This is the last three characters.
100: */
101:
102: public final String subclassCode() {
103: return value.substring(2, 5);
104: }
105:
106: /**
107: * Indicates whether or not this SQLSTATE value is defined by the
108: * international SQL standard.
109: *
110: * @return
111: * <code>true</code> if this is a standard SQLSTATE value,
112: * <code>false</code> otherwise.
113: */
114:
115: public final boolean isStandard() {
116: return isStandardChar(value.charAt(0))
117: && isStandardChar(value.charAt(2));
118: }
119:
120: /**
121: * Indicates whether or not this SQLSTATE represents an error whose cause
122: * may be transient, meaning the operation or transaction may succeed if
123: * retried.
124: * <p>
125: * The implementation in this class errs on the side of declaring things
126: * retryable, meaning it returns false only for recognized values that are
127: * known not to be worth retrying.
128: * Subclasses may override this method in vendor-specific ways.
129: *
130: * @return
131: * <code>true</code> if the error may be transient,
132: * <code>false</code> if a retry is known to be pointless.
133: */
134:
135: public boolean isWorthRetrying() {
136: if (Arrays.binarySearch(ClassCode.NOT_RETRYABLE, classCode()) >= 0)
137: return false;
138: else
139: return true;
140: }
141:
142: /**
143: * Contains constants for known SQLSTATE class codes.
144: * This list is a merging of all codes defined in the SQL/92 and X/Open
145: * standards.
146: */
147:
148: public static class ClassCode {
149: /** Private constructor prevents instantiation. */
150: private ClassCode() {
151: }
152:
153: public static final String SUCCESSFUL_COMPLETION = "00",
154: SUCCESS_WITH_WARNING = "01",
155: NO_DATA = "02",
156: DYNAMIC_SQL_ERROR = "07",
157: CONNECTION_EXCEPTION = "08",
158: FEATURE_NOT_SUPPORTED = "0A",
159: CARDINALITY_VIOLATION = "21",
160: DATA_EXCEPTION = "22",
161: INTEGRITY_CONSTRAINT_VIOLATION = "23",
162: INVALID_CURSOR_STATE = "24",
163: INVALID_TRANSACTION_STATE = "25",
164: INVALID_SQL_STATEMENT_NAME = "26",
165: TRIGGERED_DATA_CHANGE_VIOLATION = "27",
166: INVALID_AUTHORIZATION_SPECIFICATION = "28",
167: SYNTAX_ERROR_OR_ACCESS_VIOLATION_IN_DIRECT_SQL_STATEMENT = "2A",
168: DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST = "2B",
169: INVALID_CHARACTER_SET_NAME = "2C",
170: INVALID_TRANSACTION_TERMINATION = "2D",
171: INVALID_CONNECTION_NAME = "2E",
172: INVALID_SQL_DESCRIPTOR_NAME = "33",
173: INVALID_CURSOR_NAME = "34",
174: INVALID_EXCEPTION_NUMBER = "35",
175: SYNTAX_ERROR_OR_ACCESS_VIOLATION_IN_DYNAMIC_SQL_STATEMENT = "37",
176: AMBIGUOUS_CURSOR_NAME = "3C",
177: INVALID_CATALOG_NAME = "3D",
178: INVALID_SCHEMA_NAME = "3F",
179: TRANSACTION_ROLLBACK = "40",
180: SYNTAX_ERROR_OR_ACCESS_VIOLATION = "42",
181: WITH_CHECK_OPTION_VIOLATION = "44",
182: REMOTE_DATABASE_ACCESS_ERROR = "HZ";
183:
184: /**
185: * An array representing all those class codes that are known
186: * <em>not</em> to be worth retrying.
187: * The array is sorted for efficient searching.
188: */
189: public static final String[] NOT_RETRYABLE = {
190: /* Take care to keep this list sorted by value. */
191: SUCCESSFUL_COMPLETION,
192: SUCCESS_WITH_WARNING,
193: NO_DATA,
194: DYNAMIC_SQL_ERROR,
195: //CONNECTION_EXCEPTION,
196: FEATURE_NOT_SUPPORTED,
197: CARDINALITY_VIOLATION,
198: DATA_EXCEPTION,
199: INTEGRITY_CONSTRAINT_VIOLATION,
200: //INVALID_CURSOR_STATE,
201: //INVALID_TRANSACTION_STATE,
202: INVALID_SQL_STATEMENT_NAME,
203: TRIGGERED_DATA_CHANGE_VIOLATION,
204: INVALID_AUTHORIZATION_SPECIFICATION,
205: SYNTAX_ERROR_OR_ACCESS_VIOLATION_IN_DIRECT_SQL_STATEMENT,
206: DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST,
207: INVALID_CHARACTER_SET_NAME,
208: //INVALID_TRANSACTION_TERMINATION,
209: INVALID_CONNECTION_NAME,
210: INVALID_SQL_DESCRIPTOR_NAME,
211: INVALID_CURSOR_NAME,
212: INVALID_EXCEPTION_NUMBER,
213: SYNTAX_ERROR_OR_ACCESS_VIOLATION_IN_DYNAMIC_SQL_STATEMENT,
214: AMBIGUOUS_CURSOR_NAME, INVALID_CATALOG_NAME,
215: INVALID_SCHEMA_NAME,
216: //TRANSACTION_ROLLBACK,
217: SYNTAX_ERROR_OR_ACCESS_VIOLATION,
218: WITH_CHECK_OPTION_VIOLATION,
219: //REMOTE_DATABASE_ACCESS_ERROR
220: };
221: }
222: }
223:
224: /*
225: * For reference, all the SQLSTATE codes defined in the SQL/92 standard.
226: *
227: * 00000 Successful completion
228: * 01000 Warning
229: * 01001 Cursor operation conflict
230: * 01002 Disconnect error
231: * 01003 Null value eliminated in set function
232: * 01004 String data
233: * 01005 Insufficient item descriptor areas
234: * 01006 Privilege not revoked
235: * 01007 Privilege not granted
236: * 01008 Implicit zero-bit padding
237: * 01009 Search condition too long for information schema
238: * 0100A Query expression too long for information schema
239: * 02000 No data
240: * 07000 Dynamic SQL error
241: * 07001 Using clause does not match dynamic parameter specifications
242: * 07002 Using clause does not match target specifications
243: * 07003 Cursor specification cannot be executed
244: * 07004 Using clause required for dynamic parameters
245: * 07005 Prepared statement not a cursor specification
246: * 07006 Restricted data type attribute violation
247: * 07007 Using clause required for result fields
248: * 07008 Invalid descriptor count
249: * 07009 Invalid descriptor index
250: * 08000 Connection exception
251: * 08001 SQL-client unable to establish SQL-connection
252: * 08002 Connection name in use
253: * 08003 Connection does not exist
254: * 08004 SQL-server rejected establishment of SQL-connection
255: * 08006 Connection failure
256: * 08007 Transaction resolution unknown
257: * 0A000 Feature not supported
258: * 0A001 Multiple server transactions
259: * 21000 Cardinality violation
260: * 22000 Data exception
261: * 22001 String data
262: * 22002 Null value
263: * 22003 Numeric value out of range
264: * 22005 Error in assignment
265: * 22007 Invalid datetime format
266: * 22008 Datetime field overflow
267: * 22009 Invalid time zone displacement value
268: * 22011 Substring error
269: * 22012 Division by zero
270: * 22015 Interval field overflow
271: * 22018 Invalid character value for cast
272: * 22019 Invalid escape character
273: * 22021 Character not in repertoire
274: * 22022 Indicator overflow
275: * 22023 Invalid parameter value
276: * 22024 Unterminated C string
277: * 22025 Invalid escape sequence
278: * 22026 String data
279: * 22027 Trim error
280: * 23000 Integrity constraint violation
281: * 24000 Invalid cursor state
282: * 25000 Invalid transaction state
283: * 26000 Invalid SQL statement name
284: * 27000 Triggered data change violation
285: * 28000 Invalid authorization specification
286: * 2A000 Syntax error or access rule violation in direct SQL statement
287: * 2B000 Dependent privilege descriptors still exist
288: * 2C000 Invalid character set name
289: * 2D000 Invalid transaction termination
290: * 2E000 Invalid connection name
291: * 33000 Invalid SQL descriptor name
292: * 34000 Invalid cursor name
293: * 35000 Invalid condition number
294: * 37000 Syntax error or access rule violation in dynamic SQL statement
295: * 3C000 Ambiguous cursor name
296: * 3D000 Invalid catalog name
297: * 3F000 Invalid schema name
298: * 40000 Transaction rollback
299: * 40001 Serialization failure
300: * 40002 Integrity constraint violation
301: * 40003 Statement completion unknown
302: * 42000 Syntax error or access rule violation
303: * 44000 With check option violation
304: * HZ000 Remote Database Access
305: *
306: *
307: * For reference, all the SQLSTATE codes defined in the X/Open SQL standard.
308: *
309: * 00000 Success
310: * 01000 Success with warning
311: * 01002 Disconnect error
312: * 01003 Null value eliminated in set function
313: * 01004 String data, right truncation
314: * 01005 Insufficient item descriptor areas
315: * 01006 Privilege not revoked
316: * 01007 Privilege not granted
317: * 0100B Default value too long for system view
318: * 02000 No data
319: * 07000 Dynamic SQL error
320: * 07001 using-clause does not match dynamic parameters
321: * 07002 using-clause does not match target specifications
322: * 07003 Cursor specification cannot be executed
323: * 07004 using-clause is required for dynamic parameters
324: * 07005 Prepared statement is not a cursor specification
325: * 07006 Restricted data type attribute violation
326: * 07008 Invalid descriptor count
327: * 07009 Invalid descriptor index
328: * 08000 Connection exception
329: * 08001 Client unable to establish connection
330: * 08002 Connection name in use
331: * 08003 Connection does not exist
332: * 08004 Server rejected the connection
333: * 08006 Connection failure
334: * 08007 Transaction resolution unknown
335: * 0A000 Feature not supported
336: * 0A001 Multiple-server transaction
337: * 21000 Cardinality violation
338: * 21S01 Insert value list does not match column list
339: * 21S02 Degree of derived table does not match column list
340: * 22000 Data exception
341: * 22001 String data, right truncation
342: * 22002 Null value, no indicator parameter
343: * 22003 Numeric value out of range
344: * 22005 Error in assignment
345: * 22006 Invalid interval format
346: * 22007 Invalid date/time format
347: * 22008 Date/time field overflow
348: * 22011 Substring error
349: * 22012 Division by zero
350: * 22015 Interval field overflow
351: * 22018 Invalid character value for CAST
352: * 22019 Invalid escape character
353: * 22021 Translation result not in target repertoire
354: * 22024 Unterminated string
355: * 22025 Invalid escape sequence
356: * 22027 Trim error
357: * 23000 Integrity constraint violation
358: * 24000 Invalid cursor state
359: * 25000 Invalid transaction state
360: * 26000 Invalid SQL statement identifier
361: * 28000 Invalid authorisation specification
362: * 2C000 Invalid character set name
363: * 2D000 Invalid transaction termination
364: * 2E000 Invalid connection name
365: * 33000 Invalid SQL descriptor name
366: * 35000 Invalid exception number
367: * 3D000 Invalid catalog name
368: * 3F000 Invalid schema name
369: * 40000 Transaction rollback
370: * 40003 Statement completion unknown
371: * 42000 Syntax error or access violation
372: * 42S01 Base table or viewed table already exists
373: * 42S02 Base table not found
374: * 42S11 Index already exists
375: * 42S12 Index not found
376: * 42S21 Column already exists
377: * 42S22 Column not found
378: * 42S31 Schema already exists
379: * 42S32 Schema not found
380: * 42S42 Catalog not found
381: * 42S51 Character set already exists
382: * 42S52 Character set not found
383: * 42S61 Collation already exists
384: * 42S62 Collation not found
385: * 42S72 Conversion not found
386: * 42S81 Translation already exists
387: * 42S82 Translation not found
388: * 44000 WITH CHECK OPTION violation
389: * HZ000 RDA error
390: * HZ010 AccessControlViolation
391: * HZ020 BadRepetitionCount
392: * HZ030 CommandHandleUnknown
393: * HZ040 ControlAuthenticationFailure
394: * HZ050 DataResourceHandleNotSpecified
395: * HZ060 DataResourceHandleUnknown
396: * HZ070 DataResourceNameNotSpecified
397: * HZ080 DataResourceNotAvailable
398: * HZ081 (transient error)
399: * HZ090 DataResourceAlreadyOpen
400: * HZ100 DataResourceUnknown
401: * HZ110 DialogueIDUnknown
402: * HZ120 DuplicateCommandHandle
403: * HZ130 DuplicateDataResourceHandle
404: * HZ140 DuplicateDialogueID
405: * HZ150 DuplicateOperationID
406: * HZ160 InvalidSequence
407: * HZ161 (dialogue already active)
408: * HZ162 (dialogue initialising)
409: * HZ163 (dialogue not active)
410: * HZ164 (dialogue terminating)
411: * HZ165 (transaction not open)
412: * HZ166 (transaction open)
413: * HZ167 (transaction terminating)
414: * HZ170 NoDataResourceAvailable
415: * HZ180 OperationAborted
416: * HZ181 (transient error)
417: * HZ190 OperationCancelled
418: * HZ200 ServiceNotNegotiated
419: * HZ210 TransactionRolledBack
420: * HZ220 UserAuthenticationFailure
421: * HZ230 ControlServicesNotAllowed
422: * HZ300 HostIdentifierError
423: * HZ310 InvalidSQLConformanceLevel
424: * HZ320 RDATransactionNotOpen
425: * HZ325 RDATransactionOpen
426: * HZ330 SQLAccessControlViolation
427: * HZ340 SQLDatabaseResourceAlreadyOpenError
428: * HZ350 SQLDBLArgumentCountMismatch
429: * HZ360 SQLDBLArgumentTypeMismatch
430: * HZ365 SQLNoCharSet
431: * HZ370 SQLDBLTransactionStatementNotAllowed
432: * HZ380 SQLUsageModeViolation
433: * HZ410 Abort failure, service provider
434: * HZ411 Abort failure, service user
435: * HZ420 Association failure, permanent
436: * HZ421 Association failure, transient
437: * HZ430 Release failure
438: * HZ450 Begin dialogue rejected, provider
439: * HZ451 Begin dialogue rejected, user
440: * HZ460 Heuristic hazard
441: * HZ461 Heuristic mix
442: * HZ470 PAbort rollback false
443: * HZ471 PAbort rollback true
444: * HZ480 Rollback
445: * HZ490 UAbort rollback false
446: * HZ491 UAbort rollback true
447: * HZ4A0 UError
448: */
|