Skip to content

Commit 46d168c

Browse files
committed
SQLite: No support for TimeConstruct
There is no way to control hours overflow, STRFTIME returns NULL if value is incorrect, this opens way to possibly corrupted query results which is bad.
1 parent af695af commit 46d168c

File tree

1 file changed

+35
-67
lines changed
  • Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/v3

1 file changed

+35
-67
lines changed

Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/v3/Compiler.cs

Lines changed: 35 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ internal class Compiler : SqlCompiler
3232
private const string DateTimeFormat = "%Y-%m-%d %H:%M:%f";
3333
private const string DateTimeIsoFormat = "%Y-%m-%dT%H:%M:%S";
3434
private const string DateTimeOffsetExampleString = "2001-02-03 04:05:06.789+02.45";
35+
private const string STRFTIMEFunctionName = "STRFTIME";
3536

3637
private static readonly int StartOffsetIndex = DateTimeOffsetExampleString.IndexOf('+');
3738

@@ -217,9 +218,6 @@ public override void Visit(SqlFunctionCall node)
217218
arguments[1] - 1),
218219
arguments[2] - 1).AcceptVisitor(this);
219220
return;
220-
case SqlFunctionType.TimeConstruct:
221-
TimeConstruct(arguments).AcceptVisitor(this);
222-
return;
223221
case SqlFunctionType.TimeToNanoseconds:
224222
TimeToNanoseconds(arguments[0]).AcceptVisitor(this);
225223
return;
@@ -461,9 +459,9 @@ private static SqlExpression DateTimeAddInterval(SqlExpression date, SqlExpressi
461459
DateTimeAddSeconds(date, interval / Convert.ToDouble(NanosecondsPerSecond));
462460

463461
private static SqlExpression DateTimeTruncate(SqlExpression date) =>
464-
DateTime(SqlDml.FunctionCall("STRFTIME", DateWithZeroTimeFormat, date));
462+
DateTime(SqlDml.FunctionCall(STRFTIMEFunctionName, DateWithZeroTimeFormat, date));
465463

466-
private static SqlExpression DateTime(SqlExpression date) => SqlDml.FunctionCall("STRFTIME", DateTimeFormat, date);
464+
private static SqlExpression DateTime(SqlExpression date) => SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, date);
467465

468466
private static SqlCast CastToInt(SqlExpression arg) => SqlDml.Cast(arg, SqlType.Int32);
469467

@@ -504,71 +502,41 @@ private static SqlExpression DateTimeOffsetExtractOffsetAsTotalNanoseconds(SqlEx
504502
DateTimeSubtractDateTime(DateTimeOffsetExtractDateTimeAsString(dateTimeOffset), dateTimeOffset);
505503

506504
private static SqlExpression DateTimeOffsetToUtcDateTime(SqlExpression dateTimeOffset) =>
507-
SqlDml.FunctionCall("STRFTIME", DateTimeFormat, dateTimeOffset, "LOCALTIME", "UTC");
505+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, dateTimeOffset, "LOCALTIME", "UTC");
508506

509507
private static SqlExpression DateTimeOffsetToLocalDateTime(SqlExpression dateTimeOffset) =>
510-
SqlDml.FunctionCall("STRFTIME", DateTimeFormat, dateTimeOffset, "LOCALTIME");
508+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, dateTimeOffset, "LOCALTIME");
511509

512510
private static SqlExpression DateTimeToDateTimeOffset(SqlExpression dateTime) =>
513511
SqlDml.Concat(DateTime(dateTime), ServerOffsetAsString());
514512

515513
private static SqlExpression DateTimeOffsetToDateTime(SqlExpression dateTimeOffset) =>
516514
SqlDml.Cast(SqlDml.Extract(SqlDateTimeOffsetPart.DateTime, dateTimeOffset), SqlType.DateTime);
517-
//SqlDml.Concat(DateTime(node.Arguments[0]), ServerOffsetAsString());
518515

519516
private static SqlExpression DateTimeToStringIso(SqlExpression dateTime) =>
520-
SqlDml.FunctionCall("STRFTIME", DateTimeIsoFormat, dateTime);
517+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeIsoFormat, dateTime);
521518

522519
private static SqlExpression DateTimeAddYear(SqlExpression date, SqlExpression years) =>
523-
SqlDml.FunctionCall("STRFTIME", DateTimeFormat, date, SqlDml.Concat(years, " ", "YEARS"));
520+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, date, SqlDml.Concat(years, " ", "YEARS"));
524521

525522
private static SqlExpression DateTimeAddMonth(SqlExpression date, SqlExpression months) =>
526-
SqlDml.FunctionCall("STRFTIME", DateTimeFormat, date, SqlDml.Concat(months, " ", "MONTHS"));
523+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, date, SqlDml.Concat(months, " ", "MONTHS"));
527524

528525
private static SqlExpression DateTimeAddDay(SqlExpression date, SqlExpression days) =>
529-
SqlDml.FunctionCall("STRFTIME", DateTimeFormat, date, SqlDml.Concat(days, " ", "DAYS"));
526+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, date, SqlDml.Concat(days, " ", "DAYS"));
530527

531528
private static SqlExpression DateTimeAddSeconds(SqlExpression date, SqlExpression seconds) =>
532-
SqlDml.FunctionCall("STRFTIME", DateTimeFormat, date, SqlDml.Concat(seconds, " ", "SECONDS"));
529+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, date, SqlDml.Concat(seconds, " ", "SECONDS"));
533530
#if NET6_0_OR_GREATER
534531

535532
private static SqlExpression DateAddYear(SqlExpression date, SqlExpression years) =>
536-
SqlDml.FunctionCall("STRFTIME", DateFormat, date, SqlDml.Concat(years, " ", "YEARS"));
533+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateFormat, date, SqlDml.Concat(years, " ", "YEARS"));
537534

538535
private static SqlExpression DateAddMonth(SqlExpression date, SqlExpression months) =>
539-
SqlDml.FunctionCall("STRFTIME", DateFormat, date, SqlDml.Concat(months, " ", "MONTHS"));
536+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateFormat, date, SqlDml.Concat(months, " ", "MONTHS"));
540537

541538
private static SqlExpression DateAddDay(SqlExpression date, SqlExpression days) =>
542-
SqlDml.FunctionCall("STRFTIME", DateFormat, date, SqlDml.Concat(days, " ", "DAYS"));
543-
544-
private static SqlExpression TimeConstruct(IReadOnlyList<SqlExpression> arguments)
545-
{
546-
SqlExpression hour, minute, second, millisecond;
547-
if (arguments.Count == 4) {
548-
hour = arguments[0];
549-
minute = arguments[1];
550-
second = arguments[2];
551-
millisecond = arguments[3];
552-
}
553-
else if (arguments.Count == 1) {
554-
var ticks = arguments[0];
555-
hour = SqlDml.Cast(ticks / 36000000000, SqlType.Int32);
556-
minute = SqlDml.Cast((ticks / 600000000) % 60, SqlType.Int32);
557-
second = SqlDml.Cast((ticks / 10000000) % 60, SqlType.Int32);
558-
millisecond = SqlDml.Cast(ticks % 10000000, SqlType.Int32);
559-
}
560-
else {
561-
throw new InvalidOperationException("Unsupported count of parameters");
562-
}
563-
return TimeAddSeconds(
564-
TimeAddMinutes(
565-
TimeAddHours(
566-
SqlDml.Literal(new TimeOnly(0, 0, 0, 0)),
567-
hour),
568-
minute),
569-
second,
570-
millisecond);
571-
}
539+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateFormat, date, SqlDml.Concat(days, " ", "DAYS"));
572540

573541
private static SqlExpression TimeToNanoseconds(SqlExpression time)
574542
{
@@ -580,16 +548,16 @@ private static SqlExpression TimeToNanoseconds(SqlExpression time)
580548
return nPerHour + nPerMinute + nPerSecond + nPerMillisecond;
581549
}
582550

583-
private static SqlExpression TimeAddHours(SqlExpression time, SqlExpression seconds) =>
584-
SqlDml.FunctionCall("STRFTIME", TimeFormat, time, SqlDml.Concat(seconds, " ", "HOURS"));
551+
private static SqlExpression TimeAddHours(SqlExpression time, SqlExpression hours) =>
552+
SqlDml.FunctionCall(STRFTIMEFunctionName, TimeFormat, time, SqlDml.Concat(hours, " ", "HOURS"));
585553

586-
private static SqlExpression TimeAddMinutes(SqlExpression time, SqlExpression seconds) =>
587-
SqlDml.FunctionCall("STRFTIME", TimeFormat, time, SqlDml.Concat(seconds, " ", "MINUTES"));
554+
private static SqlExpression TimeAddMinutes(SqlExpression time, SqlExpression minutes) =>
555+
SqlDml.FunctionCall(STRFTIMEFunctionName, TimeFormat, time, SqlDml.Concat(minutes, " ", "MINUTES"));
588556

589557
private static SqlExpression TimeAddSeconds(SqlExpression time, SqlExpression seconds, SqlExpression milliseconds) =>
590-
SqlDml.FunctionCall("STRFTIME", TimeFormat, time, SqlDml.Concat(seconds, ".", milliseconds, " ", "SECONDS"));
558+
SqlDml.FunctionCall(STRFTIMEFunctionName, TimeFormat, time, SqlDml.Concat(seconds, ".", milliseconds, " ", "SECONDS"));
591559
private static SqlExpression TimeAddSeconds(SqlExpression time, SqlExpression seconds) =>
592-
SqlDml.FunctionCall("STRFTIME", TimeFormat, time, SqlDml.Concat(seconds, " ", "SECONDS"));
560+
SqlDml.FunctionCall(STRFTIMEFunctionName, TimeFormat, time, SqlDml.Concat(seconds, " ", "SECONDS"));
593561

594562
private static SqlExpression TimeAddInterval(SqlExpression time, SqlExpression interval) =>
595563
TimeAddSeconds(time, interval / Convert.ToDouble(NanosecondsPerSecond));
@@ -602,8 +570,8 @@ private static SqlExpression TimeSubtractTime(SqlExpression time1, SqlExpression
602570
var minutesInSecs1 = SqlDml.Extract(SqlTimePart.Minute, time1) * 60;
603571
var minutesInSecs2 = SqlDml.Extract(SqlTimePart.Minute, time2) * 60;
604572

605-
var seconds1 = SqlDml.FunctionCall("STRFTIME", "%f", time1);
606-
var seconds2 = SqlDml.FunctionCall("STRFTIME", "%f", time2);
573+
var seconds1 = SqlDml.FunctionCall(STRFTIMEFunctionName, "%f", time1);
574+
var seconds2 = SqlDml.FunctionCall(STRFTIMEFunctionName, "%f", time2);
607575

608576
var difference = ((hoursInSecs1 + minutesInSecs1 + seconds1) * NanosecondsPerSecond)
609577
- ((hoursInSecs2 + minutesInSecs2 + seconds2) * NanosecondsPerSecond);
@@ -612,41 +580,41 @@ private static SqlExpression TimeSubtractTime(SqlExpression time1, SqlExpression
612580
}
613581

614582
private static SqlExpression DateToString(SqlExpression dateTime) =>
615-
SqlDml.FunctionCall("STRFTIME", DateFormat, dateTime);
583+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateFormat, dateTime);
616584

617585
private static SqlExpression TimeToString(SqlExpression dateTime) =>
618-
SqlDml.FunctionCall("STRFTIME", TimeToStringFormat, dateTime);
586+
SqlDml.FunctionCall(STRFTIMEFunctionName, TimeToStringFormat, dateTime);
619587

620588
private static SqlExpression DateTimeToDate(SqlExpression dateTime) =>
621-
SqlDml.FunctionCall("STRFTIME", DateFormat, dateTime);
589+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateFormat, dateTime);
622590

623591
private static SqlExpression DateToDateTime(SqlExpression date) =>
624-
SqlDml.FunctionCall("STRFTIME", DateTimeFormat, SqlDml.Concat(date, " 00:00:00"));
592+
SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, SqlDml.Concat(date, " 00:00:00"));
625593

626594
private static SqlExpression DateTimeToTime(SqlExpression dateTime) =>
627-
SqlDml.FunctionCall("STRFTIME", TimeFormat, dateTime);
595+
SqlDml.FunctionCall(STRFTIMEFunctionName, TimeFormat, dateTime);
628596
private static SqlExpression TimeToDateTime(SqlExpression time) =>
629-
SqlDml.FunctionCall("STRFTIME", "1900-01-01 " + TimeFormat, time);
597+
SqlDml.FunctionCall(STRFTIMEFunctionName, "1900-01-01 " + TimeFormat, time);
630598

631599
private static SqlExpression DateTimeOffsetToTime(SqlExpression dateTimeOffset) =>
632-
DateTimeToTime(SqlDml.FunctionCall("STRFTIME", TimeFormat, DateTimeOffsetExtractDateTimeAsString(dateTimeOffset)));
600+
DateTimeToTime(SqlDml.FunctionCall(STRFTIMEFunctionName, TimeFormat, DateTimeOffsetExtractDateTimeAsString(dateTimeOffset)));
633601

634602
private static SqlExpression DateTimeOffsetToDate(SqlExpression dateTimeOffset) =>
635-
DateTimeToDate(SqlDml.FunctionCall("STRFTIME", DateFormat, DateTimeOffsetExtractDateTimeAsString(dateTimeOffset)));
603+
DateTimeToDate(SqlDml.FunctionCall(STRFTIMEFunctionName, DateFormat, DateTimeOffsetExtractDateTimeAsString(dateTimeOffset)));
636604

637605
private static SqlExpression TimeToDateTimeOffset(SqlExpression time) =>
638-
SqlDml.Concat(SqlDml.FunctionCall("STRFTIME", DateTimeFormat, SqlDml.Concat("1900-01-01 ", time)), ServerOffsetAsString());
606+
SqlDml.Concat(SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, SqlDml.Concat("1900-01-01 ", time)), ServerOffsetAsString());
639607

640608
private static SqlExpression DateToDateTimeOffset(SqlExpression date) =>
641-
SqlDml.Concat(SqlDml.FunctionCall("STRFTIME", DateTimeFormat, SqlDml.Concat(date, " 00:00:00")), ServerOffsetAsString());
609+
SqlDml.Concat(SqlDml.FunctionCall(STRFTIMEFunctionName, DateTimeFormat, SqlDml.Concat(date, " 00:00:00")), ServerOffsetAsString());
642610
#endif
643611

644612
private static SqlExpression DateOrTimeGetMilliseconds(SqlExpression date) =>
645-
CastToLong(SqlDml.FunctionCall("STRFTIME", "%f", date) * MillisecondsPerSecond) -
646-
CastToLong(SqlDml.FunctionCall("STRFTIME", "%S", date) * MillisecondsPerSecond);
613+
CastToLong(SqlDml.FunctionCall(STRFTIMEFunctionName, "%f", date) * MillisecondsPerSecond) -
614+
CastToLong(SqlDml.FunctionCall(STRFTIMEFunctionName, "%S", date) * MillisecondsPerSecond);
647615

648616
private static SqlExpression DateOrTimeGetTotalSeconds(SqlExpression date) =>
649-
SqlDml.FunctionCall("STRFTIME", "%s", date);
617+
SqlDml.FunctionCall(STRFTIMEFunctionName, "%s", date);
650618

651619
private static SqlExpression DateTimeSubtractDateTime(SqlExpression date1, SqlExpression date2) =>
652620
(((DateOrTimeGetTotalSeconds(date1) - DateOrTimeGetTotalSeconds(date2)) * MillisecondsPerSecond)
@@ -655,7 +623,7 @@ private static SqlExpression DateTimeSubtractDateTime(SqlExpression date1, SqlEx
655623
private static SqlExpression ServerOffsetAsString()
656624
{
657625
const string constDateTime = "2016-01-01 12:00:00";
658-
return OffsetToOffsetAsString((SqlDml.FunctionCall("STRFTIME", "%s", constDateTime) - SqlDml.FunctionCall("STRFTIME", "%s", constDateTime, "UTC")) / 60);
626+
return OffsetToOffsetAsString((SqlDml.FunctionCall(STRFTIMEFunctionName, "%s", constDateTime) - SqlDml.FunctionCall(STRFTIMEFunctionName, "%s", constDateTime, "UTC")) / 60);
659627
}
660628

661629
private static SqlDateTimePart ConvertDateTimeOffsetPartToDateTimePart(SqlDateTimeOffsetPart dateTimeOffsetPart)

0 commit comments

Comments
 (0)