1010using Xtensive . Sql . Ddl ;
1111using Xtensive . Sql . Dml ;
1212using Xtensive . Core ;
13+ using System . Collections . Generic ;
1314
1415namespace Xtensive . Sql . Drivers . Firebird . v2_5
1516{
1617 internal class Compiler : SqlCompiler
1718 {
18- protected static readonly long NanosecondsPerDay = TimeSpan . FromDays ( 1 ) . Ticks * 100 ;
19- protected static readonly long NanosecondsPerSecond = 1000000000 ;
20- protected static readonly long NanosecondsPerMillisecond = 1000000 ;
21- protected static readonly long MillisecondsPerDay = ( long ) TimeSpan . FromDays ( 1 ) . TotalMilliseconds ;
22- protected static readonly long MillisecondsPerSecond = 1000L ;
19+ protected const long NanosecondsPerDay = 86400000000000 ;
20+ protected const long NanosecondsPerHour = 3600000000000 ;
21+ protected const long NanosecondsPerMinute = 60000000000 ;
22+ protected const long NanosecondsPerSecond = 1000000000 ;
23+ protected const long NanosecondsPerMillisecond = 1000000 ;
24+ protected const long MillisecondsPerDay = 86400000 ;
25+ protected const long MillisecondsPerSecond = 1000L ;
26+
2327 private bool case_SqlDateTimePart_DayOfYear ;
2428 private bool case_SqlDateTimePart_Second ;
2529
@@ -228,10 +232,7 @@ public override void Visit(SqlFunctionCall node)
228232 Visit ( DateAddYear ( arguments [ 0 ] , arguments [ 1 ] ) ) ;
229233 return ;
230234 case SqlFunctionType . DateTimeConstruct :
231- Visit ( DateAddDay ( DateAddMonth ( DateAddYear ( SqlDml . Cast ( SqlDml . Literal ( new DateTime ( 2001 , 1 , 1 ) ) , SqlType . DateTime ) ,
232- arguments [ 0 ] - 2001 ) ,
233- arguments [ 1 ] - 1 ) ,
234- arguments [ 2 ] - 1 ) ) ;
235+ ConstructDateTime ( arguments ) . AcceptVisitor ( this ) ;
235236 return ;
236237#if NET6_0_OR_GREATER
237238 case SqlFunctionType . DateAddYears:
@@ -244,10 +245,7 @@ public override void Visit(SqlFunctionCall node)
244245 Visit( DateAddDay ( arguments [ 0 ] , arguments [ 1 ] ) ) ;
245246 return ;
246247 case SqlFunctionType . DateConstruct:
247- Visit( DateAddDay ( DateAddMonth ( DateAddYear ( SqlDml . Cast ( SqlDml . Literal ( new DateOnly ( 2001 , 1 , 1 ) ) , SqlType . Date) ,
248- arguments [ 0 ] - 2001 ) ,
249- arguments[ 1 ] - 1 ) ,
250- arguments[ 2 ] - 1 ) ) ;
248+ ConstructDate( arguments ) . AcceptVisitor( this ) ;
251249 return ;
252250 case SqlFunctionType . TimeAddHours:
253251 Visit( DateAddHour ( node . Arguments [ 0 ] , node . Arguments [ 1 ] ) ) ;
@@ -256,11 +254,10 @@ public override void Visit(SqlFunctionCall node)
256254 Visit( DateAddMinute ( node . Arguments [ 0 ] , node . Arguments [ 1 ] ) ) ;
257255 return ;
258256 case SqlFunctionType . TimeConstruct:
259- Visit( DateAddMillisecond ( DateAddSecond ( DateAddMinute ( DateAddHour ( SqlDml . Cast ( SqlDml . Literal ( new TimeOnly ( 0 , 0 , 0 ) ) , SqlType . Time) ,
260- arguments [ 0 ] ) ,
261- arguments [ 1 ] ) ,
262- arguments [ 2 ] ) ,
263- arguments [ 3 ] ) ) ;
257+ ConstructTime( arguments ) . AcceptVisitor( this ) ;
258+ return ;
259+ case SqlFunctionType . TimeToNanoseconds:
260+ TimeToNanoseconds( arguments [ 0 ] ) . AcceptVisitor ( this ) ;
264261 return ;
265262 case SqlFunctionType . DateToString:
266263 Visit( DateToString ( arguments [ 0 ] ) ) ;
@@ -299,6 +296,73 @@ public override void Visit(SqlAlterSequence node)
299296 translator . Translate ( context , node , NodeSection . Exit ) ;
300297 }
301298
299+ protected virtual SqlExpression ConstructDateTime ( IReadOnlyList < SqlExpression > arguments )
300+ {
301+ return DateAddDay (
302+ DateAddMonth (
303+ DateAddYear (
304+ SqlDml . Cast ( SqlDml . Literal ( new DateTime ( 2001 , 1 , 1 ) ) , SqlType . DateTime ) ,
305+ arguments [ 0 ] - 2001 ) ,
306+ arguments [ 1 ] - 1 ) ,
307+ arguments [ 2 ] - 1 ) ;
308+ }
309+ #if NET6_0_OR_GREATER
310+
311+ protected virtual SqlExpression ConstructDate ( IReadOnlyList < SqlExpression > arguments )
312+ {
313+ return DateAddDay (
314+ DateAddMonth (
315+ DateAddYear (
316+ SqlDml . Cast ( SqlDml . Literal ( new DateOnly ( 2001 , 1 , 1 ) ) , SqlType . Date ) ,
317+ arguments [ 0 ] - 2001 ) ,
318+ arguments [ 1 ] - 1 ) ,
319+ arguments [ 2 ] - 1 ) ;
320+ }
321+
322+ protected virtual SqlExpression ConstructTime ( IReadOnlyList < SqlExpression > arguments )
323+ {
324+ SqlExpression hour , minute , second , millisecond ;
325+ if ( arguments . Count == 4 ) {
326+ hour = arguments [ 0 ] ;
327+ minute = arguments [ 1 ] ;
328+ second = arguments [ 2 ] ;
329+ millisecond = arguments [ 3 ] * 10 ;
330+ }
331+ else if ( arguments . Count == 1 ) {
332+ var ticks = arguments [ 0 ] ;
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 ) ;
339+ }
340+ else {
341+ throw new InvalidOperationException ( "Unsupported count of parameters" ) ;
342+ }
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 ) ;
353+ }
354+
355+ protected virtual SqlExpression TimeToNanoseconds ( SqlExpression time )
356+ {
357+ var nPerHour = SqlDml . Extract ( SqlTimePart . Hour , time ) * NanosecondsPerHour ;
358+ var nPerMinute = SqlDml . Extract ( SqlTimePart . Minute , time ) * NanosecondsPerMinute ;
359+ var nPerSecond = SqlDml . Extract ( SqlTimePart . Second , time ) * NanosecondsPerSecond ;
360+ var nPerMillisecond = SqlDml . Extract ( SqlTimePart . Millisecond , time ) * NanosecondsPerMillisecond ;
361+
362+ return nPerHour + nPerMinute + nPerSecond + nPerMillisecond ;
363+ }
364+ #endif
365+
302366 #region Static helpers
303367
304368 protected static SqlExpression DateTimeSubtractDateTime ( SqlExpression date1 , SqlExpression date2 )
0 commit comments