Skip to content

Commit 9135f69

Browse files
committed
HHH-14433 Add possibility to drop local temporary tables to enable connection pooling in tests
1 parent 08d9fe1 commit 9135f69

File tree

5 files changed

+192
-8
lines changed

5 files changed

+192
-8
lines changed

documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ Provide a custom https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javado
551551
`*hibernate.hql.bulk_id_strategy.global_temporary.drop_tables*` (e.g. `true` or `false` (default value))::
552552
For databases that don't support local tables, but just global ones, this configuration property allows you to DROP the global tables used for multi-table bulk HQL operations when the `SessionFactory` or the `EntityManagerFactory` is closed.
553553

554+
`*hibernate.hql.bulk_id_strategy.local_temporary.drop_tables*` (e.g. `true` or `false` (default value))::
555+
This configuration property allows you to DROP the local temporary tables used for multi-table bulk HQL operations when the `SessionFactory` or the `EntityManagerFactory` is closed. This is useful when testing with a single connection pool against different schemas.
556+
554557
`*hibernate.hql.bulk_id_strategy.persistent.drop_tables*` (e.g. `true` or `false` (default value))::
555558
This configuration property is used by the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.html[`PersistentTableBulkIdStrategy`], that mimics temporary tables for databases which do not support temporary tables.
556559
It follows a pattern similar to the ANSI SQL definition of the global temporary table using a "session id" column to segment rows from the various sessions.

hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,22 @@
1212
import java.util.Iterator;
1313
import java.util.List;
1414

15+
import org.hibernate.dialect.Dialect;
1516
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
1617
import org.hibernate.engine.jdbc.spi.JdbcServices;
18+
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
19+
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
1720
import org.hibernate.mapping.JoinedSubclass;
1821
import org.hibernate.mapping.PersistentClass;
1922
import org.hibernate.mapping.RootClass;
2023
import org.hibernate.mapping.Subclass;
2124
import org.hibernate.mapping.UnionSubclass;
25+
import org.hibernate.resource.transaction.spi.DdlTransactionIsolator;
26+
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
27+
import org.hibernate.service.ServiceRegistry;
28+
import org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase;
29+
import org.hibernate.tool.schema.internal.exec.JdbcContext;
30+
import org.hibernate.tool.schema.spi.CommandAcceptanceException;
2231

2332
import org.jboss.logging.Logger;
2433

@@ -113,7 +122,7 @@ public void executeIdTableDropStatements(
113122
String[] dropStatements,
114123
JdbcServices jdbcServices,
115124
JdbcConnectionAccess connectionAccess) {
116-
if ( dropStatements == null ) {
125+
if ( dropStatements == null || dropStatements.length == 0 ) {
117126
return;
118127
}
119128

@@ -154,4 +163,100 @@ public void executeIdTableDropStatements(
154163
}
155164
}
156165

166+
public void executeIdTableCreationStatements(
167+
List<String> creationStatements,
168+
JdbcServices jdbcServices,
169+
JdbcConnectionAccess connectionAccess,
170+
ServiceRegistry serviceRegistry) {
171+
if ( creationStatements == null || creationStatements.isEmpty() ) {
172+
return;
173+
}
174+
final GenerationTargetToDatabase target = new GenerationTargetToDatabase(
175+
getDdlTransactionIsolator(
176+
jdbcServices,
177+
connectionAccess,
178+
serviceRegistry
179+
)
180+
);
181+
try {
182+
for ( String createStatement : creationStatements ) {
183+
try {
184+
target.accept( createStatement );
185+
}
186+
catch ( CommandAcceptanceException e) {
187+
// The exception will be logged, so ignore this
188+
}
189+
}
190+
}
191+
finally {
192+
target.release();
193+
}
194+
}
195+
196+
public void executeIdTableDropStatements(
197+
String[] dropStatements,
198+
JdbcServices jdbcServices,
199+
JdbcConnectionAccess connectionAccess,
200+
ServiceRegistry serviceRegistry) {
201+
if ( dropStatements == null || dropStatements.length == 0 ) {
202+
return;
203+
}
204+
205+
final GenerationTargetToDatabase target = new GenerationTargetToDatabase(
206+
getDdlTransactionIsolator(
207+
jdbcServices,
208+
connectionAccess,
209+
serviceRegistry
210+
)
211+
);
212+
try {
213+
for ( String dropStatement : dropStatements ) {
214+
try {
215+
target.accept( dropStatement );
216+
}
217+
catch ( CommandAcceptanceException e) {
218+
// The exception will be logged, so ignore this
219+
}
220+
}
221+
}
222+
finally {
223+
target.release();
224+
}
225+
}
226+
227+
public DdlTransactionIsolator getDdlTransactionIsolator(
228+
JdbcServices jdbcServices,
229+
JdbcConnectionAccess connectionAccess,
230+
ServiceRegistry serviceRegistry) {
231+
return serviceRegistry.getService( TransactionCoordinatorBuilder.class ).buildDdlTransactionIsolator(
232+
new JdbcContext() {
233+
234+
@Override
235+
public JdbcConnectionAccess getJdbcConnectionAccess() {
236+
return connectionAccess;
237+
}
238+
239+
@Override
240+
public Dialect getDialect() {
241+
return jdbcServices.getJdbcEnvironment().getDialect();
242+
}
243+
244+
@Override
245+
public SqlStatementLogger getSqlStatementLogger() {
246+
return jdbcServices.getSqlStatementLogger();
247+
}
248+
249+
@Override
250+
public SqlExceptionHelper getSqlExceptionHelper() {
251+
return jdbcServices.getSqlExceptionHelper();
252+
}
253+
254+
@Override
255+
public ServiceRegistry getServiceRegistry() {
256+
return serviceRegistry;
257+
}
258+
}
259+
);
260+
}
261+
157262
}

hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.hibernate.mapping.PersistentClass;
3434
import org.hibernate.mapping.Table;
3535
import org.hibernate.persister.entity.Queryable;
36+
import org.hibernate.service.ServiceRegistry;
3637

3738
/**
3839
* Strategy based on ANSI SQL's definition of a "global temporary table".
@@ -48,6 +49,7 @@ public class GlobalTemporaryTableBulkIdStrategy
4849

4950
private final AfterUseAction afterUseAction;
5051

52+
private ServiceRegistry serviceRegistry;
5153
private boolean dropIdTables;
5254
private String[] dropTableStatements;
5355

@@ -125,7 +127,8 @@ protected void finishPreparation(
125127
IdTableHelper.INSTANCE.executeIdTableCreationStatements(
126128
context.creationStatements,
127129
jdbcServices,
128-
connectionAccess
130+
connectionAccess,
131+
this.serviceRegistry = metadata.getDatabase().getServiceRegistry()
129132
);
130133

131134
this.dropTableStatements = dropIdTables
@@ -141,7 +144,12 @@ public void release(
141144
return;
142145
}
143146

144-
IdTableHelper.INSTANCE.executeIdTableDropStatements( dropTableStatements, jdbcServices, connectionAccess );
147+
IdTableHelper.INSTANCE.executeIdTableDropStatements(
148+
dropTableStatements,
149+
jdbcServices,
150+
connectionAccess,
151+
serviceRegistry
152+
);
145153
}
146154

147155
@Override

hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
package org.hibernate.hql.spi.id.local;
88

99
import org.hibernate.boot.TempTableDdlTransactionHandling;
10+
import org.hibernate.boot.registry.StandardServiceRegistry;
1011
import org.hibernate.boot.spi.MetadataBuildingOptions;
1112
import org.hibernate.boot.spi.MetadataImplementor;
1213
import org.hibernate.boot.spi.SessionFactoryOptions;
14+
import org.hibernate.engine.config.spi.ConfigurationService;
15+
import org.hibernate.engine.config.spi.StandardConverters;
1316
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
1417
import org.hibernate.engine.jdbc.spi.JdbcServices;
1518
import org.hibernate.engine.spi.SessionFactoryImplementor;
@@ -19,7 +22,7 @@
1922
import org.hibernate.hql.internal.ast.tree.FromElement;
2023
import org.hibernate.hql.internal.ast.tree.UpdateStatement;
2124
import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl;
22-
import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl.PreparationContext;
25+
import org.hibernate.hql.spi.id.IdTableHelper;
2326
import org.hibernate.hql.spi.id.IdTableSupport;
2427
import org.hibernate.hql.spi.id.IdTableSupportStandardImpl;
2528
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
@@ -28,21 +31,27 @@
2831
import org.hibernate.mapping.PersistentClass;
2932
import org.hibernate.mapping.Table;
3033
import org.hibernate.persister.entity.Queryable;
34+
import org.hibernate.service.ServiceRegistry;
3135

3236
/**
3337
* Strategy based on ANSI SQL's definition of a "local temporary table" (local to each db session).
3438
*
3539
* @author Steve Ebersole
3640
*/
3741
public class LocalTemporaryTableBulkIdStrategy
38-
extends AbstractMultiTableBulkIdStrategyImpl<IdTableInfoImpl, PreparationContext>
42+
extends AbstractMultiTableBulkIdStrategyImpl<IdTableInfoImpl, PreparationContextImpl>
3943
implements MultiTableBulkIdStrategy {
4044

45+
public static final String DROP_ID_TABLES = "hibernate.hql.bulk_id_strategy.local_temporary.drop_tables";
4146
public static final String SHORT_NAME = "local_temporary";
4247

4348
private final AfterUseAction afterUseAction;
4449
private TempTableDdlTransactionHandling ddlTransactionHandling;
4550

51+
private ServiceRegistry serviceRegistry;
52+
private boolean dropIdTables;
53+
private String[] dropTableStatements;
54+
4655
public LocalTemporaryTableBulkIdStrategy() {
4756
this(
4857
new IdTableSupportStandardImpl() {
@@ -65,11 +74,35 @@ public LocalTemporaryTableBulkIdStrategy(
6574
this.ddlTransactionHandling = ddlTransactionHandling;
6675
}
6776

77+
@Override
78+
protected PreparationContextImpl buildPreparationContext() {
79+
return new PreparationContextImpl();
80+
}
81+
6882
@Override
6983
protected void initialize(MetadataBuildingOptions buildingOptions, SessionFactoryOptions sessionFactoryOptions) {
7084
if ( ddlTransactionHandling == null ) {
7185
ddlTransactionHandling = sessionFactoryOptions.getTempTableDdlTransactionHandling();
7286
}
87+
final StandardServiceRegistry serviceRegistry = buildingOptions.getServiceRegistry();
88+
final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class );
89+
this.dropIdTables = configService.getSetting(
90+
DROP_ID_TABLES,
91+
StandardConverters.BOOLEAN,
92+
false
93+
);
94+
}
95+
96+
@Override
97+
protected void finishPreparation(
98+
JdbcServices jdbcServices,
99+
JdbcConnectionAccess connectionAccess,
100+
MetadataImplementor metadata,
101+
PreparationContextImpl context) {
102+
this.serviceRegistry = metadata.getDatabase().getServiceRegistry();
103+
this.dropTableStatements = dropIdTables
104+
? context.dropStatements.toArray( new String[ context.dropStatements.size() ] )
105+
: null;
73106
}
74107

75108
@Override
@@ -78,20 +111,33 @@ protected IdTableInfoImpl buildIdTableInfo(
78111
Table idTable,
79112
JdbcServices jdbcServices,
80113
MetadataImplementor metadata,
81-
PreparationContext context) {
114+
PreparationContextImpl context) {
115+
String dropStatement = buildIdTableDropStatement( idTable, jdbcServices );
116+
if ( dropIdTables ) {
117+
context.dropStatements.add( dropStatement );
118+
}
82119
return new IdTableInfoImpl(
83120
jdbcServices.getJdbcEnvironment().getQualifiedObjectNameFormatter().format(
84121
idTable.getQualifiedTableName(),
85122
jdbcServices.getJdbcEnvironment().getDialect()
86123
),
87124
buildIdTableCreateStatement( idTable, jdbcServices, metadata ),
88-
buildIdTableDropStatement( idTable, jdbcServices )
125+
dropStatement
89126
);
90127
}
91128

92129
@Override
93130
public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) {
94-
// nothing to do
131+
if ( ! dropIdTables ) {
132+
return;
133+
}
134+
135+
IdTableHelper.INSTANCE.executeIdTableDropStatements(
136+
dropTableStatements,
137+
jdbcServices,
138+
connectionAccess,
139+
serviceRegistry
140+
);
95141
}
96142

97143
@Override
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.hql.spi.id.local;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
import org.hibernate.hql.spi.id.AbstractMultiTableBulkIdStrategyImpl;
13+
14+
/**
15+
* PreparationContext implementation for GlobalTemporaryTableBulkIdStrategy. Used to collect
16+
* drop statements
17+
*
18+
* @author Steve Ebersole
19+
*/
20+
class PreparationContextImpl implements AbstractMultiTableBulkIdStrategyImpl.PreparationContext {
21+
List<String> dropStatements = new ArrayList<String>();
22+
}

0 commit comments

Comments
 (0)