diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index aee33307bc..ad4ee3a3ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -18,6 +18,7 @@ import org.hibernate.JDBCException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; +import org.hibernate.QueryTimeoutException; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.PositionSubstringFunction; @@ -66,7 +67,7 @@ public class PostgreSQL81Dialect extends Dialect { @Override public String processSql(String sql, RowSelection selection) { final boolean hasOffset = LimitHelper.hasFirstRow( selection ); - return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); + return sql + ( hasOffset ? " limit ? offset ?" : " limit ?" ); } @Override @@ -118,75 +119,84 @@ public class PostgreSQL81Dialect extends Dialect { registerColumnType( Types.NUMERIC, "numeric($p, $s)" ); registerColumnType( Types.OTHER, "uuid" ); - registerFunction( "abs", new StandardSQLFunction("abs") ); - registerFunction( "sign", new StandardSQLFunction("sign", StandardBasicTypes.INTEGER) ); + registerFunction( "abs", new StandardSQLFunction( "abs" ) ); + registerFunction( "sign", new StandardSQLFunction( "sign", StandardBasicTypes.INTEGER ) ); - registerFunction( "acos", new StandardSQLFunction("acos", StandardBasicTypes.DOUBLE) ); - registerFunction( "asin", new StandardSQLFunction("asin", StandardBasicTypes.DOUBLE) ); - registerFunction( "atan", new StandardSQLFunction("atan", StandardBasicTypes.DOUBLE) ); - registerFunction( "cos", new StandardSQLFunction("cos", StandardBasicTypes.DOUBLE) ); - registerFunction( "cot", new StandardSQLFunction("cot", StandardBasicTypes.DOUBLE) ); - registerFunction( "exp", new StandardSQLFunction("exp", StandardBasicTypes.DOUBLE) ); - registerFunction( "ln", new StandardSQLFunction("ln", StandardBasicTypes.DOUBLE) ); - registerFunction( "log", new StandardSQLFunction("log", StandardBasicTypes.DOUBLE) ); - registerFunction( "sin", new StandardSQLFunction("sin", StandardBasicTypes.DOUBLE) ); - registerFunction( "sqrt", new StandardSQLFunction("sqrt", StandardBasicTypes.DOUBLE) ); - registerFunction( "cbrt", new StandardSQLFunction("cbrt", StandardBasicTypes.DOUBLE) ); - registerFunction( "tan", new StandardSQLFunction("tan", StandardBasicTypes.DOUBLE) ); - registerFunction( "radians", new StandardSQLFunction("radians", StandardBasicTypes.DOUBLE) ); - registerFunction( "degrees", new StandardSQLFunction("degrees", StandardBasicTypes.DOUBLE) ); + registerFunction( "acos", new StandardSQLFunction( "acos", StandardBasicTypes.DOUBLE ) ); + registerFunction( "asin", new StandardSQLFunction( "asin", StandardBasicTypes.DOUBLE ) ); + registerFunction( "atan", new StandardSQLFunction( "atan", StandardBasicTypes.DOUBLE ) ); + registerFunction( "cos", new StandardSQLFunction( "cos", StandardBasicTypes.DOUBLE ) ); + registerFunction( "cot", new StandardSQLFunction( "cot", StandardBasicTypes.DOUBLE ) ); + registerFunction( "exp", new StandardSQLFunction( "exp", StandardBasicTypes.DOUBLE ) ); + registerFunction( "ln", new StandardSQLFunction( "ln", StandardBasicTypes.DOUBLE ) ); + registerFunction( "log", new StandardSQLFunction( "log", StandardBasicTypes.DOUBLE ) ); + registerFunction( "sin", new StandardSQLFunction( "sin", StandardBasicTypes.DOUBLE ) ); + registerFunction( "sqrt", new StandardSQLFunction( "sqrt", StandardBasicTypes.DOUBLE ) ); + registerFunction( "cbrt", new StandardSQLFunction( "cbrt", StandardBasicTypes.DOUBLE ) ); + registerFunction( "tan", new StandardSQLFunction( "tan", StandardBasicTypes.DOUBLE ) ); + registerFunction( "radians", new StandardSQLFunction( "radians", StandardBasicTypes.DOUBLE ) ); + registerFunction( "degrees", new StandardSQLFunction( "degrees", StandardBasicTypes.DOUBLE ) ); - registerFunction( "stddev", new StandardSQLFunction("stddev", StandardBasicTypes.DOUBLE) ); - registerFunction( "variance", new StandardSQLFunction("variance", StandardBasicTypes.DOUBLE) ); + registerFunction( "stddev", new StandardSQLFunction( "stddev", StandardBasicTypes.DOUBLE ) ); + registerFunction( "variance", new StandardSQLFunction( "variance", StandardBasicTypes.DOUBLE ) ); - registerFunction( "random", new NoArgSQLFunction("random", StandardBasicTypes.DOUBLE) ); - registerFunction( "rand", new NoArgSQLFunction("random", StandardBasicTypes.DOUBLE) ); + registerFunction( "random", new NoArgSQLFunction( "random", StandardBasicTypes.DOUBLE ) ); + registerFunction( "rand", new NoArgSQLFunction( "random", StandardBasicTypes.DOUBLE ) ); - registerFunction( "round", new StandardSQLFunction("round") ); - registerFunction( "trunc", new StandardSQLFunction("trunc") ); - registerFunction( "ceil", new StandardSQLFunction("ceil") ); - registerFunction( "floor", new StandardSQLFunction("floor") ); + registerFunction( "round", new StandardSQLFunction( "round" ) ); + registerFunction( "trunc", new StandardSQLFunction( "trunc" ) ); + registerFunction( "ceil", new StandardSQLFunction( "ceil" ) ); + registerFunction( "floor", new StandardSQLFunction( "floor" ) ); - registerFunction( "chr", new StandardSQLFunction("chr", StandardBasicTypes.CHARACTER) ); - registerFunction( "lower", new StandardSQLFunction("lower") ); - registerFunction( "upper", new StandardSQLFunction("upper") ); - registerFunction( "substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING) ); - registerFunction( "initcap", new StandardSQLFunction("initcap") ); - registerFunction( "to_ascii", new StandardSQLFunction("to_ascii") ); - registerFunction( "quote_ident", new StandardSQLFunction("quote_ident", StandardBasicTypes.STRING) ); - registerFunction( "quote_literal", new StandardSQLFunction("quote_literal", StandardBasicTypes.STRING) ); - registerFunction( "md5", new StandardSQLFunction("md5", StandardBasicTypes.STRING) ); - registerFunction( "ascii", new StandardSQLFunction("ascii", StandardBasicTypes.INTEGER) ); - registerFunction( "char_length", new StandardSQLFunction("char_length", StandardBasicTypes.LONG) ); - registerFunction( "bit_length", new StandardSQLFunction("bit_length", StandardBasicTypes.LONG) ); - registerFunction( "octet_length", new StandardSQLFunction("octet_length", StandardBasicTypes.LONG) ); + registerFunction( "chr", new StandardSQLFunction( "chr", StandardBasicTypes.CHARACTER ) ); + registerFunction( "lower", new StandardSQLFunction( "lower" ) ); + registerFunction( "upper", new StandardSQLFunction( "upper" ) ); + registerFunction( "substr", new StandardSQLFunction( "substr", StandardBasicTypes.STRING ) ); + registerFunction( "initcap", new StandardSQLFunction( "initcap" ) ); + registerFunction( "to_ascii", new StandardSQLFunction( "to_ascii" ) ); + registerFunction( "quote_ident", new StandardSQLFunction( "quote_ident", StandardBasicTypes.STRING ) ); + registerFunction( "quote_literal", new StandardSQLFunction( "quote_literal", StandardBasicTypes.STRING ) ); + registerFunction( "md5", new StandardSQLFunction( "md5", StandardBasicTypes.STRING ) ); + registerFunction( "ascii", new StandardSQLFunction( "ascii", StandardBasicTypes.INTEGER ) ); + registerFunction( "char_length", new StandardSQLFunction( "char_length", StandardBasicTypes.LONG ) ); + registerFunction( "bit_length", new StandardSQLFunction( "bit_length", StandardBasicTypes.LONG ) ); + registerFunction( "octet_length", new StandardSQLFunction( "octet_length", StandardBasicTypes.LONG ) ); - registerFunction( "age", new StandardSQLFunction("age") ); - registerFunction( "current_date", new NoArgSQLFunction("current_date", StandardBasicTypes.DATE, false) ); - registerFunction( "current_time", new NoArgSQLFunction("current_time", StandardBasicTypes.TIME, false) ); - registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", StandardBasicTypes.TIMESTAMP, false) ); + registerFunction( "age", new StandardSQLFunction( "age" ) ); + registerFunction( "current_date", new NoArgSQLFunction( "current_date", StandardBasicTypes.DATE, false ) ); + registerFunction( "current_time", new NoArgSQLFunction( "current_time", StandardBasicTypes.TIME, false ) ); + registerFunction( + "current_timestamp", + new NoArgSQLFunction( "current_timestamp", StandardBasicTypes.TIMESTAMP, false ) + ); registerFunction( "date_trunc", new StandardSQLFunction( "date_trunc", StandardBasicTypes.TIMESTAMP ) ); - registerFunction( "localtime", new NoArgSQLFunction("localtime", StandardBasicTypes.TIME, false) ); - registerFunction( "localtimestamp", new NoArgSQLFunction("localtimestamp", StandardBasicTypes.TIMESTAMP, false) ); - registerFunction( "now", new NoArgSQLFunction("now", StandardBasicTypes.TIMESTAMP) ); - registerFunction( "timeofday", new NoArgSQLFunction("timeofday", StandardBasicTypes.STRING) ); + registerFunction( "localtime", new NoArgSQLFunction( "localtime", StandardBasicTypes.TIME, false ) ); + registerFunction( + "localtimestamp", + new NoArgSQLFunction( "localtimestamp", StandardBasicTypes.TIMESTAMP, false ) + ); + registerFunction( "now", new NoArgSQLFunction( "now", StandardBasicTypes.TIMESTAMP ) ); + registerFunction( "timeofday", new NoArgSQLFunction( "timeofday", StandardBasicTypes.STRING ) ); - registerFunction( "current_user", new NoArgSQLFunction("current_user", StandardBasicTypes.STRING, false) ); - registerFunction( "session_user", new NoArgSQLFunction("session_user", StandardBasicTypes.STRING, false) ); - registerFunction( "user", new NoArgSQLFunction("user", StandardBasicTypes.STRING, false) ); - registerFunction( "current_database", new NoArgSQLFunction("current_database", StandardBasicTypes.STRING, true) ); - registerFunction( "current_schema", new NoArgSQLFunction("current_schema", StandardBasicTypes.STRING, true) ); + registerFunction( "current_user", new NoArgSQLFunction( "current_user", StandardBasicTypes.STRING, false ) ); + registerFunction( "session_user", new NoArgSQLFunction( "session_user", StandardBasicTypes.STRING, false ) ); + registerFunction( "user", new NoArgSQLFunction( "user", StandardBasicTypes.STRING, false ) ); + registerFunction( + "current_database", + new NoArgSQLFunction( "current_database", StandardBasicTypes.STRING, true ) + ); + registerFunction( "current_schema", new NoArgSQLFunction( "current_schema", StandardBasicTypes.STRING, true ) ); - registerFunction( "to_char", new StandardSQLFunction("to_char", StandardBasicTypes.STRING) ); - registerFunction( "to_date", new StandardSQLFunction("to_date", StandardBasicTypes.DATE) ); - registerFunction( "to_timestamp", new StandardSQLFunction("to_timestamp", StandardBasicTypes.TIMESTAMP) ); - registerFunction( "to_number", new StandardSQLFunction("to_number", StandardBasicTypes.BIG_DECIMAL) ); + registerFunction( "to_char", new StandardSQLFunction( "to_char", StandardBasicTypes.STRING ) ); + registerFunction( "to_date", new StandardSQLFunction( "to_date", StandardBasicTypes.DATE ) ); + registerFunction( "to_timestamp", new StandardSQLFunction( "to_timestamp", StandardBasicTypes.TIMESTAMP ) ); + registerFunction( "to_number", new StandardSQLFunction( "to_number", StandardBasicTypes.BIG_DECIMAL ) ); - registerFunction( "concat", new VarArgsSQLFunction( StandardBasicTypes.STRING, "(","||",")" ) ); + registerFunction( "concat", new VarArgsSQLFunction( StandardBasicTypes.STRING, "(", "||", ")" ) ); registerFunction( "locate", new PositionSubstringFunction() ); - registerFunction( "str", new SQLFunctionTemplate(StandardBasicTypes.STRING, "cast(?1 as varchar)") ); + registerFunction( "str", new SQLFunctionTemplate( StandardBasicTypes.STRING, "cast(?1 as varchar)" ) ); getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" ); @@ -286,7 +296,7 @@ public class PostgreSQL81Dialect extends Dialect { @Override public String getLimitString(String sql, boolean hasOffset) { - return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); + return sql + ( hasOffset ? " limit ? offset ?" : " limit ?" ); } @Override @@ -317,12 +327,12 @@ public class PostgreSQL81Dialect extends Dialect { } } LockMode lockMode = lockOptions.getAliasSpecificLockMode( aliases ); - if (lockMode == null ) { + if ( lockMode == null ) { lockMode = lockOptions.getLockMode(); } switch ( lockMode ) { case UPGRADE: - return getForUpdateString(aliases); + return getForUpdateString( aliases ); case PESSIMISTIC_READ: return getReadLockString( aliases, lockOptions.getTimeOut() ); case PESSIMISTIC_WRITE: @@ -330,9 +340,9 @@ public class PostgreSQL81Dialect extends Dialect { case UPGRADE_NOWAIT: case FORCE: case PESSIMISTIC_FORCE_INCREMENT: - return getForUpdateNowaitString(aliases); + return getForUpdateNowaitString( aliases ); case UPGRADE_SKIPLOCKED: - return getForUpdateSkipLockedString(aliases); + return getForUpdateSkipLockedString( aliases ); default: return ""; } @@ -344,7 +354,7 @@ public class PostgreSQL81Dialect extends Dialect { } @Override - public String getCaseInsensitiveLike(){ + public String getCaseInsensitiveLike() { return "ilike"; } @@ -451,19 +461,29 @@ public class PostgreSQL81Dialect extends Dialect { @Override protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException { final int sqlState = Integer.parseInt( JdbcExceptionHelper.extractSqlState( sqle ) ); - switch (sqlState) { + switch ( sqlState ) { // CHECK VIOLATION - case 23514: return extractUsingTemplate( "violates check constraint \"","\"", sqle.getMessage() ); + case 23514: + return extractUsingTemplate( "violates check constraint \"", "\"", sqle.getMessage() ); // UNIQUE VIOLATION - case 23505: return extractUsingTemplate( "violates unique constraint \"","\"", sqle.getMessage() ); + case 23505: + return extractUsingTemplate( "violates unique constraint \"", "\"", sqle.getMessage() ); // FOREIGN KEY VIOLATION - case 23503: return extractUsingTemplate( "violates foreign key constraint \"","\"", sqle.getMessage() ); + case 23503: + return extractUsingTemplate( "violates foreign key constraint \"", "\"", sqle.getMessage() ); // NOT NULL VIOLATION - case 23502: return extractUsingTemplate( "null value in column \"","\" violates not-null constraint", sqle.getMessage() ); + case 23502: + return extractUsingTemplate( + "null value in column \"", + "\" violates not-null constraint", + sqle.getMessage() + ); // TODO: RESTRICT VIOLATION - case 23001: return null; + case 23001: + return null; // ALL OTHER - default: return null; + default: + return null; } } }; @@ -485,6 +505,11 @@ public class PostgreSQL81Dialect extends Dialect { return new PessimisticLockException( message, sqlException, sql ); } + if ( "57014".equals( sqlState ) ) { + // Operation cancelled by user + return new QueryTimeoutException( message, sqlException, sql ); + } + // returning null allows other delegates to operate return null; } @@ -637,7 +662,8 @@ public class PostgreSQL81Dialect extends Dialect { @Override public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException { if ( position != 1 ) { - throw new UnsupportedOperationException( "PostgreSQL only supports REF_CURSOR parameters as the first parameter" ); + throw new UnsupportedOperationException( + "PostgreSQL only supports REF_CURSOR parameters as the first parameter" ); } return (ResultSet) statement.getObject( 1 ); } diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java b/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java index 401578a1b5..6b617b092a 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java @@ -14,6 +14,7 @@ import org.hibernate.JDBCException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; +import org.hibernate.QueryTimeoutException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -57,6 +58,17 @@ public class PostgreSQL81DialectTestCase extends BaseUnitTestCase { assertTrue(exception instanceof PessimisticLockException); } + @Test + @TestForIssue( jiraKey = "HHH-13661") + public void testQueryTimeoutException() { + final PostgreSQL81Dialect dialect = new PostgreSQL81Dialect(); + final SQLExceptionConversionDelegate delegate = dialect.buildSQLExceptionConversionDelegate(); + assertNotNull( delegate ); + + final JDBCException exception = delegate.convert( new SQLException("Client cancelled operation", "57014"), "", "" ); + assertTrue( exception instanceof QueryTimeoutException ); + } + /** * Tests that getForUpdateString(String aliases, LockOptions lockOptions) will return a String * that will effect the SELECT ... FOR UPDATE OF tableAlias1, ..., tableAliasN @@ -98,4 +110,5 @@ public class PostgreSQL81DialectTestCase extends BaseUnitTestCase { assertEquals( "PostgreSQL only supports accessing REF_CURSOR parameters by position", e.getMessage() ); } } + }