/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression Translate( SqlExpression instance, MemberInfo member, Type returnType, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(member, nameof(member)); Check.NotNull(returnType, nameof(returnType)); Check.NotNull(logger, nameof(logger)); var declaringType = member.DeclaringType; if (declaringType == typeof(DateTime) || declaringType == typeof(DateTimeOffset)) { var memberName = member.Name; if (_datePartMapping.TryGetValue(memberName, out var datePart)) { return(_sqlExpressionFactory.Function( "DATEPART", new[] { _sqlExpressionFactory.Fragment(datePart), instance }, nullable: true, argumentsPropagateNullability: new[] { false, true }, returnType)); } switch (memberName) { case nameof(DateTime.Date): return(_sqlExpressionFactory.Function( "CONVERT", new[] { _sqlExpressionFactory.Fragment("date"), instance }, nullable: true, argumentsPropagateNullability: new[] { false, true }, returnType, declaringType == typeof(DateTime) ? instance.TypeMapping : _typeMappingSource.FindMapping(typeof(DateTime)))); case nameof(DateTime.TimeOfDay): return(_sqlExpressionFactory.Convert(instance, returnType)); case nameof(DateTime.Now): return(_sqlExpressionFactory.Function( declaringType == typeof(DateTime) ? "GETDATE" : "SYSDATETIMEOFFSET", Array.Empty <SqlExpression>(), nullable: false, argumentsPropagateNullability: Array.Empty <bool>(), returnType)); case nameof(DateTime.UtcNow): var serverTranslation = _sqlExpressionFactory.Function( declaringType == typeof(DateTime) ? "GETUTCDATE" : "SYSUTCDATETIME", Array.Empty <SqlExpression>(), nullable: false, argumentsPropagateNullability: Array.Empty <bool>(), returnType); return(declaringType == typeof(DateTime) ? (SqlExpression)serverTranslation : _sqlExpressionFactory.Convert(serverTranslation, returnType)); case nameof(DateTime.Today): return(_sqlExpressionFactory.Function( "CONVERT", new SqlExpression[] { _sqlExpressionFactory.Fragment("date"), _sqlExpressionFactory.Function( "GETDATE", Array.Empty <SqlExpression>(), nullable: false, argumentsPropagateNullability: Array.Empty <bool>(), typeof(DateTime)) }, nullable: true, argumentsPropagateNullability: new[] { false, true }, returnType)); } } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { if (member.DeclaringType == typeof(DateTime)) { var memberName = member.Name; if (_datePartMapping.TryGetValue(memberName, out var datePart)) { return(_sqlExpressionFactory.Convert( SqliteExpression.Strftime( _sqlExpressionFactory, typeof(string), datePart, instance), returnType)); } if (string.Equals(memberName, nameof(DateTime.Ticks))) { return(_sqlExpressionFactory.Convert( _sqlExpressionFactory.Multiply( _sqlExpressionFactory.Subtract( _sqlExpressionFactory.Function( "julianday", new[] { instance }, typeof(double)), _sqlExpressionFactory.Constant(1721425.5)), // NB: Result of julianday('0001-01-01 00:00:00') _sqlExpressionFactory.Constant(TimeSpan.TicksPerDay)), typeof(long))); } if (string.Equals(memberName, nameof(DateTime.Millisecond))) { return(_sqlExpressionFactory.Modulo( _sqlExpressionFactory.Multiply( _sqlExpressionFactory.Convert( SqliteExpression.Strftime( _sqlExpressionFactory, typeof(string), "%f", instance), typeof(double)), _sqlExpressionFactory.Constant(1000)), _sqlExpressionFactory.Constant(1000))); } var format = "%Y-%m-%d %H:%M:%f"; SqlExpression timestring; var modifiers = new List <SqlExpression>(); switch (memberName) { case nameof(DateTime.Now): timestring = _sqlExpressionFactory.Constant("now"); modifiers.Add(_sqlExpressionFactory.Constant("localtime")); break; case nameof(DateTime.UtcNow): timestring = _sqlExpressionFactory.Constant("now"); break; case nameof(DateTime.Date): timestring = instance; modifiers.Add(_sqlExpressionFactory.Constant("start of day")); break; case nameof(DateTime.Today): timestring = _sqlExpressionFactory.Constant("now"); modifiers.Add(_sqlExpressionFactory.Constant("localtime")); modifiers.Add(_sqlExpressionFactory.Constant("start of day")); break; case nameof(DateTime.TimeOfDay): format = "%H:%M:%f"; timestring = instance; break; default: return(null); } Debug.Assert(timestring != null); return(_sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { SqliteExpression.Strftime( _sqlExpressionFactory, returnType, format, timestring, modifiers), _sqlExpressionFactory.Constant("0") }, returnType), _sqlExpressionFactory.Constant(".") }, returnType)); } return(null); }
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (Exp.Equals(method)) { return(_sqlExpressionFactory.Function( name: "exp", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Log.Equals(method)) { return(_sqlExpressionFactory.Function( name: "log", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Log10.Equals(method)) { return(_sqlExpressionFactory.Function( name: "log10", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Sqrt.Equals(method)) { return(_sqlExpressionFactory.Function( name: "sqrt", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Cbrt.Equals(method)) { return(_sqlExpressionFactory.Function( name: "cbrt", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Sin.Equals(method)) { return(_sqlExpressionFactory.Function( name: "sin", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Cos.Equals(method)) { return(_sqlExpressionFactory.Function( name: "cos", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Tan.Equals(method)) { return(_sqlExpressionFactory.Function( name: "tan", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Asin.Equals(method)) { return(_sqlExpressionFactory.Function( name: "asin", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Acos.Equals(method)) { return(_sqlExpressionFactory.Function( name: "Acos", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Atan.Equals(method)) { return(_sqlExpressionFactory.Function( name: "atan", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (Pow.Equals(method)) { return(_sqlExpressionFactory.Function( name: "pow", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } /* * if (Cosh.Equals(method)) * { * return _sqlExpressionFactory.Function( * name: "cosh", * arguments: arguments, * nullable: false, * argumentsPropagateNullability: new[] { true }, * returnType: typeof(double)); * } * * if (Acosh.Equals(method)) * { * return _sqlExpressionFactory.Function( * name: "acosh", * arguments: arguments, * nullable: false, * argumentsPropagateNullability: new[] { true }, * returnType: typeof(double)); * } */ if (CeilingDouble.Equals(method) || CeilingDecimal.Equals(method)) { return(_sqlExpressionFactory.Function( name: "ceiling", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } if (RoundDouble.Equals(method) || RoundDecimal.Equals(method)) { return(_sqlExpressionFactory.Function( name: "round", arguments: arguments, nullable: false, argumentsPropagateNullability: new[] { true }, returnType: method.ReturnType)); } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression Translate( SqlExpression instance, MemberInfo member, Type returnType, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(member, nameof(member)); Check.NotNull(returnType, nameof(returnType)); Check.NotNull(logger, nameof(logger)); if (typeof(Polygon).IsAssignableFrom(member.DeclaringType)) { Check.DebugAssert(instance.TypeMapping != null, "Instance must have typeMapping assigned."); var storeType = instance.TypeMapping.StoreType; var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase); if (isGeography) { if (Equals(_exteriorRing, member)) { return(_sqlExpressionFactory.Function( instance, "RingN", new[] { _sqlExpressionFactory.Constant(1) }, nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability: new[] { false }, returnType, _typeMappingSource.FindMapping(returnType, storeType))); } if (Equals(_numInteriorRings, member)) { return(_sqlExpressionFactory.Subtract( _sqlExpressionFactory.Function( instance, "NumRings", Array.Empty <SqlExpression>(), nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability: Array.Empty <bool>(), returnType), _sqlExpressionFactory.Constant(1))); } } if (_geometryMemberToFunctionName.TryGetValue(member, out var functionName)) { var resultTypeMapping = typeof(Geometry).IsAssignableFrom(returnType) ? _typeMappingSource.FindMapping(returnType, storeType) : _typeMappingSource.FindMapping(returnType); return(_sqlExpressionFactory.Function( instance, functionName, Array.Empty <SqlExpression>(), nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability: Array.Empty <bool>(), returnType, resultTypeMapping)); } } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression?Translate( SqlExpression?instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (instance != null) { if (IndexOfMethodInfo.Equals(method)) { return(TranslateIndexOf(instance, method, arguments[0], null)); } if (IndexOfMethodInfoWithStartingPosition.Equals(method)) { return(TranslateIndexOf(instance, method, arguments[0], arguments[1])); } if (ReplaceMethodInfo.Equals(method)) { var firstArgument = arguments[0]; var secondArgument = arguments[1]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); firstArgument = _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping); secondArgument = _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping); return(_sqlExpressionFactory.Function( "REPLACE", new[] { instance, firstArgument, secondArgument }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, stringTypeMapping)); } if (ToLowerMethodInfo.Equals(method) || ToUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( ToLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, method.ReturnType, instance.TypeMapping)); } if (SubstringMethodInfoWithOneArg.Equals(method)) { return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)), _sqlExpressionFactory.Function( "LEN", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, typeof(int)) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, instance.TypeMapping)); } if (SubstringMethodInfoWithTwoArgs.Equals(method)) { return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, instance.TypeMapping)); } if (TrimStartMethodInfoWithoutArgs?.Equals(method) == true || (TrimStartMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping)); } if (TrimEndMethodInfoWithoutArgs?.Equals(method) == true || (TrimEndMethodInfoWithCharArrayArg.Equals(method) // SqlServer RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "RTRIM", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping)); } if (TrimMethodInfoWithoutArgs?.Equals(method) == true || (TrimMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM/RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { _sqlExpressionFactory.Function( "RTRIM", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping) }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping)); } if (ContainsMethodInfo.Equals(method)) { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); if (pattern is SqlConstantExpression constantPattern) { if (!(constantPattern.Value is string patternValue)) { return(_sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Constant(null, stringTypeMapping))); } if (patternValue.Length == 0) { return(_sqlExpressionFactory.Constant(true)); } return(patternValue.Any(IsLikeWildChar) ? _sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Constant($"%{EscapeLikePattern(patternValue)}%"), _sqlExpressionFactory.Constant(LikeEscapeString)) : _sqlExpressionFactory.Like(instance, _sqlExpressionFactory.Constant($"%{patternValue}%"))); } return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Like( pattern, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "CHARINDEX", new[] { pattern, instance }, nullable: true, argumentsPropagateNullability: new[] { true, true }, typeof(int)), _sqlExpressionFactory.Constant(0)))); } if (StartsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (EndsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } } if (IsNullOrEmptyMethodInfo.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Like( argument, _sqlExpressionFactory.Constant(string.Empty)))); } if (IsNullOrWhiteSpaceMethodInfo.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( argument, _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping)))); } if (FirstOrDefaultMethodInfoWithoutArgs.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { argument, _sqlExpressionFactory.Constant(1), _sqlExpressionFactory.Constant(1) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType)); } if (LastOrDefaultMethodInfoWithoutArgs.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { argument, _sqlExpressionFactory.Function( "LEN", new[] { argument }, nullable: true, argumentsPropagateNullability: new[] { true }, typeof(int)), _sqlExpressionFactory.Constant(1) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType)); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); SqlExpression modifier = null; if (_addMilliseconds.Equals(method)) { modifier = _sqlExpressionFactory.Add( _sqlExpressionFactory.Convert( _sqlExpressionFactory.Divide( arguments[0], _sqlExpressionFactory.Constant(1000.0)), typeof(string)), _sqlExpressionFactory.Constant(" seconds")); } else if (_addTicks.Equals(method)) { modifier = _sqlExpressionFactory.Add( _sqlExpressionFactory.Convert( _sqlExpressionFactory.Divide( arguments[0], _sqlExpressionFactory.Constant((double)TimeSpan.TicksPerDay)), typeof(string)), _sqlExpressionFactory.Constant(" seconds")); } else if (_methodInfoToUnitSuffix.TryGetValue(method, out var unitSuffix)) { modifier = _sqlExpressionFactory.Add( _sqlExpressionFactory.Convert(arguments[0], typeof(string)), _sqlExpressionFactory.Constant(unitSuffix)); } if (modifier != null) { return(_sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { SqliteExpression.Strftime( _sqlExpressionFactory, method.ReturnType, "%Y-%m-%d %H:%M:%f", instance, new[] { modifier }), _sqlExpressionFactory.Constant("0") }, nullable: true, argumentsPropagateNullability: new[] { true, false }, method.ReturnType), _sqlExpressionFactory.Constant(".") }, nullable: true, argumentsPropagateNullability: new[] { true, false }, method.ReturnType)); } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression Translate( SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); Check.NotNull(logger, nameof(logger)); if (_indexOfMethodInfo.Equals(method)) { var argument = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument); argument = _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping); SqlExpression charIndexExpression; var storeType = stringTypeMapping.StoreType; if (string.Equals(storeType, "nvarchar(max)", StringComparison.OrdinalIgnoreCase) || string.Equals(storeType, "varchar(max)", StringComparison.OrdinalIgnoreCase)) { charIndexExpression = _sqlExpressionFactory.Function( "CHARINDEX", new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) }, nullable: true, argumentsPropagateNullability: new[] { true, true }, typeof(long)); charIndexExpression = _sqlExpressionFactory.Convert(charIndexExpression, typeof(int)); } else { charIndexExpression = _sqlExpressionFactory.Function( "CHARINDEX", new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) }, nullable: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType); } charIndexExpression = _sqlExpressionFactory.Subtract(charIndexExpression, _sqlExpressionFactory.Constant(1)); return(_sqlExpressionFactory.Case( new[] { new CaseWhenClause( _sqlExpressionFactory.Equal( argument, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.Constant(0)) }, charIndexExpression)); } if (_replaceMethodInfo.Equals(method)) { var firstArgument = arguments[0]; var secondArgument = arguments[1]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); firstArgument = _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping); secondArgument = _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping); return(_sqlExpressionFactory.Function( "REPLACE", new[] { instance, firstArgument, secondArgument }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, stringTypeMapping)); } if (_toLowerMethodInfo.Equals(method) || _toUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( _toLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, method.ReturnType, instance.TypeMapping)); } if (_substringMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, instance.TypeMapping)); } if (_isNullOrWhiteSpaceMethodInfo.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( _sqlExpressionFactory.Function( "LTRIM", new[] { _sqlExpressionFactory.Function( "RTRIM", new[] { argument }, nullable: true, argumentsPropagateNullability: new[] { true }, argument.Type, argument.TypeMapping) }, nullable: true, argumentsPropagateNullability: new[] { true }, argument.Type, argument.TypeMapping), _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping)))); } if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true || (_trimStartMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping)); } if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true || (_trimEndMethodInfoWithCharArrayArg.Equals(method) // SqlServer RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "RTRIM", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping)); } if (_trimMethodInfoWithoutArgs?.Equals(method) == true || (_trimMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM/RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { _sqlExpressionFactory.Function( "RTRIM", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping) }, nullable: true, argumentsPropagateNullability: new[] { true }, instance.Type, instance.TypeMapping)); } if (_containsMethodInfo.Equals(method)) { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); if (pattern is SqlConstantExpression constantPattern) { if (!(constantPattern.Value is string patternValue)) { return(_sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Constant(null, stringTypeMapping))); } if (patternValue.Length == 0) { return(_sqlExpressionFactory.Constant(true)); } return(patternValue.Any(IsLikeWildChar) ? _sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Constant($"%{EscapeLikePattern(patternValue)}%"), _sqlExpressionFactory.Constant(LikeEscapeString)) : _sqlExpressionFactory.Like(instance, _sqlExpressionFactory.Constant($"%{patternValue}%"))); } return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Like( pattern, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "CHARINDEX", new[] { pattern, instance }, nullable: true, argumentsPropagateNullability: new[] { true, true }, typeof(int)), _sqlExpressionFactory.Constant(0)))); } if (_firstOrDefaultMethodInfoWithoutArgs.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { argument, _sqlExpressionFactory.Constant(1), _sqlExpressionFactory.Constant(1) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType)); } if (_lastOrDefaultMethodInfoWithoutArgs.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { argument, _sqlExpressionFactory.Function( "LEN", new[] { argument }, nullable: true, argumentsPropagateNullability: new[] { true }, typeof(int)), _sqlExpressionFactory.Constant(1) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType)); } if (_startsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (_endsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } return(null); }
private SqlExpression TranslateSystemFunction(string function, SqlExpression instance, SqlExpression pattern, Type returnType) => _sqlExpressionFactory.Function(function, new[] { instance, pattern }, returnType);
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IList <SqlExpression> arguments) { if (_indexOfMethodInfo.Equals(method)) { var argument = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument); argument = _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping); var charIndexExpression = _sqlExpressionFactory.Subtract( _sqlExpressionFactory.Function( "CHARINDEX", new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) }, method.ReturnType), _sqlExpressionFactory.Constant(1)); return(_sqlExpressionFactory.Case( new[] { new CaseWhenClause( _sqlExpressionFactory.Equal( argument, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.Constant(0)) }, charIndexExpression)); } if (_replaceMethodInfo.Equals(method)) { var firstArgument = arguments[0]; var secondArgument = arguments[1]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); firstArgument = _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping); secondArgument = _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping); return(_sqlExpressionFactory.Function( "REPLACE", new[] { instance, firstArgument, secondArgument }, method.ReturnType, stringTypeMapping)); } if (_toLowerMethodInfo.Equals(method) || _toUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( _toLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER", new[] { instance }, method.ReturnType, instance.TypeMapping)); } if (_substringMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, method.ReturnType, instance.TypeMapping)); } if (_isNullOrWhiteSpaceMethodInfo.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( _sqlExpressionFactory.Function( "LTRIM", new[] { _sqlExpressionFactory.Function( "RTRIM", new[] { argument }, argument.Type, argument.TypeMapping) }, argument.Type, argument.TypeMapping), _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping)))); } if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true || (_trimStartMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { instance }, instance.Type, instance.TypeMapping)); } if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true || (_trimEndMethodInfoWithCharArrayArg.Equals(method) // SqlServer RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "RTRIM", new[] { instance }, instance.Type, instance.TypeMapping)); } if (_trimMethodInfoWithoutArgs?.Equals(method) == true || (_trimMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM/RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { _sqlExpressionFactory.Function( "RTRIM", new [] { instance }, instance.Type, instance.TypeMapping) }, instance.Type, instance.TypeMapping)); } if (_containsMethodInfo.Equals(method)) { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); if (pattern is SqlConstantExpression constantPattern) { if ((string)constantPattern.Value == string.Empty) { return(_sqlExpressionFactory.Constant(true)); } return(_sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "CHARINDEX", new[] { pattern, instance }, typeof(int)), _sqlExpressionFactory.Constant(0))); } return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Equal( pattern, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "CHARINDEX", new[] { pattern, instance }, typeof(int)), _sqlExpressionFactory.Constant(0)))); } if (_startsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (_endsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); if (_indexOfMethodInfo.Equals(method)) { var argument = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument); return(_sqlExpressionFactory.Subtract( _sqlExpressionFactory.Function( "instr", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping) }, method.ReturnType), _sqlExpressionFactory.Constant(1))); } if (_replaceMethodInfo.Equals(method)) { var firstArgument = arguments[0]; var secondArgument = arguments[1]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument); return(_sqlExpressionFactory.Function( "replace", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping) }, method.ReturnType, stringTypeMapping)); } if (_toLowerMethodInfo.Equals(method) || _toUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( _toLowerMethodInfo.Equals(method) ? "lower" : "upper", new[] { instance }, method.ReturnType, instance.TypeMapping)); } if (_substringMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "substr", new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, method.ReturnType, instance.TypeMapping)); } if (_isNullOrWhiteSpaceMethodInfo.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( _sqlExpressionFactory.Function( "trim", new[] { argument }, argument.Type, argument.TypeMapping), _sqlExpressionFactory.Constant(string.Empty)))); } if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true || _trimStartMethodInfoWithCharArg?.Equals(method) == true || _trimStartMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments, "ltrim")); } if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true || _trimEndMethodInfoWithCharArg?.Equals(method) == true || _trimEndMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments, "rtrim")); } if (_trimMethodInfoWithoutArgs?.Equals(method) == true || _trimMethodInfoWithCharArg?.Equals(method) == true || _trimMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments, "trim")); } if (_containsMethodInfo.Equals(method)) { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Equal( pattern, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "instr", new[] { instance, pattern }, typeof(int)), _sqlExpressionFactory.Constant(0)))); } if (_startsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (_endsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } return(null); }
public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { var declaringType = member.DeclaringType; if (declaringType == typeof(DateTime) || declaringType == typeof(DateTimeOffset)) { var memberName = member.Name; if (_datePartMapping.TryGetValue(memberName, out var datePart)) { return(_sqlExpressionFactory.Function( "DATEPART", new[] { _sqlExpressionFactory.Fragment(datePart), instance }, returnType)); } switch (memberName) { case nameof(DateTime.Date): return(_sqlExpressionFactory.Function( "CONVERT", new[] { _sqlExpressionFactory.Fragment("date"), instance }, returnType, instance.TypeMapping)); case nameof(DateTime.TimeOfDay): return(_sqlExpressionFactory.Convert(instance, returnType)); case nameof(DateTime.Now): return(_sqlExpressionFactory.Function( declaringType == typeof(DateTime) ? "GETDATE" : "SYSDATETIMEOFFSET", Array.Empty <SqlExpression>(), returnType)); case nameof(DateTime.UtcNow): var serverTranslation = _sqlExpressionFactory.Function( declaringType == typeof(DateTime) ? "GETUTCDATE" : "SYSUTCDATETIME", Array.Empty <SqlExpression>(), returnType); return(declaringType == typeof(DateTime) ? (SqlExpression)serverTranslation : _sqlExpressionFactory.Convert(serverTranslation, returnType)); case nameof(DateTime.Today): return(_sqlExpressionFactory.Function( "CONVERT", new SqlExpression[] { _sqlExpressionFactory.Fragment("date"), _sqlExpressionFactory.Function( "GETDATE", Array.Empty <SqlExpression>(), typeof(DateTime)) }, returnType)); } } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { Check.NotNull(member, nameof(member)); Check.NotNull(returnType, nameof(returnType)); if (_memberToFunctionName.TryGetValue(member, out var functionName)) { return(returnType == typeof(bool) ? _sqlExpressionFactory.Case( new[] { new CaseWhenClause( _sqlExpressionFactory.IsNotNull(instance), _sqlExpressionFactory.Function( functionName, new[] { instance }, nullResultAllowed: false, argumentsPropagateNullability: new[] { false }, returnType)) }, null) : (SqlExpression)_sqlExpressionFactory.Function( functionName, new[] { instance }, nullResultAllowed: true, argumentsPropagateNullability: new[] { true }, returnType)); } if (Equals(member, _geometryType)) { return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "GeometryType", new[] { instance }, nullResultAllowed: true, argumentsPropagateNullability: new[] { true }, returnType), _sqlExpressionFactory.Constant(" ZM") }, nullResultAllowed: true, argumentsPropagateNullability: new[] { true }, returnType), new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant("Point")), new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant("LineString")), new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant("Polygon")), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant("MultiPoint")), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant("MultiLineString")), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant("MultiPolygon")), new CaseWhenClause( _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant("GeometryCollection")))); } if (Equals(member, _ogcGeometryType)) { return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "GeometryType", new[] { instance }, nullResultAllowed: true, argumentsPropagateNullability: new[] { true }, typeof(string)), _sqlExpressionFactory.Constant(" ZM") }, nullResultAllowed: true, argumentsPropagateNullability: new[] { true }, typeof(string)), new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant(OgcGeometryType.Point)), new CaseWhenClause( _sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.LineString)), new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.Polygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPoint)), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiLineString)), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPolygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant(OgcGeometryType.GeometryCollection)))); } return(null); }
private SqlExpression TranslateSystemFunction(string function, Type returnType, params SqlExpression[] arguments) => _sqlExpressionFactory.Function(function, arguments, returnType);
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (_dateFromPartsMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "DATEFROMPARTS", arguments.Skip(1), nullResultAllowed: true, argumentsPropagateNullability: arguments.Skip(1).Select(a => true), _dateFromPartsMethodInfo.ReturnType, _typeMappingSource.FindMapping(typeof(DateTime), "date"))); } if (_dateTimeFromPartsMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "DATETIMEFROMPARTS", arguments.Skip(1), nullResultAllowed: true, argumentsPropagateNullability: arguments.Skip(1).Select(a => true), _dateTimeFromPartsMethodInfo.ReturnType, _typeMappingSource.FindMapping(typeof(DateTime), "datetime"))); } if (_dateTime2FromPartsMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "DATETIME2FROMPARTS", arguments.Skip(1), nullResultAllowed: true, argumentsPropagateNullability: arguments.Skip(1).Select(a => true), _dateTime2FromPartsMethodInfo.ReturnType, _typeMappingSource.FindMapping(typeof(DateTime), "datetime2"))); } if (_dateTimeOffsetFromPartsMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "DATETIMEOFFSETFROMPARTS", arguments.Skip(1), nullResultAllowed: true, argumentsPropagateNullability: arguments.Skip(1).Select(a => true), _dateTimeOffsetFromPartsMethodInfo.ReturnType, _typeMappingSource.FindMapping(typeof(DateTimeOffset), "datetimeoffset"))); } if (_smallDateTimeFromPartsMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "SMALLDATETIMEFROMPARTS", arguments.Skip(1), nullResultAllowed: true, argumentsPropagateNullability: arguments.Skip(1).Select(a => true), _smallDateTimeFromPartsMethodInfo.ReturnType, _typeMappingSource.FindMapping(typeof(DateTime), "smalldatetime"))); } if (_timeFromPartsMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "TIMEFROMPARTS", arguments.Skip(1), nullResultAllowed: true, argumentsPropagateNullability: arguments.Skip(1).Select(a => true), _timeFromPartsMethodInfo.ReturnType, _typeMappingSource.FindMapping(typeof(TimeSpan), "time"))); } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression Translate( SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); Check.NotNull(logger, nameof(logger)); if (_supportedMethodTranslations.TryGetValue(method, out var sqlFunctionName)) { var typeMapping = arguments.Count == 1 ? ExpressionExtensions.InferTypeMapping(arguments[0]) : ExpressionExtensions.InferTypeMapping(arguments[0], arguments[1]); var newArguments = new SqlExpression[arguments.Count]; newArguments[0] = _sqlExpressionFactory.ApplyTypeMapping(arguments[0], typeMapping); if (arguments.Count == 2) { newArguments[1] = _sqlExpressionFactory.ApplyTypeMapping(arguments[1], typeMapping); } return(_sqlExpressionFactory.Function( sqlFunctionName, newArguments, nullable: true, argumentsPropagateNullability: newArguments.Select(a => true).ToArray(), method.ReturnType, sqlFunctionName == "SIGN" ? null : typeMapping)); } if (_truncateMethodInfos.Contains(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.Function( "ROUND", new[] { argument, _sqlExpressionFactory.Constant(0), _sqlExpressionFactory.Constant(1) }, nullable: true, argumentsPropagateNullability: new[] { true, false, false }, method.ReturnType, argument.TypeMapping)); } if (_roundMethodInfos.Contains(method)) { var argument = arguments[0]; var digits = arguments.Count == 2 ? arguments[1] : _sqlExpressionFactory.Constant(0); return(_sqlExpressionFactory.Function( "ROUND", new[] { argument, digits }, nullable: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType, argument.TypeMapping)); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); if (typeof(Geometry).IsAssignableFrom(method.DeclaringType)) { var geometryExpressions = new[] { instance }.Concat( arguments.Where(e => typeof(Geometry).IsAssignableFrom(e.Type))); var typeMapping = ExpressionExtensions.InferTypeMapping(geometryExpressions.ToArray()); Check.DebugAssert(typeMapping != null, "At least one argument must have typeMapping."); var storeType = typeMapping.StoreType; var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase); if (_methodToFunctionName.TryGetValue(method, out var functionName) || (!isGeography && _geometryMethodToFunctionName.TryGetValue(method, out functionName))) { instance = _sqlExpressionFactory.ApplyTypeMapping( instance, _typeMappingSource.FindMapping(instance.Type, storeType)); var typeMappedArguments = new List <SqlExpression>(); foreach (var argument in arguments) { typeMappedArguments.Add( _sqlExpressionFactory.ApplyTypeMapping( argument, typeof(Geometry).IsAssignableFrom(argument.Type) ? _typeMappingSource.FindMapping(argument.Type, storeType) : _typeMappingSource.FindMapping(argument.Type))); } var resultTypeMapping = typeof(Geometry).IsAssignableFrom(method.ReturnType) ? _typeMappingSource.FindMapping(method.ReturnType, storeType) : _typeMappingSource.FindMapping(method.ReturnType); return(_sqlExpressionFactory.Function( instance, functionName, Simplify(typeMappedArguments, isGeography), method.ReturnType, resultTypeMapping)); } if (Equals(method, _getGeometryN)) { return(_sqlExpressionFactory.Function( instance, "STGeometryN", new[] { _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, method.ReturnType, _typeMappingSource.FindMapping(method.ReturnType, storeType))); } if (Equals(method, _isWithinDistance)) { instance = _sqlExpressionFactory.ApplyTypeMapping( instance, _typeMappingSource.FindMapping(instance.Type, storeType)); var typeMappedArguments = new List <SqlExpression>(); foreach (var argument in arguments) { typeMappedArguments.Add( _sqlExpressionFactory.ApplyTypeMapping( argument, typeof(Geometry).IsAssignableFrom(argument.Type) ? _typeMappingSource.FindMapping(argument.Type, storeType) : _typeMappingSource.FindMapping(argument.Type))); } return(_sqlExpressionFactory.LessThanOrEqual( _sqlExpressionFactory.Function( instance, "STDistance", Simplify(new[] { typeMappedArguments[0] }, isGeography), typeof(double)), typeMappedArguments[1])); } } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression?Translate( SqlExpression?instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (instance != null) { if (IndexOfMethodInfo.Equals(method)) { var argument = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument); return(_sqlExpressionFactory.Subtract( _sqlExpressionFactory.Function( "instr", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping) }, nullable: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType), _sqlExpressionFactory.Constant(1))); } if (ReplaceMethodInfo.Equals(method)) { var firstArgument = arguments[0]; var secondArgument = arguments[1]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument); return(_sqlExpressionFactory.Function( "replace", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, stringTypeMapping)); } if (ToLowerMethodInfo.Equals(method) || ToUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( ToLowerMethodInfo.Equals(method) ? "lower" : "upper", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, method.ReturnType, instance.TypeMapping)); } if (SubstringMethodInfoWithOneArg.Equals(method)) { return(_sqlExpressionFactory.Function( "substr", new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)) }, nullable: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType, instance.TypeMapping)); } if (SubstringMethodInfoWithTwoArgs.Equals(method)) { return(_sqlExpressionFactory.Function( "substr", new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, instance.TypeMapping)); } if (TrimStartMethodInfoWithoutArgs.Equals(method) == true || TrimStartMethodInfoWithCharArg.Equals(method) == true || TrimStartMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments, "ltrim")); } if (TrimEndMethodInfoWithoutArgs.Equals(method) == true || TrimEndMethodInfoWithCharArg.Equals(method) == true || TrimEndMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments, "rtrim")); } if (TrimMethodInfoWithoutArgs.Equals(method) == true || TrimMethodInfoWithCharArg.Equals(method) == true || TrimMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments, "trim")); } if (ContainsMethodInfo.Equals(method)) { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Equal( pattern, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "instr", new[] { instance, pattern }, nullable: true, argumentsPropagateNullability: new[] { true, true }, typeof(int)), _sqlExpressionFactory.Constant(0)))); } if (StartsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (EndsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } } if (IsNullOrWhiteSpaceMethodInfo.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( _sqlExpressionFactory.Function( "trim", new[] { argument }, nullable: true, argumentsPropagateNullability: new[] { true }, argument.Type, argument.TypeMapping), _sqlExpressionFactory.Constant(string.Empty)))); } if (FirstOrDefaultMethodInfoWithoutArgs.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.Function( "substr", new[] { argument, _sqlExpressionFactory.Constant(1), _sqlExpressionFactory.Constant(1) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType)); } if (LastOrDefaultMethodInfoWithoutArgs.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.Function( "substr", new[] { argument, _sqlExpressionFactory.Function( "length", new[] { argument }, nullable: true, argumentsPropagateNullability: new[] { true }, typeof(int)), _sqlExpressionFactory.Constant(1) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType)); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { return(Equals(member, _count) ? _sqlExpressionFactory.Function("NumGeometries", new[] { instance }, returnType) : null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression Translate( SqlExpression instance, MemberInfo member, Type returnType, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(member, nameof(member)); Check.NotNull(returnType, nameof(returnType)); Check.NotNull(logger, nameof(logger)); if (typeof(Geometry).IsAssignableFrom(member.DeclaringType)) { Check.DebugAssert(instance.TypeMapping != null, "Instance must have typeMapping assigned."); var storeType = instance.TypeMapping.StoreType; var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase); if (_memberToFunctionName.TryGetValue(member, out var functionName) || (!isGeography && _geometryMemberToFunctionName.TryGetValue(member, out functionName))) { var resultTypeMapping = typeof(Geometry).IsAssignableFrom(returnType) ? _typeMappingSource.FindMapping(returnType, storeType) : _typeMappingSource.FindMapping(returnType); return(_sqlExpressionFactory.Function( instance, functionName, Array.Empty <SqlExpression>(), nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability: Array.Empty <bool>(), returnType, resultTypeMapping)); } if (Equals(member, _ogcGeometryType)) { var whenClauses = new List <CaseWhenClause> { new CaseWhenClause( _sqlExpressionFactory.Constant("Point"), _sqlExpressionFactory.Constant(OgcGeometryType.Point)), new CaseWhenClause( _sqlExpressionFactory.Constant("LineString"), _sqlExpressionFactory.Constant(OgcGeometryType.LineString)), new CaseWhenClause( _sqlExpressionFactory.Constant("Polygon"), _sqlExpressionFactory.Constant(OgcGeometryType.Polygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("MultiPoint"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPoint)), new CaseWhenClause( _sqlExpressionFactory.Constant("MultiLineString"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiLineString)), new CaseWhenClause( _sqlExpressionFactory.Constant("MultiPolygon"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPolygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("GeometryCollection"), _sqlExpressionFactory.Constant(OgcGeometryType.GeometryCollection)), new CaseWhenClause( _sqlExpressionFactory.Constant("CircularString"), _sqlExpressionFactory.Constant(OgcGeometryType.CircularString)), new CaseWhenClause( _sqlExpressionFactory.Constant("CompoundCurve"), _sqlExpressionFactory.Constant(OgcGeometryType.CompoundCurve)), new CaseWhenClause( _sqlExpressionFactory.Constant("CurvePolygon"), _sqlExpressionFactory.Constant(OgcGeometryType.CurvePolygon)) }; if (isGeography) { whenClauses.Add( new CaseWhenClause( _sqlExpressionFactory.Constant("FullGlobe"), _sqlExpressionFactory.Constant((OgcGeometryType)126))); } return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( instance, "STGeometryType", Array.Empty <SqlExpression>(), nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability: Array.Empty <bool>(), typeof(string)), whenClauses, null)); } if (Equals(member, _srid)) { return(_sqlExpressionFactory.NiladicFunction( instance, "STSrid", nullable: true, instancePropagatesNullability: true, returnType)); } } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { method.ThrowIfNull(nameof(method)); arguments.ThrowIfNull(nameof(arguments)); logger.ThrowIfNull(nameof(logger)); if (_indexOfMethodInfo.Equals(method)) { var argument = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument); argument = _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping); SqlExpression charIndexExpression; charIndexExpression = _sqlExpressionFactory.Function( "AT", new[] { argument, _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping) }, true, new[] { true, true }, method.ReturnType); charIndexExpression = _sqlExpressionFactory.Subtract(charIndexExpression, _sqlExpressionFactory.Constant(1)); return(_sqlExpressionFactory.Case( new[] { new CaseWhenClause( _sqlExpressionFactory.Equal( argument, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.Constant(0)) }, charIndexExpression)); } if (_replaceMethodInfo.Equals(method)) { var firstArgument = arguments[0]; var secondArgument = arguments[1]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, firstArgument, secondArgument); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); firstArgument = _sqlExpressionFactory.ApplyTypeMapping(firstArgument, stringTypeMapping); secondArgument = _sqlExpressionFactory.ApplyTypeMapping(secondArgument, stringTypeMapping); return(_sqlExpressionFactory.Function( "REPLACE", new[] { instance, firstArgument, secondArgument }, true, new[] { true, true, true }, method.ReturnType, stringTypeMapping)); } if (_toLowerMethodInfo.Equals(method) || _toUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( _toLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER", new[] { instance }, true, new[] { true }, method.ReturnType, instance.TypeMapping)); } if (_substringMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "SUBSTR", new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, true, new[] { true, true, true }, method.ReturnType, instance.TypeMapping)); } if (_substringNoLengthMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "SUBSTR", new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)) }, true, new[] { true, true }, method.ReturnType, instance.TypeMapping)); } if (_isNullOrWhiteSpaceMethodInfo.Equals(method)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( _sqlExpressionFactory.Function( "LTRIM", new[] { _sqlExpressionFactory.Function( "RTRIM", new[] { argument }, true, new[] { true }, argument.Type, argument.TypeMapping) }, true, new[] { true }, argument.Type, argument.TypeMapping), _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping)))); } if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true || (_trimStartMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { instance }, true, new[] { true }, instance.Type, instance.TypeMapping)); } if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true || (_trimEndMethodInfoWithCharArrayArg.Equals(method) // SqlServer RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "RTRIM", new[] { instance }, true, new[] { true }, instance.Type, instance.TypeMapping)); } if (_trimMethodInfoWithoutArgs?.Equals(method) == true || (_trimMethodInfoWithCharArrayArg.Equals(method) // SqlServer LTRIM/RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(_sqlExpressionFactory.Function( "LTRIM", new[] { _sqlExpressionFactory.Function( "RTRIM", new[] { instance }, true, new[] { true }, instance.Type, instance.TypeMapping) }, true, new[] { true }, instance.Type, instance.TypeMapping)); } if (_containsMethodInfo.Equals(method)) { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); if (pattern is SqlConstantExpression constantPattern) { // Intentionally string.Empty since we don't want to match nulls here. #pragma warning disable CA1820 // Test for empty strings using string length if ((string)constantPattern.Value == string.Empty) #pragma warning restore CA1820 // Test for empty strings using string length { return(_sqlExpressionFactory.Constant(true)); } return(_sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "AT", new[] { pattern, instance }, true, new[] { true, true }, typeof(int)), _sqlExpressionFactory.Constant(0))); } return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Equal( pattern, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "AT", new[] { pattern, instance }, true, new[] { true, true }, typeof(int)), _sqlExpressionFactory.Constant(0)))); } if (_startsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (_endsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression?Translate( SqlExpression?instance, MemberInfo member, Type returnType, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (instance != null) { if (MemberToFunctionName.TryGetValue(member, out var functionName)) { return(returnType == typeof(bool) ? _sqlExpressionFactory.Case( new[] { new CaseWhenClause( _sqlExpressionFactory.IsNotNull(instance), _sqlExpressionFactory.Function( functionName, new[] { instance }, nullable: false, argumentsPropagateNullability: new[] { false }, returnType)) }, null) : _sqlExpressionFactory.Function( functionName, new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, returnType)); } if (Equals(member, GeometryType)) { return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "GeometryType", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, returnType), _sqlExpressionFactory.Constant(" ZM") }, nullable: true, argumentsPropagateNullability: new[] { true }, returnType), new[] { new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant("Point")), new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant("LineString")), new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant("Polygon")), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant("MultiPoint")), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant("MultiLineString")), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant("MultiPolygon")), new CaseWhenClause( _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant("GeometryCollection")) }, null)); } if (Equals(member, OgcGeometryType)) { return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "GeometryType", new[] { instance }, nullable: true, argumentsPropagateNullability: new[] { true }, typeof(string)), _sqlExpressionFactory.Constant(" ZM") }, nullable: true, argumentsPropagateNullability: new[] { true }, typeof(string)), new[] { new CaseWhenClause( _sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.Point)), new CaseWhenClause( _sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.LineString)), new CaseWhenClause( _sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.Polygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.MultiPoint)), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.MultiLineString)), new CaseWhenClause( _sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.MultiPolygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant(NetTopologySuite.Geometries.OgcGeometryType.GeometryCollection)) }, null)); } } return(null); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); if (_methodToFunctionName.TryGetValue(method, out var functionName)) { var finalArguments = new[] { instance }.Concat(arguments); if (method.ReturnType == typeof(bool)) { var nullCheck = (SqlExpression)_sqlExpressionFactory.IsNotNull(instance); foreach (var argument in arguments) { nullCheck = _sqlExpressionFactory.AndAlso( nullCheck, _sqlExpressionFactory.IsNotNull(argument)); } return(_sqlExpressionFactory.Case( new[] { new CaseWhenClause( nullCheck, _sqlExpressionFactory.Function( functionName, finalArguments, nullable: false, finalArguments.Select(a => false), method.ReturnType)) }, null)); } return(_sqlExpressionFactory.Function( functionName, finalArguments, nullable: true, finalArguments.Select(a => true), method.ReturnType)); } if (Equals(method, _getGeometryN)) { return(_sqlExpressionFactory.Function( "GeometryN", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, nullable: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType)); } if (Equals(method, _isWithinDistance)) { return(_sqlExpressionFactory.LessThanOrEqual( _sqlExpressionFactory.Function( "Distance", new[] { instance, arguments[0] }, nullable: true, argumentsPropagateNullability: new[] { true, true }, typeof(double)), arguments[1])); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { if (typeof(Geometry).IsAssignableFrom(member.DeclaringType)) { Debug.Assert(instance.TypeMapping != null, "Instance must have typeMapping assigned."); var storeType = instance.TypeMapping.StoreType; var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase); if (_memberToFunctionName.TryGetValue(member, out var functionName) || (!isGeography && _geometryMemberToFunctionName.TryGetValue(member, out functionName))) { var resultTypeMapping = typeof(Geometry).IsAssignableFrom(returnType) ? _typeMappingSource.FindMapping(returnType, storeType) : _typeMappingSource.FindMapping(returnType); return(_sqlExpressionFactory.Function( instance, functionName, Array.Empty <SqlExpression>(), returnType, resultTypeMapping)); } if (Equals(member, _ogcGeometryType)) { var whenClauses = new List <CaseWhenClause> { new CaseWhenClause( _sqlExpressionFactory.Constant("Point"), _sqlExpressionFactory.Constant(OgcGeometryType.Point)), new CaseWhenClause( _sqlExpressionFactory.Constant("LineString"), _sqlExpressionFactory.Constant(OgcGeometryType.LineString)), new CaseWhenClause( _sqlExpressionFactory.Constant("Polygon"), _sqlExpressionFactory.Constant(OgcGeometryType.Polygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("MultiPoint"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPoint)), new CaseWhenClause( _sqlExpressionFactory.Constant("MultiLineString"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiLineString)), new CaseWhenClause( _sqlExpressionFactory.Constant("MultiPolygon"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPolygon)), new CaseWhenClause( _sqlExpressionFactory.Constant("GeometryCollection"), _sqlExpressionFactory.Constant(OgcGeometryType.GeometryCollection)), new CaseWhenClause( _sqlExpressionFactory.Constant("CircularString"), _sqlExpressionFactory.Constant(OgcGeometryType.CircularString)), new CaseWhenClause( _sqlExpressionFactory.Constant("CompoundCurve"), _sqlExpressionFactory.Constant(OgcGeometryType.CompoundCurve)), new CaseWhenClause( _sqlExpressionFactory.Constant("CurvePolygon"), _sqlExpressionFactory.Constant(OgcGeometryType.CurvePolygon)) }; if (isGeography) { whenClauses.Add( new CaseWhenClause( _sqlExpressionFactory.Constant("FullGlobe"), _sqlExpressionFactory.Constant((OgcGeometryType)126))); } return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( instance, "STGeometryType", Array.Empty <SqlExpression>(), typeof(string)), whenClauses.ToArray())); } if (Equals(member, _srid)) { return(_sqlExpressionFactory.Function( instance, "STSrid", returnType)); } } return(null); }
public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { return(_memberToFunctionName.TryGetValue(member, out var functionName) ? _sqlExpressionFactory.Function(functionName, new[] { instance }, returnType) : null); }
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (method == IndexOfString || method == IndexOfChar) { var argument = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, argument); return(_sqlExpressionFactory.Subtract( _sqlExpressionFactory.Function( "STRPOS", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(argument, stringTypeMapping) }, method.ReturnType), _sqlExpressionFactory.Constant(1))); } if (method == Replace) { var oldValue = arguments[0]; var newValue = arguments[1]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, oldValue, newValue); return(_sqlExpressionFactory.Function( "REPLACE", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(oldValue, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(newValue, stringTypeMapping) }, method.ReturnType, stringTypeMapping)); } if (method == ToLower || method == ToUpper) { return(_sqlExpressionFactory.Function( method == ToLower ? "LOWER" : "UPPER", new[] { instance }, method.ReturnType, instance.TypeMapping)); } if (method == Substring || method == SubstringWithLength) { var args = method == Substring ? new[] { instance, GenerateOneBasedIndexExpression(arguments[0]) } : new[] { instance, GenerateOneBasedIndexExpression(arguments[0]), arguments[1] }; return(_sqlExpressionFactory.Function( "SUBSTRING", args, method.ReturnType, instance.TypeMapping)); } if (method == IsNullOrWhiteSpace) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( _sqlExpressionFactory.Function( "BTRIM", new[] { argument, _whitespace }, argument.Type, argument.TypeMapping), _sqlExpressionFactory.Constant(string.Empty, argument.TypeMapping)))); } var isTrimStart = method == TrimStartWithNoParam || method == TrimStartWithChars || method == TrimStartWithSingleChar; var isTrimEnd = method == TrimEndWithNoParam || method == TrimEndWithChars || method == TrimEndWithSingleChar; var isTrimBoth = method == TrimBothWithNoParam || method == TrimBothWithChars || method == TrimBothWithSingleChar; if (isTrimStart || isTrimEnd || isTrimBoth) { char[] trimChars = null; if (method == TrimStartWithChars || method == TrimStartWithSingleChar || method == TrimEndWithChars || method == TrimEndWithSingleChar || method == TrimBothWithChars || method == TrimBothWithSingleChar) { var constantTrimChars = arguments[0] as SqlConstantExpression; if (constantTrimChars == null) { return(null); // Don't translate if trim chars isn't a constant } trimChars = constantTrimChars.Value is char c ? new[] { c } : (char[])constantTrimChars.Value; } return(_sqlExpressionFactory.Function( isTrimStart ? "LTRIM" : isTrimEnd ? "RTRIM" : "BTRIM", new[] { instance, trimChars == null || trimChars.Length == 0 ? _whitespace : _sqlExpressionFactory.Constant(new string(trimChars)) }, instance.Type, instance.TypeMapping)); } if (method == Contains) { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); var strposCheck = _sqlExpressionFactory.GreaterThan( _sqlExpressionFactory.Function( "STRPOS", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping) }, typeof(int)), _sqlExpressionFactory.Constant(0)); if (pattern is SqlConstantExpression constantPattern) { return((string)constantPattern.Value == string.Empty ? (SqlExpression)_sqlExpressionFactory.Constant(true) : strposCheck); } return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Equal( pattern, _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)), strposCheck)); } if (method == PadLeft || method == PadLeftWithChar || method == PadRight || method == PadRightWithChar) { var args = method == PadLeft || method == PadRight ? new[] { instance, arguments[0] } : new[] { instance, arguments[0], arguments[1] }; return(_sqlExpressionFactory.Function( method == PadLeft || method == PadLeftWithChar ? "lpad" : "rpad", args, instance.Type, instance.TypeMapping)); } if (method == StartsWith) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (method == EndsWith) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } return(null); }
public SqlExpression Translate(SqlExpression instance, MemberInfo member, Type returnType) { member = member.OnInterface(typeof(IGeometry)); if (_memberToFunctionName.TryGetValue(member, out var functionName)) { SqlExpression translation = _sqlExpressionFactory.Function(functionName, new[] { instance }, returnType); if (returnType == typeof(bool)) { translation = _sqlExpressionFactory.Case( new[] { new CaseWhenClause( _sqlExpressionFactory.IsNotNull(instance), translation) }, null); } return(translation); } if (Equals(member, _geometryType)) { return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "GeometryType", new [] { instance, }, returnType), _sqlExpressionFactory.Constant(" ZM") }, returnType), new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant("Point")), new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant("LineString")), new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant("Polygon")), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant("MultiPoint")), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant("MultiLineString")), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant("MultiPolygon")), new CaseWhenClause(_sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant("GeometryCollection")))); } if (Equals(member, _ogcGeometryType)) { return(_sqlExpressionFactory.Case( _sqlExpressionFactory.Function( "rtrim", new SqlExpression[] { _sqlExpressionFactory.Function( "GeometryType", new [] { instance, }, typeof(string)), _sqlExpressionFactory.Constant(" ZM") }, typeof(string)), new CaseWhenClause(_sqlExpressionFactory.Constant("POINT"), _sqlExpressionFactory.Constant(OgcGeometryType.Point)), new CaseWhenClause(_sqlExpressionFactory.Constant("LINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.LineString)), new CaseWhenClause(_sqlExpressionFactory.Constant("POLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.Polygon)), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOINT"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPoint)), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTILINESTRING"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiLineString)), new CaseWhenClause(_sqlExpressionFactory.Constant("MULTIPOLYGON"), _sqlExpressionFactory.Constant(OgcGeometryType.MultiPolygon)), new CaseWhenClause(_sqlExpressionFactory.Constant("GEOMETRYCOLLECTION"), _sqlExpressionFactory.Constant(OgcGeometryType.GeometryCollection)))); } return(null); }
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (_methodInfoDateAddMapping != null && _methodInfoDateAddMapping.TryGetValue(method, out var dateAddPart)) { return(arguments[0] is SqlConstantExpression sqlConstant && ((sqlConstant.Value is double && ((double)sqlConstant.Value >= int.MaxValue || (double)sqlConstant.Value <= int.MinValue)) || (sqlConstant.Value is long && ((long)sqlConstant.Value >= int.MaxValue || (long)sqlConstant.Value <= int.MinValue))) ? null : _sqlExpressionFactory.Function( "DATEADD", new[] { _sqlExpressionFactory.Fragment(dateAddPart), _sqlExpressionFactory.Convert(arguments[0], typeof(int)), instance }, instance.Type, instance.TypeMapping)); } else if (_methodInfoDateAddExtensionMapping != null && _methodInfoDateAddExtensionMapping.TryGetValue(method, out var dateAddExtensionPart)) { return(arguments[1] is SqlConstantExpression sqlConstant && ((sqlConstant.Value is double && ((double)sqlConstant.Value >= int.MaxValue || (double)sqlConstant.Value <= int.MinValue)) || (sqlConstant.Value is long && ((long)sqlConstant.Value >= int.MaxValue || (long)sqlConstant.Value <= int.MinValue))) ? null : _sqlExpressionFactory.Function( "DATEADD", new[] { _sqlExpressionFactory.Fragment(dateAddExtensionPart), _sqlExpressionFactory.Convert(arguments[1], typeof(int)), arguments[0] }, arguments[0].Type, arguments[0].TypeMapping)); } else if (_methodInfoDatePartExtensionMapping != null && _methodInfoDatePartExtensionMapping.TryGetValue(method, out var datePart)) { return(_sqlExpressionFactory.Function( "DATEPART", new[] { _sqlExpressionFactory.Fragment(datePart), arguments[0] }, method.ReturnType, null)); } else if (_methodInfoDateDiffMapping != null && _methodInfoDateDiffMapping.TryGetValue(method, out var dateDiffDatePart)) { var startDate = arguments[1]; var endDate = arguments[2]; var typeMapping = ExpressionExtensions.InferTypeMapping(startDate, endDate); startDate = _sqlExpressionFactory.ApplyTypeMapping(startDate, typeMapping); endDate = _sqlExpressionFactory.ApplyTypeMapping(endDate, typeMapping); return(_sqlExpressionFactory.Function( "DATEDIFF", new[] { _sqlExpressionFactory.Fragment(dateDiffDatePart), startDate, endDate }, method.ReturnType, null)); } else if (_methodInfoDateDiffBigMapping != null && _methodInfoDateDiffBigMapping.TryGetValue(method, out var dateDiffBigDatePart)) { var startDate = arguments[1]; var endDate = arguments[2]; var typeMapping = ExpressionExtensions.InferTypeMapping(startDate, endDate); startDate = _sqlExpressionFactory.ApplyTypeMapping(startDate, typeMapping); endDate = _sqlExpressionFactory.ApplyTypeMapping(endDate, typeMapping); return(_sqlExpressionFactory.Function( "DATEDIFF_BIG", new[] { _sqlExpressionFactory.Fragment(dateDiffBigDatePart), startDate, endDate }, method.ReturnType, null)); } return(null); }
public override SqlExpression TranslateLongCount(Expression expression = null) { // TODO: Translate Count with predicate for GroupBy return(_sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Function("COUNT_BIG", new[] { _sqlExpressionFactory.Fragment("*") }, typeof(long)))); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual SqlExpression?Translate( SqlExpression?instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); Check.NotNull(logger, nameof(logger)); if (typeof(Geometry).IsAssignableFrom(method.DeclaringType) && instance != null) { var geometryExpressions = new[] { instance }.Concat( arguments.Where(e => typeof(Geometry).IsAssignableFrom(e.Type))); var typeMapping = ExpressionExtensions.InferTypeMapping(geometryExpressions.ToArray()); Check.DebugAssert(typeMapping != null, "At least one argument must have typeMapping."); var storeType = typeMapping.StoreType; var isGeography = string.Equals(storeType, "geography", StringComparison.OrdinalIgnoreCase); if (_methodToFunctionName.TryGetValue(method, out var functionName) || (!isGeography && _geometryMethodToFunctionName.TryGetValue(method, out functionName))) { instance = _sqlExpressionFactory.ApplyTypeMapping( instance, _typeMappingSource.FindMapping(instance.Type, storeType)); var typeMappedArguments = new List <SqlExpression>(); foreach (var argument in arguments) { typeMappedArguments.Add( _sqlExpressionFactory.ApplyTypeMapping( argument, typeof(Geometry).IsAssignableFrom(argument.Type) ? _typeMappingSource.FindMapping(argument.Type, storeType) : _typeMappingSource.FindMapping(argument.Type))); } var resultTypeMapping = typeof(Geometry).IsAssignableFrom(method.ReturnType) ? _typeMappingSource.FindMapping(method.ReturnType, storeType) : _typeMappingSource.FindMapping(method.ReturnType); var finalArguments = Simplify(typeMappedArguments, isGeography); var argumentsPropagateNullability = functionName == "STBuffer" ? new[] { false } : functionName == "STRelate" ? new[] { true, false } : finalArguments.Select(a => true).ToArray(); return(_sqlExpressionFactory.Function( instance, functionName, finalArguments, nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability, method.ReturnType, resultTypeMapping)); } if (Equals(method, _getGeometryN)) { return(_sqlExpressionFactory.Function( instance, "STGeometryN", new[] { _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability: new[] { false }, method.ReturnType, _typeMappingSource.FindMapping(method.ReturnType, storeType))); } if (Equals(method, _isWithinDistance)) { instance = _sqlExpressionFactory.ApplyTypeMapping( instance, _typeMappingSource.FindMapping(instance.Type, storeType)); var typeMappedArguments = new List <SqlExpression>(); foreach (var argument in arguments) { typeMappedArguments.Add( _sqlExpressionFactory.ApplyTypeMapping( argument, typeof(Geometry).IsAssignableFrom(argument.Type) ? _typeMappingSource.FindMapping(argument.Type, storeType) : _typeMappingSource.FindMapping(argument.Type))); } var finalArguments = Simplify(new[] { typeMappedArguments[0] }, isGeography); return(_sqlExpressionFactory.LessThanOrEqual( _sqlExpressionFactory.Function( instance, "STDistance", finalArguments, nullable: true, instancePropagatesNullability: true, argumentsPropagateNullability: finalArguments.Select(a => true), typeof(double)), typeMappedArguments[1])); } } return(null); }
/// <inheritdoc /> public virtual SqlExpression Translate( SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (SupportedMethodTranslations.TryGetValue(method, out var sqlFunctionName)) { var typeMapping = arguments.Count == 1 ? ExpressionExtensions.InferTypeMapping(arguments[0]) : ExpressionExtensions.InferTypeMapping(arguments[0], arguments[1]); var newArguments = new SqlExpression[arguments.Count]; newArguments[0] = _sqlExpressionFactory.ApplyTypeMapping(arguments[0], typeMapping); if (arguments.Count == 2) { newArguments[1] = _sqlExpressionFactory.ApplyTypeMapping(arguments[1], typeMapping); } // Note: GREATER/LEAST only return NULL if *all* arguments are null, but we currently can't // convey this. return(_sqlExpressionFactory.Function( sqlFunctionName, newArguments, nullable: true, argumentsPropagateNullability: TrueArrays[newArguments.Length], method.ReturnType, typeMapping)); } // PostgreSQL sign() returns 1, 0, -1, but in the same type as the argument, so we need to convert // the return type to int. if (SignMethodInfos.Contains(method)) { return (_sqlExpressionFactory.Convert( _sqlExpressionFactory.Function( "sign", arguments, nullable: true, argumentsPropagateNullability: TrueArrays[1], method.ReturnType), typeof(int), _typeMappingSource.FindMapping(typeof(int)))); } if (method == RoundDecimalTwoParams) { return(_sqlExpressionFactory.Function("round", new[] { _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0]), _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1]) }, nullable: true, argumentsPropagateNullability: TrueArrays[2], method.ReturnType, _typeMappingSource.FindMapping(typeof(decimal)))); } // PostgreSQL treats NaN values as equal, against IEEE754 if (method == DoubleIsNanMethodInfo) { return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(double.NaN))); } if (method == FloatIsNanMethodInfo) { return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(float.NaN))); } if (method == DoubleIsPositiveInfinityMethodInfo) { return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(double.PositiveInfinity))); } if (method == FloatIsPositiveInfinityMethodInfo) { return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(float.PositiveInfinity))); } if (method == DoubleIsNegativeInfinityMethodInfo) { return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(double.NegativeInfinity))); } if (method == FloatIsNegativeInfinityMethodInfo) { return(_sqlExpressionFactory.Equal(arguments[0], _sqlExpressionFactory.Constant(float.NegativeInfinity))); } return(null); }