2 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 using System.Collections;
25 using System.Reflection;
27 using System.Reflection.Emit;
30 namespace System.Data.Common
32 internal abstract class DataContainer {
37 // implementing class protocol
38 protected internal abstract object GetValue (int index);
39 internal abstract long GetInt64 (int index);
41 // used to set the array value to something neutral when the corresponding item is null (in the database sense)
42 // note: we don't actually ever look at the value written there, but the GC may like us to avoid keeping stale
43 // values in the array.
44 protected abstract void ZeroOut (int index);
45 protected abstract void SetValue (int index, object value);
46 protected abstract void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field);
48 protected abstract void DoCopyValue (DataContainer from, int from_index, int to_index);
49 protected abstract int DoCompareValues (int index1, int index2);
51 protected abstract void Resize (int length);
53 internal object this [int index] {
54 get { return IsNull (index) ? DBNull.Value : GetValue (index); }
57 CopyValue (Column.Table.DefaultValuesRowIndex, index);
61 bool is_dbnull = value == DBNull.Value;
65 SetValue (index, value);
66 null_values [index] = is_dbnull;
70 internal int Capacity {
71 get { return null_values != null ? null_values.Count : 0; }
73 int old_capacity = Capacity;
74 if (value == old_capacity)
76 if (null_values == null)
77 null_values = new BitArray (value);
79 null_values.Length = value;
88 protected DataColumn Column {
89 get { return _column; }
92 internal static DataContainer Create (Type type, DataColumn column)
94 DataContainer container;
95 switch (Type.GetTypeCode(type)) {
97 container = new Int16DataContainer ();
100 container = new Int32DataContainer ();
103 container = new Int64DataContainer ();
105 case TypeCode.String:
106 container = new StringDataContainer ();
108 case TypeCode.Boolean:
109 container = new BitDataContainer ();
112 container = new ByteDataContainer ();
115 container = new CharDataContainer ();
117 case TypeCode.Double:
118 container = new DoubleDataContainer ();
121 container = new SByteDataContainer ();
123 case TypeCode.Single:
124 container = new SingleDataContainer ();
126 case TypeCode.UInt16:
127 container = new UInt16DataContainer ();
129 case TypeCode.UInt32:
130 container = new UInt32DataContainer ();
132 case TypeCode.UInt64:
133 container = new UInt64DataContainer ();
135 case TypeCode.DateTime:
136 container = new DateTimeDataContainer ();
138 case TypeCode.Decimal:
139 container = new DecimalDataContainer ();
142 container = new ObjectDataContainer ();
145 container._type = type;
146 container._column = column;
150 internal static object GetExplicitValue (object value)
152 Type valueType = value.GetType ();
153 MethodInfo method = valueType.GetMethod ("op_Explicit", new Type[]{valueType});
155 return (method.Invoke (value, new object[]{value}));
159 internal object GetContainerData (object value)
167 if (_type.IsInstanceOfType (value)) {
169 } else if ((tc = Type.GetTypeCode (_type)) == TypeCode.String) {
170 return (Convert.ToString (value));
171 } else if (value is IConvertible) {
174 return (Convert.ToInt16 (value));
176 return (Convert.ToInt32 (value));
178 return (Convert.ToInt64 (value));
179 case TypeCode.Boolean:
180 return (Convert.ToBoolean (value));
182 return (Convert.ToByte (value));
184 return (Convert.ToChar (value));
185 case TypeCode.Double:
186 return (Convert.ToDouble (value));
188 return (Convert.ToSByte (value));
189 case TypeCode.Single:
190 return (Convert.ToSingle (value));
191 case TypeCode.UInt16:
192 return (Convert.ToUInt16 (value));
193 case TypeCode.UInt32:
194 return (Convert.ToUInt32 (value));
195 case TypeCode.UInt64:
196 return (Convert.ToUInt64 (value));
197 case TypeCode.DateTime:
198 if (value == DBNull.Value)
200 return (Convert.ToDateTime (value));
201 case TypeCode.Decimal:
202 return (Convert.ToDecimal (value));
204 throw new InvalidCastException (string.Format ("Cannot convert from {0} to {1}", value.GetType ().FullName, _type.FullName));
206 } else if ((obj = GetExplicitValue (value)) != null) {
209 throw new InvalidCastException ();
213 internal bool IsNull (int index)
215 return null_values == null || null_values [index];
218 internal void FillValues (int fromIndex)
220 for (int i = 0; i < Capacity; i++)
221 CopyValue (fromIndex, i);
224 internal void CopyValue (int from_index, int to_index)
226 CopyValue (this, from_index, to_index);
229 internal void CopyValue (DataContainer from, int from_index, int to_index)
231 DoCopyValue (from, from_index, to_index);
232 null_values [to_index] = from.null_values [from_index];
235 internal void SetItemFromDataRecord (int index, IDataRecord record, int field)
237 if (record.IsDBNull (field))
238 this [index] = DBNull.Value;
239 else if (record is ISafeDataRecord)
240 SetValueFromSafeDataRecord (index, (ISafeDataRecord) record, field);
242 this [index] = record.GetValue (field);
245 internal int CompareValues (int index1, int index2)
247 bool null1 = IsNull (index1);
248 bool null2 = IsNull (index2);
251 return null1 ? 0 : DoCompareValues (index1, index2);
252 return null1 ? -1 : 1;
256 sealed class BitDataContainer : DataContainer {
259 protected internal override object GetValue (int index)
261 return _values [index];
264 protected override void ZeroOut (int index)
266 _values [index] = false;
269 protected override void SetValue (int index, object value)
271 _values [index] = (bool) GetContainerData (value);
274 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
276 _values [index] = record.GetBooleanSafe (field);
279 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
281 _values [to_index] = (bool) GetContainerData (from.GetValue (from_index));
284 protected override int DoCompareValues (int index1, int index2)
286 bool val1 = _values [index1];
287 bool val2 = _values [index2];
288 return val1 == val2 ? 0 : val1 ? 1 : -1;
291 protected override void Resize (int size)
294 _values = new BitArray (size);
296 _values.Length = size;
299 internal override long GetInt64 (int index)
301 return Convert.ToInt64 (_values [index]);
305 sealed class CharDataContainer : DataContainer {
308 protected internal override object GetValue (int index)
310 return _values [index];
313 protected override void ZeroOut (int index)
315 _values [index] = '\0';
318 protected override void SetValue (int index, object value)
320 _values [index] = (char) GetContainerData (value);
323 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
325 _values [index] = record.GetCharSafe (field);
328 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
330 _values [to_index] = (char) GetContainerData (from.GetValue (from_index));
333 protected override int DoCompareValues (int index1, int index2)
335 char val1 = _values [index1];
336 char val2 = _values [index2];
337 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
340 protected override void Resize (int size)
342 if (_values == null) {
343 _values = new char [size];
347 char[] tmp = new char [size];
348 Array.Copy (_values, 0, tmp, 0, _values.Length);
352 internal override long GetInt64 (int index)
354 return Convert.ToInt64 (_values [index]);
358 sealed class ByteDataContainer : DataContainer {
361 protected internal override object GetValue (int index)
363 return _values [index];
366 protected override void ZeroOut (int index)
371 protected override void SetValue (int index, object value)
373 _values [index] = (byte) GetContainerData (value);
376 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
378 _values [index] = record.GetByteSafe (field);
381 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
383 _values [to_index] = (byte) GetContainerData (from.GetValue (from_index));
386 protected override int DoCompareValues (int index1, int index2)
388 int val1 = _values [index1];
389 int val2 = _values [index2];
393 protected override void Resize (int size)
395 if (_values == null) {
396 _values = new byte [size];
400 byte[] tmp = new byte [size];
401 Array.Copy (_values, 0, tmp, 0, _values.Length);
405 internal override long GetInt64 (int index)
407 return _values [index];
411 sealed class SByteDataContainer : DataContainer {
414 protected internal override object GetValue (int index)
416 return _values [index];
419 protected override void ZeroOut (int index)
424 protected override void SetValue (int index, object value)
426 _values [index] = (sbyte) GetContainerData (value);
429 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
431 _values [index] = (sbyte) record.GetByteSafe (field);
434 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
436 _values [to_index] = (sbyte) GetContainerData (from.GetValue (from_index));
439 protected override int DoCompareValues (int index1, int index2)
441 int val1 = _values [index1];
442 int val2 = _values [index2];
446 protected override void Resize (int size)
448 if (_values == null) {
449 _values = new sbyte [size];
453 sbyte[] tmp = new sbyte [size];
454 Array.Copy (_values, 0, tmp, 0, _values.Length);
458 internal override long GetInt64 (int index)
460 return _values [index];
464 sealed class Int16DataContainer : DataContainer {
467 protected internal override object GetValue (int index)
469 return _values [index];
472 protected override void ZeroOut (int index)
477 protected override void SetValue (int index, object value)
479 _values [index] = (short) GetContainerData (value);
482 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
484 _values [index] = record.GetInt16Safe (field);
487 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
489 _values [to_index] = (short) GetContainerData (from.GetValue (from_index));
492 protected override int DoCompareValues (int index1, int index2)
494 int val1 = _values [index1];
495 int val2 = _values [index2];
499 protected override void Resize (int size)
501 if (_values == null) {
502 _values = new short [size];
506 short[] tmp = new short [size];
507 Array.Copy (_values, 0, tmp, 0, _values.Length);
511 internal override long GetInt64 (int index)
513 return _values [index];
517 sealed class UInt16DataContainer : DataContainer {
520 protected internal override object GetValue (int index)
522 return _values [index];
525 protected override void ZeroOut (int index)
530 protected override void SetValue (int index, object value)
532 _values [index] = (ushort) GetContainerData (value);
535 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
537 _values [index] = (ushort) record.GetInt16Safe (field);
540 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
542 _values [to_index] = (ushort) GetContainerData (from.GetValue (from_index));
545 protected override int DoCompareValues (int index1, int index2)
547 int val1 = _values [index1];
548 int val2 = _values [index2];
552 protected override void Resize (int size)
554 if (_values == null) {
555 _values = new ushort [size];
559 ushort[] tmp = new ushort [size];
560 Array.Copy (_values, 0, tmp, 0, _values.Length);
564 internal override long GetInt64 (int index)
566 return _values [index];
570 sealed class Int32DataContainer : DataContainer {
573 protected internal override object GetValue (int index)
575 return _values [index];
578 protected override void ZeroOut (int index)
583 protected override void SetValue (int index, object value)
585 _values [index] = (int) GetContainerData (value);
588 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
590 _values [index] = record.GetInt32Safe (field);
593 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
595 _values [to_index] = (int) GetContainerData (from.GetValue (from_index));
598 protected override int DoCompareValues (int index1, int index2)
600 int val1 = _values [index1];
601 int val2 = _values [index2];
602 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
605 protected override void Resize (int size)
607 if (_values == null) {
608 _values = new int [size];
612 int[] tmp = new int [size];
613 Array.Copy (_values, 0, tmp, 0, _values.Length);
617 internal override long GetInt64 (int index)
619 return _values [index];
623 sealed class UInt32DataContainer : DataContainer {
626 protected internal override object GetValue (int index)
628 return _values [index];
631 protected override void ZeroOut (int index)
636 protected override void SetValue (int index, object value)
638 _values [index] = (uint) GetContainerData (value);
641 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
643 _values [index] = (uint) record.GetInt32Safe (field);
646 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
648 _values [to_index] = (uint) GetContainerData (from.GetValue (from_index));
651 protected override int DoCompareValues (int index1, int index2)
653 uint val1 = _values [index1];
654 uint val2 = _values [index2];
655 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
658 protected override void Resize (int size)
660 if (_values == null) {
661 _values = new uint [size];
665 uint[] tmp = new uint [size];
666 Array.Copy (_values, 0, tmp, 0, _values.Length);
670 internal override long GetInt64 (int index)
672 return _values [index];
676 sealed class Int64DataContainer : DataContainer {
679 protected internal override object GetValue (int index)
681 return _values [index];
684 protected override void ZeroOut (int index)
689 protected override void SetValue (int index, object value)
691 _values [index] = (long) GetContainerData (value);
694 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
696 _values [index] = record.GetInt64Safe (field);
699 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
701 _values [to_index] = (long) GetContainerData (from.GetValue (from_index));
704 protected override int DoCompareValues (int index1, int index2)
706 long val1 = _values [index1];
707 long val2 = _values [index2];
708 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
711 protected override void Resize (int size)
713 if (_values == null) {
714 _values = new long [size];
718 long[] tmp = new long [size];
719 Array.Copy (_values, 0, tmp, 0, _values.Length);
723 internal override long GetInt64 (int index)
725 return _values [index];
729 sealed class UInt64DataContainer : DataContainer {
732 protected internal override object GetValue (int index)
734 return _values [index];
737 protected override void ZeroOut (int index)
742 protected override void SetValue (int index, object value)
744 _values [index] = (ulong) GetContainerData (value);
747 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
749 _values [index] = (ulong) record.GetInt64Safe (field);
752 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
754 _values [to_index] = (ulong) GetContainerData (from.GetValue (from_index));
757 protected override int DoCompareValues (int index1, int index2)
759 ulong val1 = _values [index1];
760 ulong val2 = _values [index2];
761 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
764 protected override void Resize (int size)
766 if (_values == null) {
767 _values = new ulong [size];
771 ulong[] tmp = new ulong [size];
772 Array.Copy (_values, 0, tmp, 0, _values.Length);
776 internal override long GetInt64 (int index)
778 return Convert.ToInt64 (_values [index]);
782 sealed class SingleDataContainer : DataContainer {
785 protected internal override object GetValue (int index)
787 return _values [index];
790 protected override void ZeroOut (int index)
795 protected override void SetValue (int index, object value)
797 _values [index] = (float) GetContainerData (value);
800 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
802 _values [index] = record.GetFloatSafe (field);
805 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
807 _values [to_index] = (float) GetContainerData (from.GetValue (from_index));
810 protected override int DoCompareValues (int index1, int index2)
812 float val1 = _values [index1];
813 float val2 = _values [index2];
814 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
817 protected override void Resize (int size)
819 if (_values == null) {
820 _values = new float [size];
824 float[] tmp = new float [size];
825 Array.Copy (_values, 0, tmp, 0, _values.Length);
829 internal override long GetInt64 (int index)
831 return Convert.ToInt64 (_values [index]);
835 sealed class DoubleDataContainer : DataContainer {
838 protected internal override object GetValue (int index)
840 return _values [index];
843 protected override void ZeroOut (int index)
848 protected override void SetValue (int index, object value)
850 _values [index] = (double) GetContainerData (value);
853 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
855 _values [index] = record.GetDoubleSafe (field);
858 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
860 _values [to_index] = (double) GetContainerData (from.GetValue (from_index));
863 protected override int DoCompareValues (int index1, int index2)
865 double val1 = _values [index1];
866 double val2 = _values [index2];
867 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
870 protected override void Resize (int size)
872 if (_values == null) {
873 _values = new double [size];
877 double[] tmp = new double [size];
878 Array.Copy (_values, 0, tmp, 0, _values.Length);
882 internal override long GetInt64 (int index)
884 return Convert.ToInt64 (_values[index]);
888 class ObjectDataContainer : DataContainer {
891 protected internal override object GetValue (int index)
893 return _values [index];
896 protected override void ZeroOut (int index)
898 _values [index] = null;
901 protected override void SetValue (int index, object value)
903 _values [index] = value;
906 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
908 _values [index] = record.GetValue (field);
911 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
913 _values [to_index] = GetContainerData (from.GetValue (from_index));
916 protected override int DoCompareValues (int index1, int index2)
918 object obj1 = _values [index1];
919 object obj2 = _values [index2];
924 if (obj1 is IComparable) {
926 return ((IComparable)obj1).CompareTo (obj2);
928 if (obj2 is IComparable) {
929 obj2 = Convert.ChangeType (obj2, Type.GetTypeCode (obj1.GetType ()));
930 return ((IComparable)obj1).CompareTo (obj2);
935 return String.Compare (obj1.ToString (), obj2.ToString ());
938 protected override void Resize (int size)
940 if (_values == null) {
941 _values = new object [size];
945 object[] tmp = new object [size];
946 Array.Copy (_values, 0, tmp, 0, _values.Length);
950 internal override long GetInt64 (int index)
952 return Convert.ToInt64 (_values [index]);
956 sealed class DateTimeDataContainer : ObjectDataContainer {
957 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
959 base.SetValue (index, record.GetDateTimeSafe (field));
962 protected override void SetValue (int index, object value)
964 base.SetValue (index, GetContainerData (value));
968 sealed class DecimalDataContainer : ObjectDataContainer {
969 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
971 base.SetValue (index, record.GetDecimalSafe (field));
974 protected override void SetValue (int index, object value)
976 base.SetValue (index, GetContainerData (value));
980 sealed class StringDataContainer : ObjectDataContainer {
981 private void SetValue (int index, string value)
983 if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length)
984 throw new ArgumentException ("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column.");
985 base.SetValue (index, value);
988 protected override void SetValue (int index, object value)
990 SetValue (index, (string) GetContainerData (value));
993 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
995 SetValue (index, record.GetStringSafe (field));
998 protected override int DoCompareValues (int index1, int index2)
1000 DataTable table = Column.Table;
1001 return String.Compare ((string) this [index1], (string) this [index2], !table.CaseSensitive, table.Locale);