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); } }
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); }
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); } }
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")); }
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); } }
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 }
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")); }
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; }
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; }
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)); } }
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 }
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); } }
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); }
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); }
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); }
public override Expression Reduce() { return(Expression.Convert(Expression, Type, BooleanUtility.GetIntToBoolConversionMethod(Expression.Type))); }
public void Parse_BooleanToString(bool b, BooleanUtility.BoolParseType t, string expected) { Assert.IsNotNull(expected); Assert.IsTrue(expected.Equals(BooleanUtility.Parse(b, t), StringComparison.InvariantCultureIgnoreCase)); }
public void Parse_StringToBoolean(string s, bool expected) { Assert.AreEqual(expected, BooleanUtility.Parse(s)); }
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)); }