private SqlBinaryExpression MakeStartsWithExpressionImpl(
     SqlExpression target,
     SqlExpression prefix,
     SqlExpression originalPrefix = null)
 {
     // BUG: EF Core #17389 will lead to a System.NullReferenceException, if SqlExpressionFactory.Like()
     //      is being called with match and pattern as two expressions, that have not been applied a
     //      TypeMapping yet and no escapeChar (null).
     //      As a workaround, apply/infer the type mapping for the match expression manually for now.
     return(_sqlExpressionFactory.AndAlso(
                _sqlExpressionFactory.Like(
                    target,
                    _sqlExpressionFactory.ApplyDefaultTypeMapping(_sqlExpressionFactory.Function(
                                                                      "CONCAT",
                                                                      // when performing the like it is preferable to use the untransformed prefix
                                                                      // value to ensure the index can be used
                                                                      new[] { originalPrefix ?? prefix, _sqlExpressionFactory.Constant("%") },
                                                                      typeof(string)))),
                _sqlExpressionFactory.Equal(
                    _sqlExpressionFactory.Function(
                        "LEFT",
                        new[]
     {
         target,
         CharLength(prefix)
     },
                        typeof(string)),
                    prefix
                    )));
 }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments)
        {
            if (_likeMethodInfos.Any(m => Equals(method, m)))
            {
                var match = _sqlExpressionFactory.ApplyDefaultTypeMapping(arguments[1]);

                var pattern = InferStringTypeMappingOrApplyDefault(
                    arguments[2],
                    match.TypeMapping);

                var excapeChar = arguments.Count == 4
                    ? InferStringTypeMappingOrApplyDefault(
                    arguments[3],
                    match.TypeMapping)
                    : null;

                return(_sqlExpressionFactory.Like(
                           match,
                           pattern,
                           excapeChar));
            }

            if (Equals(method, _matchMethodInfo))
            {
                if (arguments[3] is SqlConstantExpression constant)
                {
                    return(_sqlExpressionFactory.MakeMatch(
                               arguments[1],
                               arguments[2],
                               (MySqlMatchSearchMode)constant.Value));
                }

                if (arguments[3] is SqlParameterExpression parameter)
                {
                    // Use nested OR clauses here, because MariaDB does not support MATCH...AGAINST from inside of
                    // CASE statements and the nested OR clauses use the fulltext index, while using CASE does not:
                    // <search_mode_1> = @p AND MATCH ... AGAINST ... OR
                    // <search_mode_2> = @p AND MATCH ... AGAINST ... OR [...]
                    var andClauses = Enum.GetValues(typeof(MySqlMatchSearchMode))
                                     .Cast <MySqlMatchSearchMode>()
                                     .OrderByDescending(m => m)
                                     .Select(m => _sqlExpressionFactory.AndAlso(
                                                 _sqlExpressionFactory.Equal(parameter, _sqlExpressionFactory.Constant(m)),
                                                 _sqlExpressionFactory.MakeMatch(arguments[1], arguments[2], m)))
                                     .ToArray();

                    return(andClauses
                           .Skip(1)
                           .Aggregate(
                               andClauses.First(),
                               (currentAnd, previousExpression) => _sqlExpressionFactory.OrElse(previousExpression, currentAnd)));
                }
            }

            return(null);
        }
Пример #3
0
        private static SqlExpression GetAndoyerDistance(
            SqlExpression left,
            SqlExpression right,
            Type resultType,
            MySqlSqlExpressionFactory sqlExpressionFactory)
        {
            SqlExpression toDegrees(SqlExpression coord)
            => sqlExpressionFactory.Divide(
                sqlExpressionFactory.Multiply(
                    coord,
                    sqlExpressionFactory.NonNullableFunction(
                        "PI",
                        Array.Empty <SqlExpression>(),
                        resultType)),
                sqlExpressionFactory.Constant(180.0));

            SqlExpression xCoord(SqlExpression point)
            => sqlExpressionFactory.NullableFunction(
                "ST_X",
                new[] { point },
                resultType);

            SqlExpression yCoord(SqlExpression point)
            => sqlExpressionFactory.NullableFunction(
                "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.NullableFunction(
                "POWER",
                new SqlExpression[]
            {
                sqlExpressionFactory.NullableFunction(
                    "SIN",
                    new[] { g },
                    resultType),
                c2Int
            },
                resultType);
            var cosG2 = sqlExpressionFactory.NullableFunction(
                "POWER",
                new SqlExpression[]
            {
                sqlExpressionFactory.NullableFunction(
                    "COS",
                    new[] { g },
                    resultType),
                c2Int
            },
                resultType);
            var sinF2 = sqlExpressionFactory.NullableFunction(
                "POWER",
                new SqlExpression[]
            {
                sqlExpressionFactory.NullableFunction(
                    "SIN",
                    new[] { f },
                    resultType),
                c2Int
            },
                resultType);
            var cosF2 = sqlExpressionFactory.NullableFunction(
                "POWER",
                new SqlExpression[]
            {
                sqlExpressionFactory.NullableFunction(
                    "COS",
                    new[] { f },
                    resultType),
                c2Int
            },
                resultType);
            var sinL2 = sqlExpressionFactory.NullableFunction(
                "POWER",
                new SqlExpression[]
            {
                sqlExpressionFactory.NullableFunction(
                    "SIN",
                    new[] { lambda },
                    resultType),
                c2Int
            },
                resultType);
            var cosL2 = sqlExpressionFactory.NullableFunction(
                "POWER",
                new SqlExpression[]
            {
                sqlExpressionFactory.NullableFunction(
                    "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.NullableFunction(
                "ATAN",
                new[]
            {
                sqlExpressionFactory.NullableFunction(
                    "SQRT",
                    new[] { sqlExpressionFactory.Divide(s, c) },
                    resultType,
                    false)
            },
                resultType);
            var r3 = sqlExpressionFactory.Divide(
                sqlExpressionFactory.Multiply(
                    c3,
                    sqlExpressionFactory.NullableFunction(
                        "SQRT",
                        new[] { sqlExpressionFactory.Multiply(s, c) },
                        resultType,
                        false)),
                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));
        }