using System; using System.Collections; namespace System.Data.Common { internal abstract class AbstractDataContainer { #region Fields BitArray _nullValues; System.Type _type; DataColumn _column; #endregion //Fields #region Properties internal abstract object this[int index] { get; set; } internal virtual int Capacity { get { return (_nullValues != null) ? _nullValues.Count : 0; } set { if (_nullValues == null) { _nullValues = new BitArray(value); } else { _nullValues.Length = value; } } } internal Type Type { get { return _type; } } protected DataColumn Column { get { return _column; } } #endregion //Properties #region Methods internal static AbstractDataContainer CreateInstance(Type type, DataColumn column) { AbstractDataContainer container; switch (Type.GetTypeCode(type)) { case TypeCode.Int16 : container = new Int16DataContainer(); break; case TypeCode.Int32 : container = new Int32DataContainer(); break; case TypeCode.Int64 : container = new Int64DataContainer(); break; case TypeCode.String : container = new StringDataContainer(); break; case TypeCode.Boolean: container = new BitDataContainer(); break; case TypeCode.Byte : container = new ByteDataContainer(); break; //case TypeCode.Char : case TypeCode.DateTime : container = new DateTimeDataContainer(); break; //case TypeCode.Decimal : case TypeCode.Double : container = new DoubleDataContainer(); break; //case TypeCode.SByte : case TypeCode.Single : container = new SingleDataContainer(); break; //case TypeCode.UInt16 : //case TypeCode.UInt32 : //case TypeCode.UInt64 : default : container = new ObjectDataContainer(); break; } container._type = type; container._column = column; return container; } internal bool IsNull(int index) { return (_nullValues != null) ? _nullValues[index] : true; } protected void SetNull(int index,bool isNull) { _nullValues[index] = isNull; } internal virtual void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { _nullValues[toIndex] = fromContainer._nullValues[fromIndex]; } internal virtual void CopyValue(int fromIndex, int toIndex) { _nullValues[toIndex] = _nullValues[fromIndex]; } internal virtual void SetItemFromDataRecord(int index, IDataRecord record, int field) { SetNull(index,record.IsDBNull(field)); } protected int CompareNulls(int index1, int index2) { bool null1 = IsNull(index1); bool null2 = IsNull(index2); if ( null1 ^ null2 ) { return null1 ? -1 : 1; } else { return 0; } } internal abstract int CompareValues(int index1, int index2); #endregion //Methods sealed class Int16DataContainer : AbstractDataContainer { #region Fields short[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { if (IsNull(index)) { return DBNull.Value; } else { return _values[index]; } } set { bool isDbNull = (value == DBNull.Value); if (value == null || isDbNull) { SetValue(index,0); } else if( value is short ) { SetValue(index,(short)value); } else { SetValue(index,Convert.ToInt16(value)); } SetNull(index,isDbNull); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new short[value]; } else { short[] tmp = new short[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods private void SetValue(int index, short value) { _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetInt16(field)); base.SetItemFromDataRecord(index,record,field); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); _values[toIndex] = _values[fromIndex]; } internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { base.CopyValue(fromContainer, fromIndex, toIndex); _values[toIndex] = ((Int16DataContainer)fromContainer)._values[fromIndex]; } internal override int CompareValues(int index1, int index2) { short s1 = _values[index1]; short s2 = _values[index2]; if ( s1 == 0 && s2 == 0 ) { int cn = CompareNulls(index1, index2); return cn; } bool b1 = IsNull(index1); bool b2 = IsNull(index2); if ( s1 == 0 && b1 ) { return -1; } if ( s2 == 0 && b2 ) { return 1; } if ( s1 <= s2 ) { return ( s1 != s2 ) ? -1 : 0; } return 1; } #endregion //Methods } sealed class Int32DataContainer : AbstractDataContainer { #region Fields int[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { if (IsNull(index)) { return DBNull.Value; } else { return _values[index]; } } set { bool isDbNull = (value == DBNull.Value); if (value == null || isDbNull) { SetValue(index,0); } else if( value is int ) { SetValue(index,(int)value); } else { SetValue(index,Convert.ToInt32(value)); } SetNull(index,isDbNull); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new int[value]; } else { int[] tmp = new int[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods private void SetValue(int index, int value) { _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetInt32(field)); base.SetItemFromDataRecord(index,record,field); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); _values[toIndex] = _values[fromIndex]; } internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { base.CopyValue(fromContainer, fromIndex, toIndex); _values[toIndex] = ((Int32DataContainer)fromContainer)._values[fromIndex]; } internal override int CompareValues(int index1, int index2) { int i1 = _values[index1]; int i2 = _values[index2]; if ( i1 == 0 && i2 == 0 ) { int cn = CompareNulls(index1, index2); return cn; } bool b1 = IsNull(index1); bool b2 = IsNull(index2); if ( i1 == 0 && b1 ) { return -1; } if ( i2 == 0 && b2 ) { return 1; } if ( i1 <= i2 ) { return ( i1 != i2 ) ? -1 : 0; } return 1; } #endregion //Methods } sealed class Int64DataContainer : AbstractDataContainer { #region Fields long[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { if (IsNull(index)) { return DBNull.Value; } else { return _values[index]; } } set { bool isDbNull = (value == DBNull.Value); if (value == null || isDbNull) { SetValue(index,0); } else if( value is long ) { SetValue(index,(long)value); } else { SetValue(index,Convert.ToInt64(value)); } SetNull(index,isDbNull); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new long[value]; } else { long[] tmp = new long[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods private void SetValue(int index, long value) { _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetInt64(field)); base.SetItemFromDataRecord(index,record,field); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); _values[toIndex] = _values[fromIndex]; } internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { base.CopyValue(fromContainer, fromIndex, toIndex); _values[toIndex] = ((Int64DataContainer)fromContainer)._values[fromIndex]; } internal override int CompareValues(int index1, int index2) { long l1 = _values[index1]; long l2 = _values[index2]; if ( l1 == 0 || l2 == 0 ) { int cn = CompareNulls(index1, index2); if (cn != 0) { return cn; } } if ( l1 <= l2 ) { return ( l1 != l2 ) ? -1 : 0; } return 1; } #endregion //Methods } sealed class SingleDataContainer : AbstractDataContainer { #region Fields float[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { if (IsNull(index)) { return DBNull.Value; } else { return _values[index]; } } set { bool isDbNull = (value == DBNull.Value); if (value == null || isDbNull) { SetValue(index,0); } else if( value is float ) { SetValue(index,(float)value); } else { SetValue(index,Convert.ToSingle(value)); } SetNull(index,isDbNull); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new float[value]; } else { float[] tmp = new float[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods private void SetValue(int index, float value) { _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetFloat(field)); base.SetItemFromDataRecord(index,record,field); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); _values[toIndex] = _values[fromIndex]; } internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { base.CopyValue(fromContainer, fromIndex, toIndex); _values[toIndex] = ((SingleDataContainer)fromContainer)._values[fromIndex]; } internal override int CompareValues(int index1, int index2) { float f1 = _values[index1]; float f2 = _values[index2]; if ( f1 == 0 || f2 == 0 ) { int cn = CompareNulls(index1, index2); if (cn != 0) { return cn; } } if ( f1 <= f2 ) { return ( f1 != f2 ) ? -1 : 0; } return 1; } #endregion //Methods } sealed class DoubleDataContainer : AbstractDataContainer { #region Fields double[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { if (IsNull(index)) { return DBNull.Value; } else { return _values[index]; } } set { bool isDbNull = (value == DBNull.Value); if (value == null || isDbNull) { SetValue(index,0); } else if( value is double ) { SetValue(index,(double)value); } else { SetValue(index,Convert.ToDouble(value)); } SetNull(index,isDbNull); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new double[value]; } else { double[] tmp = new double[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods private void SetValue(int index, double value) { _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetDouble(field)); base.SetItemFromDataRecord(index,record,field); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); _values[toIndex] = _values[fromIndex]; } internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { base.CopyValue(fromContainer, fromIndex, toIndex); _values[toIndex] = ((DoubleDataContainer)fromContainer)._values[fromIndex]; } internal override int CompareValues(int index1, int index2) { double d1 = _values[index1]; double d2 = _values[index2]; if ( d1 == 0 || d2 == 0 ) { int cn = CompareNulls(index1, index2); if (cn != 0) { return cn; } } if ( d1 <= d2 ) { return ( d1 != d2 ) ? -1 : 0; } return 1; } #endregion //Methods } sealed class ByteDataContainer : AbstractDataContainer { #region Fields byte[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { if (IsNull(index)) { return DBNull.Value; } else { return _values[index]; } } set { bool isDbNull = (value == DBNull.Value); if (value == null || isDbNull) { SetValue(index,0); } else if( value is byte ) { SetValue(index,(byte)value); } else { SetValue(index,Convert.ToByte(value)); } SetNull(index,isDbNull); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new byte[value]; } else { byte[] tmp = new byte[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods private void SetValue(int index, byte value) { _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetByte(field)); base.SetItemFromDataRecord(index,record,field); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); _values[toIndex] = _values[fromIndex]; } internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { base.CopyValue(fromContainer, fromIndex, toIndex); _values[toIndex] = ((ByteDataContainer)fromContainer)._values[fromIndex]; } internal override int CompareValues(int index1, int index2) { byte b1 = _values[index1]; byte b2 = _values[index2]; if ( b1 == 0 || b2 == 0 ) { int cn = CompareNulls(index1, index2); if (cn != 0) { return cn; } } if ( b1 <= b2 ) { return ( b1 != b2 ) ? -1 : 0; } return 1; } #endregion //Methods } sealed class BitDataContainer : AbstractDataContainer { #region Fields bool[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { bool isNull = IsNull(index); if (isNull) { return DBNull.Value; } else { return _values[index]; } } set { bool isDbNull = (value == DBNull.Value); if (value == null || isDbNull) { SetValue(index,false); } else if( value is bool ) { SetValue(index,(bool)value); } else { SetValue(index,Convert.ToBoolean(value)); } SetNull(index,isDbNull); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new bool[value]; } else { bool[] tmp = new bool[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods private void SetValue(int index, bool value) { _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetBoolean(field)); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); } internal override int CompareValues(int index1, int index2) { bool b1 = _values[index1]; bool b2 = _values[index2]; if ( b1 ^ b2 ) { return b1 ? 1 : -1; } if ( b1 ) { return 0; } return CompareNulls(index1, index2); } #endregion //Methods } class ObjectDataContainer : AbstractDataContainer { #region Fields object[] _values; #endregion //Fields #region Properties internal override object this[int index] { get { return _values[index]; } set { SetValue(index,value); SetNull(index,value == DBNull.Value); } } internal override int Capacity { set { base.Capacity = value; if (_values == null) { _values = new object[value]; } else { object[] tmp = new object[value]; Array.Copy(_values,0,tmp,0,_values.Length); _values = tmp; } } } #endregion //Properties #region Methods protected virtual void SetValue(int index, object value) { if(value == null) { value = Column.DefaultValue; } _values[index] = value; } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetValue(field)); base.SetItemFromDataRecord(index,record,field); } internal override void CopyValue(int fromIndex, int toIndex) { base.CopyValue(fromIndex, toIndex); _values[toIndex] = _values[fromIndex]; } internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex) { base.CopyValue(fromContainer, fromIndex, toIndex); _values[toIndex] = ((ObjectDataContainer)fromContainer)._values[fromIndex]; } internal override int CompareValues(int index1, int index2) { object obj1 = _values[index1]; object obj2 = _values[index2]; if(obj1 == obj2) { return 0; } else if (obj1 is IComparable) { try { return ((IComparable)obj1).CompareTo(obj2); } catch { //just suppress } if (obj2 is IComparable) { obj2 = Convert.ChangeType(obj2, Type.GetTypeCode(obj1.GetType())); return ((IComparable)obj1).CompareTo(obj2); } } return String.Compare(obj1.ToString(), obj2.ToString()); } #endregion //Methods } sealed class StringDataContainer : ObjectDataContainer { #region Methods private void SetValue(int index, string value) { if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length ) { throw new ArgumentException("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column."); } base.SetValue(index,value); } protected override void SetValue(int index, object value) { if ( value != null && value != DBNull.Value ) { if ( value is string ) { SetValue(index, (string) value); } else { SetValue(index, Convert.ToString(value)); } return; } base.SetValue(index, value); } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method SetValue(index,record.GetString(field)); base.SetItemFromDataRecord(index,record,field); } internal override int CompareValues(int index1, int index2) { bool isNull1 = IsNull(index1); bool isNull2 = IsNull(index2); if (isNull1) { return isNull2 ? 0 : -1; } else { if (isNull2) { return 1; } } return String.Compare((string)this[index1], (string)this[index2], !Column.Table.CaseSensitive); } #endregion //Methods } sealed class DateTimeDataContainer : ObjectDataContainer { #region Methods protected override void SetValue(int index, object value) { if ( value != null && value != DBNull.Value && !(value is DateTime)) { value = Convert.ToDateTime(value); } base.SetValue(index,value); } internal override void SetItemFromDataRecord(int index, IDataRecord record, int field) { // if exception thrown, it should be caught // in the caller method base.SetValue(index,record.GetDateTime(field)); base.SetItemFromDataRecord(index,record,field); } internal override int CompareValues(int index1, int index2) { bool isNull1 = IsNull(index1); bool isNull2 = IsNull(index2); if (isNull1) { return isNull2 ? 0 : -1; } else { if (isNull2) { return 1; } } return DateTime.Compare((DateTime)this[index1], (DateTime)this[index2]); } #endregion //Methods } } }