HHH-16533 Fix issues with jConnect driver related to temporal literals. Also improve truncation and casting SQL
This commit is contained in:
parent
473984f1eb
commit
53c7ef470a
|
@ -9,6 +9,10 @@ package org.hibernate.community.dialect;
|
|||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.boot.model.FunctionContributions;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
|
@ -64,6 +68,11 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
|||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
|
||||
|
||||
|
||||
/**
|
||||
* Superclass for all Sybase dialects.
|
||||
|
@ -295,16 +304,95 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
|||
if ( to == CastType.STRING ) {
|
||||
switch ( from ) {
|
||||
case DATE:
|
||||
return "str_replace(convert(varchar,?1,102),'.','-')";
|
||||
return "substring(convert(varchar,?1,23),1,10)";
|
||||
case TIME:
|
||||
return "convert(varchar,?1,108)";
|
||||
return "convert(varchar,?1,8)";
|
||||
case TIMESTAMP:
|
||||
return "str_replace(convert(varchar,?1,23),'T',' ')";
|
||||
return "convert(varchar,?1,140)";
|
||||
}
|
||||
}
|
||||
return super.castPattern( from, to );
|
||||
}
|
||||
|
||||
/* Something odd is going on with the jConnect driver when using JDBC escape syntax, so let's use native functions */
|
||||
|
||||
@Override
|
||||
public void appendDateTimeLiteral(
|
||||
SqlAppender appender,
|
||||
TemporalAccessor temporalAccessor,
|
||||
TemporalType precision,
|
||||
TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
appender.appendSql( "convert(date,'" );
|
||||
appendAsDate( appender, temporalAccessor );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
case TIME:
|
||||
appender.appendSql( "convert(time,'" );
|
||||
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
|
||||
appender.appendSql( "',8)" );
|
||||
break;
|
||||
case TIMESTAMP:
|
||||
appender.appendSql( "convert(datetime,'" );
|
||||
appendAsTimestampWithMillis( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
appender.appendSql( "convert(date,'" );
|
||||
appendAsDate( appender, date );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
case TIME:
|
||||
appender.appendSql( "convert(time,'" );
|
||||
appendAsLocalTime( appender, date );
|
||||
appender.appendSql( "',8)" );
|
||||
break;
|
||||
case TIMESTAMP:
|
||||
appender.appendSql( "convert(datetime,'" );
|
||||
appendAsTimestampWithMillis( appender, date, jdbcTimeZone );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDateTimeLiteral(
|
||||
SqlAppender appender,
|
||||
Calendar calendar,
|
||||
TemporalType precision,
|
||||
TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
appender.appendSql( "convert(date,'" );
|
||||
appendAsDate( appender, calendar );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
case TIME:
|
||||
appender.appendSql( "convert(time,'" );
|
||||
appendAsLocalTime( appender, calendar );
|
||||
appender.appendSql( "',8)" );
|
||||
break;
|
||||
case TIMESTAMP:
|
||||
appender.appendSql( "convert(datetime,'" );
|
||||
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateExtractField(TemporalUnit unit) {
|
||||
switch ( unit ) {
|
||||
|
|
|
@ -9,6 +9,10 @@ package org.hibernate.dialect;
|
|||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.boot.model.FunctionContributions;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
|
@ -63,6 +67,11 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
|||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
|
||||
|
||||
|
||||
/**
|
||||
* Superclass for all Sybase dialects.
|
||||
|
@ -313,16 +322,95 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
|||
if ( to == CastType.STRING ) {
|
||||
switch ( from ) {
|
||||
case DATE:
|
||||
return "str_replace(convert(varchar,?1,102),'.','-')";
|
||||
return "substring(convert(varchar,?1,23),1,10)";
|
||||
case TIME:
|
||||
return "convert(varchar,?1,108)";
|
||||
return "convert(varchar,?1,8)";
|
||||
case TIMESTAMP:
|
||||
return "str_replace(convert(varchar,?1,23),'T',' ')";
|
||||
return "convert(varchar,?1,140)";
|
||||
}
|
||||
}
|
||||
return super.castPattern( from, to );
|
||||
}
|
||||
|
||||
/* Something odd is going on with the jConnect driver when using JDBC escape syntax, so let's use native functions */
|
||||
|
||||
@Override
|
||||
public void appendDateTimeLiteral(
|
||||
SqlAppender appender,
|
||||
TemporalAccessor temporalAccessor,
|
||||
TemporalType precision,
|
||||
TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
appender.appendSql( "convert(date,'" );
|
||||
appendAsDate( appender, temporalAccessor );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
case TIME:
|
||||
appender.appendSql( "convert(time,'" );
|
||||
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
|
||||
appender.appendSql( "',8)" );
|
||||
break;
|
||||
case TIMESTAMP:
|
||||
appender.appendSql( "convert(datetime,'" );
|
||||
appendAsTimestampWithMillis( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
appender.appendSql( "convert(date,'" );
|
||||
appendAsDate( appender, date );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
case TIME:
|
||||
appender.appendSql( "convert(time,'" );
|
||||
appendAsLocalTime( appender, date );
|
||||
appender.appendSql( "',8)" );
|
||||
break;
|
||||
case TIMESTAMP:
|
||||
appender.appendSql( "convert(datetime,'" );
|
||||
appendAsTimestampWithMillis( appender, date, jdbcTimeZone );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDateTimeLiteral(
|
||||
SqlAppender appender,
|
||||
Calendar calendar,
|
||||
TemporalType precision,
|
||||
TimeZone jdbcTimeZone) {
|
||||
switch ( precision ) {
|
||||
case DATE:
|
||||
appender.appendSql( "convert(date,'" );
|
||||
appendAsDate( appender, calendar );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
case TIME:
|
||||
appender.appendSql( "convert(time,'" );
|
||||
appendAsLocalTime( appender, calendar );
|
||||
appender.appendSql( "',8)" );
|
||||
break;
|
||||
case TIMESTAMP:
|
||||
appender.appendSql( "convert(datetime,'" );
|
||||
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
|
||||
appender.appendSql( "',140)" );
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateExtractField(TemporalUnit unit) {
|
||||
switch ( unit ) {
|
||||
|
|
|
@ -95,7 +95,7 @@ public class SybaseTruncFunction extends TruncFunction {
|
|||
sqlAppender.append( '(' );
|
||||
sqlAppender.append( "datetime,substring(convert(varchar," );
|
||||
sqlAstArguments.get( 0 ).accept( walker );
|
||||
sqlAppender.append( ",21),1,17" );
|
||||
sqlAppender.append( ",140),1,26" );
|
||||
if ( sqlAstArguments.size() > 1 ) {
|
||||
sqlAppender.append( "-len(" );
|
||||
sqlAstArguments.get( 1 ).accept( walker );
|
||||
|
@ -105,7 +105,7 @@ public class SybaseTruncFunction extends TruncFunction {
|
|||
else {
|
||||
sqlAppender.append( ')' );
|
||||
}
|
||||
sqlAppender.append( ",21)" );
|
||||
sqlAppender.append( ",140)" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,22 +119,22 @@ public class SybaseTruncFunction extends TruncFunction {
|
|||
final String literal;
|
||||
switch ( temporalUnit ) {
|
||||
case YEAR:
|
||||
literal = "/01/01 00:00:00";
|
||||
literal = "-01-01T00:00:00.000000";
|
||||
break;
|
||||
case MONTH:
|
||||
literal = "/01 00:00:00";
|
||||
literal = "-01T00:00:00.000000";
|
||||
break;
|
||||
case DAY:
|
||||
literal = " 00:00:00";
|
||||
literal = "T00:00:00.000000";
|
||||
break;
|
||||
case HOUR:
|
||||
literal = ":00:00";
|
||||
literal = ":00:00.000000";
|
||||
break;
|
||||
case MINUTE:
|
||||
literal = ":00";
|
||||
literal = ":00.000000";
|
||||
break;
|
||||
case SECOND:
|
||||
literal = null;
|
||||
literal = ".000000";
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException( "Temporal unit not supported [" + temporalUnit + "]" );
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.cfg.AvailableSettings;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.PostgresPlusDialect;
|
||||
import org.hibernate.dialect.SybaseASEDialect;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
|
||||
|
@ -31,6 +32,7 @@ import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -40,13 +42,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RequiresDialectFeatureGroup(
|
||||
value = {
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsExpectedLobUsagePattern.class),
|
||||
@RequiresDialectFeature(feature = BasicOperationsTest.OracleDialectChecker.class)
|
||||
},
|
||||
jiraKey = "HHH-6834"
|
||||
)
|
||||
@SkipForDialect(dialectClass = OracleDialect.class, reason = "HHH-6834")
|
||||
@SkipForDialect(dialectClass = PostgresPlusDialect.class, reason = "HHH-6834")
|
||||
@SkipForDialect(dialectClass = SybaseASEDialect.class, reason = "jConnect reports the type code 11 for bigdatetime columns, which is an unknown type code..")
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsExpectedLobUsagePattern.class, jiraKey = "HHH-6834")
|
||||
@DomainModel(
|
||||
annotatedClasses = { SomeEntity.class, SomeOtherEntity.class }
|
||||
)
|
||||
|
@ -60,13 +59,6 @@ public class BasicOperationsTest {
|
|||
private static final String SOME_OTHER_ENTITY_TABLE_NAME = "SOMEOTHERENTITY";
|
||||
|
||||
|
||||
public static class OracleDialectChecker implements DialectFeatureCheck {
|
||||
@Override
|
||||
public boolean apply(Dialect dialect) {
|
||||
return !( dialect instanceof OracleDialect ) && !( dialect instanceof PostgresPlusDialect );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndDelete(SessionFactoryScope scope) {
|
||||
Date now = new Date();
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.Session;
|
|||
import org.hibernate.Transaction;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import org.hibernate.dialect.SybaseDialect;
|
||||
import org.hibernate.type.descriptor.java.JdbcTimestampJavaType;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
@ -93,6 +94,10 @@ public class DbVersionTest extends BaseCoreFunctionalTestCase {
|
|||
s.close();
|
||||
|
||||
Timestamp steveTimestamp = steve.getTimestamp();
|
||||
if ( getDialect() instanceof SybaseDialect ) {
|
||||
// Sybase has 1/300th sec precision, but not for the `getdate()` function which we use for DB generation
|
||||
steveTimestamp = new Timestamp( steveTimestamp.getTime() );
|
||||
}
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
|
|
Loading…
Reference in New Issue