Skip to content

Commit d5d0d36

Browse files
committed
[#2055] Add test for Setting hibernate.query.mutation_strategy.global_temporary.create_tables to false has no effect
1 parent df10ff7 commit d5d0d36

File tree

3 files changed

+333
-0
lines changed

3 files changed

+333
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.schema;
7+
8+
import java.util.List;
9+
import java.util.concurrent.CompletionStage;
10+
import java.util.function.Consumer;
11+
12+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
13+
import org.hibernate.cfg.Configuration;
14+
import org.hibernate.dialect.Dialect;
15+
import org.hibernate.dialect.temptable.TemporaryTable;
16+
import org.hibernate.reactive.BaseReactiveTest;
17+
import org.hibernate.reactive.provider.Settings;
18+
import org.hibernate.reactive.testing.SqlStatementTracker;
19+
import org.hibernate.reactive.util.impl.CompletionStages;
20+
21+
import org.junit.jupiter.api.AfterEach;
22+
23+
import io.vertx.junit5.VertxTestContext;
24+
import jakarta.persistence.Entity;
25+
import jakarta.persistence.GeneratedValue;
26+
import jakarta.persistence.Id;
27+
import jakarta.persistence.Inheritance;
28+
import jakarta.persistence.InheritanceType;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
32+
33+
public abstract class AbstractTemporaryTableTest extends BaseReactiveTest {
34+
private static SqlStatementTracker sqlStatementTracker;
35+
36+
final static Dialect[] dialect = new Dialect[1];
37+
38+
@FunctionalInterface
39+
protected interface CheckTemporaryTableCommandExecution {
40+
void check();
41+
}
42+
43+
@Override
44+
public void before(VertxTestContext context) {
45+
}
46+
47+
@AfterEach
48+
@Override
49+
public void after(VertxTestContext context) {
50+
sqlStatementTracker.clear();
51+
super.after( context );
52+
}
53+
54+
@Override
55+
public CompletionStage<Void> deleteEntities(Class<?>... entities) {
56+
return voidFuture();
57+
}
58+
59+
@Override
60+
protected void addServices(StandardServiceRegistryBuilder builder) {
61+
if ( sqlStatementTracker != null ) {
62+
sqlStatementTracker.registerService( builder );
63+
}
64+
}
65+
66+
protected void testTemporaryTableCreation(
67+
Consumer<Configuration> configure,
68+
CheckTemporaryTableCommandExecution temporaryTableCreationCheck,
69+
CheckTemporaryTableCommandExecution temporaryTableDopCheck,
70+
VertxTestContext context) {
71+
test( context, setupSessionFactory( constructConfiguration( configure ) )
72+
.thenCompose( v -> getSessionFactory().withSession( s -> {
73+
dialect[0] = getDialect();
74+
temporaryTableCreationCheck.check();
75+
sqlStatementTracker.clear();
76+
return voidFuture();
77+
} ) )
78+
// to ensure the factory is always closed even in case of exceptions
79+
.handle( CompletionStages::handle )
80+
.thenCompose( handler -> factoryManager.stop()
81+
.handle( CompletionStages::handle )
82+
// returns the exception thrown before the factory was stopped (if there was one)
83+
.thenCompose( unused -> handler.getResultAsCompletionStage() )
84+
.thenAccept( v -> {
85+
temporaryTableDopCheck.check();
86+
} )
87+
)
88+
);
89+
}
90+
91+
private Configuration constructConfiguration(Consumer<Configuration> configure) {
92+
Configuration configuration = super.constructConfiguration();
93+
configuration.setProperty( Settings.HBM2DDL_AUTO, "create" );
94+
configuration.addAnnotatedClass( Engineer.class );
95+
configuration.addAnnotatedClass( Doctor.class );
96+
configuration.addAnnotatedClass( Person.class );
97+
98+
sqlStatementTracker = new SqlStatementTracker(
99+
AbstractTemporaryTableTest::filter,
100+
configuration.getProperties()
101+
);
102+
103+
configure.accept( configuration );
104+
return configuration;
105+
}
106+
107+
protected static void assertNumberOfTemporaryTableCreated(int expectedNumberOfCreatedTable, String errorMessage) {
108+
assertThat( getNumberOfCommandExecuted( dialect[0].getTemporaryTableCreateCommand() ) )
109+
.as( errorMessage )
110+
.isEqualTo( expectedNumberOfCreatedTable );
111+
}
112+
113+
protected static void assertNumberOfTemporaryTableDropped(int expectedNumberOfCreatedTable, String errorMessage) {
114+
assertThat( getNumberOfCommandExecuted( dialect[0].getTemporaryTableDropCommand() ) )
115+
.as( errorMessage )
116+
.isEqualTo( expectedNumberOfCreatedTable );
117+
}
118+
119+
private static long getNumberOfCommandExecuted(String temporaryTableCommand) {
120+
List<String> loggedQueries = sqlStatementTracker.getLoggedQueries();
121+
return loggedQueries.stream().filter( q -> q.contains( temporaryTableCommand ) && q.contains( TemporaryTable.ID_TABLE_PREFIX )).count();
122+
}
123+
124+
private static boolean filter(String s) {
125+
String[] accepted = { "create", "drop" };
126+
for ( String valid : accepted ) {
127+
if ( s.toLowerCase().startsWith( valid ) ) {
128+
return true;
129+
}
130+
}
131+
return false;
132+
}
133+
134+
@Entity(name = "Person")
135+
@Inheritance(strategy = InheritanceType.JOINED)
136+
public static class Person {
137+
138+
@Id
139+
@GeneratedValue
140+
private Long id;
141+
142+
private String name;
143+
144+
private boolean employed;
145+
146+
public Long getId() {
147+
return id;
148+
}
149+
150+
public void setId(Long id) {
151+
this.id = id;
152+
}
153+
154+
public String getName() {
155+
return name;
156+
}
157+
158+
public void setName(String name) {
159+
this.name = name;
160+
}
161+
162+
public boolean isEmployed() {
163+
return employed;
164+
}
165+
166+
public void setEmployed(boolean employed) {
167+
this.employed = employed;
168+
}
169+
}
170+
171+
@Entity(name = "Doctor")
172+
public static class Doctor extends Person {
173+
}
174+
175+
@Entity(name = "Engineer")
176+
public static class Engineer extends Person {
177+
178+
private boolean fellow;
179+
180+
public boolean isFellow() {
181+
return fellow;
182+
}
183+
184+
public void setFellow(boolean fellow) {
185+
this.fellow = fellow;
186+
}
187+
}
188+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.schema;
7+
8+
9+
import java.util.function.Consumer;
10+
import java.util.stream.Stream;
11+
12+
import org.hibernate.cfg.Configuration;
13+
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableStrategy;
14+
import org.hibernate.reactive.annotations.EnabledFor;
15+
import org.hibernate.reactive.containers.DatabaseConfiguration;
16+
17+
import org.junit.jupiter.params.ParameterizedTest;
18+
import org.junit.jupiter.params.provider.Arguments;
19+
import org.junit.jupiter.params.provider.MethodSource;
20+
21+
import io.vertx.junit5.Timeout;
22+
import io.vertx.junit5.VertxTestContext;
23+
24+
import static java.util.concurrent.TimeUnit.MINUTES;
25+
import static org.junit.jupiter.params.provider.Arguments.arguments;
26+
27+
@Timeout(value = 10, timeUnit = MINUTES)
28+
@EnabledFor(value = DatabaseConfiguration.DBType.ORACLE, reason = "It uses GlobalTemporaryTableStrategy by default")
29+
public class GlobalTemporaryTableTest extends AbstractTemporaryTableTest {
30+
31+
public static Stream<Arguments> settings() {
32+
return Stream.of(
33+
arguments(
34+
(Consumer<Configuration>) (Configuration configuration) -> {
35+
configuration.setProperty( GlobalTemporaryTableStrategy.CREATE_ID_TABLES, "true" );
36+
configuration.setProperty( GlobalTemporaryTableStrategy.DROP_ID_TABLES, "true" );
37+
},
38+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableCreated(
39+
1,
40+
"Temporary table has not been created even if CREATE_ID_TABLES is true"
41+
),
42+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableDropped(
43+
1,
44+
"Temporary table has not been dropped even if DROP_ID_TABLES is true"
45+
)
46+
),
47+
arguments(
48+
(Consumer<Configuration>) (Configuration configuration) -> {
49+
configuration.setProperty( GlobalTemporaryTableStrategy.CREATE_ID_TABLES, "false" );
50+
configuration.setProperty( GlobalTemporaryTableStrategy.DROP_ID_TABLES, "false" );
51+
},
52+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableCreated(
53+
0,
54+
"Temporary table has been created even if CREATE_ID_TABLES is false"
55+
),
56+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableDropped(
57+
0,
58+
"Temporary table has been dropped even if DROP_ID_TABLES is false"
59+
)
60+
)
61+
);
62+
}
63+
64+
@ParameterizedTest
65+
@MethodSource("settings")
66+
public void testGlobalTemporaryTableCreation(
67+
Consumer<Configuration> configure,
68+
CheckTemporaryTableCommandExecution temporaryTableCreationCheck,
69+
CheckTemporaryTableCommandExecution temporaryTableDopCheck,
70+
VertxTestContext context) {
71+
testTemporaryTableCreation( configure, temporaryTableCreationCheck, temporaryTableDopCheck, context );
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.schema;
7+
8+
import java.util.function.Consumer;
9+
import java.util.stream.Stream;
10+
11+
import org.hibernate.cfg.Configuration;
12+
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy;
13+
import org.hibernate.reactive.annotations.EnabledFor;
14+
import org.hibernate.reactive.containers.DatabaseConfiguration;
15+
16+
import org.junit.jupiter.params.ParameterizedTest;
17+
import org.junit.jupiter.params.provider.Arguments;
18+
import org.junit.jupiter.params.provider.MethodSource;
19+
20+
import io.vertx.junit5.Timeout;
21+
import io.vertx.junit5.VertxTestContext;
22+
23+
import static java.util.concurrent.TimeUnit.MINUTES;
24+
import static org.junit.jupiter.params.provider.Arguments.arguments;
25+
26+
@Timeout(value = 10, timeUnit = MINUTES)
27+
@EnabledFor(value = DatabaseConfiguration.DBType.COCKROACHDB, reason = "It uses PersistentTemporaryTableStrategy by default")
28+
public class PersistentTemporaryTableTest extends AbstractTemporaryTableTest {
29+
30+
public static Stream<Arguments> settings() {
31+
return Stream.of(
32+
arguments(
33+
(Consumer<Configuration>) (Configuration configuration) -> {
34+
configuration.setProperty( PersistentTableStrategy.CREATE_ID_TABLES, "true" );
35+
configuration.setProperty( PersistentTableStrategy.DROP_ID_TABLES, "true" );
36+
},
37+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableCreated(
38+
1,
39+
"Temporary table has not been created even if CREATE_ID_TABLES is true"
40+
),
41+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableDropped(
42+
1,
43+
"Temporary table has not been dropped even if DROP_ID_TABLES is true"
44+
)
45+
),
46+
arguments(
47+
(Consumer<Configuration>) (Configuration configuration) -> {
48+
configuration.setProperty( PersistentTableStrategy.CREATE_ID_TABLES, "false" );
49+
configuration.setProperty( PersistentTableStrategy.DROP_ID_TABLES, "false" );
50+
},
51+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableCreated(
52+
0,
53+
"Temporary table has been created even if CREATE_ID_TABLES is false"
54+
),
55+
(CheckTemporaryTableCommandExecution) () -> assertNumberOfTemporaryTableDropped(
56+
0,
57+
"Temporary table has been dropped even if DROP_ID_TABLES is false"
58+
)
59+
)
60+
);
61+
}
62+
63+
@ParameterizedTest
64+
@MethodSource("settings")
65+
public void testPersistentTemporaryTableCreation(
66+
Consumer<Configuration> configure,
67+
CheckTemporaryTableCommandExecution temporaryTableCreationCheck,
68+
CheckTemporaryTableCommandExecution temporaryTableDopCheck,
69+
VertxTestContext context) {
70+
testTemporaryTableCreation( configure, temporaryTableCreationCheck, temporaryTableDopCheck, context );
71+
}
72+
}

0 commit comments

Comments
 (0)