HHH-18302 Add test for issue

This commit is contained in:
Andrea Boriero 2024-07-05 14:32:39 +02:00 committed by Steve Ebersole
parent 8766a8e012
commit a3c779a019
2 changed files with 169 additions and 7 deletions

View File

@ -28,10 +28,15 @@ import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jira; import org.hibernate.testing.orm.junit.Jira;
import org.hibernate.testing.orm.junit.Jpa; import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.RequiresDialect; import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.NamedStoredProcedureQueries; import jakarta.persistence.NamedStoredProcedureQueries;
@ -39,8 +44,11 @@ import jakarta.persistence.NamedStoredProcedureQuery;
import jakarta.persistence.ParameterMode; import jakarta.persistence.ParameterMode;
import jakarta.persistence.StoredProcedureParameter; import jakarta.persistence.StoredProcedureParameter;
import jakarta.persistence.StoredProcedureQuery; import jakarta.persistence.StoredProcedureQuery;
import jakarta.persistence.Table;
import org.hamcrest.MatcherAssert;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -55,10 +63,16 @@ import static org.junit.jupiter.api.Assertions.fail;
Phone.class, Phone.class,
Vote.class, Vote.class,
DB2StoredProcedureTest.IdHolder.class, DB2StoredProcedureTest.IdHolder.class,
DB2StoredProcedureTest.Address.class,
} ) } )
@RequiresDialect( value = DB2Dialect.class ) @RequiresDialect( value = DB2Dialect.class )
@Jira( "https://hibernate.atlassian.net/browse/HHH-18332" ) @Jira( "https://hibernate.atlassian.net/browse/HHH-18332" )
public class DB2StoredProcedureTest { public class DB2StoredProcedureTest {
private static final String CITY = "London";
private static final String STREET = "Lollard Street";
private static final String ZIP = "SE116U";
@Test @Test
public void testStoredProcedureOutParameter(EntityManagerFactoryScope scope) { public void testStoredProcedureOutParameter(EntityManagerFactoryScope scope) {
scope.inTransaction( entityManager -> { scope.inTransaction( entityManager -> {
@ -242,6 +256,88 @@ public class DB2StoredProcedureTest {
} ); } );
} }
@Test
@Jira( "https://hibernate.atlassian.net/browse/HHH-18302" )
public void testStoredProcedureInAndOutAndRefCursorParameters(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "sp_get_address_by_street_city" );
query.registerStoredProcedureParameter( "street_in", String.class, ParameterMode.IN );
query.registerStoredProcedureParameter( "city_in", String.class, ParameterMode.IN );
query.registerStoredProcedureParameter( "rec_out", ResultSet.class, ParameterMode.REF_CURSOR );
query.setParameter( "street_in", STREET )
.setParameter( "city_in", CITY );
query.execute();
ResultSet rs = (ResultSet) query.getOutputParameterValue( "rec_out" );
try {
Assertions.assertTrue( rs.next() );
MatcherAssert.assertThat( rs.getString( "street" ), is( STREET ) );
MatcherAssert.assertThat( rs.getString( "city" ), is( CITY ) );
MatcherAssert.assertThat( rs.getString( "zip" ), is( ZIP ) );
}
catch (SQLException e) {
throw new RuntimeException( e );
}
}
);
}
@Test
@Jira( "https://hibernate.atlassian.net/browse/HHH-18302" )
public void testStoredProcedureInAndOutAndRefCursorParametersDifferentRegistrationOrder(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "sp_get_address_by_street_city" );
query.registerStoredProcedureParameter( "city_in", String.class, ParameterMode.IN );
query.registerStoredProcedureParameter( "street_in", String.class, ParameterMode.IN );
query.registerStoredProcedureParameter( "rec_out", ResultSet.class, ParameterMode.REF_CURSOR );
query.setParameter( "street_in", STREET )
.setParameter( "city_in", CITY );
query.execute();
ResultSet rs = (ResultSet) query.getOutputParameterValue( "rec_out" );
try {
Assertions.assertTrue( rs.next() );
MatcherAssert.assertThat( rs.getString( "street" ), is( STREET ) );
MatcherAssert.assertThat( rs.getString( "city" ), is( CITY ) );
MatcherAssert.assertThat( rs.getString( "zip" ), is( ZIP ) );
}
catch (SQLException e) {
throw new RuntimeException( e );
}
}
);
}
@Test
@Jira( "https://hibernate.atlassian.net/browse/HHH-18302" )
public void testStoredProcedureInAndOutAndRefCursorParametersDifferentRegistrationOrder2(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "sp_get_address_by_street_city" );
query.registerStoredProcedureParameter( "rec_out", ResultSet.class, ParameterMode.REF_CURSOR );
query.registerStoredProcedureParameter( "city_in", String.class, ParameterMode.IN );
query.registerStoredProcedureParameter( "street_in", String.class, ParameterMode.IN );
query.setParameter( "street_in", STREET )
.setParameter( "city_in", CITY );
query.execute();
ResultSet rs = (ResultSet) query.getOutputParameterValue( "rec_out" );
try {
Assertions.assertTrue( rs.next() );
MatcherAssert.assertThat( rs.getString( "street" ), is( STREET ) );
MatcherAssert.assertThat( rs.getString( "city" ), is( CITY ) );
MatcherAssert.assertThat( rs.getString( "zip" ), is( ZIP ) );
}
catch (SQLException e) {
throw new RuntimeException( e );
}
}
);
}
@BeforeAll @BeforeAll
public void prepareSchema(EntityManagerFactoryScope scope) { public void prepareSchema(EntityManagerFactoryScope scope) {
scope.inTransaction( (entityManager) -> entityManager.unwrap( Session.class ).doWork( (connection) -> { scope.inTransaction( (entityManager) -> entityManager.unwrap( Session.class ).doWork( (connection) -> {
@ -355,9 +451,27 @@ public class DB2StoredProcedureTest {
" OPEN votes; " + " OPEN votes; " +
"END" "END"
); );
statement.executeUpdate(
"CREATE OR REPLACE PROCEDURE sp_get_address_by_street_city ( " +
" IN street_in VARCHAR(255), " +
" IN city_in VARCHAR(255), " +
" OUT rec_out CURSOR ) " +
"BEGIN " +
" SET rec_out = CURSOR FOR " +
" SELECT * " +
" FROM ADDRESS_TABLE A " +
" WHERE " +
" A.STREET = street_in" +
" AND A.CITY = city_in;" +
" OPEN rec_out; " +
"END;"
);
} }
} ) ); } ) );
}
@BeforeEach
public void setUp(EntityManagerFactoryScope scope){
scope.inTransaction( (entityManager) -> { scope.inTransaction( (entityManager) -> {
final Person person1 = new Person( 1L, "John Doe" ); final Person person1 = new Person( 1L, "John Doe" );
person1.setNickName( "JD" ); person1.setNickName( "JD" );
@ -377,6 +491,8 @@ public class DB2StoredProcedureTest {
phone2.setValid( false ); phone2.setValid( false );
person1.addPhone( phone2 ); person1.addPhone( phone2 );
Address address = new Address( 1l, STREET, CITY, ZIP );
entityManager.persist( address );
} ); } );
} }
@ -394,15 +510,21 @@ public class DB2StoredProcedureTest {
statement.executeUpdate( "DROP PROCEDURE outAndRefCursor" ); statement.executeUpdate( "DROP PROCEDURE outAndRefCursor" );
statement.executeUpdate( "DROP PROCEDURE sp_phone_validity" ); statement.executeUpdate( "DROP PROCEDURE sp_phone_validity" );
statement.executeUpdate( "DROP PROCEDURE sp_votes" ); statement.executeUpdate( "DROP PROCEDURE sp_votes" );
statement.executeUpdate( "DROP PROCEDURE sp_get_address_by_street_city" );
} }
catch (final SQLException ignore) { catch (final SQLException ignore) {
} }
} ); } );
} );
}
scope.inTransaction( em, (em2) -> { @AfterEach
final List<Person> people = em.createQuery( "from Person", Person.class ).getResultList(); public void cleanData(EntityManagerFactoryScope scope) {
people.forEach( em::remove ); scope.inTransaction( (em) -> {
} ); final List<Person> people = em.createQuery( "from Person", Person.class ).getResultList();
people.forEach( em::remove );
em.createQuery( "delete Address" ).executeUpdate();
} ); } );
} }
@ -429,4 +551,44 @@ public class DB2StoredProcedureTest {
Long id; Long id;
String name; String name;
} }
@Entity(name = "Address")
@Table(name = "ADDRESS_TABLE")
public static class Address {
@Id
@Column(name = "ID")
private long id;
@Column(name = "STREET")
private String street;
@Column(name = "CITY")
private String city;
@Column(name = "ZIP")
private String zip;
public Address() {
}
public Address(long id, String street, String city, String zip) {
this.id = id;
this.street = street;
this.city = city;
this.zip = zip;
}
public long getId() {
return id;
}
public String getStreet() {
return street;
}
public String getCity() {
return city;
}
public String getZip() {
return zip;
}
}
} }

View File

@ -186,7 +186,7 @@
<sql-query name="simpleScalar" callable="true"> <sql-query name="simpleScalar" callable="true">
<return-scalar column="name" type="string"/> <return-scalar column="name" type="string"/>
<return-scalar column="`value`" type="long"/> <return-scalar column="`value`" type="long"/>
{ call simpleScalar(:number) } { call simpleScalar(:p_number) }
</sql-query> </sql-query>
<sql-query name="paramhandling" callable="true"> <sql-query name="paramhandling" callable="true">
@ -261,10 +261,10 @@
<database-object> <database-object>
<create> <create>
CREATE PROCEDURE simpleScalar (IN j SMALLINT) RESULT SETS 1 CREATE PROCEDURE simpleScalar (IN p_number SMALLINT) RESULT SETS 1
P1: BEGIN P1: BEGIN
DECLARE C1 CURSOR WITH RETURN FOR DECLARE C1 CURSOR WITH RETURN FOR
SELECT j as value, 'getAll' as name from sysibm.sysdummy1; SELECT p_number as value, 'getAll' as name from sysibm.sysdummy1;
OPEN C1; OPEN C1;
END P1 END P1
</create> </create>