Skip to content

Commit 4122964

Browse files
victornoelmbladel
authored andcommitted
HHH-19472: native queries can return Object[]
1 parent 6ebfb9f commit 4122964

File tree

3 files changed

+145
-56
lines changed

3 files changed

+145
-56
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.jpa.spi;
6+
7+
import org.hibernate.query.TupleTransformer;
8+
9+
/**
10+
* A {@link TupleTransformer} for handling {@code Object[]} results from native queries.
11+
*
12+
* @since 7.0
13+
*/
14+
public class NativeQueryArrayTransformer implements TupleTransformer<Object[]> {
15+
16+
public static final NativeQueryArrayTransformer INSTANCE = new NativeQueryArrayTransformer();
17+
18+
@Override
19+
public Object[] transformTuple(Object[] tuple, String[] aliases) {
20+
return tuple;
21+
}
22+
}

hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.hibernate.FlushMode;
2626
import org.hibernate.internal.CoreLogging;
2727
import org.hibernate.internal.CoreMessageLogger;
28+
import org.hibernate.jpa.spi.NativeQueryArrayTransformer;
2829
import org.hibernate.jpa.spi.NativeQueryConstructorTransformer;
2930
import org.hibernate.jpa.spi.NativeQueryListTransformer;
3031
import org.hibernate.jpa.spi.NativeQueryMapTransformer;
@@ -377,7 +378,10 @@ else if ( Map.class.equals( resultClass ) ) {
377378
else if ( List.class.equals( resultClass ) ) {
378379
return NativeQueryListTransformer.INSTANCE;
379380
}
380-
else if ( resultClass != Object.class && resultClass != Object[].class ) {
381+
else if ( Object[].class.equals( resultClass )) {
382+
return NativeQueryArrayTransformer.INSTANCE;
383+
}
384+
else if ( resultClass != Object.class ) {
381385
// TODO: this is extremely fragile and probably a bug
382386
if ( isClass( resultClass ) && !hasJavaTypeDescriptor( resultClass ) ) {
383387
// not a basic type, so something we can attempt

hibernate-core/src/test/java/org/hibernate/orm/test/hql/SingleSelectionArrayResultTest.java

Lines changed: 118 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,81 +4,144 @@
44
*/
55
package org.hibernate.orm.test.hql;
66

7+
import java.util.stream.Stream;
8+
9+
import org.hibernate.dialect.H2Dialect;
10+
import org.hibernate.dialect.PostgreSQLDialect;
11+
import org.hibernate.query.NativeQuery;
12+
import org.hibernate.query.Query;
13+
import org.hibernate.query.SelectionQuery;
14+
715
import org.hibernate.testing.orm.domain.gambit.BasicEntity;
816
import org.hibernate.testing.orm.junit.DomainModel;
917
import org.hibernate.testing.orm.junit.Jira;
18+
import org.hibernate.testing.orm.junit.RequiresDialect;
19+
import org.hibernate.testing.orm.junit.RequiresDialects;
1020
import org.hibernate.testing.orm.junit.SessionFactory;
1121
import org.hibernate.testing.orm.junit.SessionFactoryScope;
1222
import org.junit.jupiter.api.AfterAll;
1323
import org.junit.jupiter.api.BeforeAll;
14-
import org.junit.jupiter.api.Test;
24+
import org.junit.jupiter.api.extension.ExtensionContext;
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.Arguments;
27+
import org.junit.jupiter.params.provider.ArgumentsProvider;
28+
import org.junit.jupiter.params.provider.ArgumentsSource;
1529

1630
import static org.assertj.core.api.Assertions.assertThat;
1731

1832
/**
1933
* @author Marco Belladelli
2034
*/
21-
@DomainModel( annotatedClasses = BasicEntity.class )
35+
@DomainModel(annotatedClasses = BasicEntity.class)
2236
@SessionFactory
23-
@Jira( "https://hibernate.atlassian.net/browse/HHH-18450" )
37+
@Jira("https://hibernate.atlassian.net/browse/HHH-18450")
38+
@Jira("https://hibernate.atlassian.net/browse/HHH-19472")
39+
@RequiresDialects({@RequiresDialect(H2Dialect.class), @RequiresDialect(PostgreSQLDialect.class)})
2440
public class SingleSelectionArrayResultTest {
25-
@Test
26-
public void testArrayResult(SessionFactoryScope scope) {
41+
42+
static class TestArguments implements ArgumentsProvider {
43+
@Override
44+
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
45+
return Stream.of(
46+
Arguments.of( "select 1", null, null ),
47+
Arguments.of( "select cast(1 as integer)", null, null ),
48+
Arguments.of( "select id from BasicEntity", null, null ),
49+
Arguments.of( "select cast(id as integer) from BasicEntity", null, null ),
50+
Arguments.of( "select ?1", 1, 1 ),
51+
Arguments.of( "select :p1", "p1", 1 ),
52+
Arguments.of( "select cast(?1 as integer)", 1, 1 ),
53+
Arguments.of( "select cast(:p1 as integer)", "p1", 1 )
54+
);
55+
}
56+
}
57+
58+
@ParameterizedTest
59+
@ArgumentsSource(TestArguments.class)
60+
public void testQueryObjectResult(String ql, Object arg1, Object arg2, SessionFactoryScope scope) {
61+
scope.inTransaction( session -> {
62+
Query<Object> query = session.createQuery( ql, Object.class );
63+
if ( arg1 instanceof Integer ) {
64+
query.setParameter( (Integer) arg1, arg2 );
65+
}
66+
if ( arg1 instanceof String ) {
67+
query.setParameter( (String) arg1, arg2 );
68+
}
69+
assertThat( query.getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
70+
} );
71+
}
72+
73+
@ParameterizedTest
74+
@ArgumentsSource(TestArguments.class)
75+
public void testNativeQueryObjectResult(String ql, Object arg1, Object arg2, SessionFactoryScope scope) {
76+
scope.inTransaction( session -> {
77+
NativeQuery<Object> query = session.createNativeQuery( ql, Object.class );
78+
if ( arg1 instanceof Integer ) {
79+
query.setParameter( (Integer) arg1, arg2 );
80+
}
81+
if ( arg1 instanceof String ) {
82+
query.setParameter( (String) arg1, arg2 );
83+
}
84+
assertThat( query.getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
85+
} );
86+
}
87+
88+
@ParameterizedTest
89+
@ArgumentsSource(TestArguments.class)
90+
public void testSelectionQueryObjectResult(String ql, Object arg1, Object arg2, SessionFactoryScope scope) {
91+
scope.inTransaction( session -> {
92+
SelectionQuery<Object> query = session.createSelectionQuery( ql, Object.class );
93+
if ( arg1 instanceof Integer ) {
94+
query.setParameter( (Integer) arg1, arg2 );
95+
}
96+
if ( arg1 instanceof String ) {
97+
query.setParameter( (String) arg1, arg2 );
98+
}
99+
assertThat( query.getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
100+
} );
101+
}
102+
103+
@ParameterizedTest
104+
@ArgumentsSource(TestArguments.class)
105+
public void testQueryArrayResult(String ql, Object arg1, Object arg2, SessionFactoryScope scope) {
106+
scope.inTransaction( session -> {
107+
Query<Object[]> query = session.createQuery( ql, Object[].class );
108+
if ( arg1 instanceof Integer ) {
109+
query.setParameter( (Integer) arg1, arg2 );
110+
}
111+
if ( arg1 instanceof String ) {
112+
query.setParameter( (String) arg1, arg2 );
113+
}
114+
assertThat( query.getSingleResult() ).containsExactly( 1 );
115+
} );
116+
}
117+
118+
@ParameterizedTest
119+
@ArgumentsSource(TestArguments.class)
120+
public void testNativeQueryArrayResult(String ql, Object arg1, Object arg2, SessionFactoryScope scope) {
27121
scope.inTransaction( session -> {
28-
assertThat( session.createQuery(
29-
"select 1",
30-
Object[].class
31-
).getSingleResult() ).containsExactly( 1 );
32-
assertThat( session.createQuery(
33-
"select cast(1 as integer)",
34-
Object[].class
35-
).getSingleResult() ).containsExactly( 1 );
36-
assertThat( session.createSelectionQuery(
37-
"select id from BasicEntity",
38-
Object[].class
39-
).getSingleResult() ).containsExactly( 1 );
40-
assertThat( session.createSelectionQuery(
41-
"select cast(id as integer) from BasicEntity",
42-
Object[].class
43-
).getSingleResult() ).containsExactly( 1 );
44-
assertThat( session.createSelectionQuery(
45-
"select ?1",
46-
Object[].class
47-
).setParameter( 1, 1 ).getSingleResult() ).containsExactly( 1 );
48-
assertThat( session.createQuery(
49-
"select cast(:p1 as integer)",
50-
Object[].class
51-
).setParameter( "p1", 1 ).getSingleResult() ).containsExactly( 1 );
122+
NativeQuery<Object[]> query = session.createNativeQuery( ql, Object[].class );
123+
if ( arg1 instanceof Integer ) {
124+
query.setParameter( (Integer) arg1, arg2 );
125+
}
126+
if ( arg1 instanceof String ) {
127+
query.setParameter( (String) arg1, arg2 );
128+
}
129+
assertThat( query.getSingleResult() ).containsExactly( 1 );
52130
} );
53131
}
54132

55-
@Test
56-
public void testNormalResult(SessionFactoryScope scope) {
133+
@ParameterizedTest
134+
@ArgumentsSource(TestArguments.class)
135+
public void testSelectionQueryArrayResult(String ql, Object arg1, Object arg2, SessionFactoryScope scope) {
57136
scope.inTransaction( session -> {
58-
assertThat( session.createQuery(
59-
"select 1",
60-
Object.class
61-
).getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
62-
assertThat( session.createQuery(
63-
"select cast(1 as integer)",
64-
Object.class
65-
).getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
66-
assertThat( session.createSelectionQuery(
67-
"select id from BasicEntity",
68-
Object.class
69-
).getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
70-
assertThat( session.createSelectionQuery(
71-
"select cast(id as integer) from BasicEntity",
72-
Object.class
73-
).getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
74-
assertThat( session.createSelectionQuery(
75-
"select ?1",
76-
Object.class
77-
).setParameter( 1, 1 ).getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
78-
assertThat( session.createQuery(
79-
"select cast(:p1 as integer)",
80-
Object.class
81-
).setParameter( "p1", 1 ).getSingleResult() ).isInstanceOf( Integer.class ).isEqualTo( 1 );
137+
SelectionQuery<Object[]> query = session.createSelectionQuery( ql, Object[].class );
138+
if ( arg1 instanceof Integer ) {
139+
query.setParameter( (Integer) arg1, arg2 );
140+
}
141+
if ( arg1 instanceof String ) {
142+
query.setParameter( (String) arg1, arg2 );
143+
}
144+
assertThat( query.getSingleResult() ).containsExactly( 1 );
82145
} );
83146
}
84147

0 commit comments

Comments
 (0)