Skip to content

Commit

Permalink
HHH-16533 Fix issues with jConnect driver related to temporal literal…
Browse files Browse the repository at this point in the history
…s. Also improve truncation and casting SQL
  • Loading branch information
beikov committed May 2, 2023
1 parent 473984f commit 53c7ef4
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
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;
Expand Down Expand Up @@ -64,6 +68,11 @@

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.
Expand Down Expand Up @@ -295,16 +304,95 @@ public String castPattern(CastType from, CastType to) {
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 ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
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;
Expand Down Expand Up @@ -63,6 +67,11 @@

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.
Expand Down Expand Up @@ -313,16 +322,95 @@ public String castPattern(CastType from, CastType to) {
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 ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public void render(
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 );
Expand All @@ -105,7 +105,7 @@ public void render(
else {
sqlAppender.append( ')' );
}
sqlAppender.append( ",21)" );
sqlAppender.append( ",140)" );
}

@Override
Expand All @@ -119,22 +119,22 @@ protected <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
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 + "]" );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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;
Expand All @@ -31,6 +32,7 @@
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;
Expand All @@ -40,13 +42,10 @@
/**
* @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 }
)
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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;
Expand Down Expand Up @@ -93,6 +94,10 @@ public void testCollectionNoVersion() {
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();
Expand Down

0 comments on commit 53c7ef4

Please sign in to comment.