3 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 using System.Collections;
27 namespace System.Data.Common
29 internal abstract class AbstractDataContainer
41 internal abstract object this[int index] {
46 internal virtual int Capacity {
48 return (_nullValues != null) ? _nullValues.Count : 0;
51 if (_nullValues == null) {
52 _nullValues = new BitArray(value);
55 _nullValues.Length = value;
66 protected DataColumn Column {
72 #endregion //Properties
76 internal static AbstractDataContainer CreateInstance(Type type, DataColumn column)
78 AbstractDataContainer container;
79 switch (Type.GetTypeCode(type)) {
81 container = new Int16DataContainer();
84 container = new Int32DataContainer();
87 container = new Int64DataContainer();
89 case TypeCode.String :
90 container = new StringDataContainer();
92 case TypeCode.Boolean:
93 container = new BitDataContainer();
96 container = new ByteDataContainer();
98 //case TypeCode.Char :
99 case TypeCode.DateTime :
100 container = new DateTimeDataContainer();
102 //case TypeCode.Decimal :
103 case TypeCode.Double :
104 container = new DoubleDataContainer();
106 //case TypeCode.SByte :
107 case TypeCode.Single :
108 container = new SingleDataContainer();
110 //case TypeCode.UInt16 :
111 //case TypeCode.UInt32 :
112 //case TypeCode.UInt64 :
114 container = new ObjectDataContainer();
117 container._type = type;
118 container._column = column;
122 internal bool IsNull(int index)
124 return (_nullValues != null) ? _nullValues[index] : true;
127 internal void SetNullBit(int index,bool isNull)
129 _nullValues[index] = isNull;
132 protected void SetNull(int index,bool isNull,bool isDbNull)
134 SetNullBit(index,isDbNull);
135 // this method must be called after setting the value into value array
136 // otherwise the dafault value will be overriden
138 // set the value to default
139 CopyValue(Column.Table.DefaultValuesRowIndex,index);
143 internal void FillValues(int fromIndex)
145 for(int i=0; i < Capacity; i++) {
146 CopyValue(fromIndex,i);
147 _nullValues[i] = _nullValues[fromIndex];
151 internal virtual void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
153 _nullValues[toIndex] = fromContainer._nullValues[fromIndex];
156 internal virtual void CopyValue(int fromIndex, int toIndex)
158 _nullValues[toIndex] = _nullValues[fromIndex];
161 internal virtual void SetItemFromDataRecord(int index, IDataRecord record, int field)
163 bool isDbNull = record.IsDBNull(field);
164 SetNull(index,false,isDbNull);
167 protected bool CheckAndSetNull( int index, IDataRecord record, int field)
169 bool isDbNull = record.IsDBNull(field);
170 SetNull(index,false,isDbNull);
174 protected int CompareNulls(int index1, int index2)
176 bool null1 = IsNull(index1);
177 bool null2 = IsNull(index2);
179 if ( null1 ^ null2 ) {
180 return null1 ? -1 : 1;
187 internal abstract int CompareValues(int index1, int index2);
189 internal abstract long GetInt64(int index);
193 sealed class Int16DataContainer : AbstractDataContainer
203 internal override object this[int index] {
209 return _values[index];
213 bool isDbNull = (value == DBNull.Value);
214 if (value == null || isDbNull) {
217 else if( value is short ) {
218 SetValue(index,(short)value);
222 SetValue(index,Convert.ToInt16(value));
223 } catch (Exception ex) {
224 throw new ArgumentException (ex.Message, ex);
227 SetNull(index,value == null,isDbNull);
231 internal override int Capacity {
233 base.Capacity = value;
234 if (_values == null) {
235 _values = new short[value];
238 short[] tmp = new short[value];
239 Array.Copy(_values,0,tmp,0,_values.Length);
245 #endregion //Properties
249 private void SetValue(int index, short value)
251 _values[index] = value;
254 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
256 // if exception thrown, it should be caught
257 // in the caller method
258 if (!CheckAndSetNull ( index, record,field))
259 SetValue(index,record.GetInt16(field));
262 internal override void CopyValue(int fromIndex, int toIndex)
264 base.CopyValue(fromIndex, toIndex);
265 _values[toIndex] = _values[fromIndex];
268 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
270 base.CopyValue(fromContainer, fromIndex, toIndex);
271 _values[toIndex] = ((Int16DataContainer)fromContainer)._values[fromIndex];
274 internal override int CompareValues(int index1, int index2)
276 short s1 = _values[index1];
277 short s2 = _values[index2];
279 if ( s1 == 0 && s2 == 0 ) {
280 int cn = CompareNulls(index1, index2);
284 bool b1 = IsNull(index1);
285 bool b2 = IsNull(index2);
287 if ( s1 == 0 && b1 ) {
291 if ( s2 == 0 && b2 ) {
296 return ( s1 != s2 ) ? -1 : 0;
301 internal override long GetInt64(int index)
303 return (long) _values[index];
309 sealed class Int32DataContainer : AbstractDataContainer
319 internal override object this[int index] {
325 return _values[index];
329 bool isDbNull = (value == DBNull.Value);
330 if (value == null || isDbNull) {
333 else if( value is int ) {
334 SetValue(index,(int)value);
337 SetValue(index,Convert.ToInt32(value));
339 SetNull(index,value == null,isDbNull);
343 internal override int Capacity {
345 base.Capacity = value;
346 if (_values == null) {
347 _values = new int[value];
350 int[] tmp = new int[value];
351 Array.Copy(_values,0,tmp,0,_values.Length);
357 #endregion //Properties
361 private void SetValue(int index, int value)
363 _values[index] = value;
366 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
368 // if exception thrown, it should be caught
369 // in the caller method
370 if (!CheckAndSetNull ( index, record,field))
371 SetValue(index,record.GetInt32(field));
374 internal override void CopyValue(int fromIndex, int toIndex)
376 base.CopyValue(fromIndex, toIndex);
377 _values[toIndex] = _values[fromIndex];
380 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
382 base.CopyValue(fromContainer, fromIndex, toIndex);
383 _values[toIndex] = ((Int32DataContainer)fromContainer)._values[fromIndex];
386 internal override int CompareValues(int index1, int index2)
388 int i1 = _values[index1];
389 int i2 = _values[index2];
391 if ( i1 == 0 && i2 == 0 ) {
392 int cn = CompareNulls(index1, index2);
396 bool b1 = IsNull(index1);
397 bool b2 = IsNull(index2);
399 if ( i1 == 0 && b1 ) {
403 if ( i2 == 0 && b2 ) {
408 return ( i1 != i2 ) ? -1 : 0;
413 internal override long GetInt64(int index)
415 return (long) _values[index];
421 sealed class Int64DataContainer : AbstractDataContainer
431 internal override object this[int index] {
437 return _values[index];
441 bool isDbNull = (value == DBNull.Value);
442 if (value == null || isDbNull) {
445 else if( value is long ) {
446 SetValue(index,(long)value);
449 SetValue(index,Convert.ToInt64(value));
451 SetNull(index,value == null,isDbNull);
455 internal override int Capacity {
457 base.Capacity = value;
458 if (_values == null) {
459 _values = new long[value];
462 long[] tmp = new long[value];
463 Array.Copy(_values,0,tmp,0,_values.Length);
469 #endregion //Properties
473 private void SetValue(int index, long value)
475 _values[index] = value;
478 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
480 // if exception thrown, it should be caught
481 // in the caller method
482 if (!CheckAndSetNull ( index, record,field))
483 SetValue(index,record.GetInt64(field));
486 internal override void CopyValue(int fromIndex, int toIndex)
488 base.CopyValue(fromIndex, toIndex);
489 _values[toIndex] = _values[fromIndex];
492 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
494 base.CopyValue(fromContainer, fromIndex, toIndex);
495 _values[toIndex] = ((Int64DataContainer)fromContainer)._values[fromIndex];
498 internal override int CompareValues(int index1, int index2)
500 long l1 = _values[index1];
501 long l2 = _values[index2];
503 if ( l1 == 0 || l2 == 0 ) {
504 int cn = CompareNulls(index1, index2);
511 return ( l1 != l2 ) ? -1 : 0;
516 internal override long GetInt64(int index)
518 return _values[index];
524 sealed class SingleDataContainer : AbstractDataContainer
534 internal override object this[int index] {
540 return _values[index];
544 bool isDbNull = (value == DBNull.Value);
545 if (value == null || isDbNull) {
548 else if( value is float ) {
549 SetValue(index,(float)value);
552 SetValue(index,Convert.ToSingle(value));
554 SetNull(index,value == null,isDbNull);
558 internal override int Capacity {
560 base.Capacity = value;
561 if (_values == null) {
562 _values = new float[value];
565 float[] tmp = new float[value];
566 Array.Copy(_values,0,tmp,0,_values.Length);
572 #endregion //Properties
576 private void SetValue(int index, float value)
578 _values[index] = value;
581 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
583 // if exception thrown, it should be caught
584 // in the caller method
585 if (!CheckAndSetNull ( index, record,field))
586 SetValue(index,record.GetFloat(field));
589 internal override void CopyValue(int fromIndex, int toIndex)
591 base.CopyValue(fromIndex, toIndex);
592 _values[toIndex] = _values[fromIndex];
595 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
597 base.CopyValue(fromContainer, fromIndex, toIndex);
598 _values[toIndex] = ((SingleDataContainer)fromContainer)._values[fromIndex];
601 internal override int CompareValues(int index1, int index2)
603 float f1 = _values[index1];
604 float f2 = _values[index2];
606 if ( f1 == 0 || f2 == 0 ) {
607 int cn = CompareNulls(index1, index2);
614 return ( f1 != f2 ) ? -1 : 0;
619 internal override long GetInt64(int index)
621 return Convert.ToInt64(_values[index]);
627 sealed class DoubleDataContainer : AbstractDataContainer
637 internal override object this[int index] {
643 return _values[index];
647 bool isDbNull = (value == DBNull.Value);
648 if (value == null || isDbNull) {
651 else if( value is double ) {
652 SetValue(index,(double)value);
655 SetValue(index,Convert.ToDouble(value));
657 SetNull(index,value == null,isDbNull);
661 internal override int Capacity {
663 base.Capacity = value;
664 if (_values == null) {
665 _values = new double[value];
668 double[] tmp = new double[value];
669 Array.Copy(_values,0,tmp,0,_values.Length);
675 #endregion //Properties
679 private void SetValue(int index, double value)
681 _values[index] = value;
684 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
686 // if exception thrown, it should be caught
687 // in the caller method
688 if (!CheckAndSetNull ( index, record,field))
689 SetValue(index,record.GetDouble(field));
692 internal override void CopyValue(int fromIndex, int toIndex)
694 base.CopyValue(fromIndex, toIndex);
695 _values[toIndex] = _values[fromIndex];
698 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
700 base.CopyValue(fromContainer, fromIndex, toIndex);
701 _values[toIndex] = ((DoubleDataContainer)fromContainer)._values[fromIndex];
704 internal override int CompareValues(int index1, int index2)
706 double d1 = _values[index1];
707 double d2 = _values[index2];
709 if ( d1 == 0 || d2 == 0 ) {
710 int cn = CompareNulls(index1, index2);
717 return ( d1 != d2 ) ? -1 : 0;
722 internal override long GetInt64(int index)
724 return Convert.ToInt64(_values[index]);
730 sealed class ByteDataContainer : AbstractDataContainer
740 internal override object this[int index] {
746 return _values[index];
750 bool isDbNull = (value == DBNull.Value);
751 if (value == null || isDbNull) {
754 else if( value is byte ) {
755 SetValue(index,(byte)value);
758 SetValue(index,Convert.ToByte(value));
760 SetNull(index,value == null,isDbNull);
764 internal override int Capacity {
766 base.Capacity = value;
767 if (_values == null) {
768 _values = new byte[value];
771 byte[] tmp = new byte[value];
772 Array.Copy(_values,0,tmp,0,_values.Length);
778 #endregion //Properties
782 private void SetValue(int index, byte value)
784 _values[index] = value;
787 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
789 // if exception thrown, it should be caught
790 // in the caller method
791 if (!CheckAndSetNull ( index, record,field))
792 SetValue(index,record.GetByte(field));
795 internal override void CopyValue(int fromIndex, int toIndex)
797 base.CopyValue(fromIndex, toIndex);
798 _values[toIndex] = _values[fromIndex];
801 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
803 base.CopyValue(fromContainer, fromIndex, toIndex);
804 _values[toIndex] = ((ByteDataContainer)fromContainer)._values[fromIndex];
807 internal override int CompareValues(int index1, int index2)
809 byte b1 = _values[index1];
810 byte b2 = _values[index2];
812 if ( b1 == 0 || b2 == 0 ) {
813 int cn = CompareNulls(index1, index2);
820 return ( b1 != b2 ) ? -1 : 0;
825 internal override long GetInt64(int index)
827 return (long) _values[index];
833 sealed class BitDataContainer : AbstractDataContainer
843 internal override object this[int index] {
845 bool isNull = IsNull(index);
850 return _values[index];
854 bool isDbNull = (value == DBNull.Value);
855 if (value == null || isDbNull) {
856 SetValue(index,false);
858 else if( value is bool ) {
859 SetValue(index,(bool)value);
862 SetValue(index,Convert.ToBoolean(value));
864 SetNull(index,value == null,isDbNull);
868 internal override int Capacity {
870 base.Capacity = value;
871 if (_values == null) {
872 _values = new bool[value];
875 bool[] tmp = new bool[value];
876 Array.Copy(_values,0,tmp,0,_values.Length);
882 #endregion //Properties
886 private void SetValue(int index, bool value)
888 _values[index] = value;
891 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
893 // if exception thrown, it should be caught
894 // in the caller method
895 if (!CheckAndSetNull ( index, record,field))
896 SetValue(index,record.GetBoolean(field));
899 internal override void CopyValue(int fromIndex, int toIndex)
901 base.CopyValue(fromIndex, toIndex);
902 _values[toIndex] = _values[fromIndex];
905 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
907 base.CopyValue(fromContainer, fromIndex, toIndex);
908 _values[toIndex] = ((BitDataContainer)fromContainer)._values[fromIndex];
911 internal override int CompareValues(int index1, int index2)
913 bool b1 = _values[index1];
914 bool b2 = _values[index2];
924 return CompareNulls(index1, index2);
927 internal override long GetInt64(int index)
929 return Convert.ToInt64(_values[index]);
935 class ObjectDataContainer : AbstractDataContainer
945 internal override object this[int index] {
947 return _values[index];
950 SetValue(index,value);
951 SetNull(index,value == null,value == DBNull.Value);
955 internal override int Capacity {
957 base.Capacity = value;
958 if (_values == null) {
959 _values = new object[value];
962 object[] tmp = new object[value];
963 Array.Copy(_values,0,tmp,0,_values.Length);
969 #endregion //Properties
973 protected virtual void SetValue(int index, object value)
976 value = Column.DefaultValue;
978 _values[index] = value;
981 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
983 // if exception thrown, it should be caught
984 // in the caller metho
985 SetValue(index,record.GetValue(field));
986 base.SetItemFromDataRecord(index,record,field);
989 internal override void CopyValue(int fromIndex, int toIndex)
991 base.CopyValue(fromIndex, toIndex);
992 _values[toIndex] = _values[fromIndex];
995 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
997 base.CopyValue(fromContainer, fromIndex, toIndex);
998 _values[toIndex] = ((ObjectDataContainer)fromContainer)._values[fromIndex];
1001 internal override int CompareValues(int index1, int index2)
1003 object obj1 = _values[index1];
1004 object obj2 = _values[index2];
1008 else if (obj1 is IComparable) {
1010 return ((IComparable)obj1).CompareTo(obj2);
1016 if (obj2 is IComparable) {
1017 obj2 = Convert.ChangeType(obj2, Type.GetTypeCode(obj1.GetType()));
1018 return ((IComparable)obj1).CompareTo(obj2);
1022 return String.Compare(obj1.ToString(), obj2.ToString());
1025 internal override long GetInt64(int index)
1027 return Convert.ToInt64(_values[index]);
1030 #endregion //Methods
1034 sealed class StringDataContainer : ObjectDataContainer
1038 private void SetValue(int index, string value)
1040 if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length ) {
1041 throw new ArgumentException("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column.");
1043 base.SetValue(index,value);
1046 protected override void SetValue(int index, object value)
1048 if ( value != null && value != DBNull.Value ) {
1049 if ( value is string ) {
1050 SetValue(index, (string) value);
1053 SetValue(index, Convert.ToString(value));
1058 base.SetValue(index, value);
1061 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
1063 // if exception thrown, it should be caught
1064 // in the caller method
1065 if (!CheckAndSetNull ( index, record,field))
1066 SetValue(index,record.GetString(field));
1069 internal override int CompareValues(int index1, int index2)
1071 bool isNull1 = IsNull(index1);
1072 bool isNull2 = IsNull(index2);
1075 return isNull2 ? 0 : -1;
1082 return String.Compare((string)this[index1], (string)this[index2], !Column.Table.CaseSensitive);
1085 #endregion //Methods
1088 sealed class DateTimeDataContainer : ObjectDataContainer
1092 protected override void SetValue(int index, object value)
1094 if ( value != null && value != DBNull.Value && !(value is DateTime)) {
1095 value = Convert.ToDateTime(value);
1098 base.SetValue(index,value);
1101 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
1103 // if exception thrown, it should be caught
1104 // in the caller method
1105 if (!CheckAndSetNull(index,record,field))
1106 base.SetValue(index,record.GetDateTime(field));
1109 internal override int CompareValues(int index1, int index2)
1111 bool isNull1 = IsNull(index1);
1112 bool isNull2 = IsNull(index2);
1115 return isNull2 ? 0 : -1;
1122 return DateTime.Compare((DateTime)this[index1], (DateTime)this[index2]);
1125 #endregion //Methods