HHH-15833 Disable named parameters for jConnect JDBC driver
This commit is contained in:
parent
ea87b4a2ab
commit
f998bc80b5
|
@ -17,6 +17,7 @@ import org.hibernate.boot.model.TypeContributions;
|
|||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.RowLockStrategy;
|
||||
import org.hibernate.dialect.SybaseDriverKind;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.TopLimitHandler;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
|
@ -123,7 +124,7 @@ public class SybaseASELegacyDialect extends SybaseLegacyDialect {
|
|||
|
||||
// According to Wikipedia bigdatetime and bigtime were added in 15.5
|
||||
// But with jTDS we can't use them as the driver can't handle the types
|
||||
if ( getVersion().isSameOrAfter( 15, 5 ) && !jtdsDriver ) {
|
||||
if ( getVersion().isSameOrAfter( 15, 5 ) && getDriverKind() != SybaseDriverKind.JTDS ) {
|
||||
ddlTypeRegistry.addDescriptor(
|
||||
CapacityDependentDdlType.builder( DATE, "bigdatetime", "bigdatetime", this )
|
||||
.withTypeCapacity( 3, "datetime" )
|
||||
|
@ -230,7 +231,7 @@ public class SybaseASELegacyDialect extends SybaseLegacyDialect {
|
|||
.getJdbcTypeRegistry();
|
||||
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, TinyIntJdbcType.INSTANCE );
|
||||
// At least the jTDS driver does not support this type code
|
||||
if ( jtdsDriver ) {
|
||||
if ( getDriverKind() == SybaseDriverKind.JTDS ) {
|
||||
jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.boot.model.TypeContributions;
|
|||
import org.hibernate.dialect.AbstractTransactSQLDialect;
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.NationalizationSupport;
|
||||
import org.hibernate.dialect.SybaseDriverKind;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.CountFunction;
|
||||
import org.hibernate.dialect.function.IntegralTimestampaddFunction;
|
||||
|
@ -29,6 +30,7 @@ import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
|||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.procedure.internal.JTDSCallableStatementSupport;
|
||||
import org.hibernate.procedure.internal.SybaseCallableStatementSupport;
|
||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
|
@ -69,11 +71,13 @@ import jakarta.persistence.TemporalType;
|
|||
*/
|
||||
public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
||||
|
||||
protected final boolean jtdsDriver;
|
||||
|
||||
//All Sybase dialects share an IN list size limit.
|
||||
private static final int PARAM_LIST_SIZE_LIMIT = 250000;
|
||||
private final UniqueDelegate uniqueDelegate = new SkipNullableUniqueDelegate(this);
|
||||
private final SybaseDriverKind driverKind;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
protected final boolean jtdsDriver;
|
||||
|
||||
public SybaseLegacyDialect() {
|
||||
this( DatabaseVersion.make( 11, 0 ) );
|
||||
|
@ -81,13 +85,18 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
public SybaseLegacyDialect(DatabaseVersion version) {
|
||||
super(version);
|
||||
jtdsDriver = true;
|
||||
this.driverKind = SybaseDriverKind.OTHER;
|
||||
this.jtdsDriver = true;
|
||||
}
|
||||
|
||||
public SybaseLegacyDialect(DialectResolutionInfo info) {
|
||||
super(info);
|
||||
jtdsDriver = info.getDriverName() != null
|
||||
&& info.getDriverName().contains( "jTDS" );
|
||||
this.driverKind = SybaseDriverKind.determineKind( info );
|
||||
this.jtdsDriver = driverKind == SybaseDriverKind.JTDS;
|
||||
}
|
||||
|
||||
public SybaseDriverKind getDriverKind() {
|
||||
return driverKind;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -164,7 +173,7 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
|||
super.contributeTypes(typeContributions, serviceRegistry);
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
||||
.getJdbcTypeRegistry();
|
||||
if ( jtdsDriver ) {
|
||||
if ( driverKind == SybaseDriverKind.JTDS ) {
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
||||
|
||||
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
||||
|
@ -198,7 +207,7 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
|||
@Override
|
||||
public NationalizationSupport getNationalizationSupport() {
|
||||
// At least the jTDS driver doesn't support this
|
||||
return jtdsDriver ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
||||
return driverKind == SybaseDriverKind.JTDS ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -360,6 +369,12 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
@Override
|
||||
public CallableStatementSupport getCallableStatementSupport() {
|
||||
return jtdsDriver ? JTDSCallableStatementSupport.INSTANCE : super.getCallableStatementSupport();
|
||||
return driverKind == SybaseDriverKind.JTDS ? JTDSCallableStatementSupport.INSTANCE : SybaseCallableStatementSupport.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
// Only the jTDS driver supports named parameters properly
|
||||
return driverKind == SybaseDriverKind.JTDS && super.supportsNamedParameters( databaseMetaData );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ public class SybaseASEDialect extends SybaseDialect {
|
|||
|
||||
// According to Wikipedia bigdatetime and bigtime were added in 15.5
|
||||
// But with jTDS we can't use them as the driver can't handle the types
|
||||
if ( !jtdsDriver ) {
|
||||
if ( getDriverKind() != SybaseDriverKind.JTDS ) {
|
||||
ddlTypeRegistry.addDescriptor(
|
||||
CapacityDependentDdlType.builder( DATE, "bigdatetime", "bigdatetime", this )
|
||||
.withTypeCapacity( 3, "datetime" )
|
||||
|
@ -234,7 +234,7 @@ public class SybaseASEDialect extends SybaseDialect {
|
|||
.getJdbcTypeRegistry();
|
||||
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, TinyIntJdbcType.INSTANCE );
|
||||
// At least the jTDS driver does not support this type code
|
||||
if ( jtdsDriver ) {
|
||||
if ( getDriverKind() == SybaseDriverKind.JTDS ) {
|
||||
jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
|||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.procedure.internal.JTDSCallableStatementSupport;
|
||||
import org.hibernate.procedure.internal.SybaseCallableStatementSupport;
|
||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
|
@ -69,8 +70,6 @@ import jakarta.persistence.TemporalType;
|
|||
*/
|
||||
public class SybaseDialect extends AbstractTransactSQLDialect {
|
||||
|
||||
protected final boolean jtdsDriver;
|
||||
|
||||
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 16, 0 );
|
||||
|
||||
//All Sybase dialects share an IN list size limit.
|
||||
|
@ -79,6 +78,10 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
private static final int PARAM_COUNT_LIMIT = 2000;
|
||||
|
||||
private final UniqueDelegate uniqueDelegate = new SkipNullableUniqueDelegate(this);
|
||||
private final SybaseDriverKind driverKind;
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
protected final boolean jtdsDriver;
|
||||
|
||||
public SybaseDialect() {
|
||||
this( MINIMUM_VERSION );
|
||||
|
@ -86,13 +89,14 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
public SybaseDialect(DatabaseVersion version) {
|
||||
super(version);
|
||||
jtdsDriver = true;
|
||||
this.driverKind = SybaseDriverKind.OTHER;
|
||||
this.jtdsDriver = true;
|
||||
}
|
||||
|
||||
public SybaseDialect(DialectResolutionInfo info) {
|
||||
super(info);
|
||||
jtdsDriver = info.getDriverName() != null
|
||||
&& info.getDriverName().contains( "jTDS" );
|
||||
this.driverKind = SybaseDriverKind.determineKind( info );
|
||||
this.jtdsDriver = driverKind == SybaseDriverKind.JTDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,6 +104,10 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
return MINIMUM_VERSION;
|
||||
}
|
||||
|
||||
public SybaseDriverKind getDriverKind() {
|
||||
return driverKind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType resolveSqlTypeDescriptor(
|
||||
String columnTypeName,
|
||||
|
@ -179,7 +187,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
super.contributeTypes(typeContributions, serviceRegistry);
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
||||
.getJdbcTypeRegistry();
|
||||
if ( jtdsDriver ) {
|
||||
if ( driverKind == SybaseDriverKind.JTDS ) {
|
||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
||||
|
||||
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
||||
|
@ -217,7 +225,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
@Override
|
||||
public NationalizationSupport getNationalizationSupport() {
|
||||
// At least the jTDS driver doesn't support this
|
||||
return jtdsDriver ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
||||
return driverKind == SybaseDriverKind.JTDS ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -372,7 +380,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
@Override
|
||||
public NameQualifierSupport getNameQualifierSupport() {
|
||||
if ( jtdsDriver ) {
|
||||
if ( driverKind == SybaseDriverKind.JTDS ) {
|
||||
return NameQualifierSupport.CATALOG;
|
||||
}
|
||||
else {
|
||||
|
@ -387,7 +395,15 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
@Override
|
||||
public CallableStatementSupport getCallableStatementSupport() {
|
||||
return jtdsDriver ? JTDSCallableStatementSupport.INSTANCE : super.getCallableStatementSupport();
|
||||
return driverKind == SybaseDriverKind.JTDS ?
|
||||
JTDSCallableStatementSupport.INSTANCE :
|
||||
SybaseCallableStatementSupport.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
// Only the jTDS driver supports named parameters properly
|
||||
return driverKind == SybaseDriverKind.JTDS && super.supportsNamedParameters( databaseMetaData );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -402,7 +418,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
|
||||
@Override
|
||||
public IdentityColumnSupport getIdentityColumnSupport() {
|
||||
return jtdsDriver
|
||||
return driverKind == SybaseDriverKind.JTDS
|
||||
? AbstractTransactSQLIdentityColumnSupport.INSTANCE
|
||||
: SybaseJconnIdentityColumnSupport.INSTANCE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public enum SybaseDriverKind {
|
||||
JCONNECT,
|
||||
JTDS,
|
||||
OTHER;
|
||||
|
||||
public static SybaseDriverKind determineKind(DialectResolutionInfo dialectResolutionInfo) {
|
||||
final String driverName = dialectResolutionInfo.getDriverName();
|
||||
// By default, we assume OTHER
|
||||
if ( driverName == null ) {
|
||||
return OTHER;
|
||||
}
|
||||
switch ( driverName ) {
|
||||
case "jConnect (TM) for JDBC (TM)":
|
||||
return JCONNECT;
|
||||
case "jTDS Type 4 JDBC Driver for MS SQL Server and Sybase":
|
||||
return JTDS;
|
||||
default:
|
||||
return OTHER;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ package org.hibernate.procedure.internal;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.procedure.spi.FunctionReturnImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
|
||||
|
@ -26,6 +25,7 @@ import jakarta.persistence.ParameterMode;
|
|||
* and instead requires that we render this as `@param=?`.
|
||||
*/
|
||||
public class JTDSCallableStatementSupport extends AbstractStandardCallableStatementSupport {
|
||||
|
||||
public static final JTDSCallableStatementSupport INSTANCE = new JTDSCallableStatementSupport();
|
||||
|
||||
@Override
|
||||
|
@ -33,7 +33,6 @@ public class JTDSCallableStatementSupport extends AbstractStandardCallableStatem
|
|||
final String procedureName = procedureCall.getProcedureName();
|
||||
final FunctionReturnImplementor<?> functionReturn = procedureCall.getFunctionReturn();
|
||||
final ProcedureParameterMetadataImplementor parameterMetadata = procedureCall.getParameterMetadata();
|
||||
final SharedSessionContractImplementor session = procedureCall.getSession();
|
||||
final List<? extends ProcedureParameterImplementor<?>> registrations = parameterMetadata.getRegistrationsAsList();
|
||||
final int paramStringSizeEstimate;
|
||||
if ( functionReturn == null && parameterMetadata.hasNamedParameters() ) {
|
||||
|
@ -48,14 +47,10 @@ public class JTDSCallableStatementSupport extends AbstractStandardCallableStatem
|
|||
final StringBuilder buffer;
|
||||
final int offset;
|
||||
if ( functionReturn != null ) {
|
||||
offset = 2;
|
||||
buffer = new StringBuilder( 11 + procedureName.length() + paramStringSizeEstimate ).append( "{?=call " );
|
||||
builder.setFunctionReturn( functionReturn.toJdbcFunctionReturn( session ) );
|
||||
throw new QueryException( "The jTDS driver does not support calling functions through the JDBC CallableStatement API" );
|
||||
}
|
||||
else {
|
||||
offset = 1;
|
||||
buffer = new StringBuilder( 9 + procedureName.length() + paramStringSizeEstimate ).append( "{call " );
|
||||
}
|
||||
|
||||
buffer.append( procedureName );
|
||||
|
||||
|
@ -67,7 +62,7 @@ public class JTDSCallableStatementSupport extends AbstractStandardCallableStatem
|
|||
for ( int i = 0; i < registrations.size(); i++ ) {
|
||||
final ProcedureParameterImplementor<?> parameter = registrations.get( i );
|
||||
if ( parameter.getMode() == ParameterMode.REF_CURSOR ) {
|
||||
throw new QueryException( "Dialect [" + session.getJdbcServices().getJdbcEnvironment().getDialect().getClass().getName() + "] not known to support REF_CURSOR parameters" );
|
||||
throw new QueryException( "Dialect [" + procedureCall.getSession().getJdbcServices().getJdbcEnvironment().getDialect().getClass().getName() + "] not known to support REF_CURSOR parameters" );
|
||||
}
|
||||
buffer.append( sep );
|
||||
final JdbcCallParameterRegistration registration = parameter.toJdbcParameterRegistration(
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.procedure.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.procedure.spi.FunctionReturnImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
||||
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
|
||||
import org.hibernate.query.spi.ProcedureParameterMetadataImplementor;
|
||||
import org.hibernate.sql.exec.internal.JdbcCallImpl;
|
||||
import org.hibernate.sql.exec.spi.JdbcCallParameterRegistration;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperationQueryCall;
|
||||
|
||||
import jakarta.persistence.ParameterMode;
|
||||
|
||||
/**
|
||||
* Sybase implementation of CallableStatementSupport.
|
||||
*
|
||||
* The JDBC driver of Sybase doesn't support function invocations, so we have to render a select statement instead.
|
||||
*/
|
||||
public class SybaseCallableStatementSupport extends AbstractStandardCallableStatementSupport {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final SybaseCallableStatementSupport INSTANCE = new SybaseCallableStatementSupport();
|
||||
private static final String FUNCTION_SYNTAX_START = "select ";
|
||||
private static final String FUNCTION_SYNTAX_END = ") from (select 1) t1(c1)";
|
||||
private static final String CALL_SYNTAX_START = "{call ";
|
||||
private static final String CALL_SYNTAX_END = ")}";
|
||||
|
||||
@Override
|
||||
public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedureCall) {
|
||||
final String procedureName = procedureCall.getProcedureName();
|
||||
final FunctionReturnImplementor<?> functionReturn = procedureCall.getFunctionReturn();
|
||||
final ProcedureParameterMetadataImplementor parameterMetadata = procedureCall.getParameterMetadata();
|
||||
final List<? extends ProcedureParameterImplementor<?>> registrations = parameterMetadata.getRegistrationsAsList();
|
||||
final int paramStringSizeEstimate;
|
||||
if ( functionReturn == null && parameterMetadata.hasNamedParameters() ) {
|
||||
// That's just a rough estimate. I guess most params will have fewer than 8 chars on average
|
||||
paramStringSizeEstimate = registrations.size() * 12;
|
||||
}
|
||||
else {
|
||||
// For every param rendered as '?' we have a comma, hence the estimate
|
||||
paramStringSizeEstimate = registrations.size() * 2;
|
||||
}
|
||||
final JdbcCallImpl.Builder builder = new JdbcCallImpl.Builder();
|
||||
final StringBuilder buffer;
|
||||
final int offset;
|
||||
if ( functionReturn != null ) {
|
||||
offset = 1;
|
||||
buffer = new StringBuilder( FUNCTION_SYNTAX_START.length() + FUNCTION_SYNTAX_END.length() + procedureName.length() + paramStringSizeEstimate )
|
||||
.append( FUNCTION_SYNTAX_START );
|
||||
}
|
||||
else {
|
||||
offset = 1;
|
||||
buffer = new StringBuilder( CALL_SYNTAX_START.length() + CALL_SYNTAX_END.length() + procedureName.length() + paramStringSizeEstimate )
|
||||
.append( CALL_SYNTAX_START );
|
||||
}
|
||||
|
||||
buffer.append( procedureName );
|
||||
|
||||
if ( registrations.isEmpty() ) {
|
||||
buffer.append( '(' );
|
||||
}
|
||||
else {
|
||||
char sep = '(';
|
||||
for ( int i = 0; i < registrations.size(); i++ ) {
|
||||
final ProcedureParameterImplementor<?> parameter = registrations.get( i );
|
||||
if ( parameter.getMode() == ParameterMode.REF_CURSOR ) {
|
||||
throw new QueryException( "Dialect [" + procedureCall.getSession().getJdbcServices().getJdbcEnvironment().getDialect().getClass().getName() + "] not known to support REF_CURSOR parameters" );
|
||||
}
|
||||
buffer.append( sep );
|
||||
final JdbcCallParameterRegistration registration = parameter.toJdbcParameterRegistration(
|
||||
i + offset,
|
||||
procedureCall
|
||||
);
|
||||
if ( registration.getName() != null ) {
|
||||
throw new QueryException( "The JDBC driver does not support named parameters" );
|
||||
}
|
||||
buffer.append( "?" );
|
||||
sep = ',';
|
||||
builder.addParameterRegistration( registration );
|
||||
}
|
||||
}
|
||||
|
||||
if ( functionReturn != null ) {
|
||||
buffer.append( FUNCTION_SYNTAX_END );
|
||||
}
|
||||
else {
|
||||
buffer.append( CALL_SYNTAX_END );
|
||||
}
|
||||
|
||||
builder.setCallableName( buffer.toString() );
|
||||
return builder.buildJdbcCall();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.procedure;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
import org.hibernate.dialect.SybaseASEDialect;
|
||||
import org.hibernate.jpa.HibernateHints;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.ParameterMode;
|
||||
import jakarta.persistence.StoredProcedureQuery;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInAutoCommit;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(value = SybaseASEDialect.class)
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
Person.class,
|
||||
Phone.class,
|
||||
}
|
||||
)
|
||||
public class SybaseStoredProcedureTest {
|
||||
|
||||
@BeforeEach
|
||||
public void init(EntityManagerFactoryScope scope) {
|
||||
// Force creation of the tables because Sybase checks that dependent tables exist
|
||||
scope.getEntityManagerFactory();
|
||||
doInAutoCommit(
|
||||
"DROP PROCEDURE sp_count_phones",
|
||||
"DROP FUNCTION fn_count_phones",
|
||||
"CREATE PROCEDURE sp_count_phones " +
|
||||
" @personId INT, " +
|
||||
" @phoneCount INT OUTPUT " +
|
||||
"AS " +
|
||||
"BEGIN " +
|
||||
" SELECT @phoneCount = COUNT(*) " +
|
||||
" FROM Phone " +
|
||||
" WHERE person_id = @personId " +
|
||||
"END",
|
||||
"CREATE FUNCTION fn_count_phones (@personId INT) " +
|
||||
"RETURNS INT " +
|
||||
"AS " +
|
||||
"BEGIN " +
|
||||
" DECLARE @phoneCount int " +
|
||||
" SELECT @phoneCount = COUNT(*) " +
|
||||
" FROM Phone " +
|
||||
" WHERE person_id = @personId " +
|
||||
" RETURN @phoneCount " +
|
||||
"END",
|
||||
"sp_procxmode sp_count_phones, 'chained'"
|
||||
);
|
||||
|
||||
scope.inTransaction( entityManager -> {
|
||||
Person person1 = new Person( 1L, "John Doe" );
|
||||
person1.setNickName( "JD" );
|
||||
person1.setAddress( "Earth" );
|
||||
person1.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 )
|
||||
.toInstant( ZoneOffset.UTC ) ) );
|
||||
|
||||
entityManager.persist( person1 );
|
||||
|
||||
Phone phone1 = new Phone( "123-456-7890" );
|
||||
phone1.setId( 1L );
|
||||
|
||||
person1.addPhone( phone1 );
|
||||
|
||||
Phone phone2 = new Phone( "098_765-4321" );
|
||||
phone2.setId( 2L );
|
||||
|
||||
person1.addPhone( phone2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(EntityManagerFactoryScope scope){
|
||||
scope.releaseEntityManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoredProcedureOutParameter(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "sp_count_phones" );
|
||||
query.registerStoredProcedureParameter( "personId", Long.class, ParameterMode.IN );
|
||||
query.registerStoredProcedureParameter( "phoneCount", Long.class, ParameterMode.OUT );
|
||||
|
||||
query.setParameter( "personId", 1L );
|
||||
|
||||
query.execute();
|
||||
Long phoneCount = (Long) query.getOutputParameterValue( "phoneCount" );
|
||||
assertEquals( Long.valueOf( 2 ), phoneCount );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.IsJtds.class, reverse = true, comment = "jTDS can't handle calling functions")
|
||||
public void testFunctionReturnValue(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "hibernate_orm_test.fn_count_phones", Long.class );
|
||||
query.registerStoredProcedureParameter( "personId", Long.class, ParameterMode.IN );
|
||||
query.setHint( HibernateHints.HINT_CALLABLE_FUNCTION, "true" );
|
||||
|
||||
query.setParameter( "personId", 1L );
|
||||
|
||||
query.execute();
|
||||
Long phoneCount = (Long) query.getSingleResult();
|
||||
Assert.assertEquals( Long.valueOf( 2 ), phoneCount );
|
||||
});
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import org.hibernate.dialect.PostgreSQLDialect;
|
|||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.dialect.SpannerDialect;
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.dialect.SybaseDriverKind;
|
||||
import org.hibernate.dialect.TimeZoneSupport;
|
||||
import org.hibernate.dialect.TiDBDialect;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
|
@ -651,4 +652,10 @@ abstract public class DialectFeatureChecks {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsJtds implements DialectFeatureCheck {
|
||||
public boolean apply(Dialect dialect) {
|
||||
return dialect instanceof SybaseDialect && ( (SybaseDialect) dialect ).getDriverKind() == SybaseDriverKind.JTDS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue