SqlBooleanizer.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. using System.Data.Linq.Mapping;
  2. namespace System.Data.Linq.SqlClient {
  3. /// <summary>
  4. /// Locate cases in which there is a 'Bit' but a 'Predicate' is expected or vice-versa.
  5. /// Transform these expressions into expressions of the expected type.
  6. /// </summary>
  7. internal class SqlBooleanizer {
  8. private class Booleanizer : SqlBooleanMismatchVisitor {
  9. private SqlFactory sql;
  10. internal Booleanizer(TypeSystemProvider typeProvider, MetaModel model) {
  11. this.sql = new SqlFactory(typeProvider, model);
  12. }
  13. internal override SqlSelect VisitSelect(SqlSelect select) {
  14. // DevDiv 179191
  15. if (select.Where != null && select.Where.NodeType == SqlNodeType.Coalesce) {
  16. SqlBinary bin = (SqlBinary)select.Where;
  17. if (bin.Right.NodeType == SqlNodeType.Value) {
  18. SqlValue value = (SqlValue)bin.Right;
  19. if (value.Value != null && value.Value.GetType() == typeof(bool) && (bool)value.Value == false) {
  20. select.Where = bin.Left;
  21. }
  22. }
  23. }
  24. return base.VisitSelect(select);
  25. }
  26. internal override SqlExpression ConvertValueToPredicate(SqlExpression valueExpression) {
  27. // Transform the 'Bit' expression into a 'Predicate' by forming the
  28. // following operation:
  29. // OriginalExpr = 1
  30. // Yukon and later could also handle:
  31. // OriginalExpr = 'true'
  32. // but Sql2000 does not support this.
  33. return new SqlBinary(SqlNodeType.EQ,
  34. valueExpression.ClrType, sql.TypeProvider.From(typeof(bool)),
  35. valueExpression,
  36. sql.Value(typeof(bool), valueExpression.SqlType, true, false, valueExpression.SourceExpression)
  37. );
  38. }
  39. internal override SqlExpression ConvertPredicateToValue(SqlExpression predicateExpression) {
  40. // Transform the 'Predicate' expression into a 'Bit' by forming the
  41. // following operation:
  42. // CASE
  43. // WHEN predicateExpression THEN 1
  44. // ELSE NOT(predicateExpression) THEN 0
  45. // ELSE NULL
  46. // END
  47. // Possible simplification to the generated SQL would be to detect when 'predicateExpression'
  48. // is SqlUnary(NOT) and use its operand with the literal 1 and 0 below swapped.
  49. SqlExpression valueTrue = sql.ValueFromObject(true, false, predicateExpression.SourceExpression);
  50. SqlExpression valueFalse = sql.ValueFromObject(false, false, predicateExpression.SourceExpression);
  51. if (SqlExpressionNullability.CanBeNull(predicateExpression) != false) {
  52. SqlExpression valueNull = sql.Value(valueTrue.ClrType, valueTrue.SqlType, null, false, predicateExpression.SourceExpression);
  53. return new SqlSearchedCase(
  54. predicateExpression.ClrType,
  55. new SqlWhen[] {
  56. new SqlWhen(predicateExpression, valueTrue),
  57. new SqlWhen(new SqlUnary(SqlNodeType.Not, predicateExpression.ClrType, predicateExpression.SqlType, predicateExpression, predicateExpression.SourceExpression), valueFalse)
  58. },
  59. valueNull,
  60. predicateExpression.SourceExpression
  61. );
  62. }
  63. else {
  64. return new SqlSearchedCase(
  65. predicateExpression.ClrType,
  66. new SqlWhen[] { new SqlWhen(predicateExpression, valueTrue) },
  67. valueFalse,
  68. predicateExpression.SourceExpression
  69. );
  70. }
  71. }
  72. }
  73. /// <summary>
  74. /// Rationalize boolean expressions for the given node.
  75. /// </summary>
  76. internal static SqlNode Rationalize(SqlNode node, TypeSystemProvider typeProvider, MetaModel model) {
  77. return new Booleanizer(typeProvider, model).Visit(node);
  78. }
  79. }
  80. }