Skip to content

Commit

Permalink
[hibernate#929] Draft - Initial changes for H2 db support
Browse files Browse the repository at this point in the history
  • Loading branch information
blafond committed Mar 17, 2022
1 parent 8b319a1 commit 1e04a1d
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 2 deletions.
5 changes: 5 additions & 0 deletions hibernate-reactive-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ dependencies {

//Specific implementation details of Hibernate Reactive:
implementation "io.vertx:vertx-sql-client:${vertxVersion}"
implementation 'io.agroal:agroal-api:1.12'
implementation 'io.agroal:agroal-pool:1.12'
implementation "io.vertx:vertx-jdbc-client:${vertxVersion}"

// Testing
testImplementation 'org.assertj:assertj-core:3.20.2'
Expand Down Expand Up @@ -65,6 +68,8 @@ dependencies {
testImplementation "org.testcontainers:cockroachdb:${testcontainersVersion}"
testImplementation "org.testcontainers:mssqlserver:${testcontainersVersion}"
testImplementation "org.testcontainers:oracle-xe:${testcontainersVersion}"

testImplementation "com.h2database:h2:2.1.210"
}

// Print a summary of the results of the tests (number of failures, successes and skipped)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ public PoolOptions poolOptions() {
@Override
public SqlConnectOptions connectOptions(URI uri) {
String scheme = uri.getScheme();
if( scheme.equalsIgnoreCase( "h2" )) {
return new SqlConnectOptions()
// username
.setUser("sa")
// password
.setPassword("");
}
String path = scheme.equals( "oracle" )
? oraclePath( uri )
: uri.getPath();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* Hibernate, Relational Persistence for Idiomatic Java
*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.reactive.pool.impl;


import java.net.URI;
import java.util.concurrent.CompletionStage;

import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.reactive.pool.ReactiveConnection;
import org.hibernate.reactive.vertx.VertxInstance;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.jdbcclient.JDBCConnectOptions;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.PoolOptions;
import io.vertx.sqlclient.SqlConnectOptions;
import io.vertx.sqlclient.SqlConnection;

public class H2SqlClientPool extends SqlClientPool implements ServiceRegistryAwareService {

//Asynchronous shutdown promise: we can't return it from #close as we implement a
//blocking interface.
private volatile Future<Void> closeFuture = Future.succeededFuture();

private Pool pools;
private URI uri;
private SqlStatementLogger sqlStatementLogger;
private ServiceRegistryImplementor serviceRegistry;

public H2SqlClientPool() {
}

@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
this.serviceRegistry = serviceRegistry;
sqlStatementLogger = serviceRegistry.getService( JdbcServices.class ).getSqlStatementLogger();
}

public void start() {
if ( pools == null ) {
pools = createPool( uri );
}
}

public void stop() {
if ( pools != null ) {
this.closeFuture = pools.close();
}
}

private Pool createPool(URI uri) {
SqlClientPoolConfiguration configuration = serviceRegistry.getService( SqlClientPoolConfiguration.class );
VertxInstance vertx = serviceRegistry.getService( VertxInstance.class );

return createPool( uri, configuration.connectOptions( uri ), configuration.poolOptions(), vertx.getVertx() );
}

private Pool createPool(URI uri, SqlConnectOptions connectOptions, PoolOptions poolOptions, Vertx vertx) {
JDBCConnectOptions jdbcOptions = new JDBCConnectOptions();
jdbcOptions.setUser( connectOptions.getUser() );
jdbcOptions.setJdbcUrl( "jdbc:" + uri.toString() );
JDBCPool pool = JDBCPool.pool( vertx, jdbcOptions, poolOptions );

return pool;
}

@Override
protected Pool getPool() {
return pools;
}

@Override
protected SqlStatementLogger getSqlStatementLogger() {
return sqlStatementLogger;
}

@Override
public CompletionStage<Void> getCloseFuture() {
return closeFuture.toCompletionStage();
}

@Override
public CompletionStage<ReactiveConnection> getConnection() {
return getConnectionFromPool( getPool() );
}

@Override
public CompletionStage<ReactiveConnection> getConnection(String tenantId) {
return getConnectionFromPool( getTenantPool( tenantId ) );
}

private CompletionStage<ReactiveConnection> getConnectionFromPool(Pool pool) {
start();
return pool.getConnection().toCompletionStage().thenApply( this::newConnection );
}

private SqlClientConnection newConnection(SqlConnection connection) {
return new SqlClientConnection( connection, getPool(), getSqlStatementLogger() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.hibernate.dialect.CockroachDB201Dialect;
import org.hibernate.dialect.DB297Dialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MariaDB103Dialect;
import org.hibernate.dialect.MySQL8Dialect;
import org.hibernate.dialect.Oracle12cDialect;
Expand Down Expand Up @@ -147,6 +148,9 @@ else if ( url.startsWith( "sqlserver:" ) ) {
else if ( url.startsWith( "oracle:" ) ) {
return Oracle12cDialect.class;
}
else if ( url.startsWith( "h2:" ) ) {
return H2Dialect.class;
}
else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.internal.JdbcServicesImpl;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.reactive.containers.DatabaseConfiguration;
import org.hibernate.reactive.containers.DatabaseConfiguration.DBType;
import org.hibernate.reactive.mutiny.Mutiny;
import org.hibernate.reactive.pool.ReactiveConnection;
import org.hibernate.reactive.pool.ReactiveConnectionPool;
import org.hibernate.reactive.pool.impl.H2SqlClientPool;
import org.hibernate.reactive.provider.ReactiveServiceRegistryBuilder;
import org.hibernate.reactive.provider.Settings;
import org.hibernate.reactive.provider.service.ReactiveGenerationTarget;
Expand Down Expand Up @@ -123,6 +128,10 @@ protected Configuration constructConfiguration() {
if ( DatabaseConfiguration.dbType() == DBType.DB2 && !doneTablespace ) {
configuration.setProperty(Settings.HBM2DDL_IMPORT_FILES, "/db2.sql");
doneTablespace = true;
} else if ( DatabaseConfiguration.dbType() == DBType.H2 ) {
configuration.setProperty(Settings.URL, "jdbc:h2:~/test");
} else {
configuration.setProperty( Settings.URL, DatabaseConfiguration.getJdbcUrl() );
}
//Use JAVA_TOOL_OPTIONS='-Dhibernate.show_sql=true'
configuration.setProperty( Settings.SHOW_SQL, System.getProperty(Settings.SHOW_SQL, "false") );
Expand Down Expand Up @@ -195,7 +204,17 @@ private SessionFactory createHibernateSessionFactory(Configuration configuration
return configuration.buildSessionFactory( registry );
}

protected void addServices(StandardServiceRegistryBuilder builder) {}
protected void addServices(StandardServiceRegistryBuilder builder) {
if(dbType() == DBType.H2 ) {
builder.addService( ReactiveConnectionPool.class, new H2SqlClientPool() );
builder.addService( JdbcServices.class, new JdbcServicesImpl() {
@Override
public SqlStatementLogger getSqlStatementLogger() {
return new SqlStatementLogger();
}
} );
}
}

/*
* MySQL doesn't implement 'drop table cascade constraints'.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public enum DBType {
POSTGRESQL( PostgreSQLDatabase.INSTANCE, 5432, "POSTGRES", "PG" ),
COCKROACHDB( CockroachDBDatabase.INSTANCE, 26257, "COCKROACH" ),
SQLSERVER( MSSQLServerDatabase.INSTANCE, 1433, "MSSQL", "MSSQLSERVER" ),
ORACLE( OracleDatabase.INSTANCE, 1521 );
ORACLE( OracleDatabase.INSTANCE, 1521 ),
H2( H2Database.INSTANCE, -1 );

private final TestableDatabase configuration;
private final int defaultPort;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* Hibernate, Relational Persistence for Idiomatic Java
*
* SPDX-License-Identifier: Apache-2.0
* Copyright: Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.reactive.containers;


import java.util.Map;


public class H2Database implements TestableDatabase {
public static H2Database INSTANCE = new H2Database();

private String getRegularJdbcUrl() {
return "jdbc:h2:~/test";
}

@Override
public String getJdbcUrl() {
return getRegularJdbcUrl();
}

@Override
public String getUri() {
{
return "h2:~/test";
}
}

@Override
public String getScheme() {
return "h2";
}

@Override
public String getNativeDatatypeQuery(String tableName, String columnName) {
throw new UnsupportedOperationException();
}

@Override
public String getExpectedNativeDatatype(Class<?> dataType) {
return null;
}

@Override
public String createJdbcUrl(String host, int port, String database, Map<String, String> params) {
return getRegularJdbcUrl();
}

@Override
public String jdbcStartQuery() {
throw new UnsupportedOperationException();
}

@Override
public String jdbcParamDelimiter() {
throw new UnsupportedOperationException();
}

private H2Database() {
}
}

1 comment on commit 1e04a1d

@blafond
Copy link
Owner Author

@blafond blafond commented on 1e04a1d Mar 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes get us close and it's currently failing in registering services. The H2SqlClientPool is being added as a service, but something is still wrong/missing.

> Task :hibernate-reactive-core:test
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
INFO Version [vert.x-eventloop-thread-0] HHH000412: Hibernate ORM core version 5.6.7.Final
Using database type: H2
INFO Version [vert.x-worker-thread-0] HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
INFO Dialect [vert.x-worker-thread-0] HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
INFO Dialect [vert.x-worker-thread-0] HHH000400: Using dialect: org.hibernate.dialect.H2Dialect

java.lang.NullPointerException
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.handleTypes(MetadataBuildingProcess.java:387)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:132)
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:86)
	at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:479)
	at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:709)
	at org.hibernate.reactive.BaseReactiveTest.createHibernateSessionFactory(BaseReactiveTest.java:204)
	at org.hibernate.reactive.BaseReactiveTest.lambda$startFactoryManager$8(BaseReactiveTest.java:190)
	at org.hibernate.reactive.testing.SessionFactoryManager.start(SessionFactoryManager.java:34)
	at org.hibernate.reactive.BaseReactiveTest.startFactoryManager(BaseReactiveTest.java:190)
	at org.hibernate.reactive.BaseReactiveTest.lambda$setupSessionFactory$6(BaseReactiveTest.java:175)
	at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
	at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
	at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)

Please sign in to comment.