private SqlExpression TranslateEqualsOp(SqlNodeType op, SqlExpression left, SqlExpression right, bool allowExpand) { switch (op) { case SqlNodeType.EQ: case SqlNodeType.NE: return(sql.Binary(op, left, right)); case SqlNodeType.EQ2V: { if (SqlExpressionNullability.CanBeNull(left) != false && SqlExpressionNullability.CanBeNull(right) != false) { var nodeType3 = allowExpand ? SqlNodeType.EQ2V : SqlNodeType.EQ; return(sql.Binary(SqlNodeType.Or, sql.Binary(SqlNodeType.And, sql.Unary(SqlNodeType.IsNull, (SqlExpression)SqlDuplicator.Copy(left)), sql.Unary(SqlNodeType.IsNull, (SqlExpression)SqlDuplicator.Copy(right))), sql.Binary(SqlNodeType.And, sql.Binary(SqlNodeType.And, sql.Unary(SqlNodeType.IsNotNull, (SqlExpression)SqlDuplicator.Copy(left)), sql.Unary(SqlNodeType.IsNotNull, (SqlExpression)SqlDuplicator.Copy(right))), sql.Binary(nodeType3, left, right)))); } var nodeType4 = allowExpand ? SqlNodeType.EQ2V : SqlNodeType.EQ; return(sql.Binary(nodeType4, left, right)); } case SqlNodeType.NE2V: { if (SqlExpressionNullability.CanBeNull(left) != false && SqlExpressionNullability.CanBeNull(right) != false) { var nodeType = allowExpand ? SqlNodeType.EQ2V : SqlNodeType.EQ; return(sql.Unary(SqlNodeType.Not, sql.Binary(SqlNodeType.Or, sql.Binary(SqlNodeType.And, sql.Unary(SqlNodeType.IsNull, (SqlExpression)SqlDuplicator.Copy(left)), sql.Unary(SqlNodeType.IsNull, (SqlExpression)SqlDuplicator.Copy(right))), sql.Binary(SqlNodeType.And, sql.Binary(SqlNodeType.And, sql.Unary(SqlNodeType.IsNotNull, (SqlExpression)SqlDuplicator.Copy(left)), sql.Unary(SqlNodeType.IsNotNull, (SqlExpression)SqlDuplicator.Copy(right))), sql.Binary(nodeType, left, right))))); } var nodeType2 = allowExpand ? SqlNodeType.NE2V : SqlNodeType.NE; return(sql.Binary(nodeType2, left, right)); } default: throw Error.UnexpectedNode(op); } }
/// <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 ConvertPredicateToValue(SqlExpression predicateExpression) { // Transform the 'Predicate' expression into a 'Bit' by forming the // following operation: // CASE // WHEN predicateExpression THEN 1 // ELSE NOT(predicateExpression) THEN 0 // ELSE NULL // END // Possible simplification to the generated SQL would be to detect when 'predicateExpression' // is SqlUnary(NOT) and use its operand with the literal 1 and 0 below swapped. SqlExpression valueTrue = sql.ValueFromObject(true, false, predicateExpression.SourceExpression); SqlExpression valueFalse = sql.ValueFromObject(false, false, predicateExpression.SourceExpression); if (SqlExpressionNullability.CanBeNull(predicateExpression) != false) { SqlExpression valueNull = sql.Value(valueTrue.ClrType, valueTrue.SqlType, null, false, predicateExpression.SourceExpression); return(new SqlSearchedCase( predicateExpression.ClrType, new SqlWhen[] { new SqlWhen(predicateExpression, valueTrue), new SqlWhen(new SqlUnary(SqlNodeType.Not, predicateExpression.ClrType, predicateExpression.SqlType, predicateExpression, predicateExpression.SourceExpression), valueFalse) }, valueNull, predicateExpression.SourceExpression )); } else { return(new SqlSearchedCase( predicateExpression.ClrType, new SqlWhen[] { new SqlWhen(predicateExpression, valueTrue) }, valueFalse, predicateExpression.SourceExpression )); } }