diff --git a/runtime/Sim.Data/Engine/Functions.cs b/runtime/Sim.Data/Engine/Functions.cs index fc3096b..da4f8cc 100644 --- a/runtime/Sim.Data/Engine/Functions.cs +++ b/runtime/Sim.Data/Engine/Functions.cs @@ -44,6 +44,7 @@ internal static class Functions c.CreateFunction("tsql_ceiling", x => x is null ? null : Math.Ceiling(ToDouble(x)), isDeterministic: true); c.CreateFunction("tsql_power", (x, y) => x is null || y is null ? null : Math.Pow(ToDouble(x), ToDouble(y)), isDeterministic: true); c.CreateFunction("tsql_sqrt", x => x is null ? null : Math.Sqrt(ToDouble(x)), isDeterministic: true); + c.CreateFunction("tsql_cmp", v => v is string s && Values.LooksLikeDate(s) ? Values.NormalizeDateLiteral(s) : v, isDeterministic: true); c.CreateFunction("tsql_newid", () => Guid.NewGuid().ToString().ToUpperInvariant()); c.CreateFunction("tsql_rand", () => Random.Shared.NextDouble()); } diff --git a/runtime/Sim.Data/Engine/Translator.cs b/runtime/Sim.Data/Engine/Translator.cs index 5192095..8c062de 100644 --- a/runtime/Sim.Data/Engine/Translator.cs +++ b/runtime/Sim.Data/Engine/Translator.cs @@ -911,6 +911,14 @@ internal sealed class Translator _sql.Append(Values.Quote(Values.NormalizeDateLiteral(s.Value))); return; } + // 参数的值执行时才知道:是日期样子的字符串时同样转成标准格式(教材 BETWEEN @time_start AND @time_end 传的是字符串) + if (expression is VariableReference) + { + _sql.Append("tsql_cmp("); + Expression(expression); + _sql.Append(')'); + return; + } Expression(expression); } } diff --git a/runtime/Sim.Data/Engine/Values.cs b/runtime/Sim.Data/Engine/Values.cs index fad7992..440aa8a 100644 --- a/runtime/Sim.Data/Engine/Values.cs +++ b/runtime/Sim.Data/Engine/Values.cs @@ -17,13 +17,16 @@ internal static class Values }; /// 形如日期的字符串字面量(比较时转成标准格式,例如 BETWEEN '2024/1/16 9:05:03' AND ...) - private static readonly Regex DateLike = new(@"^\d{4}[-/.]\d{1,2}[-/.]\d{1,2}([ T]\d{1,2}:\d{1,2}(:\d{1,2}(\.\d+)?)?)?$"); + private static readonly Regex DateLike = new(@"^\d{4}[-/.]\d{1,2}[-/.]\d{1,2}((\s+|T)\d{1,2}:\d{1,2}(:\d{1,2}(\.\d+)?)?)?$"); + + /// 日期和时间之间多余的空格(教材拼出的 "2024/1/23 23:59:59") + private static readonly Regex Spaces = new(@"\s+"); public static bool LooksLikeDate(string text) => DateLike.IsMatch(text.Trim()); /// 按 SQL Server 接受的写法解析日期(包括中文 Windows 上 DateTime.ToString() 的 2024/1/16 9:05:03) public static bool TryParseDateTime(string text, out DateTime value) => - DateTime.TryParseExact(text.Trim(), DateFormats, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out value); + DateTime.TryParseExact(Spaces.Replace(text.Trim(), " "), DateFormats, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out value); public static string FormatDateTime(DateTime value) => value.Millisecond == 0 && value.Ticks % TimeSpan.TicksPerMillisecond == 0