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));

            // Issue #15586: Query: TypeCompatibility chart for inference.
            return(_methodInfo.Equals(method)
                ? _sqlExpressionFactory.Function(
                       "abs",
                       new SqlExpression[]
            {
                _sqlExpressionFactory.Divide(
                    _sqlExpressionFactory.Function(
                        "random",
                        Array.Empty <SqlExpression>(),
                        nullable: false,
                        argumentsPropagateNullability: Array.Empty <bool>(),
                        method.ReturnType),
                    _sqlExpressionFactory.Constant(9223372036854780000.0))
            },
                       nullable: false,
                       argumentsPropagateNullability: Array.Empty <bool>(),
                       method.ReturnType)
                : null);
        }
    public SqlExpression?Translate(
        SqlExpression?instance,
        MemberInfo member,
        Type returnType,
        IDiagnosticsLogger <DbLoggerCategory.Query> logger)
    {
        if (typeof(Point).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 (MemberToPropertyName.TryGetValue(member, out var propertyName) ||
                (isGeography
                    ? GeographyMemberToPropertyName.TryGetValue(member, out propertyName)
                    : GeometryMemberToPropertyName.TryGetValue(member, out propertyName)) &&
                propertyName != null)
            {
                return(_sqlExpressionFactory.NiladicFunction(
                           instance,
                           propertyName,
                           nullable: true,
                           instancePropagatesNullability: true,
                           returnType));
            }
        }

        return(null);
    }
Example #3
0
        /// <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 (_memberToFunctionName.TryGetValue(member, out var functionName) &&
                instance != null)
            {
                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));
            }

            return(null);
        }
Example #4
0
        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 (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 (memberName == nameof(DateTime.Ticks))
                {
                    return(_sqlExpressionFactory.Convert(
                               _sqlExpressionFactory.Multiply(
                                   _sqlExpressionFactory.Subtract(
                                       _sqlExpressionFactory.Function(
                                           "julianday",
                                           new[] { instance ! },
        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, _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);
        }
Example #6
0
        public virtual SqlExpression?Translate(
            SqlExpression?instance,
            MethodInfo method,
            IReadOnlyList <SqlExpression> arguments,
            IDiagnosticsLogger <DbLoggerCategory.Query> logger)
        {
            if (instance?.Type.IsGenericList() == true && !IsMappedToNonArray(instance))
            {
                // Translate list[i]. Note that array[i] is translated by NpgsqlSqlTranslatingExpressionVisitor.VisitBinary (ArrayIndex)
                if (method.Name == "get_Item" && arguments.Count == 1)
                {
                    return
                        // Try translating indexing inside json column
                        (_jsonPocoTranslator.TranslateMemberAccess(instance, arguments[0], method.ReturnType) ??
                         // Other types should be subscriptable - but PostgreSQL arrays are 1-based, so adjust the index.
                         _sqlExpressionFactory.ArrayIndex(instance, GenerateOneBasedIndexExpression(arguments[0])));
                }

                return(TranslateCommon(instance, arguments));
            }

            if (instance is null && arguments.Count > 0 && arguments[0].Type.IsArrayOrGenericList() && !IsMappedToNonArray(arguments[0]))
            {
                // Extension method over an array or list
                if (method.IsClosedFormOf(SequenceEqual) && arguments[1].Type.IsArray)
                {
                    return(_sqlExpressionFactory.Equal(arguments[0], arguments[1]));
                }

                return(TranslateCommon(arguments[0], arguments.Slice(1)));
            }

            // Not an array/list
            return(null);
Example #7
0
        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 (method.IsGenericMethod &&
                method.GetGenericMethodDefinition().Equals(EnumerableMethods.Contains) &&
                arguments[0].Type == typeof(byte[]))
            {
                var source            = arguments[0];
                var sourceTypeMapping = source.TypeMapping;

                var value = arguments[1] is SqlConstantExpression constantValue
                    ? (SqlExpression)_sqlExpressionFactory.Constant(new[] { (byte)constantValue.Value }, sourceTypeMapping)
                    : _sqlExpressionFactory.Convert(arguments[1], typeof(byte[]), sourceTypeMapping);

                return(_sqlExpressionFactory.GreaterThan(
                           _sqlExpressionFactory.Function(
                               "CHARINDEX",
                               new[] { value, source },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true, true },
                               typeof(int)),
                           _sqlExpressionFactory.Constant(0)));
            }

            return(null);
        }
Example #8
0
        public virtual SqlExpression?ApplyTypeMapping(SqlExpression?sqlExpression, CoreTypeMapping?typeMapping)
        {
            if (sqlExpression == null ||
                sqlExpression.TypeMapping != null)
            {
                return(sqlExpression);
            }

#pragma warning disable IDE0066 // Convert switch statement to expression
            switch (sqlExpression)
#pragma warning restore IDE0066 // Convert switch statement to expression
            {
            case SqlConditionalExpression sqlConditionalExpression:
                return(ApplyTypeMappingOnSqlConditional(sqlConditionalExpression, typeMapping));

            case SqlBinaryExpression sqlBinaryExpression:
                return(ApplyTypeMappingOnSqlBinary(sqlBinaryExpression, typeMapping));

            case SqlUnaryExpression sqlUnaryExpression:
                return(ApplyTypeMappingOnSqlUnary(sqlUnaryExpression, typeMapping));

            case SqlConstantExpression sqlConstantExpression:
                return(sqlConstantExpression.ApplyTypeMapping(typeMapping));

            case SqlParameterExpression sqlParameterExpression:
                return(sqlParameterExpression.ApplyTypeMapping(typeMapping));

            case SqlFunctionExpression sqlFunctionExpression:
                return(sqlFunctionExpression.ApplyTypeMapping(typeMapping));

            default:
                return(sqlExpression);
            }
        }
    public PostgresFunctionExpression(
        string name,
        IEnumerable <SqlExpression> arguments,
        IEnumerable <string?>?argumentNames,
        IEnumerable <string?>?argumentSeparators,
        bool nullable,
        IEnumerable <bool> argumentsPropagateNullability,
        bool aggregateDistinct,
        SqlExpression?aggregatePredicate,
        IReadOnlyList <OrderingExpression> aggregateOrderings,
        Type type,
        RelationalTypeMapping?typeMapping)
        : base(name, arguments, nullable, argumentsPropagateNullability, type, typeMapping)
    {
        Check.NotEmpty(name, nameof(name));
        Check.NotNull(type, nameof(type));

        ArgumentNames      = (argumentNames ?? Array.Empty <string>()).ToList();
        ArgumentSeparators = (argumentSeparators ?? Array.Empty <string>()).ToList();

        if (ArgumentNames.SkipWhile(a => a is null).Contains(null))
        {
            throw new ArgumentException($"{nameof(argumentNames)} must contain nulls followed by non-nulls", nameof(argumentNames));
        }

        IsAggregateDistinct = aggregateDistinct;
        AggregatePredicate  = aggregatePredicate;
        AggregateOrderings  = aggregateOrderings;
    }
        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 (method.Equals(_regexIsMatchMethodInfo))
            {
                var input             = arguments[0];
                var pattern           = arguments[1];
                var stringTypeMapping = ExpressionExtensions.InferTypeMapping(input, pattern);

                return(_sqlExpressionFactory.Function(
                           "regexp",
                           new[]
                {
                    _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping),
                    _sqlExpressionFactory.ApplyTypeMapping(input, stringTypeMapping)
                },
                           nullable: true,
                           argumentsPropagateNullability: new[] { true, true },
                           typeof(bool)));
            }

            return(null);
        }
Example #11
0
    /// <inheritdoc />
    public virtual SqlExpression?Translate(
        SqlExpression?instance,
        MethodInfo method,
        IReadOnlyList <SqlExpression> arguments,
        IDiagnosticsLogger <DbLoggerCategory.Query> logger)
    {
        if (method == TsQueryParse || method == TsVectorParse)
        {
            return(_sqlExpressionFactory.Convert(arguments[0], method.ReturnType));
        }

        if (method.DeclaringType == typeof(NpgsqlFullTextSearchDbFunctionsExtensions))
        {
            return(method.Name switch
            {
                // Methods accepting a configuration (regconfig)
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.ToTsVector)         when arguments.Count == 3 => ConfigAccepting("to_tsvector"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.PlainToTsQuery)     when arguments.Count == 3 => ConfigAccepting("plainto_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.PhraseToTsQuery)    when arguments.Count == 3 => ConfigAccepting("phraseto_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.ToTsQuery)          when arguments.Count == 3 => ConfigAccepting("to_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.WebSearchToTsQuery) when arguments.Count == 3 => ConfigAccepting("websearch_to_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.Unaccent)           when arguments.Count == 3 => DictionaryAccepting("unaccent"),

                // Methods not accepting a configuration
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.ArrayToTsVector) => NonConfigAccepting("array_to_tsvector"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.ToTsVector) => NonConfigAccepting("to_tsvector"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.PlainToTsQuery) => NonConfigAccepting("plainto_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.PhraseToTsQuery) => NonConfigAccepting("phraseto_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.ToTsQuery) => NonConfigAccepting("to_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.WebSearchToTsQuery) => NonConfigAccepting("websearch_to_tsquery"),
                nameof(NpgsqlFullTextSearchDbFunctionsExtensions.Unaccent) => NonConfigAccepting("unaccent"),

                _ => null
            });
Example #12
0
        /// <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 (Equals(member, _isClosed) &&
                instance != null)
            {
                return(_sqlExpressionFactory.Case(
                           new[]
                {
                    new CaseWhenClause(
                        _sqlExpressionFactory.IsNotNull(instance),
                        _sqlExpressionFactory.Function(
                            "IsClosed",
                            new[] { instance },
                            nullable: false,
                            argumentsPropagateNullability: new[] { false },
                            returnType))
                },
                           null));
            }

            return(null);
        }
Example #13
0
        /// <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 (_memberToFunctionName.TryGetValue(member, out var functionName))
            {
                Check.DebugAssert(instance !.TypeMapping != null, "Instance must have typeMapping assigned.");
                var storeType   = instance.TypeMapping.StoreType;
                var isGeography = storeType == "geography";

                if (isGeography && functionName == "STIsRing")
                {
                    return(null);
                }

                var resultTypeMapping = typeof(Geometry).IsAssignableFrom(returnType)
                    ? _typeMappingSource.FindMapping(returnType, storeType)
                    : _typeMappingSource.FindMapping(returnType);

                return(_sqlExpressionFactory.Function(
                           instance,
                           functionName,
                           Enumerable.Empty <SqlExpression>(),
                           nullable: true,
                           instancePropagatesNullability: true,
                           argumentsPropagateNullability: Enumerable.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)
        {
            Check.NotNull(method, nameof(method));
            Check.NotNull(arguments, nameof(arguments));
            Check.NotNull(logger, nameof(logger));

            if (Equals(method, _getPointN) &&
                instance != null)
            {
                return(_sqlExpressionFactory.Function(
                           instance,
                           "STPointN",
                           new[]
                {
                    _sqlExpressionFactory.Add(
                        arguments[0],
                        _sqlExpressionFactory.Constant(1))
                },
                           nullable: true,
                           instancePropagatesNullability: true,
                           argumentsPropagateNullability: new[] { true },
                           method.ReturnType,
                           _typeMappingSource.FindMapping(method.ReturnType, instance.TypeMapping !.StoreType)));
            }

            return(null);
        }
Example #15
0
        /// <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 (member.Name == nameof(string.Length) &&
                instance?.Type == typeof(string))
            {
                return(_sqlExpressionFactory.Convert(
                           _sqlExpressionFactory.Function(
                               "LEN",
                               new[] { instance },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true },
                               typeof(long)),
                           returnType));
            }

            return(null);
        }
Example #16
0
        public virtual SqlExpression?ApplyTypeMapping(SqlExpression?sqlExpression, CoreTypeMapping?typeMapping)
        {
            if (sqlExpression == null ||
                sqlExpression.TypeMapping != null)
            {
                return(sqlExpression);
            }

            switch (sqlExpression)
            {
            case SqlConditionalExpression sqlConditionalExpression:
                return(ApplyTypeMappingOnSqlConditional(sqlConditionalExpression, typeMapping));

            case SqlBinaryExpression sqlBinaryExpression:
                return(ApplyTypeMappingOnSqlBinary(sqlBinaryExpression, typeMapping));

            case SqlUnaryExpression sqlUnaryExpression:
                return(ApplyTypeMappingOnSqlUnary(sqlUnaryExpression, typeMapping));

            case SqlConstantExpression sqlConstantExpression:
                return(sqlConstantExpression.ApplyTypeMapping(typeMapping));

            case SqlParameterExpression sqlParameterExpression:
                return(sqlParameterExpression.ApplyTypeMapping(typeMapping));

            default:
                return(sqlExpression);
            }
        }
Example #17
0
    /// <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, _item) &&
            instance != null)
        {
            return(_sqlExpressionFactory.Function(
                       instance,
                       "STGeometryN",
                       new[]
            {
                _sqlExpressionFactory.Add(
                    arguments[0],
                    _sqlExpressionFactory.Constant(1))
            },
                       nullable: true,
                       instancePropagatesNullability: true,
                       argumentsPropagateNullability: new[] { false },
                       method.ReturnType,
                       _typeMappingSource.FindMapping(typeof(Geometry), instance.TypeMapping !.StoreType)));
        }

        return(null);
    }
Example #18
0
        /// <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 (member.DeclaringType?.IsNullableValueType() == true &&
                instance != null)
            {
                switch (member.Name)
                {
                case nameof(Nullable <int> .Value):
                    return(instance);

                case nameof(Nullable <int> .HasValue):
                    return(_sqlExpressionFactory.IsNotNull(instance));
                }
            }

            return(null);
        }
Example #19
0
        private SqlFunctionExpression(
            [CanBeNull] SqlExpression?instance,
            [CanBeNull] string?schema,
            [NotNull] string name,
            bool niladic,
            [CanBeNull] IEnumerable <SqlExpression>?arguments,
            bool nullable,
            bool?instancePropagatesNullability,
            [CanBeNull] IEnumerable <bool>?argumentsPropagateNullability,
            bool builtIn,
            [NotNull] Type type,
            [CanBeNull] RelationalTypeMapping?typeMapping)
            : base(type, typeMapping)
        {
            Check.NotEmpty(name, nameof(name));
            Check.NotNull(type, nameof(type));

            Instance   = instance;
            Name       = name;
            Schema     = schema;
            IsNiladic  = niladic;
            IsBuiltIn  = builtIn;
            Arguments  = arguments?.ToList();
            IsNullable = nullable;
            InstancePropagatesNullability = instancePropagatesNullability;
            ArgumentsPropagateNullability = argumentsPropagateNullability?.ToList();
        }
Example #20
0
    /// <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 (method.Equals(MethodInfo))
        {
            var matchExpression   = arguments[1];
            var pattern           = arguments[2];
            var stringTypeMapping = ExpressionExtensions.InferTypeMapping(matchExpression, pattern);

            return(_sqlExpressionFactory.Function(
                       "glob",
                       new[]
            {
                _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping),
                _sqlExpressionFactory.ApplyTypeMapping(matchExpression, stringTypeMapping)
            },
                       nullable: true,
                       argumentsPropagateNullability: new[] { true, true },
                       typeof(bool)));
        }

        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 (_methodInfoDateDiffMapping.TryGetValue(method, out var datePart))
            {
                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(datePart), startDate, endDate },
                           nullable: true,
                           argumentsPropagateNullability: new[] { false, true, true },
                           typeof(int)));
            }

            return(null);
        }
Example #22
0
    public virtual SqlExpression?Translate(
        SqlExpression?instance,
        MethodInfo method,
        IReadOnlyList <SqlExpression> arguments,
        IDiagnosticsLogger <DbLoggerCategory.Query> logger)
    {
        if (method.DeclaringType != typeof(NpgsqlJsonDbFunctionsExtensions))
        {
            return(null);
        }

        var args = arguments
                   // Skip useless DbFunctions instance
                   .Skip(1)
                   // JSON extensions accept object parameters for JSON, since they must be able to handle POCOs, strings or DOM types.
                   // This means they come wrapped in a convert node, which we need to remove.
                   // Convert nodes may also come from wrapping JsonTraversalExpressions generated through POCO traversal.
                   .Select(RemoveConvert)
                   // If a function is invoked over a JSON traversal expression, that expression may come with
                   // returnText: true (i.e. operator ->> and not ->). Since the functions below require a json object and
                   // not text, we transform it.
                   .Select(a => a is PostgresJsonTraversalExpression traversal ? WithReturnsText(traversal, false) : a)
                   .ToArray();

        if (!args.Any(a => a.TypeMapping is NpgsqlJsonTypeMapping || a is PostgresJsonTraversalExpression))
        {
            throw new InvalidOperationException("The EF JSON methods require a JSON parameter and none was found.");
        }

        if (method.Name == nameof(NpgsqlJsonDbFunctionsExtensions.JsonTypeof))
        {
            return(_sqlExpressionFactory.Function(
                       ((NpgsqlJsonTypeMapping)args[0].TypeMapping !).IsJsonb ? "jsonb_typeof" : "json_typeof",
                       new[] { args[0] },
                       nullable: true,
                       argumentsPropagateNullability: TrueArrays[1],
                       typeof(string)));
        }

        // The following are jsonb-only, not support on json
        if (args.Any(a => a.TypeMapping is NpgsqlJsonTypeMapping jsonMapping && !jsonMapping.IsJsonb))
        {
            throw new InvalidOperationException("JSON methods on EF.Functions only support the jsonb type, not json.");
        }

        return(method.Name switch
        {
            nameof(NpgsqlJsonDbFunctionsExtensions.JsonContains)
            => _sqlExpressionFactory.Contains(Jsonb(args[0]), Jsonb(args[1])),
            nameof(NpgsqlJsonDbFunctionsExtensions.JsonContained)
            => _sqlExpressionFactory.ContainedBy(Jsonb(args[0]), Jsonb(args[1])),
            nameof(NpgsqlJsonDbFunctionsExtensions.JsonExists)
            => _sqlExpressionFactory.MakePostgresBinary(PostgresExpressionType.JsonExists, Jsonb(args[0]), args[1]),
            nameof(NpgsqlJsonDbFunctionsExtensions.JsonExistAny)
            => _sqlExpressionFactory.MakePostgresBinary(PostgresExpressionType.JsonExistsAny, Jsonb(args[0]), args[1]),
            nameof(NpgsqlJsonDbFunctionsExtensions.JsonExistAll)
            => _sqlExpressionFactory.MakePostgresBinary(PostgresExpressionType.JsonExistsAll, Jsonb(args[0]), args[1]),

            _ => null
        });
    private SqlExpression TranslateIndexOf(
        SqlExpression instance,
        MethodInfo method,
        SqlExpression searchExpression,
        SqlExpression?startIndex)
    {
        var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, searchExpression) !;

        searchExpression = _sqlExpressionFactory.ApplyTypeMapping(searchExpression, stringTypeMapping);
        instance         = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);

        var charIndexArguments = new List <SqlExpression> {
            searchExpression, instance
        };

        if (startIndex is not null)
        {
            charIndexArguments.Add(_sqlExpressionFactory.Add(startIndex, _sqlExpressionFactory.Constant(1)));
        }

        var argumentsPropagateNullability = Enumerable.Repeat(true, charIndexArguments.Count);

        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",
                charIndexArguments,
                nullable: true,
                argumentsPropagateNullability,
                typeof(long));

            charIndexExpression = _sqlExpressionFactory.Convert(charIndexExpression, typeof(int));
        }
        else
        {
            charIndexExpression = _sqlExpressionFactory.Function(
                "CHARINDEX",
                charIndexArguments,
                nullable: true,
                argumentsPropagateNullability,
                method.ReturnType);
        }

        charIndexExpression = _sqlExpressionFactory.Subtract(charIndexExpression, _sqlExpressionFactory.Constant(1));

        return(_sqlExpressionFactory.Case(
                   new[]
        {
            new CaseWhenClause(
                _sqlExpressionFactory.Equal(
                    searchExpression,
                    _sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
                _sqlExpressionFactory.Constant(0))
        },
                   charIndexExpression));
    }
Example #24
0
 /// <summary>
 ///     Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will
 ///     return this expression.
 /// </summary>
 /// <param name="match">The <see cref="Match" /> property of the result.</param>
 /// <param name="pattern">The <see cref="Pattern" /> property of the result.</param>
 /// <param name="escapeChar">The <see cref="EscapeChar" /> property of the result.</param>
 /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
 public virtual LikeExpression Update(
     SqlExpression match,
     SqlExpression pattern,
     SqlExpression?escapeChar)
 => match != Match || pattern != Pattern || escapeChar != EscapeChar
         ? new LikeExpression(match, pattern, escapeChar, TypeMapping)
         : this;
Example #25
0
        /// <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 (method.IsGenericMethod &&
                method.GetGenericMethodDefinition().Equals(EnumerableMethods.Contains) &&
                ValidateValues(arguments[0]))
            {
                return(_sqlExpressionFactory.In(RemoveObjectConvert(arguments[1]), arguments[0], negated: false));
            }

            if (arguments.Count == 1 &&
                method.IsContainsMethod() &&
                instance != null &&
                ValidateValues(instance))
            {
                return(_sqlExpressionFactory.In(RemoveObjectConvert(arguments[0]), instance, negated: false));
            }

            return(null);
        }
Example #26
0
 /// <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)
 => method.IsGenericMethod &&
 Equals(method.GetGenericMethodDefinition(), _methodInfo) &&
 arguments[2] is SqlConstantExpression constantExpression &&
 public CaseExpression(
     [NotNull] IReadOnlyList <CaseWhenClause> whenClauses,
     [CanBeNull] SqlExpression?elseResult = null)
     : base(Check.NotEmpty(whenClauses, nameof(whenClauses))[0].Result.Type, whenClauses[0].Result.TypeMapping)
 {
     _whenClauses.AddRange(whenClauses);
     ElseResult = elseResult;
 }
 /// <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)
 => Equals(member, _count)
         ? _sqlExpressionFactory.Function(
     "NumGeometries",
     new[] { instance ! },
        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));

            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")
                    },
 /// <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)
 => MemberToFunctionName.TryGetValue(member, out var functionName)
         ? _sqlExpressionFactory.Function(
     functionName,
     new[] { instance ! },