コード例 #1
0
        private Expression HandleValueSemantics(Expression expression)
        {
            var newExpression = base.Visit(expression);

            if (newExpression is SqlConvertedBooleanExpression)
            {
                return(newExpression);
            }

            // We don't adjust the results of local method calls, every value is a supported value here. This is a workaround, better solution in RM-5348.
            if (newExpression is MethodCallExpression)
            {
                return(newExpression);
            }

            if (BooleanUtility.IsBooleanType(newExpression.Type))
            {
                var convertedExpression = CreateValueExpressionForPredicate(newExpression);
                return(new SqlConvertedBooleanExpression(convertedExpression));
            }
            else
            {
                return(newExpression);
            }
        }
コード例 #2
0
 public void IsBooleanType()
 {
     Assert.That(BooleanUtility.IsBooleanType(typeof(bool)), Is.True);
     Assert.That(BooleanUtility.IsBooleanType(typeof(bool?)), Is.True);
     Assert.That(BooleanUtility.IsBooleanType(typeof(int)), Is.False);
     Assert.That(BooleanUtility.IsBooleanType(typeof(int?)), Is.False);
 }
コード例 #3
0
        private void GenerateSqlForInfixOperator(Expression left, Expression right, ExpressionType nodeType, Type expressionType)
        {
            if (nodeType == ExpressionType.And && BooleanUtility.IsBooleanType(expressionType))
            {
                GenerateSqlForInfixOperator(left, right, ExpressionType.AndAlso, expressionType);
            }
            else if (nodeType == ExpressionType.Or && BooleanUtility.IsBooleanType(expressionType))
            {
                GenerateSqlForInfixOperator(left, right, ExpressionType.OrElse, expressionType);
            }
            else if (nodeType == ExpressionType.ExclusiveOr && BooleanUtility.IsBooleanType(expressionType))
            {
                // SQL has no logical XOR operator, so we simulate: a XOR b <=> (a AND NOT b) OR (NOT a AND b)
                var exclusiveOrSimulationExpression = Expression.OrElse(
                    Expression.AndAlso(left, Expression.Not(right)),
                    Expression.AndAlso(Expression.Not(left), right));
                _expressionVisitor.Visit(exclusiveOrSimulationExpression);
            }
            else
            {
                string operatorString = GetRegisteredOperatorString(nodeType);

                _expressionVisitor.Visit(left);
                _commandBuilder.Append(" ");
                _commandBuilder.Append(operatorString);
                _commandBuilder.Append(" ");
                _expressionVisitor.Visit(right);
            }
        }
コード例 #4
0
 public void GetMatchingBoolType()
 {
     Assert.That(BooleanUtility.GetMatchingBoolType(typeof(int)), Is.EqualTo(typeof(bool)));
     Assert.That(BooleanUtility.GetMatchingBoolType(typeof(int?)), Is.EqualTo(typeof(bool?)));
     Assert.That(
         () => BooleanUtility.GetMatchingBoolType(typeof(bool)),
         Throws.ArgumentException.With.Message.EqualTo("Type must be Int32 or Nullable<Int32>.\r\nParameter name: type"));
 }
コード例 #5
0
 private Type GetMatchingBoolType(Expression expression)
 {
     try
     {
         return(BooleanUtility.GetMatchingBoolType(expression.Type));
     }
     catch (ArgumentException ex)
     {
         throw new ArgumentException("The inner expression must be an expression of type Int32 or Nullable<Int32>.", "expression", ex);
     }
 }
コード例 #6
0
        public Expression VisitSqlColumn(SqlColumnExpression expression)
        {
            // We always need to convert boolean columns to int columns because in the database, the column is represented as a bit (integer) value
            if (BooleanUtility.IsBooleanType(expression.Type))
            {
                var        intType             = BooleanUtility.GetMatchingIntType(expression.Type);
                Expression convertedExpression = expression.Update(intType, expression.OwningTableAlias, expression.ColumnName, expression.IsPrimaryKey);
                return(new SqlConvertedBooleanExpression(convertedExpression));
            }

            return(expression); // rely on Visit to apply correct semantics
        }
コード例 #7
0
 public void GetIntToBoolConversionMethod()
 {
     Assert.That(
         BooleanUtility.GetIntToBoolConversionMethod(typeof(int)),
         Is.Not.Null.And.EqualTo(typeof(Convert).GetMethod("ToBoolean", new[] { typeof(int) })));
     Assert.That(
         BooleanUtility.GetIntToBoolConversionMethod(typeof(int?)),
         Is.Not.Null.And.EqualTo(typeof(BooleanUtility).GetMethod("ConvertNullableIntToNullableBool", new[] { typeof(int?) })));
     Assert.That(
         () => BooleanUtility.GetIntToBoolConversionMethod(typeof(bool)),
         Throws.ArgumentException.With.Message.EqualTo("Type must be Int32 or Nullable<Int32>.\r\nParameter name: intType"));
 }
コード例 #8
0
            public CaseWhenPair(Expression when, Expression then)
            {
                ArgumentUtility.CheckNotNull("when", when);
                ArgumentUtility.CheckNotNull("then", then);

                if (!BooleanUtility.IsBooleanType(when.Type))
                {
                    throw new ArgumentException("The WHEN expression's type must be boolean.", "when");
                }

                _when = when;
                _then = then;
            }
コード例 #9
0
        public ResolvedJoinInfo(IResolvedTableInfo foreignTableInfo, Expression joinCondition)
        {
            ArgumentUtility.CheckNotNull("foreignTableInfo", foreignTableInfo);
            ArgumentUtility.CheckNotNull("joinCondition", joinCondition);

            if (!BooleanUtility.IsBooleanType(joinCondition.Type))
            {
                throw new ArgumentException("The join condition must have boolean (or nullable boolean) type.", "joinCondition");
            }

            _foreignTableInfo = foreignTableInfo;
            _joinCondition    = joinCondition;
        }
コード例 #10
0
        private Expression GetBitConversionExpression(Type sourceType, Type targetType, Expression convertedExpression)
        {
            // When selecting anything but a column, we also need to insert a "CONVERT (BIT, ...)" to convert the value to BIT.
            // For columns, we don't want that, as they already are of type BIT and we want to avoid the noise.

            if (convertedExpression is SqlColumnExpression)
            {
                return(Expression.Convert(convertedExpression, targetType, BooleanUtility.GetIntToBoolConversionMethod(sourceType)));
            }
            else
            {
                return(new SqlConvertExpression(targetType, convertedExpression));
            }
        }
コード例 #11
0
        protected override Expression VisitConstant(ConstantExpression expression)
        {
            // Always convert boolean constants to int constants because in the database, there are no boolean constants

            if (BooleanUtility.IsBooleanType(expression.Type))
            {
                var intType             = BooleanUtility.GetMatchingIntType(expression.Type);
                var convertedExpression = expression.Value == null
                                      ? Expression.Constant(null, intType)
                                      : expression.Value.Equals(true)
                                            ? Expression.Constant(1, intType)
                                            : Expression.Constant(0, intType);

                return(new SqlConvertedBooleanExpression(convertedExpression));
            }

            return(expression); // rely on Visit to apply correct semantics
        }
コード例 #12
0
        private SqlExpressionContext GetChildSemanticsForUnaryExpression(Expression expression)
        {
            switch (expression.NodeType)
            {
            case ExpressionType.Convert:
                return(_currentContext);

            case ExpressionType.Not:
                if (BooleanUtility.IsBooleanType(expression.Type))
                {
                    return(SqlExpressionContext.PredicateRequired);
                }
                else
                {
                    return(SqlExpressionContext.SingleValueRequired);
                }

            default:
                return(SqlExpressionContext.SingleValueRequired);
            }
        }
コード例 #13
0
        protected override Expression VisitBinary(BinaryExpression expression)
        {
            ArgumentUtility.CheckNotNull("expression", expression);

            var childContext = BooleanUtility.IsBooleanType(expression.Type)
                             ? GetChildSemanticsForBinaryBoolExpression(expression.NodeType)
                             : SqlExpressionContext.SingleValueRequired;
            var left  = ApplySqlExpressionContext(expression.Left, childContext);
            var right = ApplySqlExpressionContext(expression.Right, childContext);

            if (BooleanUtility.IsBooleanType(expression.Type) && expression.NodeType == ExpressionType.Coalesce)
            {
                // In predicate context, we can ignore coalesces towards false, treat like a conversion to bool instead. (SQL treats NULL values in a falsey
                // way in predicate contexts.)
                if (_currentContext == SqlExpressionContext.PredicateRequired &&
                    expression.Right is ConstantExpression &&
                    Equals(((ConstantExpression)expression.Right).Value, false))
                {
                    return(Visit(Expression.Convert(expression.Left, expression.Type)));
                }

                // We'll pull out the bool conversion marker from the operands of the Coalesce expression and instead put it around the whole expression.
                // That way, HandleValueSemantics will not try to convert us back to a value; this avoids double CASE WHENs.
                // We know that left and right must be ConvertedBooleanExpressions because Coalesce has single value semantics for its operands, and boolean
                // Coalesces must have booleans operands. Applying value semantics to boolean operands results in ConvertedBooleanExpression values.

                Assertion.DebugAssert(childContext == SqlExpressionContext.SingleValueRequired);
                Assertion.DebugAssert(left is SqlConvertedBooleanExpression);
                Assertion.DebugAssert(right is SqlConvertedBooleanExpression);
                var newCoalesceExpression = Expression.Coalesce(((SqlConvertedBooleanExpression)left).Expression, ((SqlConvertedBooleanExpression)right).Expression);
                return(new SqlConvertedBooleanExpression(newCoalesceExpression));
            }

            if (left != expression.Left || right != expression.Right)
            {
                return(Expression.MakeBinary(expression.NodeType, left, right, expression.IsLiftedToNull, expression.Method));
            }

            return(expression);
        }
コード例 #14
0
        private Expression HandlePredicateSemantics(Expression expression)
        {
            var newExpression = base.Visit(expression);

            var convertedBooleanExpression = newExpression as SqlConvertedBooleanExpression;

            if (convertedBooleanExpression != null)
            {
                var isNullableExpression = convertedBooleanExpression.Expression.Type == typeof(int?);
                return(Expression.Equal(convertedBooleanExpression.Expression, new SqlLiteralExpression(1, isNullableExpression), isNullableExpression, null));
            }

            if (!BooleanUtility.IsBooleanType(newExpression.Type))
            {
                var message = string.Format(
                    "Cannot convert an expression of type '{0}' to a boolean expression. Expression: '{1}'",
                    newExpression.Type,
                    expression);
                throw new NotSupportedException(message);
            }

            return(newExpression);
        }
コード例 #15
0
        protected override Expression VisitUnaryExpression(UnaryExpression expression)
        {
            ArgumentUtility.CheckNotNull("expression", expression);
            switch (expression.NodeType)
            {
            case ExpressionType.Not:
                if (BooleanUtility.IsBooleanType(expression.Operand.Type))
                {
                    _commandBuilder.Append("NOT ");
                }
                else
                {
                    _commandBuilder.Append("~");
                }
                break;

            case ExpressionType.Negate:
                _commandBuilder.Append("-");
                break;

            case ExpressionType.UnaryPlus:
                _commandBuilder.Append("+");
                break;

            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
                break;

            default:
                var message = string.Format("Cannot generate SQL for unary expression '{0}'.", FormattingExpressionTreeVisitor.Format(expression));
                throw new NotSupportedException(message);
            }

            VisitExpression(expression.Operand);

            return(expression);
        }
コード例 #16
0
 public override Expression Reduce()
 {
     return(Expression.Convert(Expression, Type, BooleanUtility.GetIntToBoolConversionMethod(Expression.Type)));
 }
コード例 #17
0
 public void Parse_BooleanToString(bool b, BooleanUtility.BoolParseType t, string expected)
 {
     Assert.IsNotNull(expected);
     Assert.IsTrue(expected.Equals(BooleanUtility.Parse(b, t), StringComparison.InvariantCultureIgnoreCase));
 }
コード例 #18
0
 public void Parse_StringToBoolean(string s, bool expected)
 {
     Assert.AreEqual(expected, BooleanUtility.Parse(s));
 }
コード例 #19
0
 public void ConvertNullableIntToNullableBool()
 {
     Assert.That(BooleanUtility.ConvertNullableIntToNullableBool(null), Is.EqualTo(null));
     Assert.That(BooleanUtility.ConvertNullableIntToNullableBool(0), Is.EqualTo(false));
     Assert.That(BooleanUtility.ConvertNullableIntToNullableBool(1), Is.EqualTo(true));
 }