Skip to content

Commit 3e205f9

Browse files
committed
Firebird: TimeOnly construction with hours overflow check
1 parent 6c59d90 commit 3e205f9

1 file changed

Lines changed: 21 additions & 17 deletions

File tree

  • Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5

Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/v2_5/Compiler.cs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ internal class Compiler : SqlCompiler
2424
protected const long MillisecondsPerDay = 86400000;
2525
protected const long MillisecondsPerSecond = 1000L;
2626

27-
//protected static readonly long NanosecondsPerDay = TimeSpan.FromDays(1).Ticks * 100;
28-
//protected static readonly long NanosecondsPerSecond = 1000000000;
29-
//protected static readonly long NanosecondsPerMillisecond = 1000000;
30-
//protected static readonly long MillisecondsPerDay = (long) TimeSpan.FromDays(1).TotalMilliseconds;
31-
//protected static readonly long MillisecondsPerSecond = 1000L;
3227
private bool case_SqlDateTimePart_DayOfYear;
3328
private bool case_SqlDateTimePart_Second;
3429

@@ -326,26 +321,35 @@ protected virtual SqlExpression ConstructDate(IReadOnlyList<SqlExpression> argum
326321

327322
protected virtual SqlExpression ConstructTime(IReadOnlyList<SqlExpression> arguments)
328323
{
324+
SqlExpression hour, minute, second, millisecond;
329325
if (arguments.Count == 4) {
330-
return DateAddMillisecond(
331-
DateAddSecond(
332-
DateAddMinute(
333-
DateAddHour(
334-
SqlDml.Cast(SqlDml.Literal(new TimeOnly(0, 0, 0)), SqlType.Time),
335-
arguments[0]),
336-
arguments[1]),
337-
arguments[2]),
338-
arguments[3]);
326+
hour = arguments[0];
327+
minute = arguments[1];
328+
second = arguments[2];
329+
millisecond = arguments[3] * 10;
339330
}
340331
else if (arguments.Count == 1) {
341332
var ticks = arguments[0];
342-
return TimeAddInterval(
343-
SqlDml.Cast(SqlDml.Literal(new TimeOnly(0, 0, 0, 0)), SqlType.Time),
344-
SqlHelper.IsTimeSpanTicks(ticks, out var sourceInterval) ? sourceInterval : ticks * 100);
333+
// try to optimize and reduce calculations when TimeSpan.Ticks where used for TimeOnly(ticks) ctor
334+
ticks = SqlHelper.IsTimeSpanTicks(ticks, out var sourceInterval) ? sourceInterval / 100 : ticks;
335+
hour = SqlDml.Cast(ticks / 36000000000, SqlType.Int32);
336+
minute = SqlDml.Cast((ticks / 600000000) % 60, SqlType.Int32);
337+
second = SqlDml.Cast((ticks / 10000000) % 60, SqlType.Int32);
338+
millisecond = SqlDml.Cast((ticks % 10000000) / 1000, SqlType.Int32);
345339
}
346340
else {
347341
throw new InvalidOperationException("Unsupported count of parameters");
348342
}
343+
344+
// using string version of time allows to control hours overflow
345+
// we cannot add hours, minutes and other parts to 00:00:00.0000 time
346+
// because hours might step over 24 hours and start counting from 0.
347+
var hourString = SqlDml.Cast(hour, new SqlValueType(SqlType.VarChar, 3));
348+
var minuteString = SqlDml.Cast(minute, new SqlValueType(SqlType.VarChar, 2));
349+
var secondString = SqlDml.Cast(second, new SqlValueType(SqlType.VarChar, 2));
350+
var millisecondString = SqlDml.Cast(millisecond, new SqlValueType(SqlType.VarChar, 4));
351+
var composedTimeString = SqlDml.Concat(hourString, SqlDml.Literal(":"), minuteString, SqlDml.Literal(":"), secondString, SqlDml.Literal("."), millisecondString);
352+
return SqlDml.Cast(composedTimeString, SqlType.Time);
349353
}
350354

351355
protected virtual SqlExpression TimeToNanoseconds(SqlExpression time)

0 commit comments

Comments
 (0)