diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 9adc838f0b..288e205985 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -30,6 +30,7 @@ import org.hibernate.dialect.function.AvgWithArgumentCastFunction; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; @@ -313,6 +314,12 @@ public class H2Dialect extends Dialect { exception = new PessimisticLockException(message, sqlException, sql); } + if ( 90006 == errorCode ) { + // NULL not allowed for column [90006-145] + final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName( sqlException ); + exception = new ConstraintViolationException( message, sqlException, sql, constraintName ); + } + return exception; } }; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java index 123e38e249..5a0d243feb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java @@ -37,6 +37,7 @@ import org.hibernate.dialect.function.NvlFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -462,6 +463,14 @@ public class Oracle8iDialect extends Dialect { } + // data integrity violation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + if ( 1407 == errorCode ) { + // ORA-01407: cannot update column to NULL + final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName( sqlException ); + return new ConstraintViolationException( message, sqlException, sql, constraintName ); + } + return null; } }; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE157Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE157Dialect.java index dc9a08b50e..1096672ecd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE157Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE157Dialect.java @@ -31,6 +31,7 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.QueryTimeoutException; import org.hibernate.dialect.function.SQLFunctionTemplate; +import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -104,9 +105,15 @@ public class SybaseASE157Dialect extends SybaseASE15Dialect { @Override public JDBCException convert(SQLException sqlException, String message, String sql) { final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException ); + final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException ); if("JZ0TO".equals( sqlState ) || "JZ006".equals( sqlState )){ throw new LockTimeoutException( message, sqlException, sql ); } + if ( 515 == errorCode && "ZZZZZ".equals( sqlState ) ) { + // Attempt to insert NULL value into column; column does not allow nulls. + final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName( sqlException ); + return new ConstraintViolationException( message, sqlException, sql, constraintName ); + } return null; } }; diff --git a/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java b/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java index f92c37929b..b7a5ac2659 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/internal/SQLStateConversionDelegate.java @@ -112,7 +112,8 @@ public class SQLStateConversionDelegate extends AbstractSQLExceptionConversionDe @Override public JDBCException convert(SQLException sqlException, String message, String sql) { - String sqlState = JdbcExceptionHelper.extractSqlState( sqlException ); + final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException ); + final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException ); if ( sqlState != null ) { String sqlStateClassCode = JdbcExceptionHelper.determineSqlStateClassCode( sqlState ); @@ -146,8 +147,8 @@ public class SQLStateConversionDelegate extends AbstractSQLExceptionConversionDe // MySQL Query execution was interrupted if ( "70100".equals( sqlState ) || - // Oracle user requested cancel of current operation - "72000".equals( sqlState ) ) { + // Oracle user requested cancel of current operation + ( "72000".equals( sqlState ) && errorCode == 1013 ) ) { throw new QueryTimeoutException( message, sqlException, sql ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java b/hibernate-core/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java index c3ce0b3ef5..811f8edc63 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/exception/SQLExceptionConversionTest.java @@ -26,16 +26,21 @@ package org.hibernate.test.exception; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.sql.Types; import org.junit.Test; import org.hibernate.Session; import org.hibernate.dialect.MySQLMyISAMDialect; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.jdbc.spi.ResultSetReturn; +import org.hibernate.engine.jdbc.spi.StatementPreparer; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.SQLGrammarException; import org.hibernate.jdbc.Work; import org.hibernate.testing.SkipForDialect; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import static org.junit.Assert.fail; @@ -78,14 +83,7 @@ public class SQLExceptionConversionTest extends BaseCoreFunctionalTestCase { // expected outcome } finally { - if ( ps != null ) { - try { - ((SessionImplementor)session).getTransactionCoordinator().getJdbcCoordinator().release( ps ); - } - catch( Throwable ignore ) { - // ignore... - } - } + releaseStatement( session, ps ); } } } @@ -116,14 +114,7 @@ public class SQLExceptionConversionTest extends BaseCoreFunctionalTestCase { // expected outcome } finally { - if ( ps != null ) { - try { - ((SessionImplementor)session).getTransactionCoordinator().getJdbcCoordinator().release( ps ); - } - catch( Throwable ignore ) { - // ignore... - } - } + releaseStatement( session, ps ); } } } @@ -132,4 +123,56 @@ public class SQLExceptionConversionTest extends BaseCoreFunctionalTestCase { session.getTransaction().rollback(); session.close(); } + + @Test + @TestForIssue(jiraKey = "HHH-7357") + public void testNotNullConstraint() { + final Session session = openSession(); + session.beginTransaction(); + + final User user = new User(); + user.setUsername( "Lukasz" ); + session.save( user ); + session.flush(); + + session.doWork( + new Work() { + @Override + public void execute(Connection connection) throws SQLException { + final JdbcCoordinator jdbcCoordinator = ( (SessionImplementor) session ).getTransactionCoordinator().getJdbcCoordinator(); + final StatementPreparer statementPreparer = jdbcCoordinator.getStatementPreparer(); + final ResultSetReturn resultSetReturn = jdbcCoordinator.getResultSetReturn(); + PreparedStatement ps = null; + try { + ps = statementPreparer.prepareStatement( "UPDATE T_USER SET user_name = ? WHERE user_id = ?" ); + ps.setNull( 1, Types.VARCHAR ); // Attempt to update user name to NULL (NOT NULL constraint defined). + ps.setLong( 2, user.getId() ); + resultSetReturn.executeUpdate( ps ); + + fail( "UPDATE should have failed because of not NULL constraint." ); + } + catch ( ConstraintViolationException ignore ) { + // expected outcome + } + finally { + releaseStatement( session, ps ); + } + } + } + ); + + session.getTransaction().rollback(); + session.close(); + } + + private void releaseStatement(Session session, PreparedStatement ps) { + if ( ps != null ) { + try { + ( (SessionImplementor) session ).getTransactionCoordinator().getJdbcCoordinator().release( ps ); + } + catch ( Throwable ignore ) { + // ignore... + } + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/exception/User.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/exception/User.hbm.xml index a18408ddac..110e5635c5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/exception/User.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/exception/User.hbm.xml @@ -6,7 +6,7 @@ - +