| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- //------------------------------------------------------------------------------
- // <copyright file="DataStorage.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">Microsoft</owner>
- // <owner current="true" primary="false">Microsoft</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.Common {
- using System;
- using System.Collections;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Data.SqlTypes;
- using System.Diagnostics;
- using System.Xml;
- using System.Xml.Serialization;
- internal enum StorageType {
- Empty = TypeCode.Empty, // 0
- Object = TypeCode.Object,
- DBNull = TypeCode.DBNull,
- Boolean = TypeCode.Boolean,
- Char = TypeCode.Char,
- SByte = TypeCode.SByte,
- Byte = TypeCode.Byte,
- Int16 = TypeCode.Int16,
- UInt16 = TypeCode.UInt16,
- Int32 = TypeCode.Int32,
- UInt32 = TypeCode.UInt32,
- Int64 = TypeCode.Int64,
- UInt64 = TypeCode.UInt64,
- Single = TypeCode.Single,
- Double = TypeCode.Double,
- Decimal = TypeCode.Decimal, // 15
- DateTime = TypeCode.DateTime, // 16
- TimeSpan = 17,
- String = TypeCode.String, // 18
- Guid = 19,
- ByteArray = 20,
- CharArray = 21,
- Type = 22,
- DateTimeOffset = 23,
- BigInteger = 24,
- Uri = 25,
- SqlBinary, // SqlTypes should remain at the end for IsSqlType checking
- SqlBoolean,
- SqlByte,
- SqlBytes,
- SqlChars,
- SqlDateTime,
- SqlDecimal,
- SqlDouble,
- SqlGuid,
- SqlInt16,
- SqlInt32,
- SqlInt64,
- SqlMoney,
- SqlSingle,
- SqlString,
- // SqlXml,
- };
- abstract internal class DataStorage {
- // for Whidbey 40426, searching down the Type[] is about 20% faster than using a Dictionary
- // must keep in same order as enum StorageType
- private static readonly Type[] StorageClassType = new Type[] {
- null,
- typeof(Object),
- typeof(DBNull),
- typeof(Boolean),
- typeof(Char),
- typeof(SByte),
- typeof(Byte),
- typeof(Int16),
- typeof(UInt16),
- typeof(Int32),
- typeof(UInt32),
- typeof(Int64),
- typeof(UInt64),
- typeof(Single),
- typeof(Double),
- typeof(Decimal),
- typeof(DateTime),
- typeof(TimeSpan),
- typeof(String),
- typeof(Guid),
- typeof(byte[]),
- typeof(char[]),
- typeof(Type),
- typeof(DateTimeOffset),
- typeof(System.Numerics.BigInteger),
- typeof(Uri),
- typeof(SqlBinary),
- typeof(SqlBoolean),
- typeof(SqlByte),
- typeof(SqlBytes),
- typeof(SqlChars),
- typeof(SqlDateTime),
- typeof(SqlDecimal),
- typeof(SqlDouble),
- typeof(SqlGuid),
- typeof(SqlInt16),
- typeof(SqlInt32),
- typeof(SqlInt64),
- typeof(SqlMoney),
- typeof(SqlSingle),
- typeof(SqlString),
- // typeof(SqlXml),
- };
- internal readonly DataColumn Column;
- internal readonly DataTable Table;
- internal readonly Type DataType;
- internal readonly StorageType StorageTypeCode;
- private System.Collections.BitArray dbNullBits;
- private readonly object DefaultValue;
- internal readonly object NullValue;
- internal readonly bool IsCloneable;
- internal readonly bool IsCustomDefinedType;
- internal readonly bool IsStringType;
- internal readonly bool IsValueType;
- private readonly static Func<Type, Tuple<bool, bool, bool, bool>> _inspectTypeForInterfaces = InspectTypeForInterfaces;
- private readonly static ConcurrentDictionary<Type, Tuple<bool, bool, bool, bool>> _typeImplementsInterface = new ConcurrentDictionary<Type, Tuple<bool, bool, bool, bool>>();
- protected DataStorage(DataColumn column, Type type, object defaultValue, StorageType storageType)
- : this(column, type, defaultValue, DBNull.Value, false, storageType) {
- }
- protected DataStorage(DataColumn column, Type type, object defaultValue, object nullValue, StorageType storageType)
- : this(column, type, defaultValue, nullValue, false, storageType) {
- }
- protected DataStorage(DataColumn column, Type type, object defaultValue, object nullValue, bool isICloneable, StorageType storageType) {
- Debug.Assert(storageType == GetStorageType(type), "Incorrect storage type specified");
- Column = column;
- Table = column.Table;
- DataType = type;
- StorageTypeCode = storageType;
- DefaultValue = defaultValue;
- NullValue = nullValue;
- IsCloneable = isICloneable;
- IsCustomDefinedType = IsTypeCustomType(StorageTypeCode);
- IsStringType = ((StorageType.String == StorageTypeCode) || (StorageType.SqlString == StorageTypeCode));
- IsValueType = DetermineIfValueType(StorageTypeCode, type);
- }
- internal DataSetDateTime DateTimeMode {
- get {
- return Column.DateTimeMode;
- }
- }
- internal IFormatProvider FormatProvider {
- get {
- return Table.FormatProvider;
- }
- }
- public virtual Object Aggregate(int[] recordNos, AggregateType kind) {
- if (AggregateType.Count == kind) {
- return this.AggregateCount(recordNos);
- }
- return null;
- }
- public object AggregateCount(int[] recordNos) {
- int count = 0;
- for (int i = 0; i < recordNos.Length; i++) {
- if (!this.dbNullBits.Get(recordNos[i]))
- count++;
- }
- return count;
- }
- protected int CompareBits(int recordNo1, int recordNo2) {
- bool recordNo1Null = this.dbNullBits.Get(recordNo1);
- bool recordNo2Null = this.dbNullBits.Get(recordNo2);
- if (recordNo1Null ^ recordNo2Null) {
- if (recordNo1Null)
- return -1;
- else
- return 1;
- }
- return 0;
- }
- public abstract int Compare(int recordNo1, int recordNo2);
- // only does comparision, expect value to be of the correct type
- public abstract int CompareValueTo(int recordNo1, object value);
- // only does conversion with support for reference null
- public virtual object ConvertValue(object value) {
- return value;
- }
- protected void CopyBits(int srcRecordNo, int dstRecordNo) {
- this.dbNullBits.Set(dstRecordNo, this.dbNullBits.Get(srcRecordNo));
- }
- abstract public void Copy(int recordNo1, int recordNo2);
- abstract public Object Get(int recordNo);
- protected Object GetBits(int recordNo) {
- if (this.dbNullBits.Get(recordNo)) {
- return NullValue;
- }
- return DefaultValue;
- }
- virtual public int GetStringLength(int record) {
- System.Diagnostics.Debug.Assert(false, "not a String or SqlString column");
- return Int32.MaxValue;
- }
- protected bool HasValue(int recordNo) {
- return !this.dbNullBits.Get(recordNo);
- }
- public virtual bool IsNull(int recordNo) {
- return this.dbNullBits.Get(recordNo);
- }
- // convert (may not support reference null) and store the value
- abstract public void Set(int recordNo, Object value);
- protected void SetNullBit(int recordNo, bool flag) {
- this.dbNullBits.Set(recordNo, flag);
- }
- virtual public void SetCapacity(int capacity) {
- if (null == this.dbNullBits) {
- this.dbNullBits = new BitArray(capacity);
- }
- else {
- this.dbNullBits.Length = capacity;
- }
- }
- abstract public object ConvertXmlToObject(string s);
- public virtual object ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute xmlAttrib) {
- return ConvertXmlToObject(xmlReader.Value);
- }
- abstract public string ConvertObjectToXml(object value);
- public virtual void ConvertObjectToXml(object value, XmlWriter xmlWriter, XmlRootAttribute xmlAttrib) {
- xmlWriter.WriteString(ConvertObjectToXml(value));// should it be NO OP?
- }
- public static DataStorage CreateStorage(DataColumn column, Type dataType, StorageType typeCode) {
- Debug.Assert(typeCode == GetStorageType(dataType), "Incorrect storage type specified");
- if ((StorageType.Empty == typeCode) && (null != dataType)) {
- if (typeof(INullable).IsAssignableFrom(dataType)) { // Udt, OracleTypes
- return new SqlUdtStorage(column, dataType);
- }
- else {
- return new ObjectStorage(column, dataType); // non-nullable non-primitives
- }
- }
- switch (typeCode) {
- case StorageType.Empty: throw ExceptionBuilder.InvalidStorageType(TypeCode.Empty);
- case StorageType.DBNull: throw ExceptionBuilder.InvalidStorageType(TypeCode.DBNull);
- case StorageType.Object: return new ObjectStorage(column, dataType);
- case StorageType.Boolean: return new BooleanStorage(column);
- case StorageType.Char: return new CharStorage(column);
- case StorageType.SByte: return new SByteStorage(column);
- case StorageType.Byte: return new ByteStorage(column);
- case StorageType.Int16: return new Int16Storage(column);
- case StorageType.UInt16: return new UInt16Storage(column);
- case StorageType.Int32: return new Int32Storage(column);
- case StorageType.UInt32: return new UInt32Storage(column);
- case StorageType.Int64: return new Int64Storage(column);
- case StorageType.UInt64: return new UInt64Storage(column);
- case StorageType.Single: return new SingleStorage(column);
- case StorageType.Double: return new DoubleStorage(column);
- case StorageType.Decimal: return new DecimalStorage(column);
- case StorageType.DateTime: return new DateTimeStorage(column);
- case StorageType.TimeSpan: return new TimeSpanStorage(column);
- case StorageType.String: return new StringStorage(column);
- case StorageType.Guid: return new ObjectStorage(column, dataType);
- case StorageType.ByteArray: return new ObjectStorage(column, dataType);
- case StorageType.CharArray: return new ObjectStorage(column, dataType);
- case StorageType.Type: return new ObjectStorage(column, dataType);
- case StorageType.DateTimeOffset: return new DateTimeOffsetStorage(column);
- case StorageType.BigInteger: return new BigIntegerStorage(column);
- case StorageType.Uri: return new ObjectStorage(column, dataType);
- case StorageType.SqlBinary: return new SqlBinaryStorage(column);
- case StorageType.SqlBoolean: return new SqlBooleanStorage(column);
- case StorageType.SqlByte: return new SqlByteStorage(column);
- case StorageType.SqlBytes: return new SqlBytesStorage(column);
- case StorageType.SqlChars: return new SqlCharsStorage(column);
- case StorageType.SqlDateTime: return new SqlDateTimeStorage(column); //???/ what to do
- case StorageType.SqlDecimal: return new SqlDecimalStorage(column);
- case StorageType.SqlDouble: return new SqlDoubleStorage(column);
- case StorageType.SqlGuid: return new SqlGuidStorage(column);
- case StorageType.SqlInt16: return new SqlInt16Storage(column);
- case StorageType.SqlInt32: return new SqlInt32Storage(column);
- case StorageType.SqlInt64: return new SqlInt64Storage(column);
- case StorageType.SqlMoney: return new SqlMoneyStorage(column);
- case StorageType.SqlSingle: return new SqlSingleStorage(column);
- case StorageType.SqlString: return new SqlStringStorage(column);
- // case StorageType.SqlXml: return new SqlXmlStorage(column);
- default:
- System.Diagnostics.Debug.Assert(false, "shouldn't be here");
- goto case StorageType.Object;
- }
- }
- internal static StorageType GetStorageType(Type dataType) {
- for (int i = 0; i < StorageClassType.Length; ++i) {
- if (dataType == StorageClassType[i]) {
- return (StorageType)i;
- }
- }
- TypeCode tcode = Type.GetTypeCode(dataType);
- if (TypeCode.Object != tcode) { // enum -> Int64/Int32/Int16/Byte
- return (StorageType)tcode;
- }
- return StorageType.Empty;
- }
- internal static Type GetTypeStorage(StorageType storageType) {
- return StorageClassType[(int)storageType];
- }
- internal static bool IsTypeCustomType(Type type) {
- return IsTypeCustomType(GetStorageType(type));
- }
- internal static bool IsTypeCustomType(StorageType typeCode) {
- return ((StorageType.Object == typeCode) || (StorageType.Empty == typeCode) || (StorageType.CharArray == typeCode));
- }
- internal static bool IsSqlType(StorageType storageType) {
- return (StorageType.SqlBinary <= storageType);
- }
- public static bool IsSqlType(Type dataType) {
- for (int i = (int)StorageType.SqlBinary; i < StorageClassType.Length; ++i) {
- if (dataType == StorageClassType[i]) {
- return true;
- }
- }
- return false;
- }
- private static bool DetermineIfValueType(StorageType typeCode, Type dataType) {
- bool result;
- switch (typeCode) {
- case StorageType.Boolean:
- case StorageType.Char:
- case StorageType.SByte:
- case StorageType.Byte:
- case StorageType.Int16:
- case StorageType.UInt16:
- case StorageType.Int32:
- case StorageType.UInt32:
- case StorageType.Int64:
- case StorageType.UInt64:
- case StorageType.Single:
- case StorageType.Double:
- case StorageType.Decimal:
- case StorageType.DateTime:
- case StorageType.DateTimeOffset:
- case StorageType.BigInteger:
- case StorageType.TimeSpan:
- case StorageType.Guid:
- case StorageType.SqlBinary:
- case StorageType.SqlBoolean:
- case StorageType.SqlByte:
- case StorageType.SqlDateTime:
- case StorageType.SqlDecimal:
- case StorageType.SqlDouble:
- case StorageType.SqlGuid:
- case StorageType.SqlInt16:
- case StorageType.SqlInt32:
- case StorageType.SqlInt64:
- case StorageType.SqlMoney:
- case StorageType.SqlSingle:
- case StorageType.SqlString:
- result = true;
- break;
- case StorageType.String:
- case StorageType.ByteArray:
- case StorageType.CharArray:
- case StorageType.Type:
- case StorageType.Uri:
- case StorageType.SqlBytes:
- case StorageType.SqlChars:
- result = false;
- break;
- default:
- result = dataType.IsValueType;
- break;
- }
- Debug.Assert(result == dataType.IsValueType, "typeCode mismatches dataType");
- return result;
- }
- internal static void ImplementsInterfaces(
- StorageType typeCode,
- Type dataType,
- out bool sqlType,
- out bool nullable,
- out bool xmlSerializable,
- out bool changeTracking,
- out bool revertibleChangeTracking)
- {
- Debug.Assert(typeCode == GetStorageType(dataType), "typeCode mismatches dataType");
- if (IsSqlType(typeCode)) {
- sqlType = true;
- nullable = true;
- changeTracking = false;
- revertibleChangeTracking = false;
- xmlSerializable = true;
- }
- else if (StorageType.Empty != typeCode) {
- sqlType = false;
- nullable = false;
- changeTracking = false;
- revertibleChangeTracking = false;
- xmlSerializable = false;
- }
- else {
- // Non-standard type - look it up in the dictionary or add it if not found
- Tuple<bool, bool, bool, bool> interfaces = _typeImplementsInterface.GetOrAdd(dataType, _inspectTypeForInterfaces);
- sqlType = false;
- nullable = interfaces.Item1;
- changeTracking = interfaces.Item2;
- revertibleChangeTracking = interfaces.Item3;
- xmlSerializable = interfaces.Item4;
- }
- Debug.Assert(nullable == typeof(System.Data.SqlTypes.INullable).IsAssignableFrom(dataType), "INullable");
- Debug.Assert(changeTracking == typeof(System.ComponentModel.IChangeTracking).IsAssignableFrom(dataType), "IChangeTracking");
- Debug.Assert(revertibleChangeTracking == typeof(System.ComponentModel.IRevertibleChangeTracking).IsAssignableFrom(dataType), "IRevertibleChangeTracking");
- Debug.Assert(xmlSerializable == typeof(System.Xml.Serialization.IXmlSerializable).IsAssignableFrom(dataType), "IXmlSerializable");
- }
- private static Tuple<bool, bool, bool, bool> InspectTypeForInterfaces(Type dataType) {
- Debug.Assert(dataType != null, "Type should not be null");
- return new Tuple<bool,bool,bool,bool>(
- typeof(System.Data.SqlTypes.INullable).IsAssignableFrom(dataType),
- typeof(System.ComponentModel.IChangeTracking).IsAssignableFrom(dataType),
- typeof(System.ComponentModel.IRevertibleChangeTracking).IsAssignableFrom(dataType),
- typeof(System.Xml.Serialization.IXmlSerializable).IsAssignableFrom(dataType));
- }
- internal static bool ImplementsINullableValue(StorageType typeCode, Type dataType) {
- Debug.Assert(typeCode == GetStorageType(dataType), "typeCode mismatches dataType");
- return ((StorageType.Empty == typeCode) && dataType.IsGenericType && (dataType.GetGenericTypeDefinition() == typeof(System.Nullable<>)));
- }
- public static bool IsObjectNull(object value) {
- return ((null == value) || (DBNull.Value == value) || IsObjectSqlNull(value));
- }
- public static bool IsObjectSqlNull(object value) {
- INullable inullable = (value as INullable);
- return ((null != inullable) && inullable.IsNull);
- }
- internal object GetEmptyStorageInternal(int recordCount) {
- return GetEmptyStorage(recordCount);
- }
- internal void CopyValueInternal(int record, object store, BitArray nullbits, int storeIndex) {
- CopyValue(record, store, nullbits, storeIndex);
- }
- internal void SetStorageInternal(object store, BitArray nullbits) {
- SetStorage(store, nullbits);
- }
- abstract protected Object GetEmptyStorage(int recordCount);
- abstract protected void CopyValue(int record, object store, BitArray nullbits, int storeIndex);
- abstract protected void SetStorage(object store, BitArray nullbits);
- protected void SetNullStorage(BitArray nullbits) {
- dbNullBits = nullbits;
- }
- /// <summary>wrapper around Type.GetType</summary>
- /// <param name="value">assembly qualified type name or one of the special known types</param>
- /// <returns>Type or null if not found</returns>
- /// <exception cref="InvalidOperationException">when type implements IDynamicMetaObjectProvider and not IXmlSerializable</exception>
- /// <remarks>
- /// Types like "System.Guid" will load regardless of AssemblyQualifiedName because they are special
- /// Types like "System.Data.SqlTypes.SqlString" will load because they are in the same assembly as this code
- /// Types like "System.Numerics.BigInteger" won't load because they are not special and not same assembly as this code
- /// </remarks>
- internal static Type GetType(string value) {
- Type dataType = Type.GetType(value); // throwOnError=false, ignoreCase=fase
- if (null == dataType) {
- if ("System.Numerics.BigInteger" == value) {
- dataType = typeof(System.Numerics.BigInteger);
- }
- }
- // Dev10 671061: prevent reading type from schema which implements IDynamicMetaObjectProvider and not IXmlSerializable
- // the check here prevents the type from being loaded in schema or as instance data (when DataType is object)
- ObjectStorage.VerifyIDynamicMetaObjectProvider(dataType);
- return dataType;
- }
- /// <summary>wrapper around Type.AssemblyQualifiedName</summary>
- /// <param name="type"></param>
- /// <returns>qualified name when writing in xml</returns>
- /// <exception cref="InvalidOperationException">when type implements IDynamicMetaObjectProvider and not IXmlSerializable</exception>
- internal static string GetQualifiedName(Type type)
- {
- Debug.Assert(null != type, "null type");
- ObjectStorage.VerifyIDynamicMetaObjectProvider(type);
- return type.AssemblyQualifiedName;
- }
- }
- }
|