mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-17 08:35:13 +00:00
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.dialect.DatabaseVersion;
|
import org.hibernate.dialect.DatabaseVersion;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.dialect.RowLockStrategy;
|
import org.hibernate.dialect.RowLockStrategy;
|
||||||
|
import org.hibernate.dialect.SybaseDriverKind;
|
||||||
import org.hibernate.dialect.pagination.LimitHandler;
|
import org.hibernate.dialect.pagination.LimitHandler;
|
||||||
import org.hibernate.dialect.pagination.TopLimitHandler;
|
import org.hibernate.dialect.pagination.TopLimitHandler;
|
||||||
import org.hibernate.engine.jdbc.Size;
|
import org.hibernate.engine.jdbc.Size;
|
||||||
@ -123,7 +124,7 @@ protected void registerColumnTypes(TypeContributions typeContributions, ServiceR
|
|||||||
|
|
||||||
// According to Wikipedia bigdatetime and bigtime were added in 15.5
|
// 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
|
// 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(
|
ddlTypeRegistry.addDescriptor(
|
||||||
CapacityDependentDdlType.builder( DATE, "bigdatetime", "bigdatetime", this )
|
CapacityDependentDdlType.builder( DATE, "bigdatetime", "bigdatetime", this )
|
||||||
.withTypeCapacity( 3, "datetime" )
|
.withTypeCapacity( 3, "datetime" )
|
||||||
@ -230,7 +231,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
|
|||||||
.getJdbcTypeRegistry();
|
.getJdbcTypeRegistry();
|
||||||
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, TinyIntJdbcType.INSTANCE );
|
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, TinyIntJdbcType.INSTANCE );
|
||||||
// At least the jTDS driver does not support this type code
|
// 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 );
|
jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import org.hibernate.dialect.AbstractTransactSQLDialect;
|
import org.hibernate.dialect.AbstractTransactSQLDialect;
|
||||||
import org.hibernate.dialect.DatabaseVersion;
|
import org.hibernate.dialect.DatabaseVersion;
|
||||||
import org.hibernate.dialect.NationalizationSupport;
|
import org.hibernate.dialect.NationalizationSupport;
|
||||||
|
import org.hibernate.dialect.SybaseDriverKind;
|
||||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||||
import org.hibernate.dialect.function.CountFunction;
|
import org.hibernate.dialect.function.CountFunction;
|
||||||
import org.hibernate.dialect.function.IntegralTimestampaddFunction;
|
import org.hibernate.dialect.function.IntegralTimestampaddFunction;
|
||||||
@ -29,6 +30,7 @@
|
|||||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.procedure.internal.JTDSCallableStatementSupport;
|
import org.hibernate.procedure.internal.JTDSCallableStatementSupport;
|
||||||
|
import org.hibernate.procedure.internal.SybaseCallableStatementSupport;
|
||||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
@ -69,11 +71,13 @@
|
|||||||
*/
|
*/
|
||||||
public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
||||||
|
|
||||||
protected final boolean jtdsDriver;
|
|
||||||
|
|
||||||
//All Sybase dialects share an IN list size limit.
|
//All Sybase dialects share an IN list size limit.
|
||||||
private static final int PARAM_LIST_SIZE_LIMIT = 250000;
|
private static final int PARAM_LIST_SIZE_LIMIT = 250000;
|
||||||
private final UniqueDelegate uniqueDelegate = new SkipNullableUniqueDelegate(this);
|
private final UniqueDelegate uniqueDelegate = new SkipNullableUniqueDelegate(this);
|
||||||
|
private final SybaseDriverKind driverKind;
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
protected final boolean jtdsDriver;
|
||||||
|
|
||||||
public SybaseLegacyDialect() {
|
public SybaseLegacyDialect() {
|
||||||
this( DatabaseVersion.make( 11, 0 ) );
|
this( DatabaseVersion.make( 11, 0 ) );
|
||||||
@ -81,13 +85,18 @@ public SybaseLegacyDialect() {
|
|||||||
|
|
||||||
public SybaseLegacyDialect(DatabaseVersion version) {
|
public SybaseLegacyDialect(DatabaseVersion version) {
|
||||||
super(version);
|
super(version);
|
||||||
jtdsDriver = true;
|
this.driverKind = SybaseDriverKind.OTHER;
|
||||||
|
this.jtdsDriver = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SybaseLegacyDialect(DialectResolutionInfo info) {
|
public SybaseLegacyDialect(DialectResolutionInfo info) {
|
||||||
super(info);
|
super(info);
|
||||||
jtdsDriver = info.getDriverName() != null
|
this.driverKind = SybaseDriverKind.determineKind( info );
|
||||||
&& info.getDriverName().contains( "jTDS" );
|
this.jtdsDriver = driverKind == SybaseDriverKind.JTDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SybaseDriverKind getDriverKind() {
|
||||||
|
return driverKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -164,7 +173,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
|
|||||||
super.contributeTypes(typeContributions, serviceRegistry);
|
super.contributeTypes(typeContributions, serviceRegistry);
|
||||||
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
||||||
.getJdbcTypeRegistry();
|
.getJdbcTypeRegistry();
|
||||||
if ( jtdsDriver ) {
|
if ( driverKind == SybaseDriverKind.JTDS ) {
|
||||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
||||||
|
|
||||||
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
||||||
@ -198,7 +207,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
|
|||||||
@Override
|
@Override
|
||||||
public NationalizationSupport getNationalizationSupport() {
|
public NationalizationSupport getNationalizationSupport() {
|
||||||
// At least the jTDS driver doesn't support this
|
// At least the jTDS driver doesn't support this
|
||||||
return jtdsDriver ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
return driverKind == SybaseDriverKind.JTDS ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -360,6 +369,12 @@ public UniqueDelegate getUniqueDelegate() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CallableStatementSupport getCallableStatementSupport() {
|
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 @@ protected void registerColumnTypes(TypeContributions typeContributions, ServiceR
|
|||||||
|
|
||||||
// According to Wikipedia bigdatetime and bigtime were added in 15.5
|
// 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
|
// But with jTDS we can't use them as the driver can't handle the types
|
||||||
if ( !jtdsDriver ) {
|
if ( getDriverKind() != SybaseDriverKind.JTDS ) {
|
||||||
ddlTypeRegistry.addDescriptor(
|
ddlTypeRegistry.addDescriptor(
|
||||||
CapacityDependentDdlType.builder( DATE, "bigdatetime", "bigdatetime", this )
|
CapacityDependentDdlType.builder( DATE, "bigdatetime", "bigdatetime", this )
|
||||||
.withTypeCapacity( 3, "datetime" )
|
.withTypeCapacity( 3, "datetime" )
|
||||||
@ -234,7 +234,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
|
|||||||
.getJdbcTypeRegistry();
|
.getJdbcTypeRegistry();
|
||||||
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, TinyIntJdbcType.INSTANCE );
|
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, TinyIntJdbcType.INSTANCE );
|
||||||
// At least the jTDS driver does not support this type code
|
// 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 );
|
jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.procedure.internal.JTDSCallableStatementSupport;
|
import org.hibernate.procedure.internal.JTDSCallableStatementSupport;
|
||||||
|
import org.hibernate.procedure.internal.SybaseCallableStatementSupport;
|
||||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||||
import org.hibernate.query.spi.QueryOptions;
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
@ -69,8 +70,6 @@
|
|||||||
*/
|
*/
|
||||||
public class SybaseDialect extends AbstractTransactSQLDialect {
|
public class SybaseDialect extends AbstractTransactSQLDialect {
|
||||||
|
|
||||||
protected final boolean jtdsDriver;
|
|
||||||
|
|
||||||
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 16, 0 );
|
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 16, 0 );
|
||||||
|
|
||||||
//All Sybase dialects share an IN list size limit.
|
//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 static final int PARAM_COUNT_LIMIT = 2000;
|
||||||
|
|
||||||
private final UniqueDelegate uniqueDelegate = new SkipNullableUniqueDelegate(this);
|
private final UniqueDelegate uniqueDelegate = new SkipNullableUniqueDelegate(this);
|
||||||
|
private final SybaseDriverKind driverKind;
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
protected final boolean jtdsDriver;
|
||||||
|
|
||||||
public SybaseDialect() {
|
public SybaseDialect() {
|
||||||
this( MINIMUM_VERSION );
|
this( MINIMUM_VERSION );
|
||||||
@ -86,13 +89,14 @@ public SybaseDialect() {
|
|||||||
|
|
||||||
public SybaseDialect(DatabaseVersion version) {
|
public SybaseDialect(DatabaseVersion version) {
|
||||||
super(version);
|
super(version);
|
||||||
jtdsDriver = true;
|
this.driverKind = SybaseDriverKind.OTHER;
|
||||||
|
this.jtdsDriver = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SybaseDialect(DialectResolutionInfo info) {
|
public SybaseDialect(DialectResolutionInfo info) {
|
||||||
super(info);
|
super(info);
|
||||||
jtdsDriver = info.getDriverName() != null
|
this.driverKind = SybaseDriverKind.determineKind( info );
|
||||||
&& info.getDriverName().contains( "jTDS" );
|
this.jtdsDriver = driverKind == SybaseDriverKind.JTDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -100,6 +104,10 @@ protected DatabaseVersion getMinimumSupportedVersion() {
|
|||||||
return MINIMUM_VERSION;
|
return MINIMUM_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SybaseDriverKind getDriverKind() {
|
||||||
|
return driverKind;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JdbcType resolveSqlTypeDescriptor(
|
public JdbcType resolveSqlTypeDescriptor(
|
||||||
String columnTypeName,
|
String columnTypeName,
|
||||||
@ -179,7 +187,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
|
|||||||
super.contributeTypes(typeContributions, serviceRegistry);
|
super.contributeTypes(typeContributions, serviceRegistry);
|
||||||
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
||||||
.getJdbcTypeRegistry();
|
.getJdbcTypeRegistry();
|
||||||
if ( jtdsDriver ) {
|
if ( driverKind == SybaseDriverKind.JTDS ) {
|
||||||
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
jdbcTypeRegistry.addDescriptor( Types.TINYINT, TinyIntAsSmallIntJdbcType.INSTANCE );
|
||||||
|
|
||||||
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
|
||||||
@ -217,7 +225,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
|
|||||||
@Override
|
@Override
|
||||||
public NationalizationSupport getNationalizationSupport() {
|
public NationalizationSupport getNationalizationSupport() {
|
||||||
// At least the jTDS driver doesn't support this
|
// At least the jTDS driver doesn't support this
|
||||||
return jtdsDriver ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
return driverKind == SybaseDriverKind.JTDS ? NationalizationSupport.IMPLICIT : super.getNationalizationSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -372,7 +380,7 @@ public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, D
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NameQualifierSupport getNameQualifierSupport() {
|
public NameQualifierSupport getNameQualifierSupport() {
|
||||||
if ( jtdsDriver ) {
|
if ( driverKind == SybaseDriverKind.JTDS ) {
|
||||||
return NameQualifierSupport.CATALOG;
|
return NameQualifierSupport.CATALOG;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -387,7 +395,15 @@ public UniqueDelegate getUniqueDelegate() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CallableStatementSupport getCallableStatementSupport() {
|
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
|
@Override
|
||||||
@ -402,7 +418,7 @@ public boolean supportsAlterColumnType() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IdentityColumnSupport getIdentityColumnSupport() {
|
public IdentityColumnSupport getIdentityColumnSupport() {
|
||||||
return jtdsDriver
|
return driverKind == SybaseDriverKind.JTDS
|
||||||
? AbstractTransactSQLIdentityColumnSupport.INSTANCE
|
? AbstractTransactSQLIdentityColumnSupport.INSTANCE
|
||||||
: SybaseJconnIdentityColumnSupport.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 @@
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|
||||||
import org.hibernate.procedure.spi.FunctionReturnImplementor;
|
import org.hibernate.procedure.spi.FunctionReturnImplementor;
|
||||||
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
import org.hibernate.procedure.spi.ProcedureCallImplementor;
|
||||||
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
|
import org.hibernate.procedure.spi.ProcedureParameterImplementor;
|
||||||
@ -26,6 +25,7 @@
|
|||||||
* and instead requires that we render this as `@param=?`.
|
* and instead requires that we render this as `@param=?`.
|
||||||
*/
|
*/
|
||||||
public class JTDSCallableStatementSupport extends AbstractStandardCallableStatementSupport {
|
public class JTDSCallableStatementSupport extends AbstractStandardCallableStatementSupport {
|
||||||
|
|
||||||
public static final JTDSCallableStatementSupport INSTANCE = new JTDSCallableStatementSupport();
|
public static final JTDSCallableStatementSupport INSTANCE = new JTDSCallableStatementSupport();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -33,7 +33,6 @@ public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedur
|
|||||||
final String procedureName = procedureCall.getProcedureName();
|
final String procedureName = procedureCall.getProcedureName();
|
||||||
final FunctionReturnImplementor<?> functionReturn = procedureCall.getFunctionReturn();
|
final FunctionReturnImplementor<?> functionReturn = procedureCall.getFunctionReturn();
|
||||||
final ProcedureParameterMetadataImplementor parameterMetadata = procedureCall.getParameterMetadata();
|
final ProcedureParameterMetadataImplementor parameterMetadata = procedureCall.getParameterMetadata();
|
||||||
final SharedSessionContractImplementor session = procedureCall.getSession();
|
|
||||||
final List<? extends ProcedureParameterImplementor<?>> registrations = parameterMetadata.getRegistrationsAsList();
|
final List<? extends ProcedureParameterImplementor<?>> registrations = parameterMetadata.getRegistrationsAsList();
|
||||||
final int paramStringSizeEstimate;
|
final int paramStringSizeEstimate;
|
||||||
if ( functionReturn == null && parameterMetadata.hasNamedParameters() ) {
|
if ( functionReturn == null && parameterMetadata.hasNamedParameters() ) {
|
||||||
@ -48,14 +47,10 @@ public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedur
|
|||||||
final StringBuilder buffer;
|
final StringBuilder buffer;
|
||||||
final int offset;
|
final int offset;
|
||||||
if ( functionReturn != null ) {
|
if ( functionReturn != null ) {
|
||||||
offset = 2;
|
throw new QueryException( "The jTDS driver does not support calling functions through the JDBC CallableStatement API" );
|
||||||
buffer = new StringBuilder( 11 + procedureName.length() + paramStringSizeEstimate ).append( "{?=call " );
|
|
||||||
builder.setFunctionReturn( functionReturn.toJdbcFunctionReturn( session ) );
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
offset = 1;
|
offset = 1;
|
||||||
buffer = new StringBuilder( 9 + procedureName.length() + paramStringSizeEstimate ).append( "{call " );
|
buffer = new StringBuilder( 9 + procedureName.length() + paramStringSizeEstimate ).append( "{call " );
|
||||||
}
|
|
||||||
|
|
||||||
buffer.append( procedureName );
|
buffer.append( procedureName );
|
||||||
|
|
||||||
@ -67,7 +62,7 @@ public JdbcOperationQueryCall interpretCall(ProcedureCallImplementor<?> procedur
|
|||||||
for ( int i = 0; i < registrations.size(); i++ ) {
|
for ( int i = 0; i < registrations.size(); i++ ) {
|
||||||
final ProcedureParameterImplementor<?> parameter = registrations.get( i );
|
final ProcedureParameterImplementor<?> parameter = registrations.get( i );
|
||||||
if ( parameter.getMode() == ParameterMode.REF_CURSOR ) {
|
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 );
|
buffer.append( sep );
|
||||||
final JdbcCallParameterRegistration registration = parameter.toJdbcParameterRegistration(
|
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.SQLServerDialect;
|
import org.hibernate.dialect.SQLServerDialect;
|
||||||
import org.hibernate.dialect.SpannerDialect;
|
import org.hibernate.dialect.SpannerDialect;
|
||||||
import org.hibernate.dialect.SybaseDialect;
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
|
import org.hibernate.dialect.SybaseDriverKind;
|
||||||
import org.hibernate.dialect.TimeZoneSupport;
|
import org.hibernate.dialect.TimeZoneSupport;
|
||||||
import org.hibernate.dialect.TiDBDialect;
|
import org.hibernate.dialect.TiDBDialect;
|
||||||
import org.hibernate.query.sqm.FetchClauseType;
|
import org.hibernate.query.sqm.FetchClauseType;
|
||||||
@ -651,4 +652,10 @@ public boolean apply(Dialect dialect) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class IsJtds implements DialectFeatureCheck {
|
||||||
|
public boolean apply(Dialect dialect) {
|
||||||
|
return dialect instanceof SybaseDialect && ( (SybaseDialect) dialect ).getDriverKind() == SybaseDriverKind.JTDS;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user