Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 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();
}
}
}