/// <summary> /// For CASE statements which represent boolean values: /// /// CASE XXX /// WHEN AAA THEN true ===> (XXX==AAA) || (XXX==BBB) /// WHEN BBB THEN true /// ELSE false /// etc. /// END /// /// Also, /// /// CASE XXX /// WHEN AAA THEN false ===> (XXX!=AAA) && (XXX!=BBB) /// WHEN BBB THEN false /// ELSE true /// etc. /// END /// /// The reduce to a conjunction or disjunction of equality or inequality. /// The possibility of NULL in XXX is taken into account. /// </summary> private SqlExpression TryToWriteAsSimpleBooleanExpression(Type caseType, SqlExpression discriminator, List <SqlWhen> newWhens, bool allValuesLiteral) { SqlExpression rewrite = null; if (caseType == typeof(bool) && allValuesLiteral) { bool?holdsNull = SqlExpressionNullability.CanBeNull(discriminator); // The discriminator can't hold a NULL. // In this case, we don't need the special fallback that CASE-ELSE gives. // We can just construct a boolean operation. bool?whenValue = null; for (int i = 0; i < newWhens.Count; ++i) { SqlValue lit = (SqlValue)newWhens[i].Value; // Must be SqlValue because of allValuesLiteral. bool value = (bool)lit.Value; // Must be bool because of caseType==typeof(bool). if (newWhens[i].Match != null) { // Skip the ELSE if (value) { rewrite = _sql.OrAccumulate(rewrite, _sql.Binary(SqlNodeType.EQ, discriminator, newWhens[i].Match)); } else { rewrite = _sql.AndAccumulate(rewrite, _sql.Binary(SqlNodeType.NE, discriminator, newWhens[i].Match)); } } else { whenValue = value; } } // If it could possibly hold null values. if (holdsNull != false && whenValue != null) { if (whenValue == true) { rewrite = _sql.OrAccumulate(rewrite, _sql.Unary(SqlNodeType.IsNull, discriminator, discriminator.SourceExpression)); } else { rewrite = _sql.AndAccumulate(rewrite, _sql.Unary(SqlNodeType.IsNotNull, discriminator, discriminator.SourceExpression)); } } } return(rewrite); }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { base.VisitBinaryOperator(bo); if (bo.NodeType.IsComparisonOperator() && bo.Left.ClrType != typeof(bool) && bo.Right.ClrType != typeof(bool)) { // Strip unnecessary CONVERT calls. if (bo.Left.NodeType == SqlNodeType.Convert) { var conv = (SqlUnary)bo.Left; if (CanDbConvert(conv.Operand.ClrType, bo.Right.ClrType) && conv.Operand.SqlType.ComparePrecedenceTo(bo.Right.SqlType) != 1) { return(VisitBinaryOperator(new SqlBinary(bo.NodeType, bo.ClrType, bo.SqlType, conv.Operand, bo.Right))); } } if (bo.Right.NodeType == SqlNodeType.Convert) { var conv = (SqlUnary)bo.Right; if (CanDbConvert(conv.Operand.ClrType, bo.Left.ClrType) && conv.Operand.SqlType.ComparePrecedenceTo(bo.Left.SqlType) != 1) { return(VisitBinaryOperator(new SqlBinary(bo.NodeType, bo.ClrType, bo.SqlType, bo.Left, conv.Operand))); } } } if (bo.Right != null && bo.NodeType != SqlNodeType.Concat) { SqlExpression left = bo.Left; SqlExpression right = bo.Right; this.CoerceBinaryArgs(ref left, ref right); if (bo.Left != left || bo.Right != right) { bo = sql.Binary(bo.NodeType, left, right); } bo.SetSqlType(typeProvider.PredictTypeForBinary(bo.NodeType, left.SqlType, right.SqlType)); } if (bo.NodeType.IsComparisonOperator()) { // When comparing a unicode value against a non-unicode column, // we want retype the parameter as non-unicode. Func <SqlExpression, SqlExpression, bool> needsRetype = (expr, val) => (val.NodeType == SqlNodeType.Value || val.NodeType == SqlNodeType.ClientParameter) && !(expr.NodeType == SqlNodeType.Value || expr.NodeType == SqlNodeType.ClientParameter) && val.SqlType.IsUnicodeType && !expr.SqlType.IsUnicodeType; SqlSimpleTypeExpression valueToRetype = null; if (needsRetype(bo.Left, bo.Right)) { valueToRetype = (SqlSimpleTypeExpression)bo.Right; } else if (needsRetype(bo.Right, bo.Left)) { valueToRetype = (SqlSimpleTypeExpression)bo.Left; } if (valueToRetype != null) { valueToRetype.SetSqlType(valueToRetype.SqlType.GetNonUnicodeEquivalent()); } } return(bo); }
private SqlBinary MakeCompareTo(SqlExpression left, SqlExpression right, SqlNodeType op, int iValue) { if (iValue == 0) { return(sql.Binary(op, left, right)); } if (op == SqlNodeType.EQ || op == SqlNodeType.EQ2V) { switch (iValue) { case -1: return(sql.Binary(SqlNodeType.LT, left, right)); case 1: return(sql.Binary(SqlNodeType.GT, left, right)); } } return(null); }