Example #1
0
        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));
        }
Example #2
0
        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.");
        }
Example #4
0
        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));
        }
Example #5
0
        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);
            }
Example #6
0
        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));
 }
Example #8
0
        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));
        }
Example #16
0
    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();
     }
 }
Example #18
0
        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);
        }
Example #23
0
        /// <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.");
        }
Example #25
0
 /// <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);
Example #27
0
        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?));
Example #29
0
        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);
        }
Example #30
0
 protected abstract Expression VisitSqlUnary(SqlUnaryExpression sqlCastExpression);