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);
221 SetValue(index,Convert.ToInt16(value));
223 SetNull(index,value == null,isDbNull);
227 internal override int Capacity {
229 base.Capacity = value;
230 if (_values == null) {
231 _values = new short[value];
234 short[] tmp = new short[value];
235 Array.Copy(_values,0,tmp,0,_values.Length);
241 #endregion //Properties
245 private void SetValue(int index, short value)
247 _values[index] = value;
250 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
252 // if exception thrown, it should be caught
253 // in the caller method
254 if (!CheckAndSetNull ( index, record,field))
255 SetValue(index,record.GetInt16(field));
258 internal override void CopyValue(int fromIndex, int toIndex)
260 base.CopyValue(fromIndex, toIndex);
261 _values[toIndex] = _values[fromIndex];
264 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
266 base.CopyValue(fromContainer, fromIndex, toIndex);
267 _values[toIndex] = ((Int16DataContainer)fromContainer)._values[fromIndex];
270 internal override int CompareValues(int index1, int index2)
272 short s1 = _values[index1];
273 short s2 = _values[index2];
275 if ( s1 == 0 && s2 == 0 ) {
276 int cn = CompareNulls(index1, index2);
280 bool b1 = IsNull(index1);
281 bool b2 = IsNull(index2);
283 if ( s1 == 0 && b1 ) {
287 if ( s2 == 0 && b2 ) {
292 return ( s1 != s2 ) ? -1 : 0;
297 internal override long GetInt64(int index)
299 return (long) _values[index];
305 sealed class Int32DataContainer : AbstractDataContainer
315 internal override object this[int index] {
321 return _values[index];
325 bool isDbNull = (value == DBNull.Value);
326 if (value == null || isDbNull) {
329 else if( value is int ) {
330 SetValue(index,(int)value);
333 SetValue(index,Convert.ToInt32(value));
335 SetNull(index,value == null,isDbNull);
339 internal override int Capacity {
341 base.Capacity = value;
342 if (_values == null) {
343 _values = new int[value];
346 int[] tmp = new int[value];
347 Array.Copy(_values,0,tmp,0,_values.Length);
353 #endregion //Properties
357 private void SetValue(int index, int value)
359 _values[index] = value;
362 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
364 // if exception thrown, it should be caught
365 // in the caller method
366 if (!CheckAndSetNull ( index, record,field))
367 SetValue(index,record.GetInt32(field));
370 internal override void CopyValue(int fromIndex, int toIndex)
372 base.CopyValue(fromIndex, toIndex);
373 _values[toIndex] = _values[fromIndex];
376 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
378 base.CopyValue(fromContainer, fromIndex, toIndex);
379 _values[toIndex] = ((Int32DataContainer)fromContainer)._values[fromIndex];
382 internal override int CompareValues(int index1, int index2)
384 int i1 = _values[index1];
385 int i2 = _values[index2];
387 if ( i1 == 0 && i2 == 0 ) {
388 int cn = CompareNulls(index1, index2);
392 bool b1 = IsNull(index1);
393 bool b2 = IsNull(index2);
395 if ( i1 == 0 && b1 ) {
399 if ( i2 == 0 && b2 ) {
404 return ( i1 != i2 ) ? -1 : 0;
409 internal override long GetInt64(int index)
411 return (long) _values[index];
417 sealed class Int64DataContainer : AbstractDataContainer
427 internal override object this[int index] {
433 return _values[index];
437 bool isDbNull = (value == DBNull.Value);
438 if (value == null || isDbNull) {
441 else if( value is long ) {
442 SetValue(index,(long)value);
445 SetValue(index,Convert.ToInt64(value));
447 SetNull(index,value == null,isDbNull);
451 internal override int Capacity {
453 base.Capacity = value;
454 if (_values == null) {
455 _values = new long[value];
458 long[] tmp = new long[value];
459 Array.Copy(_values,0,tmp,0,_values.Length);
465 #endregion //Properties
469 private void SetValue(int index, long value)
471 _values[index] = value;
474 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
476 // if exception thrown, it should be caught
477 // in the caller method
478 if (!CheckAndSetNull ( index, record,field))
479 SetValue(index,record.GetInt64(field));
482 internal override void CopyValue(int fromIndex, int toIndex)
484 base.CopyValue(fromIndex, toIndex);
485 _values[toIndex] = _values[fromIndex];
488 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
490 base.CopyValue(fromContainer, fromIndex, toIndex);
491 _values[toIndex] = ((Int64DataContainer)fromContainer)._values[fromIndex];
494 internal override int CompareValues(int index1, int index2)
496 long l1 = _values[index1];
497 long l2 = _values[index2];
499 if ( l1 == 0 || l2 == 0 ) {
500 int cn = CompareNulls(index1, index2);
507 return ( l1 != l2 ) ? -1 : 0;
512 internal override long GetInt64(int index)
514 return _values[index];
520 sealed class SingleDataContainer : AbstractDataContainer
530 internal override object this[int index] {
536 return _values[index];
540 bool isDbNull = (value == DBNull.Value);
541 if (value == null || isDbNull) {
544 else if( value is float ) {
545 SetValue(index,(float)value);
548 SetValue(index,Convert.ToSingle(value));
550 SetNull(index,value == null,isDbNull);
554 internal override int Capacity {
556 base.Capacity = value;
557 if (_values == null) {
558 _values = new float[value];
561 float[] tmp = new float[value];
562 Array.Copy(_values,0,tmp,0,_values.Length);
568 #endregion //Properties
572 private void SetValue(int index, float value)
574 _values[index] = value;
577 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
579 // if exception thrown, it should be caught
580 // in the caller method
581 if (!CheckAndSetNull ( index, record,field))
582 SetValue(index,record.GetFloat(field));
585 internal override void CopyValue(int fromIndex, int toIndex)
587 base.CopyValue(fromIndex, toIndex);
588 _values[toIndex] = _values[fromIndex];
591 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
593 base.CopyValue(fromContainer, fromIndex, toIndex);
594 _values[toIndex] = ((SingleDataContainer)fromContainer)._values[fromIndex];
597 internal override int CompareValues(int index1, int index2)
599 float f1 = _values[index1];
600 float f2 = _values[index2];
602 if ( f1 == 0 || f2 == 0 ) {
603 int cn = CompareNulls(index1, index2);
610 return ( f1 != f2 ) ? -1 : 0;
615 internal override long GetInt64(int index)
617 return Convert.ToInt64(_values[index]);
623 sealed class DoubleDataContainer : AbstractDataContainer
633 internal override object this[int index] {
639 return _values[index];
643 bool isDbNull = (value == DBNull.Value);
644 if (value == null || isDbNull) {
647 else if( value is double ) {
648 SetValue(index,(double)value);
651 SetValue(index,Convert.ToDouble(value));
653 SetNull(index,value == null,isDbNull);
657 internal override int Capacity {
659 base.Capacity = value;
660 if (_values == null) {
661 _values = new double[value];
664 double[] tmp = new double[value];
665 Array.Copy(_values,0,tmp,0,_values.Length);
671 #endregion //Properties
675 private void SetValue(int index, double value)
677 _values[index] = value;
680 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
682 // if exception thrown, it should be caught
683 // in the caller method
684 if (!CheckAndSetNull ( index, record,field))
685 SetValue(index,record.GetDouble(field));
688 internal override void CopyValue(int fromIndex, int toIndex)
690 base.CopyValue(fromIndex, toIndex);
691 _values[toIndex] = _values[fromIndex];
694 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
696 base.CopyValue(fromContainer, fromIndex, toIndex);
697 _values[toIndex] = ((DoubleDataContainer)fromContainer)._values[fromIndex];
700 internal override int CompareValues(int index1, int index2)
702 double d1 = _values[index1];
703 double d2 = _values[index2];
705 if ( d1 == 0 || d2 == 0 ) {
706 int cn = CompareNulls(index1, index2);
713 return ( d1 != d2 ) ? -1 : 0;
718 internal override long GetInt64(int index)
720 return Convert.ToInt64(_values[index]);
726 sealed class ByteDataContainer : AbstractDataContainer
736 internal override object this[int index] {
742 return _values[index];
746 bool isDbNull = (value == DBNull.Value);
747 if (value == null || isDbNull) {
750 else if( value is byte ) {
751 SetValue(index,(byte)value);
754 SetValue(index,Convert.ToByte(value));
756 SetNull(index,value == null,isDbNull);
760 internal override int Capacity {
762 base.Capacity = value;
763 if (_values == null) {
764 _values = new byte[value];
767 byte[] tmp = new byte[value];
768 Array.Copy(_values,0,tmp,0,_values.Length);
774 #endregion //Properties
778 private void SetValue(int index, byte value)
780 _values[index] = value;
783 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
785 // if exception thrown, it should be caught
786 // in the caller method
787 if (!CheckAndSetNull ( index, record,field))
788 SetValue(index,record.GetByte(field));
791 internal override void CopyValue(int fromIndex, int toIndex)
793 base.CopyValue(fromIndex, toIndex);
794 _values[toIndex] = _values[fromIndex];
797 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
799 base.CopyValue(fromContainer, fromIndex, toIndex);
800 _values[toIndex] = ((ByteDataContainer)fromContainer)._values[fromIndex];
803 internal override int CompareValues(int index1, int index2)
805 byte b1 = _values[index1];
806 byte b2 = _values[index2];
808 if ( b1 == 0 || b2 == 0 ) {
809 int cn = CompareNulls(index1, index2);
816 return ( b1 != b2 ) ? -1 : 0;
821 internal override long GetInt64(int index)
823 return (long) _values[index];
829 sealed class BitDataContainer : AbstractDataContainer
839 internal override object this[int index] {
841 bool isNull = IsNull(index);
846 return _values[index];
850 bool isDbNull = (value == DBNull.Value);
851 if (value == null || isDbNull) {
852 SetValue(index,false);
854 else if( value is bool ) {
855 SetValue(index,(bool)value);
858 SetValue(index,Convert.ToBoolean(value));
860 SetNull(index,value == null,isDbNull);
864 internal override int Capacity {
866 base.Capacity = value;
867 if (_values == null) {
868 _values = new bool[value];
871 bool[] tmp = new bool[value];
872 Array.Copy(_values,0,tmp,0,_values.Length);
878 #endregion //Properties
882 private void SetValue(int index, bool value)
884 _values[index] = value;
887 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
889 // if exception thrown, it should be caught
890 // in the caller method
891 if (!CheckAndSetNull ( index, record,field))
892 SetValue(index,record.GetBoolean(field));
895 internal override void CopyValue(int fromIndex, int toIndex)
897 base.CopyValue(fromIndex, toIndex);
898 _values[toIndex] = _values[fromIndex];
901 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
903 base.CopyValue(fromContainer, fromIndex, toIndex);
904 _values[toIndex] = ((BitDataContainer)fromContainer)._values[fromIndex];
907 internal override int CompareValues(int index1, int index2)
909 bool b1 = _values[index1];
910 bool b2 = _values[index2];
920 return CompareNulls(index1, index2);
923 internal override long GetInt64(int index)
925 return Convert.ToInt64(_values[index]);
931 class ObjectDataContainer : AbstractDataContainer
941 internal override object this[int index] {
943 return _values[index];
946 SetValue(index,value);
947 SetNull(index,value == null,value == DBNull.Value);
951 internal override int Capacity {
953 base.Capacity = value;
954 if (_values == null) {
955 _values = new object[value];
958 object[] tmp = new object[value];
959 Array.Copy(_values,0,tmp,0,_values.Length);
965 #endregion //Properties
969 protected virtual void SetValue(int index, object value)
972 value = Column.DefaultValue;
974 _values[index] = value;
977 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
979 // if exception thrown, it should be caught
980 // in the caller metho
981 SetValue(index,record.GetValue(field));
982 base.SetItemFromDataRecord(index,record,field);
985 internal override void CopyValue(int fromIndex, int toIndex)
987 base.CopyValue(fromIndex, toIndex);
988 _values[toIndex] = _values[fromIndex];
991 internal override void CopyValue(AbstractDataContainer fromContainer, int fromIndex, int toIndex)
993 base.CopyValue(fromContainer, fromIndex, toIndex);
994 _values[toIndex] = ((ObjectDataContainer)fromContainer)._values[fromIndex];
997 internal override int CompareValues(int index1, int index2)
999 object obj1 = _values[index1];
1000 object obj2 = _values[index2];
1004 else if (obj1 is IComparable) {
1006 return ((IComparable)obj1).CompareTo(obj2);
1012 if (obj2 is IComparable) {
1013 obj2 = Convert.ChangeType(obj2, Type.GetTypeCode(obj1.GetType()));
1014 return ((IComparable)obj1).CompareTo(obj2);
1018 return String.Compare(obj1.ToString(), obj2.ToString());
1021 internal override long GetInt64(int index)
1023 return Convert.ToInt64(_values[index]);
1026 #endregion //Methods
1030 sealed class StringDataContainer : ObjectDataContainer
1034 private void SetValue(int index, string value)
1036 if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length ) {
1037 throw new ArgumentException("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column.");
1039 base.SetValue(index,value);
1042 protected override void SetValue(int index, object value)
1044 if ( value != null && value != DBNull.Value ) {
1045 if ( value is string ) {
1046 SetValue(index, (string) value);
1049 SetValue(index, Convert.ToString(value));
1054 base.SetValue(index, value);
1057 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
1059 // if exception thrown, it should be caught
1060 // in the caller method
1061 if (!CheckAndSetNull ( index, record,field))
1062 SetValue(index,record.GetString(field));
1065 internal override int CompareValues(int index1, int index2)
1067 bool isNull1 = IsNull(index1);
1068 bool isNull2 = IsNull(index2);
1071 return isNull2 ? 0 : -1;
1078 return String.Compare((string)this[index1], (string)this[index2], !Column.Table.CaseSensitive);
1081 #endregion //Methods
1084 sealed class DateTimeDataContainer : ObjectDataContainer
1088 protected override void SetValue(int index, object value)
1090 if ( value != null && value != DBNull.Value && !(value is DateTime)) {
1091 value = Convert.ToDateTime(value);
1094 base.SetValue(index,value);
1097 internal override void SetItemFromDataRecord(int index, IDataRecord record, int field)
1099 // if exception thrown, it should be caught
1100 // in the caller method
1101 if (!CheckAndSetNull(index,record,field))
1102 base.SetValue(index,record.GetDateTime(field));
1105 internal override int CompareValues(int index1, int index2)
1107 bool isNull1 = IsNull(index1);
1108 bool isNull2 = IsNull(index2);
1111 return isNull2 ? 0 : -1;
1118 return DateTime.Compare((DateTime)this[index1], (DateTime)this[index2]);
1121 #endregion //Methods