Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wire in SqlExceptionHelper which is now useful in Vert.x 4.4.0 #1603

Merged
merged 3 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package org.hibernate.reactive.pool;

import org.hibernate.Incubating;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.reactive.provider.ReactiveServiceRegistryBuilder;
import org.hibernate.service.Service;

Expand Down Expand Up @@ -41,12 +42,27 @@ public interface ReactiveConnectionPool extends Service {
*/
CompletionStage<ReactiveConnection> getConnection();

/**
* Obtain a reactive connection, returning the connection
* via a {@link CompletionStage} and overriding the default
* {@link SqlExceptionHelper} for the pool.
*/
CompletionStage<ReactiveConnection> getConnection(SqlExceptionHelper sqlExceptionHelper);

/**
* Obtain a reactive connection for the given tenant id,
* returning the connection via a {@link CompletionStage}.
*/
CompletionStage<ReactiveConnection> getConnection(String tenantId);

/**
* Obtain a reactive connection for the given tenant id,
* returning the connection via a {@link CompletionStage}
* and overriding the default {@link SqlExceptionHelper}
* for the pool.
*/
CompletionStage<ReactiveConnection> getConnection(String tenantId, SqlExceptionHelper sqlExceptionHelper);

/**
* Obtain a lazily-initializing reactive connection. The
* actual connection might be made when the returned
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.util.ServiceLoader;
import java.util.concurrent.CompletionStage;

import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.internal.util.config.ConfigurationException;
import org.hibernate.internal.util.config.ConfigurationHelper;
Expand Down Expand Up @@ -109,6 +111,7 @@ public static VertxDriver findByClassName(String className) {

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

Expand Down Expand Up @@ -151,6 +154,15 @@ protected SqlStatementLogger getSqlStatementLogger() {
return sqlStatementLogger;
}

@Override
public SqlExceptionHelper getSqlExceptionHelper() {
if ( sqlExceptionHelper == null ) {
sqlExceptionHelper = serviceRegistry
.getService( JdbcServices.class ).getSqlExceptionHelper();
}
return sqlExceptionHelper;
}

/**
* Create a new {@link Pool} for the given JDBC URL or database URI,
* using the {@link VertxInstance} service to obtain an instance of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import java.util.concurrent.CompletionStage;

import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.reactive.mutiny.Mutiny;
import org.hibernate.reactive.stage.Stage;
Expand Down Expand Up @@ -47,10 +48,12 @@ public final class ExternalSqlClientPool extends SqlClientPool {

private final Pool pool;
private final SqlStatementLogger sqlStatementLogger;
private SqlExceptionHelper sqlExceptionHelper;

public ExternalSqlClientPool(Pool pool, SqlStatementLogger sqlStatementLogger) {
public ExternalSqlClientPool(Pool pool, SqlStatementLogger sqlStatementLogger, SqlExceptionHelper sqlExceptionHelper) {
this.pool = pool;
this.sqlStatementLogger = sqlStatementLogger;
this.sqlExceptionHelper = sqlExceptionHelper;
}

@Override
Expand All @@ -63,13 +66,17 @@ protected SqlStatementLogger getSqlStatementLogger() {
return sqlStatementLogger;
}

@Override
public SqlExceptionHelper getSqlExceptionHelper() {
return sqlExceptionHelper;
}

/**
* Since this Service implementation does not implement @{@link org.hibernate.service.spi.Stoppable}
* and we're only adapting an externally provided pool, we will not actually close such provided pool
* when Hibernate ORM is shutdown (it doesn't own the lifecycle of this external component).
* Therefore there is no need to wait for its shutdown and this method returns an already
* Therefore, there is no need to wait for its shutdown and this method returns an already
* successfully completed CompletionStage.
* @return
*/
@Override
public CompletionStage<Void> getCloseFuture() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.concurrent.CompletionStage;

import org.hibernate.engine.jdbc.internal.FormatStyle;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.reactive.adaptor.impl.JdbcNull;
import org.hibernate.reactive.adaptor.impl.ResultSetAdaptor;
Expand All @@ -25,6 +26,7 @@

import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.DatabaseException;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.PrepareOptions;
import io.vertx.sqlclient.PropertyKind;
Expand Down Expand Up @@ -53,15 +55,17 @@ public class SqlClientConnection implements ReactiveConnection {
private final static PropertyKind<Row> ORACLE_GENERATED_KEYS = PropertyKind.create( "generated-keys", Row.class );

private final SqlStatementLogger sqlStatementLogger;
private final SqlExceptionHelper sqlExceptionHelper;

private final Pool pool;
private final SqlConnection connection;
private Transaction transaction;

SqlClientConnection(SqlConnection connection, Pool pool, SqlStatementLogger sqlStatementLogger) {
SqlClientConnection(SqlConnection connection, Pool pool, SqlStatementLogger sqlStatementLogger, SqlExceptionHelper sqlExceptionHelper) {
this.pool = pool;
this.sqlStatementLogger = sqlStatementLogger;
this.connection = connection;
this.sqlExceptionHelper = sqlExceptionHelper;
LOG.tracef( "Connection created: %s", connection );
}

Expand Down Expand Up @@ -151,6 +155,11 @@ private <T> T convertException(T rows, String sql, Throwable sqlException) {
if ( sqlException == null ) {
return rows;
}
if ( sqlException instanceof DatabaseException ) {
DatabaseException de = (DatabaseException) sqlException;
sqlException = sqlExceptionHelper
.convert( new SQLException( de.getMessage(), de.getSqlState(), de.getErrorCode() ), "error executing SQL statement", sql );
}
return rethrow( sqlException );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import java.util.concurrent.CompletionStage;

import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.reactive.pool.ReactiveConnection;
import org.hibernate.reactive.pool.ReactiveConnectionPool;
Expand Down Expand Up @@ -44,6 +45,12 @@ public abstract class SqlClientPool implements ReactiveConnectionPool {
*/
protected abstract SqlStatementLogger getSqlStatementLogger();

/**
* @return a Hibernate {@link SqlExceptionHelper} for converting
* exceptions
*/
protected abstract SqlExceptionHelper getSqlExceptionHelper();

/**
* Get a {@link Pool} for the specified tenant.
* <p>
Expand All @@ -57,26 +64,45 @@ public abstract class SqlClientPool implements ReactiveConnectionPool {
* @see ReactiveConnectionPool#getConnection(String)
*/
protected Pool getTenantPool(String tenantId) {
throw new UnsupportedOperationException("multitenancy not supported by built-in SqlClientPool");
throw new UnsupportedOperationException( "multitenancy not supported by built-in SqlClientPool" );
}

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

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

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

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

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

private CompletionStage<ReactiveConnection> getConnectionFromPool(Pool pool, SqlExceptionHelper sqlExceptionHelper) {
return pool.getConnection()
.toCompletionStage().thenApply( sqlConnection -> newConnection( sqlConnection, sqlExceptionHelper ) );
}

private SqlClientConnection newConnection(SqlConnection connection) {
return new SqlClientConnection( connection, getPool(), getSqlStatementLogger() );
return newConnection( connection, getSqlExceptionHelper() );
}

private SqlClientConnection newConnection(SqlConnection connection, SqlExceptionHelper sqlExceptionHelper) {
return new SqlClientConnection( connection, getPool(), getSqlStatementLogger(), sqlExceptionHelper );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.hibernate.engine.jdbc.dialect.spi.DialectFactory;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.reactive.engine.jdbc.env.internal.ReactiveJdbcEnvironment;
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LogCategory;
Expand All @@ -27,9 +28,9 @@

import io.vertx.sqlclient.spi.DatabaseMetadata;

import static java.util.function.Function.identity;
import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.failedFuture;

/**
* A Hibernate {@link StandardServiceInitiator service initiator} that
Expand Down Expand Up @@ -96,27 +97,31 @@ private static Dialect checkDialect(Dialect dialect) {

private DialectResolutionInfo dialectResolutionInfo() {
ReactiveConnectionPool connectionPool = registry.getService( ReactiveConnectionPool.class );
return connectionPool.getConnection()
.thenCompose( DialectBuilder::buildResolutionInfo ).toCompletableFuture().join();
return connectionPool
// The default SqlExceptionHelper in ORM requires the dialect, but we haven't create a dialect yet
// so we need to override it at this stage, or we will have an exception.
.getConnection( new SqlExceptionHelper( true ) )
.thenCompose( DialectBuilder::buildResolutionInfo )
.toCompletableFuture().join();
}

private static CompletionStage<ReactiveDialectResolutionInfo> buildResolutionInfo(ReactiveConnection connection) {
try {
final DatabaseMetadata databaseMetadata = connection.getDatabaseMetadata();
return resolutionInfoStage( connection, databaseMetadata )
.thenCompose( info -> connection.close().thenApply( v -> info ) );
}
catch (Throwable t) {
try {
return connection.close()
.handle( CompletionStages::handle )
// Ignore errors when closing the connection
.thenCompose( handled -> failedFuture( t ) );
}
catch (Throwable onClose) {
return failedFuture( t );
}
}
final DatabaseMetadata databaseMetadata = connection.getDatabaseMetadata();
return resolutionInfoStage( connection, databaseMetadata )
.handle( CompletionStages::handle )
.thenCompose( handled -> {
if ( handled.hasFailed() ) {
// Something has already gone wrong: try to close the connection
// and return the original failure
return connection.close()
.handle( (unused, throwable) -> handled.getResultAsCompletionStage() )
.thenCompose( identity() );
}
else {
return connection.close()
.thenCompose( v -> handled.getResultAsCompletionStage() );
}
} );
}

private static CompletionStage<ReactiveDialectResolutionInfo> resolutionInfoStage(ReactiveConnection connection, DatabaseMetadata databaseMetadata) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ public CompletionStageHandler(R result, T throwable) {
this.throwable = throwable;
}

public boolean hasFailed() {
return throwable != null;
}

public T getThrowable() {
return throwable;
}

public R getResult() throws T {
if ( throwable == null ) {
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import java.util.Collection;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.reactive.mutiny.Mutiny;

import org.junit.Test;
Expand All @@ -27,7 +27,7 @@ protected Collection<Class<?>> annotatedEntities() {
}

Class<?> getExpectedException() {
return HibernateException.class;
return ConstraintViolationException.class;
}

@Test
Expand Down
Loading