HHH-12905 - Bind value [null] was not of specified type in StoredProcedureQuery

This commit is contained in:
Roland Kurucz 2018-08-11 20:27:51 +02:00 committed by Guillaume Smet
parent 4a4ecc434b
commit cc1ffbaaa0
4 changed files with 297 additions and 52 deletions

View File

@ -79,8 +79,19 @@ public class ParameterBindImpl<T> implements ParameterBind<T> {
}
if ( procedureParameter.getParameterType() != null ) {
if ( !procedureParameter.getParameterType().isInstance( value ) && !procedureParameter.getHibernateType().getReturnedClass().isInstance( value ) ) {
throw new IllegalArgumentException( "Bind value [" + value + "] was not of specified type [" + procedureParameter.getParameterType() );
if ( value == null ) {
if ( !procedureParameter.isPassNullsEnabled() ) {
throw new IllegalArgumentException( "The parameter with the [" +
( procedureParameter.getName() != null
? procedureParameter.getName() + "] name"
: procedureParameter.getPosition() + "] position" )
+ " was null. You need to call ParameterRegistration#enablePassingNulls(true) in order to pass null parameters." );
}
}
else if ( !procedureParameter.getParameterType().isInstance( value ) &&
!procedureParameter.getHibernateType().getReturnedClass().isInstance( value ) ) {
throw new IllegalArgumentException( "Bind value [" + value + "] was not of specified type [" + procedureParameter
.getParameterType() );
}
}

View File

@ -28,14 +28,19 @@ import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.result.Output;
import org.hibernate.result.ResultSetOutput;
import org.hibernate.type.StringType;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Vlad Mihalcea
@ -98,6 +103,18 @@ public class MySQLStoredProcedureTest extends BaseEntityManagerFunctionalTestCas
" RETURN phoneCount; " +
"END"
);
statement.executeUpdate(
"CREATE PROCEDURE sp_is_null (" +
" IN param varchar(255), " +
" OUT result BIT(1) " +
") " +
"BEGIN " +
" IF (param IS NULL) THEN SET result = 1; " +
" ELSE SET result = 0; " +
" END IF; " +
"END"
);
} finally {
if ( statement != null ) {
statement.close();
@ -193,6 +210,24 @@ public class MySQLStoredProcedureTest extends BaseEntityManagerFunctionalTestCas
entityManager.getTransaction().rollback();
entityManager.close();
}
entityManager = createEntityManager();
entityManager.getTransaction().begin();
try {
Session session = entityManager.unwrap( Session.class );
session.doWork( connection -> {
try (Statement statement = connection.createStatement()) {
statement.executeUpdate( "DROP PROCEDURE IF EXISTS sp_is_null" );
}
catch (SQLException ignore) {
}
} );
}
finally {
entityManager.getTransaction().rollback();
entityManager.close();
}
}
@Test
@ -332,4 +367,52 @@ public class MySQLStoredProcedureTest extends BaseEntityManagerFunctionalTestCas
entityManager.close();
}
}
@Test
@TestForIssue( jiraKey = "HHH-12905")
public void testStoredProcedureNullParameter() {
doInJPA( this::entityManagerFactory, entityManager -> {
ProcedureCall procedureCall = entityManager.unwrap( Session.class ).createStoredProcedureCall("sp_is_null");
procedureCall.registerParameter( 1, StringType.class, ParameterMode.IN).enablePassingNulls( true);
procedureCall.registerParameter( 2, Boolean.class, ParameterMode.OUT);
procedureCall.setParameter(1, null);
Boolean result = (Boolean) procedureCall.getOutputParameterValue( 2 );
assertTrue( result );
});
doInJPA( this::entityManagerFactory, entityManager -> {
ProcedureCall procedureCall = entityManager.unwrap( Session.class ).createStoredProcedureCall("sp_is_null");
procedureCall.registerParameter( 1, StringType.class, ParameterMode.IN).enablePassingNulls( true);
procedureCall.registerParameter( 2, Boolean.class, ParameterMode.OUT);
procedureCall.setParameter(1, "test");
Boolean result = (Boolean) procedureCall.getOutputParameterValue( 2 );
assertFalse( result );
});
}
@Test
@TestForIssue( jiraKey = "HHH-12905")
public void testStoredProcedureNullParameterHibernateWithoutEnablePassingNulls() {
doInJPA( this::entityManagerFactory, entityManager -> {
try {
ProcedureCall procedureCall = entityManager.unwrap( Session.class ).createStoredProcedureCall("sp_is_null");
procedureCall.registerParameter( 1, StringType.class, ParameterMode.IN);
procedureCall.registerParameter( 2, Boolean.class, ParameterMode.OUT);
procedureCall.setParameter(1, null);
procedureCall.getOutputParameterValue( 2 );
fail("Should have thrown exception");
}
catch (IllegalArgumentException e) {
assertEquals( "The parameter on the [1] position was null. You need to call ParameterRegistration#enablePassingNulls in order to pass null parameters.", e.getMessage() );
}
});
}
}

View File

@ -16,12 +16,16 @@ import java.sql.Types;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Properties;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureQuery;
import org.hibernate.Session;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.type.StringType;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
@ -31,6 +35,7 @@ import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
@ -106,6 +111,25 @@ public class PostgreSQLStoredProcedureTest extends BaseEntityManagerFunctionalTe
} );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Session session = entityManager.unwrap( Session.class );
session.doWork( connection -> {
Statement statement = null;
try {
statement = connection.createStatement();
statement.executeUpdate( "DROP FUNCTION sp_is_null()" );
}
catch (SQLException ignore) {
}
finally {
if ( statement != null ) {
statement.close();
}
}
} );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Session session = entityManager.unwrap( Session.class );
@ -158,6 +182,19 @@ public class PostgreSQLStoredProcedureTest extends BaseEntityManagerFunctionalTe
"$BODY$ " +
"LANGUAGE plpgsql;"
);
statement.executeUpdate(
"CREATE OR REPLACE FUNCTION sp_is_null( " +
" IN param varchar(255), " +
" OUT result boolean) " +
" RETURNS boolean AS " +
"$BODY$ " +
" BEGIN " +
" select param is null into result; " +
" END; " +
"$BODY$ " +
"LANGUAGE plpgsql;"
);
}
finally {
if ( statement != null ) {
@ -171,7 +208,8 @@ public class PostgreSQLStoredProcedureTest extends BaseEntityManagerFunctionalTe
Person person1 = new Person( "John Doe" );
person1.setNickName( "JD" );
person1.setAddress( "Earth" );
person1.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) ) );
person1.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 )
.toInstant( ZoneOffset.UTC ) ) );
entityManager.persist( person1 );
@ -260,14 +298,15 @@ public class PostgreSQLStoredProcedureTest extends BaseEntityManagerFunctionalTe
}
} );
assertEquals( Long.valueOf( 2 ), phoneCount );
} catch (Exception e) {
}
catch (Exception e) {
assertEquals( SQLFeatureNotSupportedException.class, e.getCause().getClass() );
}
} );
}
@Test
@TestForIssue( jiraKey = "HHH-11863")
@TestForIssue(jiraKey = "HHH-11863")
public void testSysRefCursorAsOutParameter() {
doInJPA( this::entityManagerFactory, entityManager -> {
@ -275,7 +314,7 @@ public class PostgreSQLStoredProcedureTest extends BaseEntityManagerFunctionalTe
Session session = entityManager.unwrap( Session.class );
try(ResultSet resultSet = session.doReturningWork( connection -> {
try (ResultSet resultSet = session.doReturningWork( connection -> {
CallableStatement function = null;
try {
function = connection.prepareCall( "{ ? = call singleRefCursor() }" );
@ -294,7 +333,7 @@ public class PostgreSQLStoredProcedureTest extends BaseEntityManagerFunctionalTe
}
}
catch (Exception e) {
fail(e.getMessage());
fail( e.getMessage() );
}
assertEquals( Long.valueOf( 1 ), value );
@ -307,16 +346,67 @@ public class PostgreSQLStoredProcedureTest extends BaseEntityManagerFunctionalTe
assertFalse( function.hasMoreResults() );
value = null;
try ( ResultSet resultSet = (ResultSet) function.getOutputParameterValue( 1 ) ) {
try (ResultSet resultSet = (ResultSet) function.getOutputParameterValue( 1 )) {
while ( resultSet.next() ) {
value = resultSet.getLong( 1 );
}
}
catch (SQLException e) {
fail(e.getMessage());
fail( e.getMessage() );
}
assertEquals( Long.valueOf( 1 ), value );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-12905")
public void testStoredProcedureNullParameterHibernate() {
doInJPA( this::entityManagerFactory, entityManager -> {
ProcedureCall procedureCall = entityManager.unwrap( Session.class )
.createStoredProcedureCall( "sp_is_null" );
procedureCall.registerParameter( 1, StringType.class, ParameterMode.IN ).enablePassingNulls( true );
procedureCall.registerParameter( 2, Boolean.class, ParameterMode.OUT );
procedureCall.setParameter( 1, null );
Boolean result = (Boolean) procedureCall.getOutputParameterValue( 2 );
assertTrue( result );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
ProcedureCall procedureCall = entityManager.unwrap( Session.class )
.createStoredProcedureCall( "sp_is_null" );
procedureCall.registerParameter( 1, StringType.class, ParameterMode.IN ).enablePassingNulls( true );
procedureCall.registerParameter( 2, Boolean.class, ParameterMode.OUT );
procedureCall.setParameter( 1, "test" );
Boolean result = (Boolean) procedureCall.getOutputParameterValue( 2 );
assertFalse( result );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-12905")
public void testStoredProcedureNullParameterHibernateWithoutEnablePassingNulls() {
doInJPA( this::entityManagerFactory, entityManager -> {
try {
ProcedureCall procedureCall = entityManager.unwrap( Session.class )
.createStoredProcedureCall( "sp_is_null" );
procedureCall.registerParameter( "param", StringType.class, ParameterMode.IN );
procedureCall.registerParameter( "result", Boolean.class, ParameterMode.OUT );
procedureCall.setParameter( "param", null );
procedureCall.getOutputParameterValue( "result" );
fail("Should have thrown exception");
}
catch (IllegalArgumentException e) {
assertEquals( "The parameter with the [param] position was null. You need to call ParameterRegistration#enablePassingNulls in order to pass null parameters.", e.getMessage() );
}
} );
}
}

View File

@ -29,7 +29,7 @@ import javax.persistence.ParameterMode;
import javax.sql.rowset.serial.SerialBlob;
import javax.sql.rowset.serial.SerialClob;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.BigIntegerType;
import org.hibernate.type.BinaryType;
@ -61,17 +61,17 @@ import org.hibernate.type.UUIDBinaryType;
import org.hibernate.type.UrlType;
import org.hibernate.type.YesNoType;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Vlad Mihalcea
*/
@TestForIssue( jiraKey = "HHH-12661" )
public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctionalTestCase {
private static final String TEST_STRING = "test_string";
@ -79,6 +79,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
private static final byte[] TEST_BYTE_ARRAY = TEST_STRING.getBytes();
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testNumericBooleanTypeInParameter() {
doInHibernate( this::sessionFactory, session -> {
session.createStoredProcedureQuery( "test" )
@ -89,6 +90,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testYesNoTypeInParameter() {
doInHibernate( this::sessionFactory, session -> {
session.createStoredProcedureQuery( "test" )
@ -99,6 +101,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testStringTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -108,6 +111,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testMaterializedClobTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -117,6 +121,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testTextTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -126,6 +131,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testCharacterTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -135,6 +141,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testTrueFalseTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -144,6 +151,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testBooleanTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -153,6 +161,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testByteTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -162,6 +171,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testShortTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -171,6 +181,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testIntegerTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -180,6 +191,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testLongTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -198,6 +210,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testDoubleTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -207,6 +220,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testBigIntegerTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -216,6 +230,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testBigDecimalTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -225,6 +240,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testTimestampTypeDateInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -234,6 +250,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testTimestampTypeTimestampInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -243,6 +260,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testTimeTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -252,6 +270,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testDateTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -261,6 +280,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testCalendarTypeCalendarInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -270,6 +290,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testCurrencyTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -279,6 +300,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testLocaleTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -288,6 +310,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testTimeZoneTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -297,6 +320,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testUrlTypeInParameter() throws MalformedURLException {
final URL url = new URL( "http://example.com");
inTransaction(
@ -307,6 +331,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testClassTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -316,6 +341,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testBlobTypeInParameter() throws SQLException {
final Blob blob = new SerialBlob( TEST_BYTE_ARRAY);
inTransaction(
@ -326,6 +352,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testClobTypeInParameter() throws SQLException {
final Clob clob = new SerialClob( TEST_CHAR_ARRAY);
inTransaction(
@ -336,6 +363,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testBinaryTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -345,6 +373,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testCharArrayTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -354,6 +383,7 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
}
@Test
@TestForIssue( jiraKey = "HHH-12661" )
public void testUUIDBinaryTypeInParameter() {
inTransaction(
session -> session.createStoredProcedureQuery("test")
@ -361,4 +391,35 @@ public class StoredProcedureParameterTypeTest extends BaseNonConfigCoreFunctiona
.setParameter( 1, UUID.randomUUID())
);
}
@Test
@TestForIssue(jiraKey = "HHH-12905")
public void testStringTypeInParameterIsNull() {
inTransaction(
session -> {
ProcedureCall procedureCall = session.createStoredProcedureCall( "test" );
procedureCall.registerParameter( 1, StringType.class, ParameterMode.IN ).enablePassingNulls( true );
procedureCall.setParameter( 1, null );
}
);
}
@Test
@TestForIssue(jiraKey = "HHH-12905")
public void testStringTypeInParameterIsNullWithoutEnablePassingNulls() {
inTransaction(
session -> {
try {
ProcedureCall procedureCall = session.createStoredProcedureCall( "test" );
procedureCall.registerParameter( 1, StringType.class, ParameterMode.IN );
procedureCall.setParameter( 1, null );
fail("Should have thrown exception");
}
catch (IllegalArgumentException e) {
assertTrue( e.getMessage().endsWith( "You need to call ParameterRegistration#enablePassingNulls(true) in order to pass null parameters." ) );
}
}
);
}
}