Skip to content

Commit 1e04a1d

Browse files
committed
[hibernate#929] Draft - Initial changes for H2 db support
1 parent 8b319a1 commit 1e04a1d

File tree

7 files changed

+210
-2
lines changed

7 files changed

+210
-2
lines changed

hibernate-reactive-core/build.gradle

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ dependencies {
2626

2727
//Specific implementation details of Hibernate Reactive:
2828
implementation "io.vertx:vertx-sql-client:${vertxVersion}"
29+
implementation 'io.agroal:agroal-api:1.12'
30+
implementation 'io.agroal:agroal-pool:1.12'
31+
implementation "io.vertx:vertx-jdbc-client:${vertxVersion}"
2932

3033
// Testing
3134
testImplementation 'org.assertj:assertj-core:3.20.2'
@@ -65,6 +68,8 @@ dependencies {
6568
testImplementation "org.testcontainers:cockroachdb:${testcontainersVersion}"
6669
testImplementation "org.testcontainers:mssqlserver:${testcontainersVersion}"
6770
testImplementation "org.testcontainers:oracle-xe:${testcontainersVersion}"
71+
72+
testImplementation "com.h2database:h2:2.1.210"
6873
}
6974

7075
// Print a summary of the results of the tests (number of failures, successes and skipped)

hibernate-reactive-core/src/main/java/org/hibernate/reactive/pool/impl/DefaultSqlClientPoolConfiguration.java

+7
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ public PoolOptions poolOptions() {
9292
@Override
9393
public SqlConnectOptions connectOptions(URI uri) {
9494
String scheme = uri.getScheme();
95+
if( scheme.equalsIgnoreCase( "h2" )) {
96+
return new SqlConnectOptions()
97+
// username
98+
.setUser("sa")
99+
// password
100+
.setPassword("");
101+
}
95102
String path = scheme.equals( "oracle" )
96103
? oraclePath( uri )
97104
: uri.getPath();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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.pool.impl;
7+
8+
9+
import java.net.URI;
10+
import java.util.concurrent.CompletionStage;
11+
12+
import org.hibernate.engine.jdbc.spi.JdbcServices;
13+
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
14+
import org.hibernate.reactive.pool.ReactiveConnection;
15+
import org.hibernate.reactive.vertx.VertxInstance;
16+
import org.hibernate.service.spi.ServiceRegistryAwareService;
17+
import org.hibernate.service.spi.ServiceRegistryImplementor;
18+
19+
import io.vertx.core.Future;
20+
import io.vertx.core.Vertx;
21+
import io.vertx.jdbcclient.JDBCConnectOptions;
22+
import io.vertx.jdbcclient.JDBCPool;
23+
import io.vertx.sqlclient.Pool;
24+
import io.vertx.sqlclient.PoolOptions;
25+
import io.vertx.sqlclient.SqlConnectOptions;
26+
import io.vertx.sqlclient.SqlConnection;
27+
28+
public class H2SqlClientPool extends SqlClientPool implements ServiceRegistryAwareService {
29+
30+
//Asynchronous shutdown promise: we can't return it from #close as we implement a
31+
//blocking interface.
32+
private volatile Future<Void> closeFuture = Future.succeededFuture();
33+
34+
private Pool pools;
35+
private URI uri;
36+
private SqlStatementLogger sqlStatementLogger;
37+
private ServiceRegistryImplementor serviceRegistry;
38+
39+
public H2SqlClientPool() {
40+
}
41+
42+
@Override
43+
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
44+
this.serviceRegistry = serviceRegistry;
45+
sqlStatementLogger = serviceRegistry.getService( JdbcServices.class ).getSqlStatementLogger();
46+
}
47+
48+
public void start() {
49+
if ( pools == null ) {
50+
pools = createPool( uri );
51+
}
52+
}
53+
54+
public void stop() {
55+
if ( pools != null ) {
56+
this.closeFuture = pools.close();
57+
}
58+
}
59+
60+
private Pool createPool(URI uri) {
61+
SqlClientPoolConfiguration configuration = serviceRegistry.getService( SqlClientPoolConfiguration.class );
62+
VertxInstance vertx = serviceRegistry.getService( VertxInstance.class );
63+
64+
return createPool( uri, configuration.connectOptions( uri ), configuration.poolOptions(), vertx.getVertx() );
65+
}
66+
67+
private Pool createPool(URI uri, SqlConnectOptions connectOptions, PoolOptions poolOptions, Vertx vertx) {
68+
JDBCConnectOptions jdbcOptions = new JDBCConnectOptions();
69+
jdbcOptions.setUser( connectOptions.getUser() );
70+
jdbcOptions.setJdbcUrl( "jdbc:" + uri.toString() );
71+
JDBCPool pool = JDBCPool.pool( vertx, jdbcOptions, poolOptions );
72+
73+
return pool;
74+
}
75+
76+
@Override
77+
protected Pool getPool() {
78+
return pools;
79+
}
80+
81+
@Override
82+
protected SqlStatementLogger getSqlStatementLogger() {
83+
return sqlStatementLogger;
84+
}
85+
86+
@Override
87+
public CompletionStage<Void> getCloseFuture() {
88+
return closeFuture.toCompletionStage();
89+
}
90+
91+
@Override
92+
public CompletionStage<ReactiveConnection> getConnection() {
93+
return getConnectionFromPool( getPool() );
94+
}
95+
96+
@Override
97+
public CompletionStage<ReactiveConnection> getConnection(String tenantId) {
98+
return getConnectionFromPool( getTenantPool( tenantId ) );
99+
}
100+
101+
private CompletionStage<ReactiveConnection> getConnectionFromPool(Pool pool) {
102+
start();
103+
return pool.getConnection().toCompletionStage().thenApply( this::newConnection );
104+
}
105+
106+
private SqlClientConnection newConnection(SqlConnection connection) {
107+
return new SqlClientConnection( connection, getPool(), getSqlStatementLogger() );
108+
}
109+
}

hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/NoJdbcEnvironmentInitiator.java

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.hibernate.dialect.CockroachDB201Dialect;
1010
import org.hibernate.dialect.DB297Dialect;
1111
import org.hibernate.dialect.Dialect;
12+
import org.hibernate.dialect.H2Dialect;
1213
import org.hibernate.dialect.MariaDB103Dialect;
1314
import org.hibernate.dialect.MySQL8Dialect;
1415
import org.hibernate.dialect.Oracle12cDialect;
@@ -147,6 +148,9 @@ else if ( url.startsWith( "sqlserver:" ) ) {
147148
else if ( url.startsWith( "oracle:" ) ) {
148149
return Oracle12cDialect.class;
149150
}
151+
else if ( url.startsWith( "h2:" ) ) {
152+
return H2Dialect.class;
153+
}
150154
else {
151155
return null;
152156
}

hibernate-reactive-core/src/test/java/org/hibernate/reactive/BaseReactiveTest.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,15 @@
1616
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
1717
import org.hibernate.cfg.Configuration;
1818
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
19+
import org.hibernate.engine.jdbc.internal.JdbcServicesImpl;
20+
import org.hibernate.engine.jdbc.spi.JdbcServices;
21+
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
1922
import org.hibernate.reactive.containers.DatabaseConfiguration;
2023
import org.hibernate.reactive.containers.DatabaseConfiguration.DBType;
2124
import org.hibernate.reactive.mutiny.Mutiny;
2225
import org.hibernate.reactive.pool.ReactiveConnection;
26+
import org.hibernate.reactive.pool.ReactiveConnectionPool;
27+
import org.hibernate.reactive.pool.impl.H2SqlClientPool;
2328
import org.hibernate.reactive.provider.ReactiveServiceRegistryBuilder;
2429
import org.hibernate.reactive.provider.Settings;
2530
import org.hibernate.reactive.provider.service.ReactiveGenerationTarget;
@@ -123,6 +128,10 @@ protected Configuration constructConfiguration() {
123128
if ( DatabaseConfiguration.dbType() == DBType.DB2 && !doneTablespace ) {
124129
configuration.setProperty(Settings.HBM2DDL_IMPORT_FILES, "/db2.sql");
125130
doneTablespace = true;
131+
} else if ( DatabaseConfiguration.dbType() == DBType.H2 ) {
132+
configuration.setProperty(Settings.URL, "jdbc:h2:~/test");
133+
} else {
134+
configuration.setProperty( Settings.URL, DatabaseConfiguration.getJdbcUrl() );
126135
}
127136
//Use JAVA_TOOL_OPTIONS='-Dhibernate.show_sql=true'
128137
configuration.setProperty( Settings.SHOW_SQL, System.getProperty(Settings.SHOW_SQL, "false") );
@@ -195,7 +204,17 @@ private SessionFactory createHibernateSessionFactory(Configuration configuration
195204
return configuration.buildSessionFactory( registry );
196205
}
197206

198-
protected void addServices(StandardServiceRegistryBuilder builder) {}
207+
protected void addServices(StandardServiceRegistryBuilder builder) {
208+
if(dbType() == DBType.H2 ) {
209+
builder.addService( ReactiveConnectionPool.class, new H2SqlClientPool() );
210+
builder.addService( JdbcServices.class, new JdbcServicesImpl() {
211+
@Override
212+
public SqlStatementLogger getSqlStatementLogger() {
213+
return new SqlStatementLogger();
214+
}
215+
} );
216+
}
217+
}
199218

200219
/*
201220
* MySQL doesn't implement 'drop table cascade constraints'.

hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DatabaseConfiguration.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public enum DBType {
2525
POSTGRESQL( PostgreSQLDatabase.INSTANCE, 5432, "POSTGRES", "PG" ),
2626
COCKROACHDB( CockroachDBDatabase.INSTANCE, 26257, "COCKROACH" ),
2727
SQLSERVER( MSSQLServerDatabase.INSTANCE, 1433, "MSSQL", "MSSQLSERVER" ),
28-
ORACLE( OracleDatabase.INSTANCE, 1521 );
28+
ORACLE( OracleDatabase.INSTANCE, 1521 ),
29+
H2( H2Database.INSTANCE, -1 );
2930

3031
private final TestableDatabase configuration;
3132
private final int defaultPort;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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.containers;
7+
8+
9+
import java.util.Map;
10+
11+
12+
public class H2Database implements TestableDatabase {
13+
public static H2Database INSTANCE = new H2Database();
14+
15+
private String getRegularJdbcUrl() {
16+
return "jdbc:h2:~/test";
17+
}
18+
19+
@Override
20+
public String getJdbcUrl() {
21+
return getRegularJdbcUrl();
22+
}
23+
24+
@Override
25+
public String getUri() {
26+
{
27+
return "h2:~/test";
28+
}
29+
}
30+
31+
@Override
32+
public String getScheme() {
33+
return "h2";
34+
}
35+
36+
@Override
37+
public String getNativeDatatypeQuery(String tableName, String columnName) {
38+
throw new UnsupportedOperationException();
39+
}
40+
41+
@Override
42+
public String getExpectedNativeDatatype(Class<?> dataType) {
43+
return null;
44+
}
45+
46+
@Override
47+
public String createJdbcUrl(String host, int port, String database, Map<String, String> params) {
48+
return getRegularJdbcUrl();
49+
}
50+
51+
@Override
52+
public String jdbcStartQuery() {
53+
throw new UnsupportedOperationException();
54+
}
55+
56+
@Override
57+
public String jdbcParamDelimiter() {
58+
throw new UnsupportedOperationException();
59+
}
60+
61+
private H2Database() {
62+
}
63+
}

0 commit comments

Comments
 (0)