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