Skip to content

Commit 5503733

Browse files
committed
attempt to do a better job of interpreting database error codes
1 parent f0bfef9 commit 5503733

9 files changed

+108
-68
lines changed

Diff for: hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java

+11-6
Original file line numberDiff line numberDiff line change
@@ -1133,13 +1133,18 @@ public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
11331133
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
11341134
return (sqlException, message, sql) -> switch ( extractErrorCode( sqlException ) ) {
11351135
case -952 -> new LockTimeoutException( message, sqlException, sql );
1136-
case -803 -> new ConstraintViolationException(
1137-
message,
1138-
sqlException,
1139-
sql,
1136+
case -803 -> new ConstraintViolationException( message, sqlException, sql,
11401137
ConstraintViolationException.ConstraintKind.UNIQUE,
1141-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
1142-
);
1138+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
1139+
case -530,-531 -> new ConstraintViolationException( message, sqlException, sql,
1140+
ConstraintViolationException.ConstraintKind.FOREIGN_KEY,
1141+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
1142+
case -407 -> new ConstraintViolationException( message, sqlException, sql,
1143+
ConstraintViolationException.ConstraintKind.NOT_NULL,
1144+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
1145+
case -543,-545 -> new ConstraintViolationException( message, sqlException, sql,
1146+
ConstraintViolationException.ConstraintKind.CHECK,
1147+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
11431148
default -> null;
11441149
};
11451150
}

Diff for: hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java

+15-11
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
3737
import org.hibernate.engine.spi.SessionFactoryImplementor;
3838
import org.hibernate.exception.ConstraintViolationException;
39+
import org.hibernate.exception.ConstraintViolationException.ConstraintKind;
3940
import org.hibernate.exception.LockAcquisitionException;
4041
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
4142
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
@@ -807,23 +808,26 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
807808
return (sqlException, message, sql) ->
808809
switch ( extractErrorCode( sqlException ) ) {
809810
case 23505 ->
810-
// Unique constraint violation
811-
new ConstraintViolationException(
812-
message,
813-
sqlException,
814-
sql,
815-
ConstraintViolationException.ConstraintKind.UNIQUE,
816-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
817-
);
811+
// Unique index or primary key violation
812+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.UNIQUE,
813+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
818814
case 40001 ->
819815
// DEADLOCK DETECTED
820816
new LockAcquisitionException(message, sqlException, sql);
821817
case 50200 ->
822818
// LOCK NOT AVAILABLE
823819
new PessimisticLockException(message, sqlException, sql);
824-
case 90006 ->
825-
// NULL not allowed for column [90006-145]
826-
new ConstraintViolationException( message, sqlException, sql,
820+
case 23502 ->
821+
// NULL not allowed for column
822+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.NOT_NULL,
823+
getViolatedConstraintNameExtractor().extractConstraintName(sqlException) );
824+
case 23503, 23506 ->
825+
// Referential integrity constraint violation
826+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.FOREIGN_KEY,
827+
getViolatedConstraintNameExtractor().extractConstraintName(sqlException) );
828+
case 23513, 23514 ->
829+
// Check constraint violation
830+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.CHECK,
827831
getViolatedConstraintNameExtractor().extractConstraintName(sqlException) );
828832
case 57014 ->
829833
new QueryTimeoutException( message, sqlException, sql );

Diff for: hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java

+13-4
Original file line numberDiff line numberDiff line change
@@ -349,13 +349,22 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
349349
return new LockAcquisitionException( message, sqlException, sql );
350350
case 1062:
351351
// Unique constraint violation
352-
return new ConstraintViolationException(
353-
message,
354-
sqlException,
355-
sql,
352+
return new ConstraintViolationException( message, sqlException, sql,
356353
ConstraintViolationException.ConstraintKind.UNIQUE,
357354
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
358355
);
356+
case 1048:
357+
// Null constraint violation
358+
return new ConstraintViolationException( message, sqlException, sql,
359+
ConstraintViolationException.ConstraintKind.NOT_NULL, null );
360+
case 1451, 1452:
361+
// Foreign key constraint violation
362+
return new ConstraintViolationException( message, sqlException, sql,
363+
ConstraintViolationException.ConstraintKind.FOREIGN_KEY, null );
364+
case 3819:
365+
// Check constraint violation
366+
return new ConstraintViolationException( message, sqlException, sql,
367+
ConstraintViolationException.ConstraintKind.CHECK, null );
359368
}
360369

361370
final String sqlState = extractSqlState( sqlException );

Diff for: hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java

+14-6
Original file line numberDiff line numberDiff line change
@@ -1253,13 +1253,21 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
12531253
return new LockAcquisitionException( message, sqlException, sql );
12541254
case 1062:
12551255
// Unique constraint violation
1256-
return new ConstraintViolationException(
1257-
message,
1258-
sqlException,
1259-
sql,
1256+
return new ConstraintViolationException( message, sqlException, sql,
12601257
ConstraintViolationException.ConstraintKind.UNIQUE,
1261-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
1262-
);
1258+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
1259+
case 1048:
1260+
// Null constraint violation
1261+
return new ConstraintViolationException( message, sqlException, sql,
1262+
ConstraintViolationException.ConstraintKind.NOT_NULL, null );
1263+
case 1451, 1452:
1264+
// Foreign key constraint violation
1265+
return new ConstraintViolationException( message, sqlException, sql,
1266+
ConstraintViolationException.ConstraintKind.FOREIGN_KEY, null );
1267+
case 3819:
1268+
// Check constraint violation
1269+
return new ConstraintViolationException( message, sqlException, sql,
1270+
ConstraintViolationException.ConstraintKind.CHECK, null );
12631271
}
12641272

12651273
final String sqlState = extractSqlState( sqlException );

Diff for: hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java

+14-9
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
4040
import org.hibernate.engine.spi.SessionFactoryImplementor;
4141
import org.hibernate.exception.ConstraintViolationException;
42+
import org.hibernate.exception.ConstraintViolationException.ConstraintKind;
4243
import org.hibernate.exception.LockAcquisitionException;
4344
import org.hibernate.exception.LockTimeoutException;
4445
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
@@ -1166,16 +1167,20 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
11661167
// data integrity violation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11671168
case 1 ->
11681169
// ORA-00001: unique constraint violated
1169-
new ConstraintViolationException(
1170-
message,
1171-
sqlException,
1172-
sql,
1173-
ConstraintViolationException.ConstraintKind.UNIQUE,
1174-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
1175-
);
1176-
case 1407 ->
1170+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.UNIQUE,
1171+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
1172+
case 1400, 1407 ->
1173+
// ORA-01400: cannot insert NULL into column
11771174
// ORA-01407: cannot update column to NULL
1178-
new ConstraintViolationException( message, sqlException, sql,
1175+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.NOT_NULL,
1176+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
1177+
case 2291, 2292 ->
1178+
// ORA-02291, ORA-02292: integrity constraint violated
1179+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.FOREIGN_KEY,
1180+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
1181+
case 2290 ->
1182+
//ORA-02290 check constraint violated
1183+
new ConstraintViolationException( message, sqlException, sql, ConstraintKind.CHECK,
11791184
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
11801185
default -> null;
11811186
};

Diff for: hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -830,13 +830,12 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
830830

831831
return switch ( extractErrorCode( sqlException ) ) {
832832
case 1222 -> new LockTimeoutException( message, sqlException, sql );
833-
case 2627, 2601 -> new ConstraintViolationException(
834-
message,
835-
sqlException,
836-
sql,
833+
case 2627, 2601 -> new ConstraintViolationException( message, sqlException, sql,
837834
ConstraintViolationException.ConstraintKind.UNIQUE,
838835
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
839836
);
837+
case 515 -> new ConstraintViolationException( message, sqlException, sql,
838+
ConstraintViolationException.ConstraintKind.NOT_NULL, null );
840839
default -> null;
841840
};
842841
};

Diff for: hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java

+11-24
Original file line numberDiff line numberDiff line change
@@ -708,40 +708,27 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
708708
switch ( errorCode ) {
709709
case 515:
710710
// Attempt to insert NULL value into column; column does not allow nulls.
711-
return new ConstraintViolationException(
712-
message,
713-
sqlException,
714-
sql,
715-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
716-
);
711+
return new ConstraintViolationException( message, sqlException, sql,
712+
ConstraintViolationException.ConstraintKind.NOT_NULL,
713+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
717714
case 546:
718715
// Foreign key violation
719-
return new ConstraintViolationException(
720-
message,
721-
sqlException,
722-
sql,
723-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
724-
);
716+
return new ConstraintViolationException( message, sqlException, sql,
717+
ConstraintViolationException.ConstraintKind.FOREIGN_KEY,
718+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
725719
case 2601:
726720
// Unique constraint violation
727-
return new ConstraintViolationException(
728-
message,
729-
sqlException,
730-
sql,
721+
return new ConstraintViolationException( message, sqlException, sql,
731722
ConstraintViolationException.ConstraintKind.UNIQUE,
732-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
733-
);
723+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
734724
}
735725
break;
736726
case "ZZZZZ":
737727
if ( 515 == errorCode ) {
738728
// Attempt to insert NULL value into column; column does not allow nulls.
739-
return new ConstraintViolationException(
740-
message,
741-
sqlException,
742-
sql,
743-
getViolatedConstraintNameExtractor().extractConstraintName( sqlException )
744-
);
729+
return new ConstraintViolationException( message, sqlException, sql,
730+
ConstraintViolationException.ConstraintKind.NOT_NULL,
731+
getViolatedConstraintNameExtractor().extractConstraintName( sqlException ) );
745732
}
746733
break;
747734
}

Diff for: hibernate-core/src/main/java/org/hibernate/exception/ConstraintViolationException.java

+3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ public ConstraintKind getKind() {
5757
}
5858

5959
public enum ConstraintKind {
60+
NOT_NULL,
6061
UNIQUE,
62+
FOREIGN_KEY,
63+
CHECK,
6164
OTHER
6265
}
6366
}

Diff for: hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.hibernate.QueryTimeoutException;
1212
import org.hibernate.exception.AuthException;
1313
import org.hibernate.exception.ConstraintViolationException;
14+
import org.hibernate.exception.ConstraintViolationException.ConstraintKind;
1415
import org.hibernate.exception.DataException;
1516
import org.hibernate.exception.JDBCConnectionException;
1617
import org.hibernate.exception.LockAcquisitionException;
@@ -78,10 +79,16 @@ public SQLStateConversionDelegate(ConversionContext conversionContext) {
7879
"23", // "integrity constraint violation"
7980
"27", // "triggered data change violation"
8081
"44": // "with check option violation"
81-
final String constraintName = getConversionContext()
82-
.getViolatedConstraintNameExtractor()
83-
.extractConstraintName( sqlException );
84-
return new ConstraintViolationException( message, sqlException, sql, constraintName );
82+
final String constraintName =
83+
getConversionContext().getViolatedConstraintNameExtractor()
84+
.extractConstraintName( sqlException );
85+
if ( sqlState.length() > 5 ) {
86+
final ConstraintKind constraintKind = constraintKind( sqlState.substring( 0, 5 ) );
87+
return new ConstraintViolationException( message, sqlException, sql, constraintKind, constraintName );
88+
}
89+
else {
90+
return new ConstraintViolationException( message, sqlException, sql, constraintName );
91+
}
8592
case
8693
"08": // "connection exception"
8794
return new JDBCConnectionException( message, sqlException, sql );
@@ -96,4 +103,17 @@ public SQLStateConversionDelegate(ConversionContext conversionContext) {
96103
}
97104
return null;
98105
}
106+
107+
private static ConstraintKind constraintKind(String trimmedState) {
108+
return switch ( trimmedState ) {
109+
case "23502" -> ConstraintKind.NOT_NULL;
110+
case "23505" -> ConstraintKind.UNIQUE;
111+
case "23503" -> ConstraintKind.FOREIGN_KEY;
112+
// 23510-3 indicate CHECK on Db2,
113+
// 23514 indicates CHECK on Postgres,
114+
// 23513-4 indicate CHECK on h2
115+
case "23510", "23511", "23512", "23513", "23514" -> ConstraintKind.CHECK;
116+
default -> ConstraintKind.OTHER;
117+
};
118+
}
99119
}

0 commit comments

Comments
 (0)