private SqlExpression ApplyTypeMappingOnSqlUnary( SqlUnaryExpression sqlUnaryExpression, RelationalTypeMapping typeMapping) { SqlExpression operand; RelationalTypeMapping resultTypeMapping; switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.Not: resultTypeMapping = _boolTypeMapping; operand = ApplyDefaultTypeMapping(sqlUnaryExpression.Operand); break; case ExpressionType.Convert: resultTypeMapping = typeMapping; operand = ApplyDefaultTypeMapping(sqlUnaryExpression.Operand); break; case ExpressionType.Negate: resultTypeMapping = typeMapping; operand = ApplyTypeMapping(sqlUnaryExpression.Operand, typeMapping); break; default: throw new InvalidOperationException(); } return(new SqlUnaryExpression( sqlUnaryExpression.OperatorType, operand, sqlUnaryExpression.Type, resultTypeMapping)); }
protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Convert: { _relationalCommandBuilder.Append("CAST("); var requiresBrackets = RequiresBrackets(sqlUnaryExpression.Operand); if (requiresBrackets) { _relationalCommandBuilder.Append("("); } Visit(sqlUnaryExpression.Operand); if (requiresBrackets) { _relationalCommandBuilder.Append(")"); } _relationalCommandBuilder.Append(" AS "); _relationalCommandBuilder.Append(sqlUnaryExpression.TypeMapping.StoreType); _relationalCommandBuilder.Append(")"); } break; case ExpressionType.Not: { _relationalCommandBuilder.Append("NOT ("); Visit(sqlUnaryExpression.Operand); _relationalCommandBuilder.Append(")"); } break; case ExpressionType.Equal: { Visit(sqlUnaryExpression.Operand); _relationalCommandBuilder.Append(" IS NULL"); } break; case ExpressionType.NotEqual: { Visit(sqlUnaryExpression.Operand); _relationalCommandBuilder.Append(" IS NOT NULL"); } break; case ExpressionType.Negate: { _relationalCommandBuilder.Append("-"); Visit(sqlUnaryExpression.Operand); } break; } return(sqlUnaryExpression); }
protected Expression VisitJetConvertExpression(SqlUnaryExpression convertExpression) { var typeMapping = convertExpression.TypeMapping; if (typeMapping == null) { throw new InvalidOperationException(RelationalStrings.UnsupportedType(convertExpression.Type.ShortDisplayName())); } if (_convertMappings.TryGetValue(typeMapping.ClrType.Name, out var function)) { Visit( _sqlExpressionFactory.NullChecked( convertExpression.Operand, _sqlExpressionFactory.Function( function, new[] { convertExpression.Operand }, typeMapping.ClrType))); return(convertExpression); } if (typeMapping.ClrType.Name == nameof(String)) { Sql.Append("("); Visit(convertExpression.Operand); Sql.Append(@" & '')"); return(convertExpression); } throw new InvalidOperationException($"Cannot cast to CLR type '{typeMapping.ClrType.Name}' with Jet."); }
protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { var parentSearchCondition = _isSearchCondition; bool resultCondition; switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Not: _isSearchCondition = true; resultCondition = true; break; case ExpressionType.Convert: case ExpressionType.Negate: _isSearchCondition = false; resultCondition = false; break; case ExpressionType.Equal: case ExpressionType.NotEqual: _isSearchCondition = false; resultCondition = true; break; default: throw new InvalidOperationException("Unknown operator type encountered in SqlUnaryExpression."); } var operand = (SqlExpression)Visit(sqlUnaryExpression.Operand); _isSearchCondition = parentSearchCondition; return(ApplyConversion(sqlUnaryExpression.Update(operand), condition: resultCondition)); }
protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { Check.NotNull(sqlUnaryExpression, nameof(sqlUnaryExpression)); var parentOptimize = _optimize; bool resultCondition; switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Not when sqlUnaryExpression.Type == typeof(bool): _optimize = true; resultCondition = true; break; case ExpressionType.Not: _optimize = false; resultCondition = false; break; case ExpressionType.Convert: case ExpressionType.Negate: _optimize = false; resultCondition = false; break; case ExpressionType.Equal: case ExpressionType.NotEqual: _optimize = false; resultCondition = true; break; default: throw new InvalidOperationException("Unknown operator type encountered in SqlUnaryExpression."); } SqlExpression expression; // TODO: Simplify for .NET 5, due to the already existing bool expression optimizations performed by `SqlNullabilityProcessor`. // This custom logic can probably be removed completely. // See `GearsOfWarQueryMySqlTest`. // Optimize translation of the following expressions: // context.Table.Where(t => !t.BoolColumn) // translate to: `boolColumn` = FALSE // instead of: NOT(`boolColumn` = TRUE) // Translating to "NOT(`boolColumn`)" would not use indices in MySQL 5.7. if (sqlUnaryExpression.OperatorType == ExpressionType.Not && sqlUnaryExpression.Operand is ColumnExpression columnExpression && columnExpression.TypeMapping is MySqlBoolTypeMapping && columnExpression.Type == typeof(bool)) { _optimize = false; expression = _sqlExpressionFactory.MakeBinary( ExpressionType.Equal, (SqlExpression)Visit(sqlUnaryExpression.Operand), _sqlExpressionFactory.Constant(false), sqlUnaryExpression.TypeMapping); }
protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { var parentSearchCondition = _isSearchCondition; bool resultCondition; switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Not: _isSearchCondition = true; resultCondition = true; break; case ExpressionType.Convert: case ExpressionType.Negate: _isSearchCondition = false; resultCondition = false; break; default: _isSearchCondition = false; resultCondition = true; break; } var operand = (SqlExpression)Visit(sqlUnaryExpression.Operand); _isSearchCondition = parentSearchCondition; return(ApplyConversion(sqlUnaryExpression.Update(operand), condition: resultCondition)); }
protected virtual string VisitUnary(SqlUnaryExpression expr) { if (expr.Operator == SqlOperator.Not && expr.Operand is SqlInExpression ex) { ex.Not = true; return(VisitIn(ex)); } return($"{OperatorText(expr.Operator)} {Visit(expr.Operand)}".Braces(!expr.IsTop)); }
protected virtual Expression VisitSqlUnaryExpression([NotNull] SqlUnaryExpression sqlUnaryExpression) { var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); return(SimplifyUnaryExpression( sqlUnaryExpression.OperatorType, newOperand, sqlUnaryExpression.Type, sqlUnaryExpression.TypeMapping)); }
private Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); return(SimplifyUnaryExpression( sqlUnaryExpression.OperatorType, newOperand, sqlUnaryExpression.Type, sqlUnaryExpression.TypeMapping !)); }
protected override Expression VisitExtension(Expression extensionExpression) { return(extensionExpression switch { ProjectionExpression projectionExpression => VisitProjectionExpression(projectionExpression), ColumnExpression columnExpression => VisitColumn(columnExpression), SqlUnaryExpression sqlUnaryExpression => VisitSqlUnaryExpression(sqlUnaryExpression), SqlBinaryExpression sqlBinaryExpression => VisitSqlBinaryExpression(sqlBinaryExpression), _ => base.VisitExtension(extensionExpression) });
protected override Expression VisitExtension(Expression extensionExpression) { Check.NotNull(extensionExpression, nameof(extensionExpression)); return(extensionExpression switch { SqlUnaryExpression sqlUnaryExpression => VisitSqlUnaryExpression(sqlUnaryExpression), SqlBinaryExpression sqlBinaryExpression => VisitSqlBinaryExpression(sqlBinaryExpression), SelectExpression selectExpression => VisitSelectExpression(selectExpression), _ => base.VisitExtension(extensionExpression), });
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasDbFunction( typeof(DbJsonValueExtensions).GetMethod(nameof(DbJsonValueExtensions.JSON_VALUE), new System.Type[] { typeof(string), typeof(string) })) .HasTranslation(args => { var arguments = args.ToList(); SqlUnaryExpression sqlUnaryExp = null; SqlConstantExpression sqlConstExp = null; string sql = ""; if (arguments[0] is SqlUnaryExpression) { sqlUnaryExp = arguments[0] as SqlUnaryExpression; } if (arguments[1] is SqlConstantExpression) { sqlConstExp = arguments[1] as SqlConstantExpression; } if (sqlUnaryExp != null) { var sqlColumnExp = sqlUnaryExp.Operand as ColumnExpression; return(new SqlFunctionExpression( null, null, "JSON_VALUE", false, new[] { sqlColumnExp as SqlExpression, sqlConstExp }, true, typeof(string), null )); } else { return(new SqlFunctionExpression( null, null, "JSON_VALUE", false, args, true, typeof(string), null )); } }); modelBuilder.ConfigureMGSurveyDbContext(_mgSurveyStoreOptions); base.OnModelCreating(modelBuilder); }
private SqlUnaryExpression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) { var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); // IsNull/IsNotNull if (sqlUnaryExpression.OperatorType == ExpressionType.Equal || sqlUnaryExpression.OperatorType == ExpressionType.NotEqual) { _isNullable = false; } return(sqlUnaryExpression.Update(newOperand)); }
protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { var parentOptimize = _optimize; bool resultCondition; switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Not: _optimize = true; resultCondition = true; break; case ExpressionType.Convert: case ExpressionType.Negate: _optimize = false; resultCondition = false; break; case ExpressionType.Equal: case ExpressionType.NotEqual: _optimize = false; resultCondition = true; break; default: throw new InvalidOperationException("Unknown operator type encountered in SqlUnaryExpression."); } SqlExpression expression; // Optimize translation of the following expressions: // context.Table.Where(t => !t.BoolColumn) // translate to: `boolColumn` = FALSE // instead of: NOT(`boolColumn` = TRUE) // Translating to "NOT(`boolColumn`)" would not use indices in MySQL 5.7. if (sqlUnaryExpression.OperatorType == ExpressionType.Not && sqlUnaryExpression.Operand is ColumnExpression columnExpression && columnExpression.TypeMapping is MySqlBoolTypeMapping && columnExpression.Type == typeof(bool)) { _optimize = false; expression = _sqlExpressionFactory.MakeBinary( ExpressionType.Equal, (SqlExpression)Visit(sqlUnaryExpression.Operand), _sqlExpressionFactory.Constant(false), sqlUnaryExpression.TypeMapping); }
protected override Expression VisitExtension(Expression expression) { if (expression is ShapedQueryExpression shapedQueryExpression) { var queryExpression = shapedQueryExpression.QueryExpression; if (shapedQueryExpression.QueryExpression is SelectExpression selectExpression && selectExpression.Projection.Count() == 1 && selectExpression.Projection.Single().Expression is ExistsExpression existsExpression && existsExpression.Subquery is SelectExpression subquerySelectExpression) { subquerySelectExpression.AddToProjection(new SqlConstantExpression(Expression.Constant("COUNT(*)"), new VfpIntegerTypeMapping())); var projection = (SqlExpression) new SqlBinaryExpression( ExpressionType.LessThan, new SqlConstantExpression(Expression.Constant("0"), new VfpIntegerTypeMapping()), new ScalarSubqueryExpression(subquerySelectExpression), typeof(bool), new VfpLogicalTypeMapping() ); if (existsExpression.IsNegated) { projection = new SqlUnaryExpression(ExpressionType.Not, projection, typeof(bool), new VfpLogicalTypeMapping()); } queryExpression = selectExpression.Update( new List <ProjectionExpression> { selectExpression.Projection.FirstOrDefault().Update(projection) }, new List <TableExpressionBase> { new SingleRowTableExpression() }, selectExpression.Predicate, selectExpression.GroupBy.ToList(), selectExpression.Having, selectExpression.Orderings.ToList(), selectExpression.Limit, selectExpression.Offset ); } return(shapedQueryExpression.Update(Visit(queryExpression), shapedQueryExpression.ShaperExpression)); } return(base.VisitExtension(expression)); }
private SqlExpression ApplyTypeMappingOnSqlUnary( SqlUnaryExpression sqlUnaryExpression, CoreTypeMapping?typeMapping) { SqlExpression operand; Type resultType; CoreTypeMapping?resultTypeMapping; switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.Not when sqlUnaryExpression.IsLogicalNot(): { resultTypeMapping = _boolTypeMapping; resultType = typeof(bool); operand = ApplyDefaultTypeMapping(sqlUnaryExpression.Operand); break; } case ExpressionType.Convert: resultTypeMapping = typeMapping; // Since we are applying convert, resultTypeMapping decides the clrType resultType = resultTypeMapping?.ClrType ?? sqlUnaryExpression.Type; operand = ApplyDefaultTypeMapping(sqlUnaryExpression.Operand); break; case ExpressionType.Not: case ExpressionType.Negate: resultTypeMapping = typeMapping; // While Not is logical, negate is numeric hence we use clrType from TypeMapping resultType = resultTypeMapping?.ClrType ?? sqlUnaryExpression.Type; operand = ApplyTypeMapping(sqlUnaryExpression.Operand, typeMapping); break; default: throw new InvalidOperationException( CosmosStrings.UnsupportedOperatorForSqlExpression( sqlUnaryExpression.OperatorType, typeof(SqlUnaryExpression).ShortDisplayName())); } return(new SqlUnaryExpression(sqlUnaryExpression.OperatorType, operand, resultType, resultTypeMapping)); }
public override void Unary(SqlUnaryExpression node) { if (node.NodeType == SqlExpressionType.Not) { SqlBuilder.Append("Not "); var expre = LogicExpression(node.Expression); expre.Accept(this); } else if (node.NodeType == SqlExpressionType.Negate) { SqlBuilder.Append("-"); node.Expression.Accept(this); } else { throw new ArgumentException(); } }
private Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) { if (sqlUnaryExpression.OperatorType == ExpressionType.Not) { return(VisitNot(sqlUnaryExpression)); } // NULL IS NULL -> true // non_nullablee_constant IS NULL -> false if (sqlUnaryExpression.OperatorType == ExpressionType.Equal && sqlUnaryExpression.Operand is SqlConstantExpression innerConstantNull1) { return(_sqlExpressionFactory.Constant(innerConstantNull1.Value == null, sqlUnaryExpression.TypeMapping)); } // NULL IS NOT NULL -> false // non_nullablee_constant IS NOT NULL -> true if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual && sqlUnaryExpression.Operand is SqlConstantExpression innerConstantNull2) { return(_sqlExpressionFactory.Constant(innerConstantNull2.Value != null, sqlUnaryExpression.TypeMapping)); } if (sqlUnaryExpression.Operand is SqlUnaryExpression innerUnary) { // (!a) IS NULL <==> a IS NULL if (sqlUnaryExpression.OperatorType == ExpressionType.Equal && innerUnary.OperatorType == ExpressionType.Not) { return(Visit(_sqlExpressionFactory.IsNull(innerUnary.Operand))); } // (!a) IS NOT NULL <==> a IS NOT NULL if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual && innerUnary.OperatorType == ExpressionType.Not) { return(Visit(_sqlExpressionFactory.IsNotNull(innerUnary.Operand))); } } var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); return(sqlUnaryExpression.Update(newOperand)); }
public virtual SqlExpression ApplyTypeMapping(SqlExpression sqlExpression, RelationalTypeMapping typeMapping) { if (sqlExpression == null || sqlExpression.TypeMapping != null) { return(sqlExpression); } return(sqlExpression switch { CaseExpression e => ApplyTypeMappingOnCase(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 VisitSqlUnary(SqlUnaryExpression sqlCastExpression) { _isNullable = false; var canOptimize = _canOptimize; _canOptimize = false; var newOperand = (SqlExpression)Visit(sqlCastExpression.Operand); // result of IsNull/IsNotNull can never be null if (sqlCastExpression.OperatorType == ExpressionType.Equal || sqlCastExpression.OperatorType == ExpressionType.NotEqual) { _isNullable = false; } _canOptimize = canOptimize; return(sqlCastExpression.Update(newOperand)); }
protected override Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) { var result = base.VisitSqlUnaryExpression(sqlUnaryExpression); if (result is SqlUnaryExpression newUnaryExpression && newUnaryExpression.Operand is SqlParameterExpression parameterOperand) { var parameterValue = _parametersValues[parameterOperand.Name]; if (sqlUnaryExpression.OperatorType == ExpressionType.Equal) { return(SqlExpressionFactory.Constant(parameterValue == null, sqlUnaryExpression.TypeMapping)); } if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual) { return(SqlExpressionFactory.Constant(parameterValue != null, sqlUnaryExpression.TypeMapping)); } } return(result); }
private SqlExpression ApplyTypeMappingOnSqlUnary( SqlUnaryExpression sqlUnaryExpression, RelationalTypeMapping typeMapping) { SqlExpression operand; RelationalTypeMapping resultTypeMapping; switch (sqlUnaryExpression.OperatorType) { case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.Not when sqlUnaryExpression.IsLogicalNot(): { resultTypeMapping = _boolTypeMapping; operand = ApplyDefaultTypeMapping(sqlUnaryExpression.Operand); break; } case ExpressionType.Convert: resultTypeMapping = typeMapping; operand = ApplyDefaultTypeMapping(sqlUnaryExpression.Operand); break; case ExpressionType.Not: case ExpressionType.Negate: resultTypeMapping = typeMapping; operand = ApplyTypeMapping(sqlUnaryExpression.Operand, typeMapping); break; default: throw new InvalidOperationException( $"The unary expression operator type {sqlUnaryExpression.OperatorType} is not supported."); } return new SqlUnaryExpression( sqlUnaryExpression.OperatorType, operand, sqlUnaryExpression.Type, resultTypeMapping); }
/// <inheritdoc /> 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), 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 Expression VisitJetConvertExpression(SqlUnaryExpression convertExpression) { var typeMapping = convertExpression.TypeMapping; if (typeMapping == null) { throw new InvalidOperationException(RelationalStrings.UnsupportedType(convertExpression.Type.ShortDisplayName())); } // We are explicitly converting to the target type (convertExpression.Type) and not the CLR type of the // accociated type mapping. This allows for conversions on the database side (e.g. CDBL()) but handling // of the returned value using a different (unaligned) type mapping (e.g. date/time related ones). if (_convertMappings.TryGetValue(convertExpression.Type.Name, out var function)) { Visit( _sqlExpressionFactory.NullChecked( convertExpression.Operand, _sqlExpressionFactory.Function( function, new[] { convertExpression.Operand }, false, new[] { false }, typeMapping.ClrType))); return(convertExpression); } if (typeMapping.ClrType.Name == nameof(String)) { Sql.Append("("); Visit(convertExpression.Operand); Sql.Append(@" & '')"); return(convertExpression); } throw new InvalidOperationException($"Cannot cast to CLR type '{typeMapping.ClrType.Name}' with Jet."); }
/// <summary> /// Visits the children of the sql unary expression. /// </summary> /// <param name="sqlUnaryExpression"> 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 VisitSqlUnary([NotNull] SqlUnaryExpression sqlUnaryExpression);
protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) => sqlUnaryExpression.OperatorType == ExpressionType.Convert ? VisitJetConvertExpression(sqlUnaryExpression) : base.VisitSqlUnary(sqlUnaryExpression);
private Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) { // !(true) -> false // !(false) -> true if (sqlUnaryExpression.OperatorType == ExpressionType.Not && sqlUnaryExpression.Operand is SqlConstantExpression innerConstantBool && innerConstantBool.Value is bool value) { return(value ? _sqlExpressionFactory.Constant(false, sqlUnaryExpression.TypeMapping) : _sqlExpressionFactory.Constant(true, sqlUnaryExpression.TypeMapping)); } // NULL IS NULL -> true // non_nullablee_constant IS NULL -> false if (sqlUnaryExpression.OperatorType == ExpressionType.Equal && sqlUnaryExpression.Operand is SqlConstantExpression innerConstantNull1) { return(_sqlExpressionFactory.Constant(innerConstantNull1.Value == null, sqlUnaryExpression.TypeMapping)); } // NULL IS NOT NULL -> false // non_nullablee_constant IS NOT NULL -> true if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual && sqlUnaryExpression.Operand is SqlConstantExpression innerConstantNull2) { return(_sqlExpressionFactory.Constant(innerConstantNull2.Value != null, sqlUnaryExpression.TypeMapping)); } if (sqlUnaryExpression.Operand is SqlUnaryExpression innerUnary) { if (sqlUnaryExpression.OperatorType == ExpressionType.Not) { // !(!a) -> a if (innerUnary.OperatorType == ExpressionType.Not) { return(Visit(innerUnary.Operand)); } if (innerUnary.OperatorType == ExpressionType.Equal) { //!(a IS NULL) -> a IS NOT NULL return(Visit(_sqlExpressionFactory.IsNotNull(innerUnary.Operand))); } //!(a IS NOT NULL) -> a IS NULL if (innerUnary.OperatorType == ExpressionType.NotEqual) { return(Visit(_sqlExpressionFactory.IsNull(innerUnary.Operand))); } } // (!a) IS NULL <==> a IS NULL if (sqlUnaryExpression.OperatorType == ExpressionType.Equal && innerUnary.OperatorType == ExpressionType.Not) { return(Visit(_sqlExpressionFactory.IsNull(innerUnary.Operand))); } // (!a) IS NOT NULL <==> a IS NOT NULL if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual && innerUnary.OperatorType == ExpressionType.Not) { return(Visit(_sqlExpressionFactory.IsNotNull(innerUnary.Operand))); } } if (sqlUnaryExpression.Operand is SqlBinaryExpression innerBinary) { // De Morgan's if (innerBinary.OperatorType == ExpressionType.AndAlso || innerBinary.OperatorType == ExpressionType.OrElse) { var newLeft = (SqlExpression)Visit(_sqlExpressionFactory.Not(innerBinary.Left)); var newRight = (SqlExpression)Visit(_sqlExpressionFactory.Not(innerBinary.Right)); return(innerBinary.OperatorType == ExpressionType.AndAlso ? _sqlExpressionFactory.OrElse(newLeft, newRight) : _sqlExpressionFactory.AndAlso(newLeft, newRight)); } // note that those optimizations are only valid in 2-value logic // they are safe to do here because null semantics removes possibility of nulls in the tree // however if we decide to do "partial" null semantics (that doesn't distinguish between NULL and FALSE, e.g. for predicates) // we need to be extra careful here if (TryNegate(innerBinary.OperatorType, out var negated)) { return(Visit( _sqlExpressionFactory.MakeBinary( negated, innerBinary.Left, innerBinary.Right, innerBinary.TypeMapping))); } } var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); return(sqlUnaryExpression.Update(newOperand)); }
/// <summary> /// Checks if the given sql unary expression represents a logical NOT operation. /// </summary> /// <param name="sqlUnaryExpression"> A sql unary expression to check. </param> /// <returns> A bool value indicating if the given expression represents a logical NOT operation. </returns> public static bool IsLogicalNot([NotNull] this SqlUnaryExpression sqlUnaryExpression) => sqlUnaryExpression.OperatorType == ExpressionType.Not && (sqlUnaryExpression.Type == typeof(bool) || sqlUnaryExpression.Type == typeof(bool?));
protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) { if (sqlUnaryExpression.OperatorType != ExpressionType.Convert) { return(base.VisitSqlUnary(sqlUnaryExpression)); } var typeMapping = sqlUnaryExpression.TypeMapping; var storeTypeLower = typeMapping.StoreType.ToLower(); string castMapping = null; foreach (var kvp in _castMappings) { foreach (var storeType in kvp.Value) { if (storeTypeLower.StartsWith(storeType)) { castMapping = kvp.Key; break; } } if (castMapping != null) { break; } } if (castMapping == null) { throw new InvalidOperationException($"Cannot cast from type '{typeMapping.StoreType}'"); } if (castMapping == "signed" && storeTypeLower.Contains("unsigned")) { castMapping = "unsigned"; } // FLOAT and DOUBLE are supported by CAST() as of MySQL 8.0.17. // For server versions before that, a workaround is applied, that casts to a DECIMAL, // that is then added to 0e0, which results in a DOUBLE. // As of MySQL 8.0.18, a FLOAT cast might unnecessarily drop decimal places and round, // so we just keep casting to double instead. MySqlConnector ensures, that a System.Single // will be returned if expected, even if we return a DOUBLE. // REF: https://stackoverflow.com/a/32991084/2618319 var useDecimalToDoubleWorkaround = false; if (castMapping.StartsWith("float") && !_options.ServerVersion.SupportsFloatCast) { castMapping = "double"; } if (castMapping.StartsWith("double") && !_options.ServerVersion.SupportsDoubleCast) { useDecimalToDoubleWorkaround = true; castMapping = "decimal(65,30)"; } if (useDecimalToDoubleWorkaround) { Sql.Append("("); } Sql.Append("CAST("); Visit(sqlUnaryExpression.Operand); Sql.Append(" AS "); Sql.Append(castMapping); Sql.Append(")"); if (useDecimalToDoubleWorkaround) { Sql.Append(" + 0e0)"); } return(sqlUnaryExpression); }
protected abstract Expression VisitSqlUnary(SqlUnaryExpression sqlCastExpression);