public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); if (Equals(method, _item)) { return(_sqlExpressionFactory.Function( "GeometryN", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, method.ReturnType)); } return(null); }
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IList <SqlExpression> arguments) { if (typeof(ILineString).IsAssignableFrom(method.DeclaringType)) { if (Equals(method.OnInterface(typeof(ILineString)), _getPointN)) { return(_sqlExpressionFactory.Function( instance, "STPointN", new[] { _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, method.ReturnType, _typeMappingSource.FindMapping(method.ReturnType, instance.TypeMapping.StoreType))); } } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); if (Equals(method, _item)) { return(_sqlExpressionFactory.Function( instance, "STGeometryN", new[] { _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, method.ReturnType, _typeMappingSource.FindMapping(typeof(Geometry), instance.TypeMapping.StoreType))); } 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 (Equals(method, _getInteriorRingN)) { return(_sqlExpressionFactory.Function( "InteriorRingN", new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)) }, nullable: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType)); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (Equals(method, _isNullOrEmptyMethodInfo)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( argument, _sqlExpressionFactory.Constant(string.Empty)))); } if (Equals(method, _concatMethodInfo)) { return(_sqlExpressionFactory.Add( arguments[0], arguments[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 (Equals(method, _isNullOrEmptyMethodInfo)) { var argument = arguments[0]; return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(argument), _sqlExpressionFactory.Equal( argument, _sqlExpressionFactory.Constant(string.Empty)))); } if (Equals(method, _concatMethodInfoTwoArgs)) { return(_sqlExpressionFactory.Add( arguments[0], arguments[1])); } if (Equals(method, _concatMethodInfoThreeArgs)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], arguments[2]))); } if (Equals(method, _concatMethodInfoFourArgs)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], _sqlExpressionFactory.Add( arguments[2], arguments[3])))); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); if (Equals(method, _getPointN)) { return(_sqlExpressionFactory.Function( "PointN", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, nullable: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType)); } return(null); }
SqlExpression TranslateStartsEndsWith(SqlExpression instance, SqlExpression pattern, bool startsWith) { var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); if (pattern is SqlConstantExpression constantExpression) { // The pattern is constant. Aside from null, we escape all special characters (%, _, \) // in C# and send a simple LIKE return(constantExpression.Value is string constantPattern ? _sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Constant( startsWith ? EscapeLikePattern(constantPattern) + '%' : '%' + EscapeLikePattern(constantPattern))) : _sqlExpressionFactory.Like(instance, _sqlExpressionFactory.Constant(null, stringTypeMapping))); } // The pattern is non-constant, we use LEFT or RIGHT to extract substring and compare. // For StartsWith we also first run a LIKE to quickly filter out most non-matching results (sargable, but imprecise // because of wildchars). SqlExpression leftRight = _sqlExpressionFactory.Function( startsWith ? "left" : "right", new[] { instance, _sqlExpressionFactory.Function( "length", new[] { pattern }, nullable: true, argumentsPropagateNullability: TrueArrays[1], typeof(int)) }, nullable: true, argumentsPropagateNullability: TrueArrays[2], typeof(string), stringTypeMapping); // LEFT/RIGHT of a citext return a text, so for non-default text mappings we apply an explicit cast. if (instance.TypeMapping != _textTypeMapping) { leftRight = _sqlExpressionFactory.Convert(leftRight, typeof(string), instance.TypeMapping); } // Also add an explicit cast on the pattern; this is only required because of // The following is only needed because of https://github.com/aspnet/EntityFrameworkCore/issues/19120 var castPattern = pattern.TypeMapping == _textTypeMapping ? pattern : _sqlExpressionFactory.Convert(pattern, typeof(string), pattern.TypeMapping); return(startsWith ? _sqlExpressionFactory.AndAlso( _sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Add( pattern, _sqlExpressionFactory.Constant("%")), _sqlExpressionFactory.Constant(string.Empty)), _sqlExpressionFactory.Equal(leftRight, castPattern)) : _sqlExpressionFactory.Equal(leftRight, castPattern)); }
/// <summary> /// 更新 Select 语句 /// </summary> /// <param name="selectExpression"></param> /// <returns></returns> private Expression VisitSelect(SelectExpression selectExpression) { var oldOffset = selectExpression.Offset; if (oldOffset == null) { return(selectExpression); } var oldLimit = selectExpression.Limit; var oldOrderings = selectExpression.Orderings; // 在子查询中 OrderBy 必须写 Top 数量 var newOrderings = oldOrderings.Count > 0 && (oldLimit != null || selectExpression == root) ? oldOrderings.ToList() : new List <OrderingExpression>(); // 更新表达式 selectExpression = selectExpression.Update(selectExpression.Projection.ToList(), selectExpression.Tables.ToList(), selectExpression.Predicate, selectExpression.GroupBy.ToList(), selectExpression.Having, orderings: newOrderings, limit: null, offset: null); var rowOrderings = oldOrderings.Count != 0 ? oldOrderings : new[] { new OrderingExpression(new SqlFragmentExpression("(SELECT 1)"), true) }; _ = selectExpression.PushdownIntoSubquery(); // .NET 6 该方法已无返回值 var subQuery = (SelectExpression)selectExpression.Tables[0]; var projection = new RowNumberExpression(Array.Empty <SqlExpression>(), rowOrderings, oldOffset.TypeMapping); var left = GenerateOuterColumnAccessor(subQuery, projection, "row"); selectExpression.ApplyPredicate(sqlExpressionFactory.GreaterThan(left, oldOffset)); if (oldLimit != null) { if (oldOrderings.Count == 0) { selectExpression.ApplyPredicate(sqlExpressionFactory.LessThanOrEqual(left, sqlExpressionFactory.Add(oldOffset, oldLimit))); } else { // 这里不支持子查询的 OrderBy 操作 selectExpression.ApplyLimit(oldLimit); } } return(selectExpression); }
private static SqlExpression GetAndoyerDistance( SqlExpression left, SqlExpression right, Type resultType, ISqlExpressionFactory sqlExpressionFactory) { SqlExpression toDegrees(SqlExpression coord) => sqlExpressionFactory.Divide( sqlExpressionFactory.Multiply( coord, sqlExpressionFactory.Function( "PI", Array.Empty <SqlExpression>(), resultType)), sqlExpressionFactory.Constant(180.0)); SqlExpression xCoord(SqlExpression point) => sqlExpressionFactory.Function( "ST_X", new[] { point }, resultType); SqlExpression yCoord(SqlExpression point) => sqlExpressionFactory.Function( "ST_Y", new[] { point }, resultType); var c0 = sqlExpressionFactory.Constant(0.0); var c1 = sqlExpressionFactory.Constant(1.0); var c2 = sqlExpressionFactory.Constant(2.0); var c3 = sqlExpressionFactory.Constant(3.0); var c2Int = sqlExpressionFactory.Constant(2); var lon1 = toDegrees(xCoord(left)); var lat1 = toDegrees(yCoord(left)); var lon2 = toDegrees(xCoord(right)); var lat2 = toDegrees(yCoord(right)); var g = sqlExpressionFactory.Divide( sqlExpressionFactory.Subtract( lat1, lat2), c2); var lambda = sqlExpressionFactory.Divide( sqlExpressionFactory.Subtract( lon1, lon2), c2); var f = sqlExpressionFactory.Divide( sqlExpressionFactory.Add( lat1, lat2), c2); var sinG2 = sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "SIN", new[] { g }, resultType), c2Int }, resultType); var cosG2 = sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "COS", new[] { g }, resultType), c2Int }, resultType); var sinF2 = sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "SIN", new[] { f }, resultType), c2Int }, resultType); var cosF2 = sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "COS", new[] { f }, resultType), c2Int }, resultType); var sinL2 = sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "SIN", new[] { lambda }, resultType), c2Int }, resultType); var cosL2 = sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "COS", new[] { lambda }, resultType), c2Int }, resultType); var s = sqlExpressionFactory.Add( sqlExpressionFactory.Multiply(sinG2, cosL2), sqlExpressionFactory.Multiply(cosF2, sinL2)); var c = sqlExpressionFactory.Add( sqlExpressionFactory.Multiply(cosG2, cosL2), sqlExpressionFactory.Multiply(sinF2, sinL2)); var radiusA = sqlExpressionFactory.Constant(6378137.0); var radiusB = sqlExpressionFactory.Constant(6356752.3142451793); var flattening = sqlExpressionFactory.Divide( sqlExpressionFactory.Subtract(radiusA, radiusB), radiusA); var omega = sqlExpressionFactory.Function( "ATAN", new[] { sqlExpressionFactory.Function( "SQRT", new[] { sqlExpressionFactory.Divide(s, c) }, resultType) }, resultType); var r3 = sqlExpressionFactory.Divide( sqlExpressionFactory.Multiply( c3, sqlExpressionFactory.Function( "SQRT", new[] { sqlExpressionFactory.Multiply(s, c) }, resultType)), omega); var d = sqlExpressionFactory.Multiply( sqlExpressionFactory.Multiply(c2, omega), radiusA); var h1 = sqlExpressionFactory.Divide( sqlExpressionFactory.Subtract(r3, c1), sqlExpressionFactory.Multiply(c2, c)); var h2 = sqlExpressionFactory.Divide( sqlExpressionFactory.Add(r3, c1), sqlExpressionFactory.Multiply(c2, s)); var andoyer = sqlExpressionFactory.Multiply( d, sqlExpressionFactory.Add( c1, sqlExpressionFactory.Multiply( flattening, sqlExpressionFactory.Subtract( sqlExpressionFactory.Multiply( sqlExpressionFactory.Multiply( h1, sinF2), cosG2), sqlExpressionFactory.Multiply( sqlExpressionFactory.Multiply( h2, cosF2), sinG2))))); return(sqlExpressionFactory.Case( new[] { new CaseWhenClause( sqlExpressionFactory.OrElse( sqlExpressionFactory.OrElse( sqlExpressionFactory.AndAlso( sqlExpressionFactory.Equal(lambda, c0), sqlExpressionFactory.Equal(g, c0)), sqlExpressionFactory.Equal(s, c0)), sqlExpressionFactory.Equal(c, c0)), c0), }, andoyer)); }
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 (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 (_substringMethodInfo.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 SqlExpression?Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { 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( "TRIM", new[] { argument }, argument.Type, argument.TypeMapping), _sqlExpressionFactory.Constant(string.Empty)))); } 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 constantExpression) { if (constantExpression.Value is string constantString) { return(constantString.Any(c => IsLikeWildChar(c)) ? _sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Constant('%' + EscapeLikePattern(constantString) + '%')) : _sqlExpressionFactory.Like( instance, _sqlExpressionFactory.Constant('%' + constantString + '%'))); } } } if (_startsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], true)); } if (_endsWithMethodInfo.Equals(method)) { return(TranslateStartsEndsWith(instance, arguments[0], false)); } return(null); }
private Expression VisitSelect(SelectExpression selectExpression) { var oldOffset = selectExpression.Offset; if (oldOffset == null) { return(selectExpression); } var oldLimit = selectExpression.Limit; var oldOrderings = selectExpression.Orderings; //order by in subQuery without TOP N is invalid. var newOrderings = oldOrderings.Count > 0 && (oldLimit != null || selectExpression == root) ? oldOrderings.ToList() : new List <OrderingExpression>(); selectExpression = selectExpression.Update(selectExpression.Projection.ToList(), selectExpression.Tables.ToList(), selectExpression.Predicate, selectExpression.GroupBy.ToList(), selectExpression.Having, orderings: newOrderings, limit: null, offset: null, selectExpression.IsDistinct, selectExpression.Alias); var rowOrderings = oldOrderings.Count != 0 ? oldOrderings : new[] { new OrderingExpression(new SqlFragmentExpression("(SELECT 1)"), true) }; _ = selectExpression.PushdownIntoSubquery(); var subQuery = (SelectExpression)selectExpression.Tables[0]; var projection = new RowNumberExpression(Array.Empty <SqlExpression>(), rowOrderings, oldOffset.TypeMapping); var left = GenerateOuterColumnAccessor(subQuery, projection, "row"); selectExpression.ApplyPredicate(sqlExpressionFactory.GreaterThan(left, oldOffset)); if (oldLimit != null) { if (oldOrderings.Count == 0) { selectExpression.ApplyPredicate(sqlExpressionFactory.LessThanOrEqual(left, sqlExpressionFactory.Add(oldOffset, oldLimit))); } else { //the above one not working when used as subQuery with orderBy selectExpression.ApplyLimit(oldLimit); } } return(selectExpression); }
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 (instance != null) { 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 (_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, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { Check.NotNull(method, nameof(method)); Check.NotNull(arguments, nameof(arguments)); Check.NotNull(logger, nameof(logger)); if (instance != null) { if (_containsMethodInfo.Equals(method)) { return(TranslateSystemFunction("CONTAINS", typeof(bool), instance, arguments[0])); } if (_startsWithMethodInfo.Equals(method)) { return(TranslateSystemFunction("STARTSWITH", typeof(bool), instance, arguments[0])); } if (_endsWithMethodInfo.Equals(method)) { return(TranslateSystemFunction("ENDSWITH", typeof(bool), instance, arguments[0])); } if (_toLowerMethodInfo.Equals(method)) { return(TranslateSystemFunction("LOWER", method.ReturnType, instance)); } if (_toUpperMethodInfo.Equals(method)) { return(TranslateSystemFunction("UPPER", method.ReturnType, instance)); } } if (_firstOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(TranslateSystemFunction("LEFT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1))); } if (_lastOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(TranslateSystemFunction("RIGHT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1))); } if (_stringConcatWithTwoArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], arguments[1])); } if (_stringConcatWithThreeArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], arguments[2]))); } if (_stringConcatWithFourArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], _sqlExpressionFactory.Add( arguments[2], arguments[3])))); } 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 (instance != null) { if (_containsMethodInfo.Equals(method)) { return(TranslateSystemFunction("CONTAINS", typeof(bool), instance, arguments[0])); } if (_startsWithMethodInfo.Equals(method)) { return(TranslateSystemFunction("STARTSWITH", typeof(bool), instance, arguments[0])); } if (_endsWithMethodInfo.Equals(method)) { return(TranslateSystemFunction("ENDSWITH", typeof(bool), instance, arguments[0])); } if (_toLowerMethodInfo.Equals(method)) { return(TranslateSystemFunction("LOWER", method.ReturnType, instance)); } if (_toUpperMethodInfo.Equals(method)) { return(TranslateSystemFunction("UPPER", method.ReturnType, instance)); } if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true || (_trimStartMethodInfoWithCharArrayArg.Equals(method) // Cosmos DB LTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(TranslateSystemFunction("LTRIM", method.ReturnType, instance)); } if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true || (_trimEndMethodInfoWithCharArrayArg.Equals(method) // Cosmos DB RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(TranslateSystemFunction("RTRIM", method.ReturnType, instance)); } if (_trimMethodInfoWithoutArgs?.Equals(method) == true || (_trimMethodInfoWithCharArrayArg.Equals(method) // Cosmos DB TRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(TranslateSystemFunction("TRIM", method.ReturnType, instance)); } if (_substringMethodInfoWithOneArg.Equals(method)) { return(TranslateSystemFunction( "SUBSTRING", method.ReturnType, instance, arguments[0], TranslateSystemFunction("LENGTH", typeof(int), instance))); } if (_substringMethodInfoWithTwoArgs.Equals(method)) { return(TranslateSystemFunction("SUBSTRING", method.ReturnType, instance, arguments[0], arguments[1])); } } if (_firstOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(TranslateSystemFunction("LEFT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1))); } if (_lastOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(TranslateSystemFunction("RIGHT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1))); } if (_stringConcatWithTwoArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], arguments[1])); } if (_stringConcatWithThreeArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], arguments[2]))); } if (_stringConcatWithFourArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], _sqlExpressionFactory.Add( arguments[2], arguments[3])))); } return(null); }
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, nullResultAllowed: false, finalArguments.Select(a => false), method.ReturnType)) }, null)); } return(_sqlExpressionFactory.Function( functionName, finalArguments, nullResultAllowed: true, finalArguments.Select(a => true), method.ReturnType)); } if (Equals(method, _getGeometryN)) { return(_sqlExpressionFactory.Function( "GeometryN", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, nullResultAllowed: true, argumentsPropagateNullability: new[] { true, true }, method.ReturnType)); } if (Equals(method, _isWithinDistance)) { return(_sqlExpressionFactory.LessThanOrEqual( _sqlExpressionFactory.Function( "Distance", new[] { instance, arguments[0] }, nullResultAllowed: true, argumentsPropagateNullability: new[] { true, true }, typeof(double)), arguments[1])); } 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); 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) { // 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( "CHARINDEX", new[] { pattern, instance }, nullable: true, argumentsPropagateNullability: new[] { true, true }, typeof(int)), _sqlExpressionFactory.Constant(0))); } return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.Equal( 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)); } 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 (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); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments) { if (s_containsMethodInfo.Equals(method)) { var pos = TranslateOneArgFunction("STRPOS", instance, arguments[0], typeof(long)); return(_sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.GreaterThan(pos, _sqlExpressionFactory.Constant(0L)))); } if (s_startsWithMethodInfo.Equals(method)) { return(TranslateOneArgFunction("STARTS_WITH", instance, arguments[0], typeof(bool))); } if (s_endsWithMethodInfo.Equals(method)) { return(TranslateOneArgFunction("ENDS_WITH", instance, arguments[0], typeof(bool))); } if (s_indexOfMethodInfo.Equals(method)) { var pos = TranslateOneArgFunction("STRPOS", instance, arguments[0], typeof(long)); return(_sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Subtract(pos, _sqlExpressionFactory.Constant(1L)))); } if (s_replaceMethodInfo.Equals(method)) { return(TranslateTwoArgFunction("REPLACE", instance, arguments[0], arguments[1], typeof(string))); } if (s_toLowerMethodInfo.Equals(method)) { return(TranslateNoArgFunction("LOWER", instance, typeof(string))); } if (s_toUpperMethodInfo.Equals(method)) { return(TranslateNoArgFunction("UPPER", instance, typeof(string))); } if (s_substringMethodInfo.Equals(method)) { return(TranslateOneArgFunction("SUBSTR", instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1L)), typeof(string))); } if (s_substringWithLengthMethodInfo.Equals(method)) { return(TranslateTwoArgFunction("SUBSTR", instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1L)), arguments[1], typeof(string))); } if (s_trimStartMethodInfoWithoutArgs.Equals(method)) { return(TranslateNoArgFunction("LTRIM", instance, typeof(string))); } if (s_trimStartMethodInfoWithCharArg.Equals(method)) { return(TranslateOneArgFunction("LTRIM", instance, arguments[0], typeof(string))); } if (s_trimEndMethodInfoWithoutArgs.Equals(method)) { return(TranslateNoArgFunction("RTRIM", instance, typeof(string))); } if (s_trimEndMethodInfoWithCharArg.Equals(method)) { return(TranslateOneArgFunction("RTRIM", instance, arguments[0], typeof(string))); } if (s_trimMethodInfoWithoutArgs.Equals(method)) { return(TranslateNoArgFunction("TRIM", instance, typeof(string))); } if (s_trimMethodInfoWithCharArg.Equals(method)) { return(TranslateOneArgFunction("TRIM", instance, arguments[0], typeof(string))); } if (s_padLeftMethodInfo.Equals(method)) { return(TranslateOneArgFunction("LPAD", instance, arguments[0], typeof(string))); } if (s_padLeftWithStringMethodInfo.Equals(method)) { return(TranslateTwoArgFunction("LPAD", instance, arguments[0], arguments[1], typeof(string))); } if (s_padRightMethodInfo.Equals(method)) { return(TranslateOneArgFunction("RPAD", instance, arguments[0], typeof(string))); } if (s_padRightWithStringMethodInfo.Equals(method)) { return(TranslateTwoArgFunction("RPAD", instance, arguments[0], arguments[1], typeof(string))); } if (s_formatOneArgMethodInfo.Equals(method) || s_formatTwoArgMethodInfo.Equals(method) || s_formatThreeArgMethodInfo.Equals(method) || s_formatVarArgMethodInfo.Equals(method)) { return(TranslateStaticFunction("FORMAT", arguments, typeof(string))); } if (s_joinMethodInfo.Equals(method)) { return(TranslateTwoArgFunction("ARRAY_TO_STRING", arguments[1], arguments[0], _sqlExpressionFactory.Constant(""), typeof(string))); } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> 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()); Debug.Assert(typeMapping != null, "At least one argument must have typeMapping."); var storeType = typeMapping.StoreType; if (_methodToFunctionName.TryGetValue(method, out var functionName) || _geometryMethodToFunctionName.TryGetValue(method, out functionName)) { instance = _sqlExpressionFactory.ApplyTypeMapping( instance, _typeMappingSource.FindMapping(instance.Type, storeType)); var typeMappedArguments = new List <SqlExpression> { instance }; 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( functionName, typeMappedArguments, method.ReturnType, resultTypeMapping)); } if (Equals(method, _getGeometryN)) { return(_sqlExpressionFactory.Function( "ST_GeometryN", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)) }, method.ReturnType, _typeMappingSource.FindMapping(method.ReturnType, storeType))); } if (Equals(method, _distance)) { return(GetDistanceCallBySrid( instance, arguments[0], method.ReturnType, _typeMappingSource.FindMapping(method.ReturnType, storeType))); } if (Equals(method, _isWithinDistance)) { return(_sqlExpressionFactory.LessThanOrEqual( GetDistanceCallBySrid( instance, arguments[0], _distance.ReturnType, _typeMappingSource.FindMapping(_distance.ReturnType)), arguments[1])); } } return(null); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <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)); 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) { if (instance != null) { 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); }
/// <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) { 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()); Debug.Assert(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); }
public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> 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) }, true, null, 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) }, true, null, method.ReturnType, stringTypeMapping)); } if (_toLowerMethodInfo.Equals(method) || _toUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( _toLowerMethodInfo.Equals(method) ? "lower" : "upper", new[] { instance }, true, null, method.ReturnType, instance.TypeMapping)); } if (_substringMethodInfo.Equals(method)) { return(_sqlExpressionFactory.Function( "substr", new[] { instance, _sqlExpressionFactory.Add(arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, true, null, 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 }, true, null, 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 }, true, null, 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, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (instance != null) { if (IndexOfMethodInfo.Equals(method)) { return(TranslateSystemFunction("INDEX_OF", typeof(int), instance, arguments[0])); } if (IndexOfMethodInfoWithStartingPosition.Equals(method)) { return(TranslateSystemFunction("INDEX_OF", typeof(int), instance, arguments[0], arguments[1])); } if (ReplaceMethodInfo.Equals(method)) { return(TranslateSystemFunction("REPLACE", method.ReturnType, instance, arguments[0], arguments[1])); } if (ContainsMethodInfo.Equals(method)) { return(TranslateSystemFunction("CONTAINS", typeof(bool), instance, arguments[0])); } if (StartsWithMethodInfo.Equals(method)) { return(TranslateSystemFunction("STARTSWITH", typeof(bool), instance, arguments[0])); } if (EndsWithMethodInfo.Equals(method)) { return(TranslateSystemFunction("ENDSWITH", typeof(bool), instance, arguments[0])); } if (ToLowerMethodInfo.Equals(method)) { return(TranslateSystemFunction("LOWER", method.ReturnType, instance)); } if (ToUpperMethodInfo.Equals(method)) { return(TranslateSystemFunction("UPPER", method.ReturnType, instance)); } if (TrimStartMethodInfoWithoutArgs.Equals(method) == true || (TrimStartMethodInfoWithCharArrayArg.Equals(method) // Cosmos DB LTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(TranslateSystemFunction("LTRIM", method.ReturnType, instance)); } if (TrimEndMethodInfoWithoutArgs.Equals(method) == true || (TrimEndMethodInfoWithCharArrayArg.Equals(method) // Cosmos DB RTRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(TranslateSystemFunction("RTRIM", method.ReturnType, instance)); } if (TrimMethodInfoWithoutArgs.Equals(method) == true || (TrimMethodInfoWithCharArrayArg.Equals(method) // Cosmos DB TRIM does not take arguments && ((arguments[0] as SqlConstantExpression)?.Value as Array)?.Length == 0)) { return(TranslateSystemFunction("TRIM", method.ReturnType, instance)); } if (SubstringMethodInfoWithOneArg.Equals(method)) { return(TranslateSystemFunction( "SUBSTRING", method.ReturnType, instance, arguments[0], TranslateSystemFunction("LENGTH", typeof(int), instance))); } if (SubstringMethodInfoWithTwoArgs.Equals(method)) { return(arguments[0] is SqlConstantExpression constant && constant.Value is int intValue && intValue == 0 ? TranslateSystemFunction("LEFT", method.ReturnType, instance, arguments[1]) : TranslateSystemFunction("SUBSTRING", method.ReturnType, instance, arguments[0], arguments[1])); } } if (FirstOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(TranslateSystemFunction("LEFT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1))); } if (LastOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(TranslateSystemFunction("RIGHT", typeof(char), arguments[0], _sqlExpressionFactory.Constant(1))); } if (StringConcatWithTwoArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], arguments[1])); } if (StringConcatWithThreeArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], arguments[2]))); } if (StringConcatWithFourArguments.Equals(method)) { return(_sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Add( arguments[1], _sqlExpressionFactory.Add( arguments[2], arguments[3])))); } if (StringComparisonWithComparisonTypeArgumentInstance.Equals(method) || StringComparisonWithComparisonTypeArgumentStatic.Equals(method)) { var comparisonTypeArgument = arguments[^ 1];
private static SqlExpression GetHaversineDistance( SqlExpression left, SqlExpression right, Type resultType, ISqlExpressionFactory sqlExpressionFactory) { // HAVERSINE = 6371000 * 2 * ASIN( // SQRT( // POWER(SIN((ST_Y(pt2) - ST_Y(pt1)) * pi()/180 / 2), 2) + // COS(ST_Y(pt1) * pi()/180) * // COS(ST_Y(pt2) * pi()/180) * // POWER(SIN((ST_X(pt2) - ST_X(pt1)) * pi()/180 / 2), 2) // ) // ) return(sqlExpressionFactory.Multiply( sqlExpressionFactory.Constant(6370986.0), // see https://postgis.net/docs/manual-1.4/ST_Distance_Sphere.html sqlExpressionFactory.Multiply( sqlExpressionFactory.Constant(2.0), sqlExpressionFactory.Function( "ASIN", new[] { sqlExpressionFactory.Function( "SQRT", new[] { sqlExpressionFactory.Add( sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "SIN", new[] { sqlExpressionFactory.Divide( sqlExpressionFactory.Divide( sqlExpressionFactory.Multiply( sqlExpressionFactory.Subtract( sqlExpressionFactory.Function( "ST_Y", new[] { right }, resultType), sqlExpressionFactory.Function( "ST_Y", new[] { left }, resultType)), sqlExpressionFactory.Function( "PI", Array.Empty <SqlExpression>(), resultType)), sqlExpressionFactory.Constant(180.0)), sqlExpressionFactory.Constant(2.0)) }, resultType), sqlExpressionFactory.Constant(2), }, resultType), sqlExpressionFactory.Multiply( sqlExpressionFactory.Function( "COS", new[] { sqlExpressionFactory.Divide( sqlExpressionFactory.Multiply( sqlExpressionFactory.Function( "ST_Y", new[] { left }, resultType), sqlExpressionFactory.Function( "PI", Array.Empty <SqlExpression>(), resultType)), sqlExpressionFactory.Constant(180.0)), }, resultType), sqlExpressionFactory.Multiply( sqlExpressionFactory.Function( "COS", new[] { sqlExpressionFactory.Divide( sqlExpressionFactory.Multiply( sqlExpressionFactory.Function( "ST_Y", new[] { right }, resultType), sqlExpressionFactory.Function( "PI", Array.Empty <SqlExpression>(), resultType)), sqlExpressionFactory.Constant(180.0)), }, resultType), sqlExpressionFactory.Function( "POWER", new SqlExpression[] { sqlExpressionFactory.Function( "SIN", new[] { sqlExpressionFactory.Divide( sqlExpressionFactory.Divide( sqlExpressionFactory.Multiply( sqlExpressionFactory.Subtract( sqlExpressionFactory.Function( "ST_X", new[] { right }, resultType), sqlExpressionFactory.Function( "ST_X", new[] { left }, resultType)), sqlExpressionFactory.Function( "PI", Array.Empty <SqlExpression>(), resultType)), sqlExpressionFactory.Constant(180.0)), sqlExpressionFactory.Constant(2.0)) }, resultType), sqlExpressionFactory.Constant(2), }, resultType)))) }, resultType) }, resultType)))); }