PageRenderTime 35ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/referencesource/System.Data.Linq/SqlClient/Query/SqlExpressionNullability.cs

http://github.com/mono/mono
C# | 120 lines | 88 code | 17 blank | 15 comment | 15 complexity | 87cd90b77a1e282f4376260d1fa5d961 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Linq;
  8. using System.Linq.Expressions;
  9. using System.Data.Linq;
  10. using System.Data.Linq.Provider;
  11. using System.Diagnostics.CodeAnalysis;
  12. namespace System.Data.Linq.SqlClient {
  13. internal static class SqlExpressionNullability {
  14. /// <summary>
  15. /// Determines whether the given expression may return a null result.
  16. /// </summary>
  17. /// <param name="expr">The expression to check.</param>
  18. /// <returns>null means that it couldn't be determined</returns>
  19. [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification="These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
  20. internal static bool? CanBeNull(SqlExpression expr) {
  21. switch (expr.NodeType) {
  22. case SqlNodeType.ExprSet:
  23. SqlExprSet exprSet = (SqlExprSet)expr;
  24. return CanBeNull(exprSet.Expressions);
  25. case SqlNodeType.SimpleCase:
  26. SqlSimpleCase sc = (SqlSimpleCase)expr;
  27. return CanBeNull(sc.Whens.Select(w => w.Value));
  28. case SqlNodeType.Column:
  29. SqlColumn col = (SqlColumn)expr;
  30. if (col.MetaMember != null) {
  31. return col.MetaMember.CanBeNull;
  32. }
  33. else if (col.Expression != null) {
  34. return CanBeNull(col.Expression);
  35. }
  36. return null; // Don't know.
  37. case SqlNodeType.ColumnRef:
  38. SqlColumnRef cref = (SqlColumnRef)expr;
  39. return CanBeNull(cref.Column);
  40. case SqlNodeType.Value:
  41. return ((SqlValue)expr).Value == null;
  42. case SqlNodeType.New:
  43. case SqlNodeType.Multiset:
  44. case SqlNodeType.Grouping:
  45. case SqlNodeType.DiscriminatedType:
  46. case SqlNodeType.IsNotNull: // IsNull\IsNotNull always return true or false and can never return NULL.
  47. case SqlNodeType.IsNull:
  48. case SqlNodeType.Exists:
  49. return false;
  50. case SqlNodeType.Add:
  51. case SqlNodeType.Sub:
  52. case SqlNodeType.Mul:
  53. case SqlNodeType.Div:
  54. case SqlNodeType.Mod:
  55. case SqlNodeType.BitAnd:
  56. case SqlNodeType.BitOr:
  57. case SqlNodeType.BitXor:
  58. case SqlNodeType.Concat: {
  59. SqlBinary bop = (SqlBinary)expr;
  60. bool? left = CanBeNull(bop.Left);
  61. bool? right = CanBeNull(bop.Right);
  62. return (left != false) || (right != false);
  63. }
  64. case SqlNodeType.Negate:
  65. case SqlNodeType.BitNot: {
  66. SqlUnary uop = (SqlUnary)expr;
  67. return CanBeNull(uop.Operand);
  68. }
  69. case SqlNodeType.Lift: {
  70. SqlLift lift = (SqlLift)expr;
  71. return CanBeNull(lift.Expression);
  72. }
  73. case SqlNodeType.OuterJoinedValue:
  74. return true;
  75. default:
  76. return null; // Don't know.
  77. }
  78. }
  79. /// <summary>
  80. /// Used to determine nullability for a collection of expressions.
  81. /// * If at least one of the expressions is nullable, the collection is nullable.
  82. /// * If no expressions are nullable, but at least one is 'don't know', the collection is 'don't know'.
  83. /// * Otherwise all expressions are non-nullable and the nullability is false.
  84. /// </summary>
  85. private static bool? CanBeNull(IEnumerable<SqlExpression> exprs) {
  86. bool hasAtleastOneUnknown = false;
  87. foreach(SqlExpression e in exprs) {
  88. bool? nullability = CanBeNull(e);
  89. // Even one expression that could return null means the
  90. // collection can return null.
  91. if (nullability == true)
  92. return true;
  93. // If there is one or more 'unknown' and no definitely nullable
  94. // results then the collection nullability is 'unknown'.
  95. if (nullability == null)
  96. hasAtleastOneUnknown = true;
  97. }
  98. if (hasAtleastOneUnknown)
  99. return null;
  100. return false;
  101. }
  102. }
  103. }