10
10
using Xtensive . Sql . Ddl ;
11
11
using Xtensive . Sql . Dml ;
12
12
using Xtensive . Core ;
13
+ using System . Collections . Generic ;
13
14
14
15
namespace Xtensive . Sql . Drivers . Firebird . v2_5
15
16
{
16
17
internal class Compiler : SqlCompiler
17
18
{
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
+
23
27
private bool case_SqlDateTimePart_DayOfYear ;
24
28
private bool case_SqlDateTimePart_Second ;
25
29
@@ -228,10 +232,7 @@ public override void Visit(SqlFunctionCall node)
228
232
Visit ( DateAddYear ( arguments [ 0 ] , arguments [ 1 ] ) ) ;
229
233
return ;
230
234
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 ) ;
235
236
return ;
236
237
#if NET6_0_OR_GREATER
237
238
case SqlFunctionType . DateAddYears:
@@ -244,10 +245,7 @@ public override void Visit(SqlFunctionCall node)
244
245
Visit( DateAddDay ( arguments [ 0 ] , arguments [ 1 ] ) ) ;
245
246
return ;
246
247
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 ) ;
251
249
return ;
252
250
case SqlFunctionType . TimeAddHours:
253
251
Visit( DateAddHour ( node . Arguments [ 0 ] , node . Arguments [ 1 ] ) ) ;
@@ -256,11 +254,10 @@ public override void Visit(SqlFunctionCall node)
256
254
Visit( DateAddMinute ( node . Arguments [ 0 ] , node . Arguments [ 1 ] ) ) ;
257
255
return ;
258
256
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 ) ;
264
261
return ;
265
262
case SqlFunctionType . DateToString:
266
263
Visit( DateToString ( arguments [ 0 ] ) ) ;
@@ -299,6 +296,73 @@ public override void Visit(SqlAlterSequence node)
299
296
translator . Translate ( context , node , NodeSection . Exit ) ;
300
297
}
301
298
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
+
302
366
#region Static helpers
303
367
304
368
protected static SqlExpression DateTimeSubtractDateTime ( SqlExpression date1 , SqlExpression date2 )
0 commit comments