HHH-15833 Disable named parameters for jConnect JDBC driver

This commit is contained in:
Christian Beikov 2023-04-27 13:12:03 +02:00
parent e60d2c878b
commit aad0c55f9b
9 changed files with 334 additions and 32 deletions

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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 ) );
}
else {
offset = 1;
buffer = new StringBuilder( 9 + procedureName.length() + paramStringSizeEstimate ).append( "{call " );
throw new QueryException( "The jTDS driver does not support calling functions through the JDBC CallableStatement API" );
}
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(

View File

@ -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();
}
}

View File

@ -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 );
});
}
}

View File

@ -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;
}
}
}