PageRenderTime 48ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://github.com/mono/mono
C# | 155 lines | 114 code | 6 blank | 35 comment | 20 complexity | fb556595ccf5dba1044cb3d12edd0910 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.Collections.ObjectModel;
  5. using System.Linq.Expressions;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Data.Linq;
  9. using System.Data.Linq.Mapping;
  10. using System.Data.Linq.Provider;
  11. using System.Diagnostics.CodeAnalysis;
  12. namespace System.Data.Linq.SqlClient {
  13. /// <summary>
  14. /// Method used for dealing with dynamic types. The ClrType of SqlNode is the
  15. /// statically known type originating in the source expression tree. For methods
  16. /// like GetType(), we need to know the dynamic type that will be constructed.
  17. /// </summary>
  18. internal static class TypeSource {
  19. private class Visitor : SqlVisitor {
  20. class UnwrapStack {
  21. public UnwrapStack(UnwrapStack last, bool unwrap) {
  22. Last = last;
  23. Unwrap = unwrap;
  24. }
  25. public UnwrapStack Last { get; private set; }
  26. public bool Unwrap { get; private set; }
  27. }
  28. UnwrapStack UnwrapSequences;
  29. internal SqlExpression sourceExpression;
  30. internal Type sourceType;
  31. [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.")]
  32. internal override SqlNode Visit(SqlNode node) {
  33. if (node == null)
  34. return null;
  35. sourceExpression = node as SqlExpression;
  36. if (sourceExpression != null) {
  37. Type type = sourceExpression.ClrType;
  38. UnwrapStack unwrap = this.UnwrapSequences;
  39. while (unwrap != null) {
  40. if (unwrap.Unwrap) {
  41. type = TypeSystem.GetElementType(type);
  42. }
  43. unwrap = unwrap.Last;
  44. }
  45. sourceType = type;
  46. }
  47. if (sourceType != null && TypeSystem.GetNonNullableType(sourceType).IsValueType) {
  48. return node; // Value types can't also have a dynamic type.
  49. }
  50. if (sourceType != null && TypeSystem.HasIEnumerable(sourceType)) {
  51. return node; // Sequences can't be polymorphic.
  52. }
  53. switch (node.NodeType) {
  54. case SqlNodeType.ScalarSubSelect:
  55. case SqlNodeType.Multiset:
  56. case SqlNodeType.Element:
  57. case SqlNodeType.SearchedCase:
  58. case SqlNodeType.ClientCase:
  59. case SqlNodeType.SimpleCase:
  60. case SqlNodeType.Member:
  61. case SqlNodeType.DiscriminatedType:
  62. case SqlNodeType.New:
  63. case SqlNodeType.FunctionCall:
  64. case SqlNodeType.MethodCall:
  65. case SqlNodeType.Convert: // Object identity does not survive convert. It does survive Cast.
  66. // Dig no further.
  67. return node;
  68. case SqlNodeType.TypeCase:
  69. sourceType = ((SqlTypeCase)node).RowType.Type;
  70. return node;
  71. case SqlNodeType.Link:
  72. sourceType = ((SqlLink)node).RowType.Type;
  73. return node;
  74. case SqlNodeType.Table:
  75. sourceType = ((SqlTable)node).RowType.Type;
  76. return node;
  77. case SqlNodeType.Value:
  78. SqlValue val = (SqlValue)node;
  79. if (val.Value != null) {
  80. // In some cases the ClrType of a Value node may
  81. // differ from the actual runtime type of the value.
  82. // Therefore, we ensure here that the correct type is set.
  83. sourceType = val.Value.GetType();
  84. }
  85. return node;
  86. }
  87. return base.Visit(node);
  88. }
  89. internal override SqlSelect VisitSelect(SqlSelect select) {
  90. /*
  91. * We're travelling through <expression> of something like:
  92. *
  93. * SELECT <expression>
  94. * FROM <alias>
  95. *
  96. * Inside the expression there may be a reference to <alias> that
  97. * represents the dynamic type that we're trying to discover.
  98. *
  99. * In this case, the type relationship between AliasRef and Alias is
  100. * T to IEnumerable<T>.
  101. *
  102. * We need to remember to 'unpivot' the type of IEnumerable<T> to
  103. * get the correct dynamic type.
  104. *
  105. * Since SELECTs may be nested, we use a stack of pivots.
  106. *
  107. */
  108. this.UnwrapSequences = new UnwrapStack(this.UnwrapSequences, true);
  109. VisitExpression(select.Selection);
  110. this.UnwrapSequences = this.UnwrapSequences.Last;
  111. return select;
  112. }
  113. internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
  114. if (this.UnwrapSequences != null && this.UnwrapSequences.Unwrap) {
  115. this.UnwrapSequences = new UnwrapStack(this.UnwrapSequences, false);
  116. this.VisitAlias(aref.Alias);
  117. this.UnwrapSequences = this.UnwrapSequences.Last;
  118. } else {
  119. this.VisitAlias(aref.Alias);
  120. }
  121. return aref;
  122. }
  123. internal override SqlExpression VisitColumnRef(SqlColumnRef cref) {
  124. this.VisitColumn(cref.Column); // Travel through column references
  125. return cref;
  126. }
  127. }
  128. /// <summary>
  129. /// Get a MetaType that represents the dynamic type of the given node.
  130. /// </summary>
  131. internal static MetaType GetSourceMetaType(SqlNode node, MetaModel model) {
  132. Visitor v = new Visitor();
  133. v.Visit(node);
  134. Type type = v.sourceType;
  135. type = TypeSystem.GetNonNullableType(type); // Emulate CLR's behavior: strip nullability from type.
  136. return model.GetMetaType(type);
  137. }
  138. /// <summary>
  139. /// Retrieve the expression that will represent the _dynamic_ type of the
  140. /// given expression. This is either a SqlDiscriminatedType or a SqlValue
  141. /// of type Type.
  142. /// </summary>
  143. internal static SqlExpression GetTypeSource(SqlExpression expr) {
  144. Visitor v = new Visitor();
  145. v.Visit(expr);
  146. return v.sourceExpression;
  147. }
  148. }
  149. }