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(_containsMethod) &&
                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.NullableFunction(
                               "LOCATE",
                               new[] { value, source },
                               typeof(int)),
                           _sqlExpressionFactory.Constant(0)));
            }

            return(null);
        }
Пример #2
0
        /// <inheritdoc />
        protected override Expression VisitUnary(UnaryExpression unaryExpression)
        {
            if (unaryExpression.NodeType == ExpressionType.ArrayLength)
            {
                if (TranslationFailed(unaryExpression.Operand, Visit(unaryExpression.Operand), out var sqlOperand))
                {
                    return(QueryCompilationContext.NotTranslatedExpression);
                }

                if (sqlOperand.Type == typeof(byte[]) &&
                    (sqlOperand.TypeMapping is null or MySqlByteArrayTypeMapping))
                {
                    return(_sqlExpressionFactory.NullableFunction(
                               "LENGTH",
                               new[] { sqlOperand },
                               typeof(int)));
                }

                return(_jsonPocoTranslator?.TranslateArrayLength(sqlOperand) ??
                       QueryCompilationContext.NotTranslatedExpression);
            }

            // Make explicit casts implicit if they are applied to a JSON traversal object.
            // It is pretty common for Newtonsoft.Json objects to be cast to other types (e.g. casting from
            // JToken to JArray to check an arrays length via the JContainer.Count property).
            if (unaryExpression.NodeType == ExpressionType.Convert ||
                unaryExpression.NodeType == ExpressionType.ConvertChecked)
            {
                var visitedOperand = Visit(unaryExpression.Operand);
                if (visitedOperand is MySqlJsonTraversalExpression traversal)
                {
                    return(unaryExpression.Type == typeof(object)
                        ? traversal
                        : traversal.Clone(
                               traversal.ReturnsText,
                               unaryExpression.Type,
                               Dependencies.TypeMappingSource.FindMapping(unaryExpression.Type)));
                }

                ResetTranslationErrorDetails();
            }

            var visitedExpression = base.VisitUnary(unaryExpression);

            if (visitedExpression is SqlUnaryExpression sqlUnaryExpression &&
                sqlUnaryExpression.OperatorType == ExpressionType.Not &&
                sqlUnaryExpression.Type != typeof(bool))
            {
                // MySQL implicitly casts numbers used in BITWISE NOT operations (~ operator) to BIGINT UNSIGNED.
                // We need to cast them back, to get the expected result.
                return(_sqlExpressionFactory.Convert(
                           sqlUnaryExpression,
                           sqlUnaryExpression.Type,
                           sqlUnaryExpression.TypeMapping));
            }

            return(visitedExpression);
        }