Skip to content

Commit f357be8

Browse files
committed
grab changes for Extensions, Infrastructure and Query blocks
1 parent cb53ce7 commit f357be8

8 files changed

Lines changed: 275 additions & 36 deletions

File tree

src/EFCore.SingleStore/Extensions/SingleStoreDbFunctionsExtensions.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,158 @@ namespace Microsoft.EntityFrameworkCore
1515
/// </summary>
1616
public static class SingleStoreDbFunctionsExtensions
1717
{
18+
#region ConvertTimeZone
19+
20+
/// <summary>
21+
/// Converts the `DateTime` value <paramref name="dateTime"/> from the time zone given by <paramref name="fromTimeZone"/> to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
22+
/// Corresponds to `CONVERT_TZ(dateTime, fromTimeZone, toTimeZone)`.
23+
/// </summary>
24+
/// <param name="_">The DbFunctions instance.</param>
25+
/// <param name="dateTime">The `DateTime` value to convert.</param>
26+
/// <param name="fromTimeZone">The time zone to convert from.</param>
27+
/// <param name="toTimeZone">The time zone to convert to.</param>
28+
/// <returns>The converted value.</returns>
29+
public static DateTime? ConvertTimeZone(
30+
[CanBeNull] this DbFunctions _,
31+
DateTime dateTime,
32+
string fromTimeZone,
33+
string toTimeZone)
34+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
35+
36+
/// <summary>
37+
/// Converts the `DateOnly` value <paramref name="dateOnly"/> from the time zone given by <paramref name="fromTimeZone"/> to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
38+
/// Corresponds to `CONVERT_TZ(dateTime, fromTimeZone, toTimeZone)`..
39+
/// </summary>
40+
/// <param name="_">The DbFunctions instance.</param>
41+
/// <param name="dateOnly">The `DateOnly` value to convert.</param>
42+
/// <param name="fromTimeZone">The time zone to convert from.</param>
43+
/// <param name="toTimeZone">The time zone to convert to.</param>
44+
/// <returns>The converted value.</returns>
45+
public static DateOnly? ConvertTimeZone(
46+
[CanBeNull] this DbFunctions _,
47+
DateOnly dateOnly,
48+
string fromTimeZone,
49+
string toTimeZone)
50+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
51+
52+
/// <summary>
53+
/// Converts the `DateTime?` value <paramref name="dateTime"/> from the time zone given by <paramref name="fromTimeZone"/> to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
54+
/// Corresponds to `CONVERT_TZ(dateTime, fromTimeZone, toTimeZone)`.
55+
/// </summary>
56+
/// <param name="_">The DbFunctions instance.</param>
57+
/// <param name="dateTime">The `DateTime?` value to convert.</param>
58+
/// <param name="fromTimeZone">The time zone to convert from.</param>
59+
/// <param name="toTimeZone">The time zone to convert to.</param>
60+
/// <returns>The converted value.</returns>
61+
public static DateTime? ConvertTimeZone(
62+
[CanBeNull] this DbFunctions _,
63+
DateTime? dateTime,
64+
string fromTimeZone,
65+
string toTimeZone)
66+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
67+
68+
/// <summary>
69+
/// Converts the `DateOnly?` value <paramref name="dateOnly"/> from the time zone given by <paramref name="fromTimeZone"/> to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
70+
/// Corresponds to `CONVERT_TZ(dateTime, fromTimeZone, toTimeZone)`..
71+
/// </summary>
72+
/// <param name="_">The DbFunctions instance.</param>
73+
/// <param name="dateOnly">The `DateOnly?` value to convert.</param>
74+
/// <param name="fromTimeZone">The time zone to convert from.</param>
75+
/// <param name="toTimeZone">The time zone to convert to.</param>
76+
/// <returns>The converted value.</returns>
77+
public static DateOnly? ConvertTimeZone(
78+
[CanBeNull] this DbFunctions _,
79+
DateOnly? dateOnly,
80+
string fromTimeZone,
81+
string toTimeZone)
82+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
83+
84+
/// <summary>
85+
/// Converts the `DateTime` value <paramref name="dateTime"/> from `@@session.time_zone` to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
86+
/// Corresponds to `CONVERT_TZ(dateTime, @@session.time_zone, toTimeZone)`.
87+
/// </summary>
88+
/// <param name="_">The DbFunctions instance.</param>
89+
/// <param name="dateTime">The `DateTime` value to convert.</param>
90+
/// <param name="toTimeZone">The time zone to convert to.</param>
91+
/// <returns>The converted value.</returns>
92+
public static DateTime? ConvertTimeZone(
93+
[CanBeNull] this DbFunctions _,
94+
DateTime dateTime,
95+
string toTimeZone)
96+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
97+
98+
/// <summary>
99+
/// Converts the `DateTimeOffset` value <paramref name="dateTimeOffset"/> from `+00:00`/UTC to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value as a `DateTime`.
100+
/// Corresponds to `CONVERT_TZ(dateTime, '+00:00', toTimeZone)`.
101+
/// </summary>
102+
/// <param name="_">The DbFunctions instance.</param>
103+
/// <param name="dateTimeOffset">The `DateTimeOffset` value to convert.</param>
104+
/// <param name="toTimeZone">The time zone to convert to.</param>
105+
/// <returns>The converted `DateTime?` value.</returns>
106+
public static DateTime? ConvertTimeZone(
107+
[CanBeNull] this DbFunctions _,
108+
DateTimeOffset dateTimeOffset,
109+
string toTimeZone)
110+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
111+
112+
/// <summary>
113+
/// Converts the `DateOnly` value <paramref name="dateOnly"/> from `@@session.time_zone` to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
114+
/// Corresponds to `CONVERT_TZ(dateTime, @@session.time_zone, toTimeZone)`.
115+
/// </summary>
116+
/// <param name="_">The DbFunctions instance.</param>
117+
/// <param name="dateOnly">The `DateOnly` value to convert.</param>
118+
/// <param name="toTimeZone">The time zone to convert to.</param>
119+
/// <returns>The converted value.</returns>
120+
public static DateOnly? ConvertTimeZone(
121+
[CanBeNull] this DbFunctions _,
122+
DateOnly dateOnly,
123+
string toTimeZone)
124+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
125+
126+
/// <summary>
127+
/// Converts the `DateTime?` value <paramref name="dateTime"/> from `@@session.time_zone` to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
128+
/// Corresponds to `CONVERT_TZ(dateTime, @@session.time_zone, toTimeZone)`.
129+
/// </summary>
130+
/// <param name="_">The DbFunctions instance.</param>
131+
/// <param name="dateTime">The `DateTime?` value to convert.</param>
132+
/// <param name="toTimeZone">The time zone to convert to.</param>
133+
/// <returns>The converted value.</returns>
134+
public static DateTime? ConvertTimeZone(
135+
[CanBeNull] this DbFunctions _,
136+
DateTime? dateTime,
137+
string toTimeZone)
138+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
139+
140+
/// <summary>
141+
/// Converts the `DateTimeOffset?` value <paramref name="dateTimeOffset"/> from `+00:00`/UTC to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value as a `DateTime`.
142+
/// Corresponds to `CONVERT_TZ(dateTime, '+00:00', toTimeZone)`.
143+
/// </summary>
144+
/// <param name="_">The DbFunctions instance.</param>
145+
/// <param name="dateTimeOffset">The `DateTimeOffset?` value to convert.</param>
146+
/// <param name="toTimeZone">The time zone to convert to.</param>
147+
/// <returns>The converted `DateTime?` value.</returns>
148+
public static DateTime? ConvertTimeZone(
149+
[CanBeNull] this DbFunctions _,
150+
DateTimeOffset? dateTimeOffset,
151+
string toTimeZone)
152+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
153+
154+
/// <summary>
155+
/// Converts the `DateOnly?` value <paramref name="dateOnly"/> from `@@session.time_zone` to the time zone given by <paramref name="toTimeZone"/> and returns the resulting value.
156+
/// Corresponds to `CONVERT_TZ(dateTime, @@session.time_zone, toTimeZone)`.
157+
/// </summary>
158+
/// <param name="_">The DbFunctions instance.</param>
159+
/// <param name="dateOnly">The `DateOnly?` value to convert.</param>
160+
/// <param name="toTimeZone">The time zone to convert to.</param>
161+
/// <returns>The converted value.</returns>
162+
public static DateOnly? ConvertTimeZone(
163+
[CanBeNull] this DbFunctions _,
164+
DateOnly? dateOnly,
165+
string toTimeZone)
166+
=> throw new InvalidOperationException(CoreStrings.FunctionOnClient(nameof(ConvertTimeZone)));
167+
168+
#endregion ConvertTimeZone
169+
18170
/// <summary>
19171
/// Counts the number of year boundaries crossed between the startDate and endDate.
20172
/// Corresponds to TIMESTAMPDIFF(YEAR,startDate,endDate).

src/EFCore.SingleStore/Extensions/SingleStorePropertyExtensions.cs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ public static SingleStoreValueGenerationStrategy GetValueGenerationStrategy([Not
6565

6666
if (property.ValueGenerated == ValueGenerated.OnAddOrUpdate)
6767
{
68-
if (IsCompatibleComputedColumn(property))
68+
// We explicitly check for RowVersion when generation migrations. We therefore handle RowVersion separately from other cases
69+
// of using CURRENT_TIMESTAMP etc. and we don't generate a SingleStoreValueGenerationStrategy.ComputedColumn annotation.
70+
if (IsCompatibleComputedColumn(property) &&
71+
!property.IsConcurrencyToken)
6972
{
7073
return SingleStoreValueGenerationStrategy.ComputedColumn;
7174
}
@@ -145,7 +148,10 @@ is StoreObjectIdentifier principal
145148

146149
if (property.ValueGenerated == ValueGenerated.OnAddOrUpdate)
147150
{
148-
if (IsCompatibleComputedColumn(property))
151+
// We explicitly check for RowVersion when generation migrations. We therefore handle RowVersion separately from other cases
152+
// of using CURRENT_TIMESTAMP etc. and we don't generate a SingleStoreValueGenerationStrategy.ComputedColumn annotation.
153+
if (IsCompatibleComputedColumn(property, storeObject, typeMappingSource) &&
154+
!property.IsConcurrencyToken)
149155
{
150156
return SingleStoreValueGenerationStrategy.ComputedColumn;
151157
}
@@ -422,20 +428,35 @@ private static bool IsCompatibleCurrentTimestampColumn(
422428
/// <returns> <see langword="true"/> if compatible. </returns>
423429
public static bool IsCompatibleComputedColumn(IReadOnlyProperty property)
424430
{
425-
var type = property.ClrType;
431+
var valueConverter = GetConverter(property);
432+
var type = (valueConverter?.ProviderClrType ?? property.ClrType).UnwrapNullableType();
426433

427434
// RowVersion uses byte[] and the BytesToDateTimeConverter.
428-
return (type == typeof(DateTime) || type == typeof(DateTimeOffset)) && !HasConverter(property)
429-
|| type == typeof(byte[]) && !HasExternalConverter(property);
435+
return type == typeof(DateTime) ||
436+
type == typeof(DateTimeOffset) ||
437+
type == typeof(byte[]) && valueConverter is BytesToDateTimeConverter;
430438
}
431439

432-
private static bool HasConverter(IReadOnlyProperty property)
433-
=> GetConverter(property) != null;
434-
435-
private static bool HasExternalConverter(IReadOnlyProperty property)
440+
private static bool IsCompatibleComputedColumn(
441+
IReadOnlyProperty property,
442+
in StoreObjectIdentifier storeObject,
443+
ITypeMappingSource typeMappingSource)
436444
{
437-
var converter = GetConverter(property);
438-
return converter != null && !(converter is BytesToDateTimeConverter);
445+
if (storeObject.StoreObjectType != StoreObjectType.Table)
446+
{
447+
return false;
448+
}
449+
450+
var valueConverter = property.GetValueConverter() ??
451+
(property.FindRelationalTypeMapping(storeObject) ??
452+
typeMappingSource?.FindMapping((IProperty)property))?.Converter;
453+
454+
var type = (valueConverter?.ProviderClrType ?? property.ClrType).UnwrapNullableType();
455+
456+
// RowVersion uses byte[] and the BytesToDateTimeConverter.
457+
return type == typeof(DateTime) ||
458+
type == typeof(DateTimeOffset) ||
459+
type == typeof(byte[]) && valueConverter is BytesToDateTimeConverter;
439460
}
440461

441462
private static ValueConverter GetConverter(IReadOnlyProperty property)

src/EFCore.SingleStore/Infrastructure/ServerVersionSupport.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public virtual bool PropertyOrVersion(string propertyNameOrServerVersion)
9696
public virtual bool JsonValue => false;
9797
public virtual bool Values => false;
9898
public virtual bool ValuesWithRows => false;
99-
public virtual bool OffsetReferencesOuterQuery => false;
99+
public virtual bool WhereSubqueryReferencesOuterQuery => false;
100100

101101
public virtual bool JsonTableImplementationStable => JsonTable;
102102
public virtual bool JsonTableImplementationWithoutMySqlBugs => JsonTable;

src/EFCore.SingleStore/Infrastructure/SingleStoreServerVersion.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ internal SingleStoreServerVersionSupport([NotNull] ServerVersion serverVersion)
9595
public override bool JsonValue => false;
9696
public override bool Values => false;
9797
public override bool ValuesWithRows => false;
98-
public override bool OffsetReferencesOuterQuery => false;
98+
public override bool WhereSubqueryReferencesOuterQuery => false;
9999

100100
public override bool JsonTableImplementationStable => false;
101101
public override bool JsonTableImplementationWithoutMySqlBugs => false; // Other non-fatal bugs regarding JSON_TABLE.

src/EFCore.SingleStore/Query/ExpressionTranslators/Internal/SingleStoreDbFunctionsExtensionsMethodTranslator.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
1313
using Microsoft.EntityFrameworkCore.Storage;
1414
using EntityFrameworkCore.SingleStore.Query.Internal;
15+
using EntityFrameworkCore.SingleStore.Utilities;
1516

1617
namespace EntityFrameworkCore.SingleStore.Query.ExpressionTranslators.Internal
1718
{
@@ -23,6 +24,40 @@ public class SingleStoreDbFunctionsExtensionsMethodTranslator : IMethodCallTrans
2324
{
2425
private readonly SingleStoreSqlExpressionFactory _sqlExpressionFactory;
2526

27+
private static readonly HashSet<MethodInfo> _convertTimeZoneMethodInfos =
28+
[
29+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
30+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
31+
new[] { typeof(DbFunctions), typeof(DateTime), typeof(string), typeof(string) }),
32+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
33+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
34+
new[] { typeof(DbFunctions), typeof(DateOnly), typeof(string), typeof(string) }),
35+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
36+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
37+
new[] { typeof(DbFunctions), typeof(DateTime?), typeof(string), typeof(string) }),
38+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
39+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
40+
new[] { typeof(DbFunctions), typeof(DateOnly?), typeof(string), typeof(string) }),
41+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
42+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
43+
new[] { typeof(DbFunctions), typeof(DateTime), typeof(string) }),
44+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
45+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
46+
new[] { typeof(DbFunctions), typeof(DateTimeOffset), typeof(string) }),
47+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
48+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
49+
new[] { typeof(DbFunctions), typeof(DateOnly), typeof(string) }),
50+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
51+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
52+
new[] { typeof(DbFunctions), typeof(DateTime?), typeof(string) }),
53+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
54+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
55+
new[] { typeof(DbFunctions), typeof(DateTimeOffset?), typeof(string) }),
56+
typeof(SingleStoreDbFunctionsExtensions).GetRuntimeMethod(
57+
nameof(SingleStoreDbFunctionsExtensions.ConvertTimeZone),
58+
new[] { typeof(DbFunctions), typeof(DateOnly?), typeof(string) }),
59+
];
60+
2661
private static readonly Type[] _supportedLikeTypes = {
2762
typeof(int),
2863
typeof(long),
@@ -149,6 +184,29 @@ public virtual SqlExpression Translate(
149184
IReadOnlyList<SqlExpression> arguments,
150185
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
151186
{
187+
if (_convertTimeZoneMethodInfos.TryGetValue(method, out _))
188+
{
189+
// Will not just return `NULL` if any of its parameters is `NULL`, but also if `fromTimeZone` or `toTimeZone` is incorrect.
190+
// Will do no conversion at all if `dateTime` is outside the supported range.
191+
return _sqlExpressionFactory.NullableFunction(
192+
"CONVERT_TZ",
193+
arguments.Count == 3
194+
?
195+
[
196+
arguments[1],
197+
// The implicit fromTimeZone is UTC for DateTimeOffset values and the current session time zone otherwise.
198+
method.GetParameters()[1].ParameterType.UnwrapNullableType() == typeof(DateTimeOffset)
199+
? _sqlExpressionFactory.Constant("+00:00")
200+
: _sqlExpressionFactory.Fragment("@@session.time_zone"),
201+
arguments[2]
202+
]
203+
: new[] { arguments[1], arguments[2], arguments[3] },
204+
method.ReturnType.UnwrapNullableType(),
205+
null,
206+
false,
207+
Statics.GetTrueValues(arguments.Count));
208+
}
209+
152210
if (_likeMethodInfos.Any(m => Equals(method, m)))
153211
{
154212
var match = _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1]);

src/EFCore.SingleStore/Query/ExpressionTranslators/Internal/SingleStoreStringComparisonMethodTranslator.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Diagnostics;
8+
using System.Globalization;
89
using System.Linq;
910
using System.Linq.Expressions;
1011
using System.Reflection;
@@ -539,7 +540,9 @@ protected virtual SqlExpression GetLikeExpressionUsingParameter(QueryCompilation
539540
QueryCompilationContext.QueryContextParameter);
540541

541542
var escapedPatternParameter =
542-
queryCompilationContext.RegisterRuntimeParameter(patternParameter.Name + "_rewritten", lambda);
543+
queryCompilationContext.RegisterRuntimeParameter(
544+
$"{patternParameter.Name}_{methodType.ToString().ToLower(CultureInfo.InvariantCulture)}",
545+
lambda);
543546

544547
return _sqlExpressionFactory.Like(
545548
targetTransform(target),

0 commit comments

Comments
 (0)