diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java index a30ca62011268c8386cba6b008c8fcd5e028bd1b..7415b82ea1941ee0d7ccb8bf52a7e2f33ce874d2 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslator.java @@ -32,6 +32,7 @@ import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DeadlockLoserDataAccessException; import org.springframework.dao.PermissionDeniedDataAccessException; import org.springframework.dao.TransientDataAccessResourceException; +import org.springframework.dao.DuplicateKeyException; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.InvalidResultSetAccessException; @@ -224,6 +225,10 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep logTranslation(task, sql, sqlEx, false); return new InvalidResultSetAccessException(task, sql, sqlEx); } + else if (Arrays.binarySearch(this.sqlErrorCodes.getDuplicateKeyCodes(), errorCode) >= 0) { + logTranslation(task, sql, sqlEx, false); + return new DuplicateKeyException(buildMessage(task, sql, sqlEx), sqlEx); + } else if (Arrays.binarySearch(this.sqlErrorCodes.getDataIntegrityViolationCodes(), errorCode) >= 0) { logTranslation(task, sql, sqlEx, false); return new DataIntegrityViolationException(buildMessage(task, sql, sqlEx), sqlEx); diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java index 52c67bf5dc6dfbefda5a19b5b1c35748ac096371..30359828176fe11b864fb54aed87e174723cda26 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/SQLErrorCodes.java @@ -41,6 +41,8 @@ public class SQLErrorCodes { private String[] invalidResultSetAccessCodes = new String[0]; + private String[] duplicateKeyCodes = new String[0]; + private String[] dataIntegrityViolationCodes = new String[0]; private String[] permissionDeniedCodes = new String[0]; @@ -112,6 +114,14 @@ public class SQLErrorCodes { return this.invalidResultSetAccessCodes; } + public String[] getDuplicateKeyCodes() { + return duplicateKeyCodes; + } + + public void setDuplicateKeyCodes(String[] duplicateKeyCodes) { + this.duplicateKeyCodes = duplicateKeyCodes; + } + public void setDataIntegrityViolationCodes(String[] dataIntegrityViolationCodes) { this.dataIntegrityViolationCodes = StringUtils.sortStringArray(dataIntegrityViolationCodes); } diff --git a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml index 1471888adcf413dbae4f2188b58be6bcb856b3a1..e05709b8d5d0c2e42a1b020c2aed7df36fc7787d 100644 --- a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml +++ b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/support/sql-error-codes.xml @@ -21,8 +21,11 @@ -007,-029,-097,-104,-109,-115,-128,-199,-204,-206,-301,-408,-441,-491 + + -803 + - -407,-530,-531,-532,-543,-544,-545,-603,-667,-803 + -407,-530,-531,-532,-543,-544,-545,-603,-667 -904,-971 @@ -45,8 +48,11 @@ 42802,42821,42X01,42X02,42X03,42X04,42X05,42X06,42X07,42X08 + + 23505 + - 22001,22005,23502,23503,23505,23513,X0Y32 + 22001,22005,23502,23503,23513,X0Y32 04501,08004,42Y07 @@ -63,8 +69,11 @@ 42000,42001,42101,42102,42111,42112,42121,42122,42132 + + 23001 + - 22003,22012,22025,23000,23001 + 22003,22012,22025,23000 90046,90100,90117,90121,90126 @@ -78,6 +87,9 @@ -22,-28 + + -104 + -9 @@ -93,8 +105,11 @@ -201,-217,-696 + + -239,-268,-6017 + - -239,-268,-692,-11030 + -692,-11030 @@ -108,8 +123,11 @@ 229 + + 2601,2627 + - 544,2601,2627,8114,8115 + 544,8114,8115 1222 @@ -123,8 +141,11 @@ 1054,1064,1146 + + 1062 + - 630,839,840,893,1062,1169,1215,1216,1217,1451,1452,1557 + 630,839,840,893,1169,1215,1216,1217,1451,1452,1557 1 @@ -144,8 +165,11 @@ 17003 + + 1 + - 1,1400,1722,2291,2292 + 1400,1722,2291,2292 17002,17447 @@ -168,8 +192,11 @@ 03000,42000,42601,42602,42622,42804,42P01 + + 23505 + - 23000,23502,23503,23505,23514 + 23000,23502,23503,23514 53000,53100,53200,53300 @@ -196,8 +223,11 @@ 101,102,103,104,105,106,107,108,109,110,111,112,113,116,120,121,123,207,208,213,257,512 + + 2601 + - 233,423,511,515,530,547,2601,2615,2714 + 233,423,511,515,530,547,2615,2714 921,1105 diff --git a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java index d5ee4e48798c588ed1b71304bdd88f89da3fa735..b33aa870acc8c6080cd7123653a31326089fa071 100644 --- a/org.springframework.jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java +++ b/org.springframework.jdbc/src/test/java/org/springframework/jdbc/support/SQLErrorCodeSQLExceptionTranslatorTests.java @@ -27,6 +27,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DeadlockLoserDataAccessException; +import org.springframework.dao.DuplicateKeyException; import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.InvalidResultSetAccessException; @@ -39,6 +40,7 @@ public class SQLErrorCodeSQLExceptionTranslatorTests extends TestCase { static { ERROR_CODES.setBadSqlGrammarCodes(new String[] { "1", "2" }); ERROR_CODES.setInvalidResultSetAccessCodes(new String[] { "3", "4" }); + ERROR_CODES.setDuplicateKeyCodes(new String[] {"10"}); ERROR_CODES.setDataAccessResourceFailureCodes(new String[] { "5" }); ERROR_CODES.setDataIntegrityViolationCodes(new String[] { "6" }); ERROR_CODES.setCannotAcquireLockCodes(new String[] { "7" }); @@ -64,6 +66,12 @@ public class SQLErrorCodeSQLExceptionTranslatorTests extends TestCase { checkTranslation(sext, 7, CannotAcquireLockException.class); checkTranslation(sext, 8, DeadlockLoserDataAccessException.class); checkTranslation(sext, 9, CannotSerializeTransactionException.class); + checkTranslation(sext, 10, DuplicateKeyException.class); + + SQLException dupKeyEx = new SQLException("", "", 10); + DataAccessException dksex = sext.translate("task", "SQL", dupKeyEx); + assertTrue("Not instance of DataIntegrityViolationException", + DataIntegrityViolationException.class.isAssignableFrom(dksex.getClass())); // Test fallback. We assume that no database will ever return this error code, // but 07xxx will be bad grammar picked up by the fallback SQLState translator diff --git a/org.springframework.transaction/src/main/java/org/springframework/dao/DuplicateKeyException.java b/org.springframework.transaction/src/main/java/org/springframework/dao/DuplicateKeyException.java new file mode 100644 index 0000000000000000000000000000000000000000..5267f2ec3c880945a97b6691b5757080711ea0eb --- /dev/null +++ b/org.springframework.transaction/src/main/java/org/springframework/dao/DuplicateKeyException.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.dao; + +/** + * Exception thrown when an attempt to insert or update data + * results in violation of an primary key or unique constraint. + * Note that this is not necessarily a purely relational concept; + * unique primary keys are required by most database types. + * + * @author Thomas Risberg + */ +public class DuplicateKeyException extends DataIntegrityViolationException { + + /** + * Constructor for DuplicateKeyException. + * @param msg the detail message + */ + public DuplicateKeyException(String msg) { + super(msg); + } + + /** + * Constructor for DuplicateKeyException. + * @param msg the detail message + * @param cause the root cause from the data access API in use + */ + public DuplicateKeyException(String msg, Throwable cause) { + super(msg, cause); + } + +} \ No newline at end of file