Skip to content

Commit

Permalink
HHH-18043 Change the temporal arithmetic to use nanoseconds
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed May 2, 2024
1 parent 80dfc59 commit c2f6abd
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -811,19 +811,10 @@ public int getDefaultTimestampPrecision() {
return 7;
}

/**
* SQL server supports up to 7 decimal digits of
* fractional second precision in a datetime2,
* but unfortunately its duration arithmetic
* functions have a nasty habit of overflowing.
* So to give ourselves a little extra headroom,
* we will use {@code microsecond} as the native
* unit of precision (but even then we have to
* use tricks when calling {@code dateadd()}).
*/
@Override
public long getFractionalSecondPrecisionInNanos() {
return 1_000; //microseconds!
// return 100; // 1/10th microsecond
return 1; // Even though SQL Server only supports 1/10th microsecond precision, use nanosecond scale for easier computation
}

@Override
Expand All @@ -840,7 +831,7 @@ public String extractPattern(TemporalUnit unit) {
// return "(datepart(second,?2)*1000000000+datepart(nanosecond,?2))";
case SECOND:
//this should evaluate to a floating point type
return "(datepart(second,?2)+datepart(nanosecond,?2)/1e9)";
return "(datepart(second,?2)+datepart(nanosecond,?2)/1000000000)";
case EPOCH:
return "datediff_big(second, '1970-01-01', ?2)";
case WEEK:
Expand All @@ -861,13 +852,11 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType,
// calls to dateadd() to add a whole duration
switch (unit) {
case NANOSECOND:
//Java Durations are usually the only thing
//we find expressed in nanosecond precision,
//and they can easily be very large
return "dateadd(nanosecond,?2%1000000000,dateadd(second,?2/1000000000,?3))";
case NATIVE:
//microsecond is the "native" precision
return "dateadd(microsecond,?2%1000000,dateadd(second,?2/1000000,?3))";
return "dateadd(nanosecond,?2%1000000000,dateadd(second,?2/1000000000,?3))";
// case NATIVE:
// // 1/10th microsecond is the "native" precision
// return "dateadd(nanosecond,?2%10000000,dateadd(second,?2/10000000,?3))";
default:
return "dateadd(?1,?2,?3)";
}
Expand All @@ -876,7 +865,7 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType,
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
if ( unit == TemporalUnit.NATIVE ) {//use microsecond as the "native" precision
return "datediff_big(microsecond,?2,?3)";
return "datediff_big(nanosecond,?2,?3)";
}

//datediff() returns an int, and can easily
Expand All @@ -889,9 +878,9 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT

@Override
public String translateDurationField(TemporalUnit unit) {
//use microsecond as the "native" precision
//use nanosecond as the "native" precision
if ( unit == TemporalUnit.NATIVE ) {
return "microsecond";
return "nanosecond";
}

return super.translateDurationField( unit );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -779,19 +779,10 @@ public int getDefaultTimestampPrecision() {
return 7;
}

/**
* SQL server supports up to 7 decimal digits of
* fractional second precision in {@code datetime2},
* but unfortunately its duration arithmetic
* functions have a nasty habit of overflowing.
* So to give ourselves a little extra headroom,
* we will use {@code microsecond} as the native
* unit of precision (but even then we have to
* use tricks when calling {@code dateadd()}).
*/
@Override
public long getFractionalSecondPrecisionInNanos() {
return 1_000; //microseconds!
// return 100; // 1/10th microsecond
return 1; // Even though SQL Server only supports 1/10th microsecond precision, use nanosecond scale for easier computation
}

@Override
Expand All @@ -808,7 +799,7 @@ public String extractPattern(TemporalUnit unit) {
// return "(datepart(second,?2)*1000000000+datepart(nanosecond,?2))";
case SECOND:
//this should evaluate to a floating point type
return "(datepart(second,?2)+datepart(nanosecond,?2)/1e9)";
return "(datepart(second,?2)+datepart(nanosecond,?2)/1000000000)";
case EPOCH:
return "datediff_big(second, '1970-01-01', ?2)";
default:
Expand All @@ -824,13 +815,11 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType,
// calls to dateadd() to add a whole duration
switch (unit) {
case NANOSECOND:
//Java Durations are usually the only thing
//we find expressed in nanosecond precision,
//and they can easily be very large
return "dateadd(nanosecond,?2%1000000000,dateadd(second,?2/1000000000,?3))";
case NATIVE:
//microsecond is the "native" precision
return "dateadd(microsecond,?2%1000000,dateadd(second,?2/1000000,?3))";
return "dateadd(nanosecond,?2%1000000000,dateadd(second,?2/1000000000,?3))";
// case NATIVE:
// // 1/10th microsecond is the "native" precision
// return "dateadd(nanosecond,?2%10000000,dateadd(second,?2/10000000,?3))";
default:
return "dateadd(?1,?2,?3)";
}
Expand All @@ -839,8 +828,8 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType,
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
if ( unit == TemporalUnit.NATIVE ) {
//use microsecond as the "native" precision
return "datediff_big(microsecond,?2,?3)";
//use nanosecond as the "native" precision
return "datediff_big(nanosecond,?2,?3)";
}
else {
//datediff() returns an int, and can easily
Expand All @@ -854,9 +843,9 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT

@Override
public String translateDurationField(TemporalUnit unit) {
//use microsecond as the "native" precision
//use nanosecond as the "native" precision
if ( unit == TemporalUnit.NATIVE ) {
return "microsecond";
return "nanosecond";
}
else {
return super.translateDurationField( unit );
Expand Down

0 comments on commit c2f6abd

Please sign in to comment.