Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Linq.SqlClient {
internal abstract class DbFormatter {
internal abstract string Format(SqlNode node, bool isDebug);
internal abstract string Format(SqlNode node);
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq.Expressions;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Data.Linq;
namespace System.Data.Linq.SqlClient {
// SQL Client extensions to ExpressionType
internal enum InternalExpressionType {
Known = 2000,
LinkedTable = 2001
}
abstract internal class InternalExpression : Expression {
#pragma warning disable 618 // Disable the 'obsolete' warning.
internal InternalExpression(InternalExpressionType nt, Type type)
: base ((ExpressionType)nt, type) {
}
#pragma warning restore 618
internal static KnownExpression Known(SqlExpression expr) {
return new KnownExpression(expr, expr.ClrType);
}
internal static KnownExpression Known(SqlNode node, Type type) {
return new KnownExpression(node, type);
}
}
internal sealed class KnownExpression : InternalExpression {
SqlNode node;
internal KnownExpression(SqlNode node, Type type)
: base(InternalExpressionType.Known, type) {
this.node = node;
}
internal SqlNode Node {
get { return this.node; }
}
}
internal sealed class LinkedTableExpression : InternalExpression {
private SqlLink link;
private ITable table;
internal LinkedTableExpression(SqlLink link, ITable table, Type type)
: base(InternalExpressionType.LinkedTable, type) {
this.link = link;
this.table = table;
}
internal SqlLink Link {
get {return this.link;}
}
internal ITable Table {
get {return this.table;}
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Data;
using System.Data.Common;
namespace System.Data.Linq.SqlClient {
internal interface IConnectionManager {
DbConnection UseConnection(IConnectionUser user);
void ReleaseConnection(IConnectionUser user);
}
internal interface IConnectionUser {
void CompleteUse();
}
}

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Linq;
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// This class defines the rules for inheritance behaviors. The rules:
///
/// (1) The same field may not be mapped to different database columns.
/// The DistinguishedMemberName and AreSameMember methods describe what 'same' means between two MemberInfos.
/// (2) Discriminators held in fixed-length fields in the database don't need
/// to be manually padded in inheritance mapping [InheritanceMapping(Code='x')].
///
/// </summary>
static class InheritanceRules {
/// <summary>
/// Creates a name that is the same when the member should be considered 'same'
/// for the purposes of the inheritance feature.
/// </summary>
internal static object DistinguishedMemberName(MemberInfo mi) {
PropertyInfo pi = mi as PropertyInfo;
FieldInfo fi = mi as FieldInfo;
if (fi != null) {
// Human readable variant:
// return "fi:" + mi.Name + ":" + mi.DeclaringType;
return new MetaPosition(mi);
}
else if (pi != null) {
MethodInfo meth = null;
if (pi.CanRead) {
meth = pi.GetGetMethod();
}
if (meth == null && pi.CanWrite) {
meth = pi.GetSetMethod();
}
bool isVirtual = meth != null && meth.IsVirtual;
// Human readable variant:
// return "pi:" + mi.Name + ":" + (isVirtual ? "virtual" : mi.DeclaringType.ToString());
if (isVirtual) {
return mi.Name;
} else {
return new MetaPosition(mi);
}
}
else {
throw Error.ArgumentOutOfRange("mi");
}
}
/// <summary>
/// Compares two MemberInfos for 'same-ness'.
/// </summary>
internal static bool AreSameMember(MemberInfo mi1, MemberInfo mi2) {
return DistinguishedMemberName(mi1).Equals(DistinguishedMemberName(mi2));
}
/// <summary>
/// The representation of a inheritance code when mapped to a specific provider type.
/// </summary>
internal static object InheritanceCodeForClientCompare(object rawCode, System.Data.Linq.SqlClient.ProviderType providerType) {
// If its a fixed-size string type in the store then pad it with spaces so that
// comparing the string on the client agrees with the value returnd on the store.
if (providerType.IsFixedSize && rawCode.GetType()==typeof(string)) {
string s = (string) rawCode;
if (providerType.Size.HasValue && s.Length!=providerType.Size) {
s = s.PadRight(providerType.Size.Value).Substring(0,providerType.Size.Value);
}
return s;
}
return rawCode;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// Annotation about a particular SqlNode.
/// </summary>
internal abstract class SqlNodeAnnotation {
string message;
internal SqlNodeAnnotation(string message) {
this.message = message;
}
internal string Message {
get {return this.message;}
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// Associate annotations with SqlNodes.
/// </summary>
internal class SqlNodeAnnotations {
Dictionary<SqlNode, List<SqlNodeAnnotation>> annotationMap = new Dictionary<SqlNode, List<SqlNodeAnnotation>>();
Dictionary<Type, string> uniqueTypes = new Dictionary<Type, string>();
/// <summary>
/// Add an annotation to the given node.
/// </summary>
internal void Add(SqlNode node, SqlNodeAnnotation annotation) {
List<SqlNodeAnnotation> list = null;
if (!this.annotationMap.TryGetValue(node, out list)) {
list = new List<SqlNodeAnnotation>();
this.annotationMap[node]=list;
}
uniqueTypes[annotation.GetType()] = String.Empty;
list.Add(annotation);
}
/// <summary>
/// Gets the annotations for the given node. Null if none.
/// </summary>
internal List<SqlNodeAnnotation> Get(SqlNode node) {
List<SqlNodeAnnotation> list = null;
this.annotationMap.TryGetValue(node, out list);
return list;
}
/// <summary>
/// Whether the given node has annotations.
/// </summary>
internal bool NodeIsAnnotated(SqlNode node) {
if (node == null)
return false;
return this.annotationMap.ContainsKey(node);
}
/// <summary>
/// Checks whether there's at least one annotation of the given type.
/// </summary>
internal bool HasAnnotationType(Type type) {
return this.uniqueTypes.ContainsKey(type);
}
}
}

View File

@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics.CodeAnalysis;
namespace System.Data.Linq.SqlClient {
internal static class SqlNodeTypeOperators {
/// <summary>
/// Determines whether the given unary operator node type returns a value that
/// is predicate.
/// </summary>
[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.")]
internal static bool IsPredicateUnaryOperator(this SqlNodeType nodeType) {
switch (nodeType) {
case SqlNodeType.Not:
case SqlNodeType.Not2V:
case SqlNodeType.IsNull:
case SqlNodeType.IsNotNull:
return true;
case SqlNodeType.Negate:
case SqlNodeType.BitNot:
case SqlNodeType.Count:
case SqlNodeType.LongCount:
case SqlNodeType.Max:
case SqlNodeType.Min:
case SqlNodeType.Sum:
case SqlNodeType.Avg:
case SqlNodeType.Stddev:
case SqlNodeType.Convert:
case SqlNodeType.ValueOf:
case SqlNodeType.OuterJoinedValue:
case SqlNodeType.ClrLength:
return false;
default:
throw Error.UnexpectedNode(nodeType);
}
}
/// <summary>
/// Determines whether the given unary operator expects a predicate as input.
/// </summary>
[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.")]
internal static bool IsUnaryOperatorExpectingPredicateOperand(this SqlNodeType nodeType) {
switch (nodeType) {
case SqlNodeType.Not:
case SqlNodeType.Not2V:
return true;
case SqlNodeType.IsNull:
case SqlNodeType.IsNotNull:
case SqlNodeType.Negate:
case SqlNodeType.BitNot:
case SqlNodeType.Count:
case SqlNodeType.LongCount:
case SqlNodeType.Max:
case SqlNodeType.Min:
case SqlNodeType.Sum:
case SqlNodeType.Avg:
case SqlNodeType.Stddev:
case SqlNodeType.Convert:
case SqlNodeType.ValueOf:
case SqlNodeType.OuterJoinedValue:
case SqlNodeType.ClrLength:
return false;
default:
throw Error.UnexpectedNode(nodeType);
}
}
/// <summary>
/// Determines whether the given binary operator node type returns a value that
/// is a predicate boolean.
/// </summary>
[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.")]
internal static bool IsPredicateBinaryOperator(this SqlNodeType nodeType) {
switch (nodeType) {
case SqlNodeType.GE:
case SqlNodeType.GT:
case SqlNodeType.LE:
case SqlNodeType.LT:
case SqlNodeType.EQ:
case SqlNodeType.NE:
case SqlNodeType.EQ2V:
case SqlNodeType.NE2V:
case SqlNodeType.And:
case SqlNodeType.Or:
return true;
case SqlNodeType.Add:
case SqlNodeType.Sub:
case SqlNodeType.Mul:
case SqlNodeType.Div:
case SqlNodeType.Mod:
case SqlNodeType.BitAnd:
case SqlNodeType.BitOr:
case SqlNodeType.BitXor:
case SqlNodeType.Concat:
case SqlNodeType.Coalesce:
return false;
default:
throw Error.UnexpectedNode(nodeType);
}
}
/// <summary>
/// Determines whether this operator is a binary comparison operator (i.e. >, =>, ==, etc)
/// </summary>
[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.")]
internal static bool IsComparisonOperator(this SqlNodeType nodeType)
{
switch (nodeType)
{
case SqlNodeType.GE:
case SqlNodeType.GT:
case SqlNodeType.LE:
case SqlNodeType.LT:
case SqlNodeType.EQ:
case SqlNodeType.NE:
case SqlNodeType.EQ2V:
case SqlNodeType.NE2V:
return true;
case SqlNodeType.And:
case SqlNodeType.Or:
case SqlNodeType.Add:
case SqlNodeType.Sub:
case SqlNodeType.Mul:
case SqlNodeType.Div:
case SqlNodeType.Mod:
case SqlNodeType.BitAnd:
case SqlNodeType.BitOr:
case SqlNodeType.BitXor:
case SqlNodeType.Concat:
case SqlNodeType.Coalesce:
return false;
default:
throw Error.UnexpectedNode(nodeType);
}
}
/// <summary>
/// Determines whether the given binary operator node type returns a value that
/// is a predicate boolean.
/// </summary>
[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.")]
internal static bool IsBinaryOperatorExpectingPredicateOperands(this SqlNodeType nodeType) {
switch (nodeType) {
case SqlNodeType.And:
case SqlNodeType.Or:
return true;
case SqlNodeType.EQ:
case SqlNodeType.EQ2V:
case SqlNodeType.GE:
case SqlNodeType.GT:
case SqlNodeType.LE:
case SqlNodeType.LT:
case SqlNodeType.NE:
case SqlNodeType.NE2V:
case SqlNodeType.Add:
case SqlNodeType.Sub:
case SqlNodeType.Mul:
case SqlNodeType.Div:
case SqlNodeType.Mod:
case SqlNodeType.BitAnd:
case SqlNodeType.BitOr:
case SqlNodeType.BitXor:
case SqlNodeType.Concat:
case SqlNodeType.Coalesce:
return false;
default:
throw Error.UnexpectedNode(nodeType);
}
}
/// <summary>
/// Determines whether the given node requires support on the client for evaluation.
/// For example, LINK nodes may be delay-executed only when the user requests the result.
/// </summary>
internal static bool IsClientAidedExpression(this SqlExpression expr) {
switch (expr.NodeType) {
case SqlNodeType.Link:
case SqlNodeType.Element:
case SqlNodeType.Multiset:
case SqlNodeType.ClientQuery:
case SqlNodeType.TypeCase:
case SqlNodeType.New:
return true;
default:
return false;
};
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// Annotation which indicates that the given node will cause a compatibility problem
/// for the indicated set of providers.
/// </summary>
internal class SqlServerCompatibilityAnnotation : SqlNodeAnnotation {
SqlProvider.ProviderMode[] providers;
/// <summary>
/// Constructor
/// </summary>
/// <param name="message">The compatibility message.</param>
/// <param name="providers">The set of providers this compatibility issue applies to.</param>
internal SqlServerCompatibilityAnnotation(string message, params SqlProvider.ProviderMode[] providers)
: base(message) {
this.providers = providers;
}
/// <summary>
/// Returns true if this annotation applies to the specified provider.
/// </summary>
internal bool AppliesTo(SqlProvider.ProviderMode provider) {
foreach (SqlProvider.ProviderMode p in providers) {
if (p == provider) {
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.ObjectModel;
using System.Text;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// Methods for checking whethe a query was compatible with the
/// server it will be sent to.
/// </summary>
static internal class SqlServerCompatibilityCheck {
/// <summary>
/// Private visitor class checks each node for compatibility annotations.
/// </summary>
private class Visitor : SqlVisitor {
private SqlProvider.ProviderMode provider;
internal SqlNodeAnnotations annotations;
internal Visitor(SqlProvider.ProviderMode provider) {
this.provider = provider;
}
/// <summary>
/// The reasons why this query is not 2K compatible.
/// </summary>
internal Collection<string> reasons = new Collection<string>();
internal override SqlNode Visit(SqlNode node) {
if (annotations.NodeIsAnnotated(node)) {
foreach (SqlNodeAnnotation annotation in annotations.Get(node)) {
SqlServerCompatibilityAnnotation ssca = annotation as SqlServerCompatibilityAnnotation;
if (ssca != null && ssca.AppliesTo(provider)) {
reasons.Add(annotation.Message);
}
}
}
return base.Visit(node);
}
}
/// <summary>
/// Checks whether the given node is supported on the given server.
/// </summary>
internal static void ThrowIfUnsupported(SqlNode node, SqlNodeAnnotations annotations, SqlProvider.ProviderMode provider) {
// Check to see whether there's at least one SqlServerCompatibilityAnnotation.
if (annotations.HasAnnotationType(typeof(SqlServerCompatibilityAnnotation))) {
Visitor visitor = new Visitor(provider);
visitor.annotations = annotations;
visitor.Visit(node);
// If any messages were recorded, then throw an exception.
if (visitor.reasons.Count > 0) {
throw Error.ExpressionNotSupportedForSqlServerVersion(visitor.reasons);
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,302 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Security;
using System.Security.Permissions;
using System.Linq;
namespace System.Data.Linq.SqlClient {
internal static class TypeSystem {
internal static bool IsSequenceType(Type seqType) {
return seqType != typeof(string)
&& seqType != typeof(byte[])
&& seqType != typeof(char[])
&& FindIEnumerable(seqType) != null;
}
internal static bool HasIEnumerable(Type seqType) {
return FindIEnumerable(seqType) != null;
}
private static Type FindIEnumerable(Type seqType) {
if (seqType == null || seqType == typeof(string))
return null;
if (seqType.IsArray)
return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());
if (seqType.IsGenericType) {
foreach (Type arg in seqType.GetGenericArguments()) {
Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
if (ienum.IsAssignableFrom(seqType)) {
return ienum;
}
}
}
Type[] ifaces = seqType.GetInterfaces();
if (ifaces != null && ifaces.Length > 0) {
foreach (Type iface in ifaces) {
Type ienum = FindIEnumerable(iface);
if (ienum != null) return ienum;
}
}
if (seqType.BaseType != null && seqType.BaseType != typeof(object)) {
return FindIEnumerable(seqType.BaseType);
}
return null;
}
internal static Type GetFlatSequenceType(Type elementType) {
Type ienum = FindIEnumerable(elementType);
if (ienum != null) return ienum;
return typeof(IEnumerable<>).MakeGenericType(elementType);
}
internal static Type GetSequenceType(Type elementType) {
return typeof(IEnumerable<>).MakeGenericType(elementType);
}
internal static Type GetElementType(Type seqType) {
Type ienum = FindIEnumerable(seqType);
if (ienum == null) return seqType;
return ienum.GetGenericArguments()[0];
}
internal static bool IsNullableType(Type type) {
return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
internal static bool IsNullAssignable(Type type) {
return !type.IsValueType || IsNullableType(type);
}
internal static Type GetNonNullableType(Type type) {
if (IsNullableType(type)) {
return type.GetGenericArguments()[0];
}
return type;
}
internal static Type GetMemberType(MemberInfo mi) {
FieldInfo fi = mi as FieldInfo;
if (fi != null) return fi.FieldType;
PropertyInfo pi = mi as PropertyInfo;
if (pi != null) return pi.PropertyType;
EventInfo ei = mi as EventInfo;
if (ei != null) return ei.EventHandlerType;
return null;
}
internal static IEnumerable<FieldInfo> GetAllFields(Type type, BindingFlags flags) {
Dictionary<MetaPosition, FieldInfo> seen = new Dictionary<MetaPosition, FieldInfo>();
Type currentType = type;
do {
foreach (FieldInfo fi in currentType.GetFields(flags)) {
if (fi.IsPrivate || type == currentType) {
MetaPosition mp = new MetaPosition(fi);
seen[mp] = fi;
}
}
currentType = currentType.BaseType;
} while (currentType != null);
return seen.Values;
}
internal static IEnumerable<PropertyInfo> GetAllProperties(Type type, BindingFlags flags) {
Dictionary<MetaPosition, PropertyInfo> seen = new Dictionary<MetaPosition, PropertyInfo>();
Type currentType = type;
do {
foreach (PropertyInfo pi in currentType.GetProperties(flags)) {
if (type == currentType || IsPrivate(pi)) {
MetaPosition mp = new MetaPosition(pi);
seen[mp] = pi;
}
}
currentType = currentType.BaseType;
} while (currentType != null);
return seen.Values;
}
private static bool IsPrivate(PropertyInfo pi) {
MethodInfo mi = pi.GetGetMethod() ?? pi.GetSetMethod();
if (mi != null) {
return mi.IsPrivate;
}
return true;
}
private static ILookup<string, MethodInfo> _sequenceMethods;
internal static MethodInfo FindSequenceMethod(string name, Type[] args, params Type[] typeArgs) {
if (_sequenceMethods == null) {
_sequenceMethods = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).ToLookup(m => m.Name);
}
MethodInfo mi = _sequenceMethods[name].FirstOrDefault(m => ArgsMatchExact(m, args, typeArgs));
if (mi == null)
return null;
if (typeArgs != null)
return mi.MakeGenericMethod(typeArgs);
return mi;
}
internal static MethodInfo FindSequenceMethod(string name, IEnumerable sequence) {
return FindSequenceMethod(name, new Type[] {sequence.GetType()}, new Type[] {GetElementType(sequence.GetType())});
}
private static ILookup<string, MethodInfo> _queryMethods;
internal static MethodInfo FindQueryableMethod(string name, Type[] args, params Type[] typeArgs) {
if (_queryMethods == null) {
_queryMethods = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).ToLookup(m => m.Name);
}
MethodInfo mi = _queryMethods[name].FirstOrDefault(m => ArgsMatchExact(m, args, typeArgs));
if (mi == null)
throw Error.NoMethodInTypeMatchingArguments(typeof(Queryable));
if (typeArgs != null)
return mi.MakeGenericMethod(typeArgs);
return mi;
}
internal static MethodInfo FindStaticMethod(Type type, string name, Type[] args, params Type[] typeArgs) {
MethodInfo mi = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
.FirstOrDefault(m => m.Name == name && ArgsMatchExact(m, args, typeArgs));
if (mi == null)
throw Error.NoMethodInTypeMatchingArguments(type);
if (typeArgs != null)
return mi.MakeGenericMethod(typeArgs);
return mi;
}
private static bool ArgsMatchExact(MethodInfo m, Type[] argTypes, Type[] typeArgs) {
ParameterInfo[] mParams = m.GetParameters();
if (mParams.Length != argTypes.Length)
return false;
if (!m.IsGenericMethodDefinition && m.IsGenericMethod && m.ContainsGenericParameters) {
m = m.GetGenericMethodDefinition();
}
if (m.IsGenericMethodDefinition) {
if (typeArgs == null || typeArgs.Length == 0)
return false;
if (m.GetGenericArguments().Length != typeArgs.Length)
return false;
m = m.MakeGenericMethod(typeArgs);
mParams = m.GetParameters();
}
else if (typeArgs != null && typeArgs.Length > 0) {
return false;
}
for (int i = 0, n = argTypes.Length; i < n; i++) {
Type parameterType = mParams[i].ParameterType;
if (parameterType == null)
return false;
Type argType = argTypes[i];
if (!parameterType.IsAssignableFrom(argType))
return false;
}
return true;
}
/// <summary>
/// Returns true if the type is one of the built in simple types.
/// </summary>
internal static bool IsSimpleType(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
type = type.GetGenericArguments()[0];
if (type.IsEnum)
return true;
if (type == typeof(Guid))
return true;
TypeCode tc = Type.GetTypeCode(type);
switch (tc)
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case TypeCode.Char:
case TypeCode.String:
case TypeCode.Boolean:
case TypeCode.DateTime:
return true;
case TypeCode.Object:
return (typeof(TimeSpan) == type) || (typeof(DateTimeOffset) == type);
default:
return false;
}
}
}
/// <summary>
/// Hashable MetaDataToken+Assembly. This type uniquely describes a metadata element
/// like a MemberInfo. MetaDataToken by itself is not sufficient because its only
/// unique within a single assembly.
/// </summary>
internal struct MetaPosition : IEqualityComparer<MetaPosition>, IEqualityComparer {
private int metadataToken;
private Assembly assembly;
internal MetaPosition(MemberInfo mi)
: this(mi.DeclaringType.Assembly, mi.MetadataToken) {
}
private MetaPosition(Assembly assembly, int metadataToken) {
this.assembly = assembly;
this.metadataToken = metadataToken;
}
// Equality is implemented here according to the advice in
// CLR via C# 2ed, J. Richter, p 146. In particular, ValueType.Equals
// should not be called for perf reasons.
#region Object Members
public override bool Equals(object obj) {
if (obj == null)
return false;
if (obj.GetType() != this.GetType())
return false;
return AreEqual(this, (MetaPosition)obj);
}
public override int GetHashCode() {
return metadataToken;
}
#endregion
#region IEqualityComparer<MetaPosition> Members
public bool Equals(MetaPosition x, MetaPosition y) {
return AreEqual(x, y);
}
public int GetHashCode(MetaPosition obj) {
return obj.metadataToken;
}
#endregion
#region IEqualityComparer Members
bool IEqualityComparer.Equals(object x, object y) {
return this.Equals((MetaPosition)x, (MetaPosition)y);
}
int IEqualityComparer.GetHashCode(object obj) {
return this.GetHashCode((MetaPosition) obj);
}
#endregion
private static bool AreEqual(MetaPosition x, MetaPosition y) {
return (x.metadataToken == y.metadataToken)
&& (x.assembly == y.assembly);
}
// Since MetaPositions are immutable, we overload the equality operator
// to test for value equality, rather than reference equality
public static bool operator==(MetaPosition x, MetaPosition y) {
return AreEqual(x, y);
}
public static bool operator !=(MetaPosition x, MetaPosition y) {
return !AreEqual(x, y);
}
internal static bool AreSameMember(MemberInfo x, MemberInfo y) {
if (x.MetadataToken != y.MetadataToken || x.DeclaringType.Assembly != y.DeclaringType.Assembly) {
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,263 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// Abstracts the provider side type system. Encapsulates:
/// - Mapping from runtime types to provider types.
/// - Parsing type strings in the provider's language.
/// - Handling application defined (opaque) types.
/// - Type coercion precedence rules.
/// - Type family organization.
/// </summary>
internal abstract class TypeSystemProvider {
internal abstract ProviderType PredictTypeForUnary(SqlNodeType unaryOp, ProviderType operandType);
internal abstract ProviderType PredictTypeForBinary(SqlNodeType binaryOp, ProviderType leftType, ProviderType rightType);
/// <summary>
/// Return the provider type corresponding to the given clr type.
/// </summary>
internal abstract ProviderType From(Type runtimeType);
/// <summary>
/// Return the provider type corresponding to the given object instance.
/// </summary>
internal abstract ProviderType From(object o);
/// <summary>
/// Return the provider type corresponding to the given clr type and size.
/// </summary>
internal abstract ProviderType From(Type type, int? size);
/// <summary>
/// Return a type by parsing a string. The format of the string is
/// provider specific.
/// </summary>
internal abstract ProviderType Parse(string text);
/// <summary>
/// Return a type understood only by the application.
/// Each call with the same index will return the same ProviderType.
/// </summary>
internal abstract ProviderType GetApplicationType(int index);
/// <summary>
/// Returns the most precise type in the family of the type given.
/// A family is a group types that serve similar functions. For example,
/// in SQL SmallInt and Int are part of one family.
/// </summary>
internal abstract ProviderType MostPreciseTypeInFamily(ProviderType type);
/// <summary>
/// For LOB data types that have large type equivalents, this function returns the equivalent large
/// data type. If the type is not an LOB or cannot be converted, the function returns the current type.
/// For example SqlServer defines the 'Image' LOB type, whose large type equivalent is VarBinary(MAX).
/// </summary>
internal abstract ProviderType GetBestLargeType(ProviderType type);
/// <summary>
/// Returns a type that can be used to hold values for both the current
/// type and the specified type without data loss.
/// </summary>
internal abstract ProviderType GetBestType(ProviderType typeA, ProviderType typeB);
internal abstract ProviderType ReturnTypeOfFunction(SqlFunctionCall functionCall);
/// <summary>
/// Get a type that can hold the same information but belongs to a different type family.
/// For example, to represent a SQL NChar as an integer type, we need to use the type int.
/// (SQL smallint would not be able to contain characters with unicode >32768)
/// </summary>
/// <param name="toType">Type of the target type family</param>
/// <returns>Smallest type of target type family that can hold equivalent information</returns>
internal abstract ProviderType ChangeTypeFamilyTo(ProviderType type, ProviderType typeWithFamily);
internal abstract void InitializeParameter(ProviderType type, System.Data.Common.DbParameter parameter, object value);
}
/// <summary>
/// Flags control the format of string returned by ToQueryString().
/// </summary>
[Flags]
internal enum QueryFormatOptions {
None = 0,
SuppressSize = 1
}
/// <summary>
/// An abstract type exposed by the TypeSystemProvider.
/// </summary>
internal abstract class ProviderType {
/// <summary>
/// True if this type is a Unicode type (eg, ntext, etc).
/// </summary>
internal abstract bool IsUnicodeType { get; }
/// <summary>
/// For a unicode type, return it's non-unicode equivalent.
/// </summary>
internal abstract ProviderType GetNonUnicodeEquivalent();
/// <summary>
/// True if this type has only a CLR representation and no provider representation.
/// </summary>
internal abstract bool IsRuntimeOnlyType { get; }
/// <summary>
/// True if this type is an application defined type.
/// </summary>
internal abstract bool IsApplicationType { get; }
/// <summary>
/// Determine whether this is the given application type.
/// </summary>
internal abstract bool IsApplicationTypeOf(int index);
/// <summary>
/// Returns the CLR type which most closely corresponds to this provider type.
/// </summary>
internal abstract Type GetClosestRuntimeType();
/// <summary>
/// Compare implicit type coercion precedence.
/// -1 means there is an implicit conversion from this->type.
/// 0 means there is a two way implicit conversion from this->type
/// 1 means there is an implicit conversion from type->this.
/// </summary>
internal abstract int ComparePrecedenceTo(ProviderType type);
/// <summary>
/// Determines whether two types are in the same type family.
/// A family is a group types that serve similar functions. For example,
/// in SQL SmallInt and Int are part of one family.
/// </summary>
internal abstract bool IsSameTypeFamily(ProviderType type);
/// <summary>
/// Used to indicate if the type supports comparison in provider.
/// </summary>
/// <returns>Returns true if type supports comparison in provider.</returns>
internal abstract bool SupportsComparison { get; }
/// <summary>
/// Used to indicate if the types supports Length function (LEN in T-SQL).
/// </summary>
/// <returns>Returns true if type supports use of length function on the type.</returns>
internal abstract bool SupportsLength { get; }
/// <summary>
/// Returns true if the given values will be equal to eachother for this type.
/// </summary>
internal abstract bool AreValuesEqual(object o1, object o2);
/// <summary>
/// Determines whether this type is a LOB (large object) type, or an equivalent type.
/// For example, on SqlServer, Image and VarChar(MAX) among others are considered large types.
/// </summary>
/// <returns></returns>
internal abstract bool IsLargeType { get; }
/// <summary>
/// Convert this type into a string that can be used in a query.
/// </summary>
internal abstract string ToQueryString();
/// <summary>
/// Convert this type into a string that can be used in a query.
/// </summary>
internal abstract string ToQueryString(QueryFormatOptions formatOptions);
/// <summary>
/// Whether this type is fixed size or not.
/// </summary>
internal abstract bool IsFixedSize { get; }
/// <summary>
/// The type has a size or is large.
/// </summary>
internal abstract bool HasSizeOrIsLarge { get; }
/// <summary>
/// The size of this type.
/// </summary>
internal abstract int? Size { get; }
/// <summary>
/// True if the type can be ordered.
/// </summary>
internal abstract bool IsOrderable { get; }
/// <summary>
/// True if the type can be grouped.
/// </summary>
internal abstract bool IsGroupable { get; }
/// <summary>
/// True if the type can appear in a column
/// </summary>
internal abstract bool CanBeColumn { get; }
/// <summary>
/// True if the type can appear as a parameter
/// </summary>
internal abstract bool CanBeParameter { get; }
/// <summary>
/// True if the type is a single character type.
/// </summary>
internal abstract bool IsChar { get; }
/// <summary>
/// True if the type is a multi-character type.
/// </summary>
internal abstract bool IsString { get; }
/// <summary>
/// True if the type is a number.
/// </summary>
internal abstract bool IsNumeric { get; }
/// <summary>
/// Returns true if the type uses precision and scale. For example, returns true
/// for SqlDBTypes Decimal, Float and Real.
/// </summary>
internal abstract bool HasPrecisionAndScale { get; }
/// <summary>
/// Determines if it is safe to suppress size specifications for
/// the operand of a cast/convert. For example, when casting to string,
/// all these types have length less than the default sized used by SqlServer,
/// so the length specification can be omitted without fear of truncation.
/// </summary>
internal abstract bool CanSuppressSizeForConversionToString{ get; }
public static bool operator ==(ProviderType typeA, ProviderType typeB) {
if ((object)typeA == (object)typeB)
return true;
if ((object)typeA != null)
return typeA.Equals(typeB);
return false;
}
public static bool operator != (ProviderType typeA, ProviderType typeB) {
if ((object)typeA == (object)typeB)
return false;
if ((object)typeA != null)
return !typeA.Equals(typeB);
return true;
}
public override bool Equals(object obj) {
return base.Equals(obj);
}
public override int GetHashCode() {
return base.GetHashCode();
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// DLinq-providerbase-specific custom exception factory.
/// </summary>
internal partial class Error {
/// <summary>
/// Exception thrown when a query cannot execute against a particular SQL server version.
/// </summary>
static internal Exception ExpressionNotSupportedForSqlServerVersion(Collection<string> reasons) {
StringBuilder exceptionMessage = new StringBuilder(Strings.CannotTranslateExpressionToSql);
foreach (string reason in reasons) {
exceptionMessage.AppendLine(reason);
}
return new NotSupportedException(exceptionMessage.ToString());
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// Flags that control the optimization of SQL produced.
/// Only optimization flags should go here because QA will be looking
/// here to see what optimizations they need to test.
/// </summary>
[Flags]
internal enum OptimizationFlags {
None = 0,
SimplifyCaseStatements = 1,
OptimizeLinkExpansions = 2,
All = SimplifyCaseStatements | OptimizeLinkExpansions
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace System.Data.Linq.SqlClient {
#if PERFORMANCE_BUILD
class PerfTimer {
long startTime;
long stopTime;
long frequency;
public PerfTimer() {
QueryPerformanceFrequency(out frequency);
}
public void Start() {
Thread.Sleep(0);
QueryPerformanceCounter(out startTime);
}
public void Stop() {
QueryPerformanceCounter(out stopTime);
}
public long Duration {
get { return (long)( 1000000.0 * (double)(stopTime - startTime) / (double) frequency ); }
}
[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long count);
[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long frequency);
}
#endif
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Data.Linq.SqlClient {
internal class SqlRowNumberChecker {
Visitor rowNumberVisitor;
internal SqlRowNumberChecker() {
this.rowNumberVisitor = new Visitor();
}
internal bool HasRowNumber(SqlNode node) {
this.rowNumberVisitor.Visit(node);
return rowNumberVisitor.HasRowNumber;
}
internal bool HasRowNumber(SqlRow row) {
foreach (SqlColumn column in row.Columns) {
if (this.HasRowNumber(column)) {
return true;
}
}
return false;
}
internal SqlColumn RowNumberColumn {
get {
return rowNumberVisitor.HasRowNumber ? rowNumberVisitor.CurrentColumn : null;
}
}
private class Visitor: SqlVisitor {
bool hasRowNumber = false;
public bool HasRowNumber {
get { return hasRowNumber; }
}
public SqlColumn CurrentColumn { private set; get; }
internal override SqlRowNumber VisitRowNumber(SqlRowNumber rowNumber) {
this.hasRowNumber = true;
return rowNumber;
}
// shortcuts
internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss) {
return ss;
}
internal override SqlExpression VisitSubSelect(SqlSubSelect ss) {
return ss;
}
internal override SqlRow VisitRow(SqlRow row)
{
for (int i = 0, n = row.Columns.Count; i < n; i++) {
row.Columns[i].Expression = this.VisitExpression(row.Columns[i].Expression);
if (this.hasRowNumber) {
this.CurrentColumn = row.Columns[i];
break;
}
}
return row;
}
internal override SqlSelect VisitSelect(SqlSelect select) {
this.Visit(select.Row);
this.Visit(select.Where);
return select;
}
}
}
}

View File

@@ -0,0 +1,445 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
namespace System.Data.Linq.SqlClient {
using System.Data.Linq.Mapping;
using System.Diagnostics.CodeAnalysis;
internal static class Funcletizer {
internal static Expression Funcletize(Expression expression) {
return new Localizer(new LocalMapper().MapLocals(expression)).Localize(expression);
}
class Localizer : ExpressionVisitor {
Dictionary<Expression, bool> locals;
internal Localizer(Dictionary<Expression, bool> locals) {
this.locals = locals;
}
internal Expression Localize(Expression expression) {
return this.Visit(expression);
}
internal override Expression Visit(Expression exp) {
if (exp == null) {
return null;
}
if (this.locals.ContainsKey(exp)) {
return MakeLocal(exp);
}
if (exp.NodeType == (ExpressionType)InternalExpressionType.Known) {
return exp;
}
return base.Visit(exp);
}
private static Expression MakeLocal(Expression e) {
if (e.NodeType == ExpressionType.Constant) {
return e;
}
else if (e.NodeType == ExpressionType.Convert || e.NodeType == ExpressionType.ConvertChecked) {
UnaryExpression ue = (UnaryExpression)e;
if (ue.Type == typeof(object)) {
Expression local = MakeLocal(ue.Operand);
return (e.NodeType == ExpressionType.Convert) ? Expression.Convert(local, e.Type) : Expression.ConvertChecked(local, e.Type);
}
// convert a const null
if (ue.Operand.NodeType == ExpressionType.Constant) {
ConstantExpression c = (ConstantExpression)ue.Operand;
if (c.Value == null) {
return Expression.Constant(null, ue.Type);
}
}
}
return Expression.Invoke(Expression.Constant(Expression.Lambda(e).Compile()));
}
}
class DependenceChecker : ExpressionVisitor {
HashSet<ParameterExpression> inScope = new HashSet<ParameterExpression>();
bool isIndependent = true;
/// <summary>
/// This method returns 'true' when the expression doesn't reference any parameters
/// from outside the scope of the expression.
/// </summary>
static public bool IsIndependent(Expression expression) {
var v = new DependenceChecker();
v.Visit(expression);
return v.isIndependent;
}
internal override Expression VisitLambda(LambdaExpression lambda) {
foreach (var p in lambda.Parameters) {
this.inScope.Add(p);
}
return base.VisitLambda(lambda);
}
internal override Expression VisitParameter(ParameterExpression p) {
this.isIndependent &= this.inScope.Contains(p);
return p;
}
}
class LocalMapper : ExpressionVisitor {
bool isRemote;
Dictionary<Expression, bool> locals;
internal Dictionary<Expression, bool> MapLocals(Expression expression) {
this.locals = new Dictionary<Expression, bool>();
this.isRemote = false;
this.Visit(expression);
return this.locals;
}
internal override Expression Visit(Expression expression) {
if (expression == null) {
return null;
}
bool saveIsRemote = this.isRemote;
switch (expression.NodeType) {
case (ExpressionType)InternalExpressionType.Known:
return expression;
case (ExpressionType)ExpressionType.Constant:
break;
default:
this.isRemote = false;
base.Visit(expression);
if (!this.isRemote
&& expression.NodeType != ExpressionType.Lambda
&& expression.NodeType != ExpressionType.Quote
&& DependenceChecker.IsIndependent(expression)) {
this.locals[expression] = true; // Not 'Add' because the same expression may exist in the tree twice.
}
break;
}
if (typeof(ITable).IsAssignableFrom(expression.Type) ||
typeof(DataContext).IsAssignableFrom(expression.Type)) {
this.isRemote = true;
}
this.isRemote |= saveIsRemote;
return expression;
}
internal override Expression VisitMemberAccess(MemberExpression m) {
base.VisitMemberAccess(m);
this.isRemote |= (m.Expression != null && typeof(ITable).IsAssignableFrom(m.Expression.Type));
return m;
}
internal override Expression VisitMethodCall(MethodCallExpression m) {
base.VisitMethodCall(m);
this.isRemote |= m.Method.DeclaringType == typeof(System.Data.Linq.Provider.DataManipulation)
|| Attribute.IsDefined(m.Method, typeof(FunctionAttribute));
return m;
}
}
}
internal abstract class ExpressionVisitor {
internal ExpressionVisitor() {
}
[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.")]
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "[....]: Cast is dependent on node type and casts do not happen unecessarily in a single code path.")]
internal virtual Expression Visit(Expression exp) {
if (exp == null)
return exp;
switch (exp.NodeType) {
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Not:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.ArrayLength:
case ExpressionType.Quote:
case ExpressionType.TypeAs:
return this.VisitUnary((UnaryExpression)exp);
case ExpressionType.Add:
case ExpressionType.AddChecked:
case ExpressionType.Subtract:
case ExpressionType.SubtractChecked:
case ExpressionType.Multiply:
case ExpressionType.MultiplyChecked:
case ExpressionType.Divide:
case ExpressionType.Modulo:
case ExpressionType.Power:
case ExpressionType.And:
case ExpressionType.AndAlso:
case ExpressionType.Or:
case ExpressionType.OrElse:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
case ExpressionType.RightShift:
case ExpressionType.LeftShift:
case ExpressionType.ExclusiveOr:
return this.VisitBinary((BinaryExpression)exp);
case ExpressionType.TypeIs:
return this.VisitTypeIs((TypeBinaryExpression)exp);
case ExpressionType.Conditional:
return this.VisitConditional((ConditionalExpression)exp);
case ExpressionType.Constant:
return this.VisitConstant((ConstantExpression)exp);
case ExpressionType.Parameter:
return this.VisitParameter((ParameterExpression)exp);
case ExpressionType.MemberAccess:
return this.VisitMemberAccess((MemberExpression)exp);
case ExpressionType.Call:
return this.VisitMethodCall((MethodCallExpression)exp);
case ExpressionType.Lambda:
return this.VisitLambda((LambdaExpression)exp);
case ExpressionType.New:
return this.VisitNew((NewExpression)exp);
case ExpressionType.NewArrayInit:
case ExpressionType.NewArrayBounds:
return this.VisitNewArray((NewArrayExpression)exp);
case ExpressionType.Invoke:
return this.VisitInvocation((InvocationExpression)exp);
case ExpressionType.MemberInit:
return this.VisitMemberInit((MemberInitExpression)exp);
case ExpressionType.ListInit:
return this.VisitListInit((ListInitExpression)exp);
case ExpressionType.UnaryPlus:
if (exp.Type == typeof(TimeSpan))
return this.VisitUnary((UnaryExpression)exp);
throw Error.UnhandledExpressionType(exp.NodeType);
default:
throw Error.UnhandledExpressionType(exp.NodeType);
}
}
internal virtual MemberBinding VisitBinding(MemberBinding binding) {
switch (binding.BindingType) {
case MemberBindingType.Assignment:
return this.VisitMemberAssignment((MemberAssignment)binding);
case MemberBindingType.MemberBinding:
return this.VisitMemberMemberBinding((MemberMemberBinding)binding);
case MemberBindingType.ListBinding:
return this.VisitMemberListBinding((MemberListBinding)binding);
default:
throw Error.UnhandledBindingType(binding.BindingType);
}
}
internal virtual ElementInit VisitElementInitializer(ElementInit initializer) {
ReadOnlyCollection<Expression> arguments = this.VisitExpressionList(initializer.Arguments);
if (arguments != initializer.Arguments) {
return Expression.ElementInit(initializer.AddMethod, arguments);
}
return initializer;
}
internal virtual Expression VisitUnary(UnaryExpression u) {
Expression operand = this.Visit(u.Operand);
if (operand != u.Operand) {
return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method);
}
return u;
}
internal virtual Expression VisitBinary(BinaryExpression b) {
Expression left = this.Visit(b.Left);
Expression right = this.Visit(b.Right);
if (left != b.Left || right != b.Right) {
return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method);
}
return b;
}
internal virtual Expression VisitTypeIs(TypeBinaryExpression b) {
Expression expr = this.Visit(b.Expression);
if (expr != b.Expression) {
return Expression.TypeIs(expr, b.TypeOperand);
}
return b;
}
internal virtual Expression VisitConstant(ConstantExpression c) {
return c;
}
internal virtual Expression VisitConditional(ConditionalExpression c) {
Expression test = this.Visit(c.Test);
Expression ifTrue = this.Visit(c.IfTrue);
Expression ifFalse = this.Visit(c.IfFalse);
if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse) {
return Expression.Condition(test, ifTrue, ifFalse);
}
return c;
}
internal virtual Expression VisitParameter(ParameterExpression p) {
return p;
}
internal virtual Expression VisitMemberAccess(MemberExpression m) {
Expression exp = this.Visit(m.Expression);
if (exp != m.Expression) {
return Expression.MakeMemberAccess(exp, m.Member);
}
return m;
}
internal virtual Expression VisitMethodCall(MethodCallExpression m) {
Expression obj = this.Visit(m.Object);
IEnumerable<Expression> args = this.VisitExpressionList(m.Arguments);
if (obj != m.Object || args != m.Arguments) {
return Expression.Call(obj, m.Method, args);
}
return m;
}
internal virtual ReadOnlyCollection<Expression> VisitExpressionList(ReadOnlyCollection<Expression> original) {
List<Expression> list = null;
for (int i = 0, n = original.Count; i < n; i++) {
Expression p = this.Visit(original[i]);
if (list != null) {
list.Add(p);
}
else if (p != original[i]) {
list = new List<Expression>(n);
for (int j = 0; j < i; j++) {
list.Add(original[j]);
}
list.Add(p);
}
}
if (list != null)
return new ReadOnlyCollection<Expression>(list);
return original;
}
internal virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment) {
Expression e = this.Visit(assignment.Expression);
if (e != assignment.Expression) {
return Expression.Bind(assignment.Member, e);
}
return assignment;
}
internal virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) {
IEnumerable<MemberBinding> bindings = this.VisitBindingList(binding.Bindings);
if (bindings != binding.Bindings) {
return Expression.MemberBind(binding.Member, bindings);
}
return binding;
}
internal virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) {
IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(binding.Initializers);
if (initializers != binding.Initializers) {
return Expression.ListBind(binding.Member, initializers);
}
return binding;
}
internal virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original) {
List<MemberBinding> list = null;
for (int i = 0, n = original.Count; i < n; i++) {
MemberBinding b = this.VisitBinding(original[i]);
if (list != null) {
list.Add(b);
}
else if (b != original[i]) {
list = new List<MemberBinding>(n);
for (int j = 0; j < i; j++) {
list.Add(original[j]);
}
list.Add(b);
}
}
if (list != null)
return list;
return original;
}
internal virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original) {
List<ElementInit> list = null;
for (int i = 0, n = original.Count; i < n; i++) {
ElementInit init = this.VisitElementInitializer(original[i]);
if (list != null) {
list.Add(init);
}
else if (init != original[i]) {
list = new List<ElementInit>(n);
for (int j = 0; j < i; j++) {
list.Add(original[j]);
}
list.Add(init);
}
}
if (list != null) {
return list;
}
return original;
}
internal virtual Expression VisitLambda(LambdaExpression lambda) {
Expression body = this.Visit(lambda.Body);
if (body != lambda.Body) {
return Expression.Lambda(lambda.Type, body, lambda.Parameters);
}
return lambda;
}
internal virtual NewExpression VisitNew(NewExpression nex) {
IEnumerable<Expression> args = this.VisitExpressionList(nex.Arguments);
if (args != nex.Arguments) {
if (nex.Members != null) {
return Expression.New(nex.Constructor, args, nex.Members);
}
else {
return Expression.New(nex.Constructor, args);
}
}
return nex;
}
internal virtual Expression VisitMemberInit(MemberInitExpression init) {
NewExpression n = this.VisitNew(init.NewExpression);
IEnumerable<MemberBinding> bindings = this.VisitBindingList(init.Bindings);
if (n != init.NewExpression || bindings != init.Bindings) {
return Expression.MemberInit(n, bindings);
}
return init;
}
internal virtual Expression VisitListInit(ListInitExpression init) {
NewExpression n = this.VisitNew(init.NewExpression);
IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(init.Initializers);
if (n != init.NewExpression || initializers != init.Initializers) {
return Expression.ListInit(n, initializers);
}
return init;
}
internal virtual Expression VisitNewArray(NewArrayExpression na) {
IEnumerable<Expression> exprs = this.VisitExpressionList(na.Expressions);
if (exprs != na.Expressions) {
if (na.NodeType == ExpressionType.NewArrayInit) {
return Expression.NewArrayInit(na.Type.GetElementType(), exprs);
}
else {
return Expression.NewArrayBounds(na.Type.GetElementType(), exprs);
}
}
return na;
}
internal virtual Expression VisitInvocation(InvocationExpression iv) {
IEnumerable<Expression> args = this.VisitExpressionList(iv.Arguments);
Expression expr = this.Visit(iv.Expression);
if (args != iv.Arguments || expr != iv.Expression) {
return Expression.Invoke(expr, args);
}
return iv;
}
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Linq;
namespace System.Data.Linq.SqlClient {
/// <summary>
/// Converts expressions of type NText, Text, Image to NVarChar(MAX), VarChar(MAX), VarBinary(MAX)
/// where necessary. This can only be done on SQL2005, so we add a SqlServerCompatibilityAnnotation
/// to the changed nodes.
/// </summary>
internal class LongTypeConverter {
Visitor visitor;
internal LongTypeConverter(SqlFactory sql) {
this.visitor = new Visitor(sql);
}
internal SqlNode AddConversions(SqlNode node, SqlNodeAnnotations annotations) {
visitor.Annotations = annotations;
return visitor.Visit(node);
}
class Visitor : SqlVisitor {
SqlFactory sql;
SqlNodeAnnotations annotations;
internal SqlNodeAnnotations Annotations {
set { this.annotations = value; }
}
internal Visitor(SqlFactory sql) {
this.sql = sql;
}
private SqlExpression ConvertToMax(SqlExpression expr, ProviderType newType) {
return sql.UnaryConvert(expr.ClrType, newType, expr, expr.SourceExpression);
}
// returns CONVERT(VARCHAR/NVARCHAR/VARBINARY(MAX), expr) if provType is one of Text, NText or Image
// otherwise just returns expr
// changed is true if CONVERT(...(MAX),...) was added
private SqlExpression ConvertToMax(SqlExpression expr, out bool changed) {
changed = false;
if (!expr.SqlType.IsLargeType)
return expr;
ProviderType newType = sql.TypeProvider.GetBestLargeType(expr.SqlType);
changed = true;
if (expr.SqlType != newType) {
return ConvertToMax(expr, newType);
}
changed = false;
return expr;
}
private void ConvertColumnsToMax(SqlSelect select, out bool changed, out bool containsLongExpressions) {
SqlRow row = select.Row;
changed = false;
containsLongExpressions = false;
foreach (SqlColumn col in row.Columns) {
bool columnChanged;
containsLongExpressions = containsLongExpressions || col.SqlType.IsLargeType;
col.Expression = ConvertToMax(col.Expression, out columnChanged);
changed = changed || columnChanged;
}
}
internal override SqlSelect VisitSelect(SqlSelect select) {
if (select.IsDistinct) {
bool changed;
bool containsLongExpressions;
ConvertColumnsToMax(select, out changed, out containsLongExpressions);
if (containsLongExpressions) {
this.annotations.Add(select, new SqlServerCompatibilityAnnotation(
Strings.TextNTextAndImageCannotOccurInDistinct(select.SourceExpression), SqlProvider.ProviderMode.Sql2000, SqlProvider.ProviderMode.SqlCE));
}
}
return base.VisitSelect(select);
}
internal override SqlNode VisitUnion(SqlUnion su) {
bool changedLeft = false;
bool containsLongExpressionsLeft = false;
SqlSelect left = su.Left as SqlSelect;
if (left != null) {
ConvertColumnsToMax(left, out changedLeft, out containsLongExpressionsLeft);
}
bool changedRight = false;
bool containsLongExpressionsRight = false;
SqlSelect right = su.Right as SqlSelect;
if (right != null) {
ConvertColumnsToMax(right, out changedRight, out containsLongExpressionsRight);
}
if (!su.All && (containsLongExpressionsLeft || containsLongExpressionsRight)) {
// unless the UNION is 'ALL', the server will perform a DISTINCT operation,
// which isn't valid for large types (text, ntext, image)
this.annotations.Add(su, new SqlServerCompatibilityAnnotation(
Strings.TextNTextAndImageCannotOccurInUnion(su.SourceExpression), SqlProvider.ProviderMode.Sql2000, SqlProvider.ProviderMode.SqlCE));
}
return base.VisitUnion(su);
}
internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) {
if (fc.Name == "LEN") {
bool changed;
fc.Arguments[0] = ConvertToMax(fc.Arguments[0],out changed);
if (fc.Arguments[0].SqlType.IsLargeType) {
this.annotations.Add(fc, new SqlServerCompatibilityAnnotation(
Strings.LenOfTextOrNTextNotSupported(fc.SourceExpression), SqlProvider.ProviderMode.Sql2000));
}
}
return base.VisitFunctionCall(fc);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More