public virtual SqlExpression?ApplyTypeMapping(SqlExpression?sqlExpression, RelationalTypeMapping?typeMapping) { #pragma warning disable IDE0046 // Convert to conditional expression if (sqlExpression == null #pragma warning restore IDE0046 // Convert to conditional expression || sqlExpression.TypeMapping != null) { return(sqlExpression); } return(sqlExpression switch { CaseExpression e => ApplyTypeMappingOnCase(e, typeMapping), CollateExpression e => ApplyTypeMappingOnCollate(e, typeMapping), DistinctExpression e => ApplyTypeMappingOnDistinct(e, typeMapping), LikeExpression e => ApplyTypeMappingOnLike(e), SqlBinaryExpression e => ApplyTypeMappingOnSqlBinary(e, typeMapping), SqlUnaryExpression e => ApplyTypeMappingOnSqlUnary(e, typeMapping), SqlConstantExpression e => e.ApplyTypeMapping(typeMapping), SqlFragmentExpression e => e, SqlFunctionExpression e => e.ApplyTypeMapping(typeMapping), SqlParameterExpression e => e.ApplyTypeMapping(typeMapping), _ => sqlExpression });
protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) { var shouldExplicitParameterTypes = _fbOptions.ExplicitParameterTypes; if (shouldExplicitParameterTypes) { Sql.Append("CAST("); } base.VisitSqlParameter(sqlParameterExpression); if (shouldExplicitParameterTypes) { Sql.Append(" AS "); if (sqlParameterExpression.Type == typeof(string)) { Sql.Append(((IFbSqlGenerationHelper)Dependencies.SqlGenerationHelper).StringParameterQueryType()); } else { Sql.Append(sqlParameterExpression.TypeMapping.StoreType); } Sql.Append(")"); } return(sqlParameterExpression); }
/// <summary> /// Visits the children of the sql parameter expression. /// </summary> /// <param name="sqlParameterExpression"> The expression to visit. </param> /// <returns> The modified expression, if it or any subexpression was modified; otherwise, returns the original expression. </returns> protected abstract Expression VisitSqlParameter([NotNull] SqlParameterExpression sqlParameterExpression);
void IExpressionVisitor.Visit(SqlParameterExpression expr) { }
public virtual SqlExpression Translate( SqlExpression instance, MethodInfo method, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (_indexOfMethodInfo.Equals(method)) { return(new MySqlStringComparisonMethodTranslator(_sqlExpressionFactory, _options) .MakeIndexOfExpression(instance, arguments[0])); } if (_replaceMethodInfo.Equals(method)) { var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, arguments[0], arguments[1]); var replacementArgument = _sqlExpressionFactory.ApplyTypeMapping(arguments[1], stringTypeMapping); var replaceCall = _sqlExpressionFactory.NullableFunction( "REPLACE", new[] { _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(arguments[0], stringTypeMapping), _sqlExpressionFactory.ApplyTypeMapping(arguments[1], stringTypeMapping) }, method.ReturnType, stringTypeMapping); // Due to a bug in all versions of MariaDB and all MySQL versions below 8.0.x (exact version that fixed the issue is // currently unclear), using `null` as the replacement argument in a REPLACE() call leads to unexpected results, in which // the call returns the original string, instead of `null`. // See https://jira.mariadb.org/browse/MDEV-24263 return(_sqlExpressionFactory.Case( new[] { new CaseWhenClause( _sqlExpressionFactory.IsNotNull(replacementArgument), replaceCall) }, _sqlExpressionFactory.Constant(null, RelationalTypeMapping.NullMapping))); } if (_toLowerMethodInfo.Equals(method) || _toUpperMethodInfo.Equals(method)) { return(_sqlExpressionFactory.NullableFunction( _toLowerMethodInfo.Equals(method) ? "LOWER" : "UPPER", new[] { instance }, method.ReturnType, instance.TypeMapping)); } if (_substringMethodInfoWithOneArg.Equals(method)) { return(_sqlExpressionFactory.Function( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)), _sqlExpressionFactory.NullableFunction( "CHAR_LENGTH", new[] { instance }, typeof(int)) }, nullable: true, argumentsPropagateNullability: new[] { true, true, true }, method.ReturnType, instance.TypeMapping)); } if (_substringMethodInfoWithTwoArgs.Equals(method)) { return(_sqlExpressionFactory.NullableFunction( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Add( arguments[0], _sqlExpressionFactory.Constant(1)), arguments[1] }, method.ReturnType, instance.TypeMapping)); } if (_isNullOrWhiteSpaceMethodInfo.Equals(method)) { return(_sqlExpressionFactory.OrElse( _sqlExpressionFactory.IsNull(arguments[0]), _sqlExpressionFactory.Equal( ProcessTrimMethod(arguments[0], null, null), _sqlExpressionFactory.Constant(string.Empty)))); } if (_trimStartMethodInfoWithoutArgs?.Equals(method) == true || _trimStartMethodInfoWithCharArg?.Equals(method) == true || _trimStartMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments.Count > 0 ? arguments[0] : null, "LEADING")); } if (_trimEndMethodInfoWithoutArgs?.Equals(method) == true || _trimEndMethodInfoWithCharArg?.Equals(method) == true || _trimEndMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments.Count > 0 ? arguments[0] : null, "TRAILING")); } if (_trimMethodInfoWithoutArgs?.Equals(method) == true || _trimMethodInfoWithCharArg?.Equals(method) == true || _trimMethodInfoWithCharArrayArg.Equals(method)) { return(ProcessTrimMethod(instance, arguments.Count > 0 ? arguments[0] : null, null)); } if (_containsMethodInfo.Equals(method)) { return(new MySqlStringComparisonMethodTranslator(_sqlExpressionFactory, _options) .MakeContainsExpression(instance, arguments[0])); } if (_startsWithMethodInfo.Equals(method)) { return(new MySqlStringComparisonMethodTranslator(_sqlExpressionFactory, _options) .MakeStartsWithExpression(instance, arguments[0])); } if (_endsWithMethodInfo.Equals(method)) { return(new MySqlStringComparisonMethodTranslator(_sqlExpressionFactory, _options) .MakeEndsWithExpression(instance, arguments[0])); } if (_padLeftWithOneArg.Equals(method)) { return(TranslatePadLeftRight( true, instance, arguments[0], _sqlExpressionFactory.Constant(" "), method.ReturnType)); } if (_padRightWithOneArg.Equals(method)) { return(TranslatePadLeftRight( false, instance, arguments[0], _sqlExpressionFactory.Constant(" "), method.ReturnType)); } if (_padLeftWithTwoArgs.Equals(method)) { return(TranslatePadLeftRight( true, instance, arguments[0], arguments[1], method.ReturnType)); } if (_padRightWithTwoArgs.Equals(method)) { return(TranslatePadLeftRight( false, instance, arguments[0], arguments[1], method.ReturnType)); } if (_firstOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(_sqlExpressionFactory.NullableFunction( "SUBSTRING", new[] { arguments[0], _sqlExpressionFactory.Constant(1), _sqlExpressionFactory.Constant(1) }, method.ReturnType)); } if (_lastOrDefaultMethodInfoWithoutArgs.Equals(method)) { return(_sqlExpressionFactory.NullableFunction( "SUBSTRING", new[] { arguments[0], _sqlExpressionFactory.NullableFunction( "CHAR_LENGTH", new[] { arguments[0] }, typeof(int)), _sqlExpressionFactory.Constant(1) }, method.ReturnType)); } if (_removeMethodInfoWithOneArg.Equals(method)) { return(_sqlExpressionFactory.NullableFunction( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Constant(1), arguments[0], }, method.ReturnType, instance.TypeMapping)); } if (_removeMethodInfoWithTwoArgs.Equals(method)) { var firstSubString = _sqlExpressionFactory.NullableFunction( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Constant(1), arguments[0] }, method.ReturnType, instance.TypeMapping); var secondSubString = _sqlExpressionFactory.NullableFunction( "SUBSTRING", new[] { instance, _sqlExpressionFactory.Add( _sqlExpressionFactory.Add( arguments[0], arguments[1]), _sqlExpressionFactory.Constant(1)), _sqlExpressionFactory.Subtract( _sqlExpressionFactory.NullableFunction( "CHAR_LENGTH", new[] { instance }, typeof(int)), _sqlExpressionFactory.Add( arguments[0], arguments[1])), }, method.ReturnType, instance.TypeMapping); var concat = _sqlExpressionFactory.NullableFunction( "CONCAT", new[] { firstSubString, secondSubString }, method.ReturnType, instance.TypeMapping); return(concat); } if (_concatMethodInfos.Contains( (method.IsGenericMethod ? method.GetGenericMethodDefinition() : null) ?? method)) { // Handle // string[] // IEnumerable<string> // object[] // IEnumerable<T> // and // string, ... // object, ... // // Some call signature variants can never reach this code, because they will be directly called and thus only their result // is translated. var concatArguments = arguments[0] is MySqlComplexFunctionArgumentExpression mySqlComplexFunctionArgumentExpression ? new SqlExpression[] { mySqlComplexFunctionArgumentExpression } : arguments.Select( e => e switch { SqlConstantExpression c => _sqlExpressionFactory.Constant(c.Value.ToString()), SqlParameterExpression p => p.ApplyTypeMapping( ((MySqlStringTypeMapping)_typeMappingSource.GetMapping(typeof(string))).Clone(forceToString: true)), _ => e, })
protected abstract Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression);
protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) { return(ApplyConversion(sqlParameterExpression, condition: false)); }
protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) { return(new SqlFragmentExpression(sqlParameterExpression.Name)); }
protected override Expression VisitSqlParameter(SqlParameterExpression x) { return(x); }
protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) { Check.NotNull(sqlParameterExpression, nameof(sqlParameterExpression)); return(ApplyConversion(sqlParameterExpression, condition: false)); }
public override void Parameter(SqlParameterExpression node) { var name = MsSqlHelper.FormatParamName(node.Name); SqlBuilder.Append(name); }
protected override Expression VisitBinary(BinaryExpression node) { var visitedLeft = Visit(node.Left); var visitedRight = Visit(node.Right); var left = visitedLeft.UnwrapInnerExpression(); var right = visitedRight.UnwrapInnerExpression(); var leftMapping = FindTypeMapping(left); var rightMapping = FindTypeMapping(right); var madeChange = false; if (rightMapping != null) { if (left is SqlParameterExpression leftParameter) { if (leftParameter.TypeMapping is null) { left = new SqlParameterExpression( leftParameter.Expression.UnwrapInnerExpression(), leftParameter.IsNullable, rightMapping); madeChange = true; } } else if (left is ConstantExpression constant && rightMapping.SourceConversion != null) { left = new SqlParameterExpression( left, left.Type.IsNullableType() || !left.Type.GetTypeInfo().IsValueType, rightMapping); madeChange = true; } } if (leftMapping != null) { if (right is SqlParameterExpression rightParameter) { if (rightParameter.TypeMapping is null) { right = new SqlParameterExpression( rightParameter.Expression.UnwrapInnerExpression(), rightParameter.IsNullable, leftMapping); } madeChange = true; } else if (right is ConstantExpression constant && leftMapping.SourceConversion != null) { right = new SqlParameterExpression( right, right.Type.IsNullableType() || !right.Type.GetTypeInfo().IsValueType, leftMapping); madeChange = true; } } return(madeChange ? node.UpdateWithConversion(left, right) : node.Update(visitedLeft, node.Conversion, visitedRight)); }
public void AddParameter(SqlParameterExpression node) { var hash = ExpressionEqualityComparer.Instance.GetHashCode(node); if (parameterCache.TryGetValue(hash, out var cachedIndex)) { Append(queryFormattingProvider.FormatParameterName($"p{cachedIndex}")); return; } var parameterName = queryFormattingProvider.FormatParameterName($"p{parameterIndex}"); parameterCache[hash] = parameterIndex; parameterIndex++; Append(parameterName); EmitSql(); var typeMapping = node.TypeMapping ?? typeMappingProvider.FindMapping(node.Type); if (typeMapping is null) { throw new InvalidOperationException($"Could not find a type mapping for a parameter value: {node}"); } Expression value = node; if (typeMapping.SourceConversion is LambdaExpression conversion) { var expansion = value; var inputType = conversion.Parameters.Single().Type; if (expansion.Type != inputType) { if (expansion.Type == typeMapping.TargetConversion.Parameters.Single().Type) { expansion = typeMapping.TargetConversion.ExpandParameters(expansion); } else { expansion = Expression.Convert(expansion, inputType); } } value = conversion.ExpandParameters(expansion); } if (node.Type.IsNullableType() || !node.Type.GetTypeInfo().IsValueType) { value = Expression.Condition( Expression.Equal(node, Expression.Constant(null)), Expression.Constant(null), Expression.Convert(value, typeof(object))); } var expression = Expression.Call( GetType().GetMethod(nameof(RuntimeAddParameter), BindingFlags.NonPublic | BindingFlags.Static), dbCommandVariable, Expression.Constant(parameterName), Expression.Constant(typeMapping.DbType, typeof(DbType?)), Expression.Lambda(typeof(Func <object>), Expression.Convert(value, typeof(object)))); blockExpressions.Add(expression); dbParameterExpressions.Add(expression); }