Implementing ProcedureParamBindings

This commit is contained in:
Andrea Boriero 2021-09-27 08:08:32 +02:00 committed by Christian Beikov
parent d4007c5071
commit 6931635c4f
4 changed files with 105 additions and 97 deletions

View File

@ -31,48 +31,47 @@ public class PostgresCallableStatementSupport implements CallableStatementSuppor
ParameterMetadataImplementor parameterMetadata,
ProcedureParamBindings paramBindings,
SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception( getClass() );
// // if there are any parameters, see if the first is REF_CURSOR
// final boolean firstParamIsRefCursor = ! parameterRegistrations.isEmpty()
// && parameterRegistrations.get( 0 ).getMode() == ParameterMode.REF_CURSOR;
//
// if ( firstParamIsRefCursor ) {
// // validate that the parameter strategy is positional (cannot mix, and REF_CURSOR is inherently positional)
// if ( parameterStrategy == ParameterStrategy.NAMED ) {
// throw new HibernateException( "Cannot mix named parameters and REF_CURSOR parameter on PostgreSQL" );
// }
// }
//
// final StringBuilder buffer;
// if ( firstParamIsRefCursor ) {
// buffer = new StringBuilder().append( "{? = call " );
// }
// else {
// buffer = new StringBuilder().append( "{call " );
// }
//
// buffer.append( procedureName ).append( "(" );
//
// String sep = "";
//
// // skip the first registration if it was a REF_CURSOR
// final int startIndex = firstParamIsRefCursor ? 1 : 0;
// for ( int i = startIndex; i < parameterRegistrations.size(); i++ ) {
// final ParameterRegistrationImplementor parameter = parameterRegistrations.get( i );
//
// // any additional REF_CURSOR parameter registrations are an error
// if ( parameter.getMode() == ParameterMode.REF_CURSOR ) {
// throw new HibernateException( "PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered" );
// }
//
// for ( int ignored : parameter.getSqlTypes() ) {
// buffer.append( sep ).append( "?" );
// sep = ",";
// }
// }
//
// return buffer.append( ")}" ).toString();
// if there are any parameters, see if the first is REF_CURSOR
final boolean firstParamIsRefCursor = parameterMetadata.getParameterCount() != 0
&& paramBindings..getMode() == ParameterMode.REF_CURSOR;
if ( firstParamIsRefCursor ) {
// validate that the parameter strategy is positional (cannot mix, and REF_CURSOR is inherently positional)
if ( parameterStrategy == ParameterStrategy.NAMED ) {
throw new HibernateException( "Cannot mix named parameters and REF_CURSOR parameter on PostgreSQL" );
}
}
final StringBuilder buffer;
if ( firstParamIsRefCursor ) {
buffer = new StringBuilder().append( "{? = call " );
}
else {
buffer = new StringBuilder().append( "{call " );
}
buffer.append( procedureName ).append( "(" );
String sep = "";
// skip the first registration if it was a REF_CURSOR
final int startIndex = firstParamIsRefCursor ? 1 : 0;
for ( int i = startIndex; i < parameterRegistrations.size(); i++ ) {
final ParameterRegistrationImplementor parameter = parameterRegistrations.get( i );
// any additional REF_CURSOR parameter registrations are an error
if ( parameter.getMode() == ParameterMode.REF_CURSOR ) {
throw new HibernateException( "PostgreSQL supports only one REF_CURSOR parameter, but multiple were registered" );
}
for ( int ignored : parameter.getSqlTypes() ) {
buffer.append( sep ).append( "?" );
sep = ",";
}
}
return buffer.append( ")}" ).toString();
}
@Override

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.procedure.internal;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@ -14,6 +16,7 @@ import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.LockModeType;
@ -27,7 +30,6 @@ import jakarta.persistence.TransactionRequiredException;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.ScrollMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -62,8 +64,11 @@ import org.hibernate.result.Output;
import org.hibernate.result.ResultSetOutput;
import org.hibernate.result.UpdateCountOutput;
import org.hibernate.result.spi.ResultContext;
import org.hibernate.sql.exec.spi.JdbcCall;
import org.hibernate.sql.results.NoMoreOutputsException;
import org.jboss.logging.Logger;
/**
* Standard implementation of {@link ProcedureCall}
*
@ -72,6 +77,7 @@ import org.hibernate.sql.results.NoMoreOutputsException;
public class ProcedureCallImpl<R>
extends AbstractQuery<R>
implements ProcedureCallImplementor<R>, ResultContext {
private static final Logger LOG = Logger.getLogger( ProcedureCallImpl.class );
private final String procedureName;
@ -432,51 +438,51 @@ public class ProcedureCallImpl<R>
// both: (1) add the `? = ` part and also (2) register a REFCURSOR parameter for DBs (Oracle, PGSQL) that
// need it.
// final String call = getSession().getJdbcServices().getJdbcEnvironment().getDialect().getCallableStatementSupport().renderCallableStatement(
// procedureName,
// getParameterMetadata(),
// paramBindings,
// getSession()
// );
//
// LOG.debugf( "Preparing procedure call : %s", call );
// final CallableStatement statement = (CallableStatement) getSession()
// .getJdbcCoordinator()
// .getStatementPreparer()
// .prepareStatement( call, true );
//
//
// // prepare parameters
//
// getParameterMetadata().visitRegistrations(
// new Consumer<QueryParameter<?>>() {
// int i = 1;
//
// @Override
// public void accept(QueryParameter queryParameter) {
// try {
// final ProcedureParameterImplementor registration = (ProcedureParameterImplementor) queryParameter;
// registration.prepare( statement, i, ProcedureCallImpl.this );
final JdbcCall call = getSession().getJdbcServices().getJdbcEnvironment().getDialect().getCallableStatementSupport().interpretCall(
procedureName,
functionReturn,
getParameterMetadata(),
paramBindings,
getSession()
);
LOG.debugf( "Preparing procedure call : %s", call );
final CallableStatement statement = (CallableStatement) getSession()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( call.getSql(), true );
// prepare parameters
getParameterMetadata().visitRegistrations(
new Consumer<QueryParameter<?>>() {
int i = 1;
@Override
public void accept(QueryParameter queryParameter) {
try {
final ProcedureParameterImplementor registration = (ProcedureParameterImplementor) queryParameter;
registration.prepare( statement, i, ProcedureCallImpl.this );
// if ( registration.getMode() == ParameterMode.REF_CURSOR ) {
// i++;
i++;
// }
// else {
// i += registration.getSqlTypes().length;
// }
// }
// catch (SQLException e) {
// throw getSession().getJdbcServices().getSqlExceptionHelper().convert(
// e,
// "Error preparing registered callable parameter",
// getProcedureName()
// );
// }
// }
// }
// );
//
// return new ProcedureOutputsImpl( this, statement );
throw new NotYetImplementedFor6Exception( getClass() );
}
catch (SQLException e) {
throw getSession().getJdbcServices().getSqlExceptionHelper().convert(
e,
"Error preparing registered callable parameter",
getProcedureName()
);
}
}
}
);
return new ProcedureOutputsImpl( this, statement );
}
@Override

View File

@ -13,7 +13,6 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.procedure.spi.ProcedureParameterBindingImplementor;
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.procedure.ProcedureParameterBinding;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
@ -45,17 +44,16 @@ public class ProcedureParamBindings implements QueryParameterBindings {
}
@Override
public <P> QueryParameterBinding<P> getBinding(QueryParameterImplementor<P> parameter) {
// return getBinding( parameterMetadata.resolve( parameter ) );
throw new NotYetImplementedFor6Exception( getClass() );
public <P> ProcedureParameterBinding<P> getBinding(QueryParameterImplementor<P> parameter) {
return getQueryParamerBinding( (ProcedureParameterImplementor) parameter );
}
public ProcedureParameterBindingImplementor<?> getBinding(ProcedureParameterImplementor<?> parameter) {
public <P> ProcedureParameterBinding<P> getQueryParamerBinding(ProcedureParameterImplementor<P> parameter) {
final ProcedureParameterImplementor procParam = parameterMetadata.resolve( parameter );
ProcedureParameterBindingImplementor binding = bindingMap.get( procParam );
if ( binding == null ) {
if ( ! parameterMetadata.containsReference( parameter ) ) {
if ( !parameterMetadata.containsReference( parameter ) ) {
throw new IllegalArgumentException( "Passed parameter is not registered with this query" );
}
@ -68,15 +66,23 @@ public class ProcedureParamBindings implements QueryParameterBindings {
}
@Override
public ProcedureParameterBinding<?> getBinding(String name) {
// return (ProcedureParameterBinding<?>) getBinding( parameterMetadata.getQueryParameter( name ) );
throw new NotYetImplementedFor6Exception( getClass() );
public <P> ProcedureParameterBinding<P> getBinding(String name) {
final ProcedureParameterImplementor<P> parameter = (ProcedureParameterImplementor<P>) parameterMetadata
.getQueryParameter( name );
if ( parameter == null ) {
throw new IllegalArgumentException( "Parameter does not exist: " + name );
}
return getQueryParamerBinding( parameter );
}
@Override
public ProcedureParameterBinding getBinding(int position) {
// return getBinding( parameterMetadata.getQueryParameter( position ) );
throw new NotYetImplementedFor6Exception( getClass() );
public <P> ProcedureParameterBinding<P> getBinding(int position) {
final ProcedureParameterImplementor<P> parameter = (ProcedureParameterImplementor<P>) parameterMetadata
.getQueryParameter( position );
if ( parameter == null ) {
throw new IllegalArgumentException( "Parameter at position " + position + "does not exist" );
}
return getQueryParamerBinding( parameter );
}
@Override
@ -101,5 +107,4 @@ public class ProcedureParamBindings implements QueryParameterBindings {
return false;
}
}

View File

@ -63,7 +63,6 @@ import org.hibernate.type.YesNoType;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.NotImplementedYet;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
@ -74,7 +73,6 @@ import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Vlad Mihalcea
*/
@NotImplementedYet
@DomainModel
@SessionFactory
public class StoredProcedureParameterTypeTest {