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;
26 using System.Reflection.Emit;
28 namespace System.Data.Common
30 internal abstract class DataContainer {
35 // implementing class protocol
36 protected abstract object GetValue (int index);
37 internal abstract long GetInt64 (int index);
39 // used to set the array value to something neutral when the corresponding item is null (in the database sense)
40 // note: we don't actually ever look at the value written there, but the GC may like us to avoid keeping stale
41 // values in the array.
42 protected abstract void ZeroOut (int index);
43 protected abstract void SetValue (int index, object value);
44 protected abstract void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field);
46 protected abstract void DoCopyValue (DataContainer from, int from_index, int to_index);
47 protected abstract int DoCompareValues (int index1, int index2);
49 protected abstract void Resize (int length);
51 internal object this [int index] {
52 get { return IsNull (index) ? DBNull.Value : GetValue (index); }
55 CopyValue (Column.Table.DefaultValuesRowIndex, index);
59 bool is_dbnull = value == DBNull.Value;
63 SetValue (index, value);
64 null_values [index] = is_dbnull;
68 internal int Capacity {
69 get { return null_values != null ? null_values.Count : 0; }
71 int old_capacity = Capacity;
72 if (value == old_capacity)
74 if (null_values == null)
75 null_values = new BitArray (value);
77 null_values.Length = value;
86 protected DataColumn Column {
87 get { return _column; }
90 internal static DataContainer Create (Type type, DataColumn column)
92 DataContainer container;
93 switch (Type.GetTypeCode(type)) {
95 container = new Int16DataContainer ();
98 container = new Int32DataContainer ();
101 container = new Int64DataContainer ();
103 case TypeCode.String:
104 container = new StringDataContainer ();
106 case TypeCode.Boolean:
107 container = new BitDataContainer ();
110 container = new ByteDataContainer ();
113 container = new CharDataContainer ();
115 case TypeCode.Double:
116 container = new DoubleDataContainer ();
119 container = new SByteDataContainer ();
121 case TypeCode.Single:
122 container = new SingleDataContainer ();
124 case TypeCode.UInt16:
125 container = new UInt16DataContainer ();
127 case TypeCode.UInt32:
128 container = new UInt32DataContainer ();
130 case TypeCode.UInt64:
131 container = new UInt64DataContainer ();
133 case TypeCode.DateTime:
134 container = new DateTimeDataContainer ();
136 case TypeCode.Decimal:
137 container = new DecimalDataContainer ();
140 container = new ObjectDataContainer ();
143 container._type = type;
144 container._column = column;
148 internal static object GetExplicitValue (object value)
150 Type valueType = value.GetType ();
151 MethodInfo method = valueType.GetMethod ("op_Explicit", new Type[]{valueType});
153 return (method.Invoke (value, new object[]{value}));
157 internal object GetContainerData (object value)
161 if (_type.IsInstanceOfType (value)) {
163 } else if (value is IConvertible) {
164 switch (Type.GetTypeCode(_type)) {
166 return (Convert.ToInt16 (value));
168 return (Convert.ToInt32 (value));
170 return (Convert.ToInt64 (value));
171 case TypeCode.String:
172 return (Convert.ToString (value));
173 case TypeCode.Boolean:
174 return (Convert.ToBoolean (value));
176 return (Convert.ToByte (value));
178 return (Convert.ToChar (value));
179 case TypeCode.Double:
180 return (Convert.ToDouble (value));
182 return (Convert.ToSByte (value));
183 case TypeCode.Single:
184 return (Convert.ToSingle (value));
185 case TypeCode.UInt16:
186 return (Convert.ToUInt16 (value));
187 case TypeCode.UInt32:
188 return (Convert.ToUInt32 (value));
189 case TypeCode.UInt64:
190 return (Convert.ToUInt64 (value));
191 case TypeCode.DateTime:
192 return (Convert.ToDateTime (value));
193 case TypeCode.Decimal:
194 return (Convert.ToDecimal (value));
196 throw new InvalidCastException ();
198 } else if ((obj = GetExplicitValue (value)) != null) {
201 throw new InvalidCastException ();
205 internal bool IsNull (int index)
207 return null_values == null || null_values [index];
210 internal void FillValues (int fromIndex)
212 for (int i = 0; i < Capacity; i++)
213 CopyValue (fromIndex, i);
216 internal void CopyValue (int from_index, int to_index)
218 CopyValue (this, from_index, to_index);
221 internal void CopyValue (DataContainer from, int from_index, int to_index)
223 DoCopyValue (from, from_index, to_index);
224 null_values [to_index] = from.null_values [from_index];
227 internal void SetItemFromDataRecord (int index, IDataRecord record, int field)
229 if (record.IsDBNull (field))
230 this [index] = DBNull.Value;
231 else if (record is ISafeDataRecord)
232 SetValueFromSafeDataRecord (index, (ISafeDataRecord) record, field);
234 this [index] = record.GetValue (field);
237 internal int CompareValues (int index1, int index2)
239 bool null1 = IsNull (index1);
240 bool null2 = IsNull (index2);
243 return null1 ? 0 : DoCompareValues (index1, index2);
244 return null1 ? -1 : 1;
248 sealed class BitDataContainer : DataContainer {
251 protected override object GetValue (int index)
253 return _values [index];
256 protected override void ZeroOut (int index)
258 _values [index] = false;
261 protected override void SetValue (int index, object value)
263 _values [index] = (bool) GetContainerData (value);
266 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
268 _values [index] = record.GetBooleanSafe (field);
271 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
273 _values [to_index] = ((BitDataContainer) from)._values [from_index];
276 protected override int DoCompareValues (int index1, int index2)
278 bool val1 = _values [index1];
279 bool val2 = _values [index2];
280 return val1 == val2 ? 0 : val1 ? 1 : -1;
283 protected override void Resize (int size)
286 _values = new BitArray (size);
288 _values.Length = size;
291 internal override long GetInt64 (int index)
293 return Convert.ToInt64 (_values [index]);
297 sealed class CharDataContainer : DataContainer {
300 protected override object GetValue (int index)
302 return _values [index];
305 protected override void ZeroOut (int index)
307 _values [index] = '\0';
310 protected override void SetValue (int index, object value)
312 _values [index] = (char) GetContainerData (value);
315 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
317 _values [index] = record.GetCharSafe (field);
320 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
322 _values [to_index] = ((CharDataContainer) from)._values [from_index];
325 protected override int DoCompareValues (int index1, int index2)
327 char val1 = _values [index1];
328 char val2 = _values [index2];
329 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
332 protected override void Resize (int size)
334 if (_values == null) {
335 _values = new char [size];
339 char[] tmp = new char [size];
340 Array.Copy (_values, 0, tmp, 0, _values.Length);
344 internal override long GetInt64 (int index)
346 return Convert.ToInt64 (_values [index]);
350 sealed class ByteDataContainer : DataContainer {
353 protected override object GetValue (int index)
355 return _values [index];
358 protected override void ZeroOut (int index)
363 protected override void SetValue (int index, object value)
365 _values [index] = (byte) GetContainerData (value);
368 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
370 _values [index] = record.GetByteSafe (field);
373 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
375 _values [to_index] = ((ByteDataContainer) from)._values [from_index];
378 protected override int DoCompareValues (int index1, int index2)
380 int val1 = _values [index1];
381 int val2 = _values [index2];
385 protected override void Resize (int size)
387 if (_values == null) {
388 _values = new byte [size];
392 byte[] tmp = new byte [size];
393 Array.Copy (_values, 0, tmp, 0, _values.Length);
397 internal override long GetInt64 (int index)
399 return _values [index];
403 sealed class SByteDataContainer : DataContainer {
406 protected override object GetValue (int index)
408 return _values [index];
411 protected override void ZeroOut (int index)
416 protected override void SetValue (int index, object value)
418 _values [index] = (sbyte) GetContainerData (value);
421 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
423 _values [index] = (sbyte) record.GetByteSafe (field);
426 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
428 _values [to_index] = ((SByteDataContainer) from)._values [from_index];
431 protected override int DoCompareValues (int index1, int index2)
433 int val1 = _values [index1];
434 int val2 = _values [index2];
438 protected override void Resize (int size)
440 if (_values == null) {
441 _values = new sbyte [size];
445 sbyte[] tmp = new sbyte [size];
446 Array.Copy (_values, 0, tmp, 0, _values.Length);
450 internal override long GetInt64 (int index)
452 return _values [index];
456 sealed class Int16DataContainer : DataContainer {
459 protected override object GetValue (int index)
461 return _values [index];
464 protected override void ZeroOut (int index)
469 protected override void SetValue (int index, object value)
471 _values [index] = (short) GetContainerData (value);
474 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
476 _values [index] = record.GetInt16Safe (field);
479 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
481 _values [to_index] = ((Int16DataContainer) from)._values [from_index];
484 protected override int DoCompareValues (int index1, int index2)
486 int val1 = _values [index1];
487 int val2 = _values [index2];
491 protected override void Resize (int size)
493 if (_values == null) {
494 _values = new short [size];
498 short[] tmp = new short [size];
499 Array.Copy (_values, 0, tmp, 0, _values.Length);
503 internal override long GetInt64 (int index)
505 return _values [index];
509 sealed class UInt16DataContainer : DataContainer {
512 protected override object GetValue (int index)
514 return _values [index];
517 protected override void ZeroOut (int index)
522 protected override void SetValue (int index, object value)
524 _values [index] = (ushort) GetContainerData (value);
527 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
529 _values [index] = (ushort) record.GetInt16Safe (field);
532 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
534 _values [to_index] = ((UInt16DataContainer) from)._values [from_index];
537 protected override int DoCompareValues (int index1, int index2)
539 int val1 = _values [index1];
540 int val2 = _values [index2];
544 protected override void Resize (int size)
546 if (_values == null) {
547 _values = new ushort [size];
551 ushort[] tmp = new ushort [size];
552 Array.Copy (_values, 0, tmp, 0, _values.Length);
556 internal override long GetInt64 (int index)
558 return _values [index];
562 sealed class Int32DataContainer : DataContainer {
565 protected override object GetValue (int index)
567 return _values [index];
570 protected override void ZeroOut (int index)
575 protected override void SetValue (int index, object value)
577 _values [index] = (int) GetContainerData (value);
580 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
582 _values [index] = record.GetInt32Safe (field);
585 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
587 _values [to_index] = ((Int32DataContainer) from)._values [from_index];
590 protected override int DoCompareValues (int index1, int index2)
592 int val1 = _values [index1];
593 int val2 = _values [index2];
594 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
597 protected override void Resize (int size)
599 if (_values == null) {
600 _values = new int [size];
604 int[] tmp = new int [size];
605 Array.Copy (_values, 0, tmp, 0, _values.Length);
609 internal override long GetInt64 (int index)
611 return _values [index];
615 sealed class UInt32DataContainer : DataContainer {
618 protected override object GetValue (int index)
620 return _values [index];
623 protected override void ZeroOut (int index)
628 protected override void SetValue (int index, object value)
630 _values [index] = (uint) GetContainerData (value);
633 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
635 _values [index] = (uint) record.GetInt32Safe (field);
638 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
640 _values [to_index] = ((UInt32DataContainer) from)._values [from_index];
643 protected override int DoCompareValues (int index1, int index2)
645 uint val1 = _values [index1];
646 uint val2 = _values [index2];
647 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
650 protected override void Resize (int size)
652 if (_values == null) {
653 _values = new uint [size];
657 uint[] tmp = new uint [size];
658 Array.Copy (_values, 0, tmp, 0, _values.Length);
662 internal override long GetInt64 (int index)
664 return _values [index];
668 sealed class Int64DataContainer : DataContainer {
671 protected override object GetValue (int index)
673 return _values [index];
676 protected override void ZeroOut (int index)
681 protected override void SetValue (int index, object value)
683 _values [index] = (long) GetContainerData (value);
686 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
688 _values [index] = record.GetInt64Safe (field);
691 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
693 _values [to_index] = ((Int64DataContainer) from)._values [from_index];
696 protected override int DoCompareValues (int index1, int index2)
698 long val1 = _values [index1];
699 long val2 = _values [index2];
700 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
703 protected override void Resize (int size)
705 if (_values == null) {
706 _values = new long [size];
710 long[] tmp = new long [size];
711 Array.Copy (_values, 0, tmp, 0, _values.Length);
715 internal override long GetInt64 (int index)
717 return _values [index];
721 sealed class UInt64DataContainer : DataContainer {
724 protected override object GetValue (int index)
726 return _values [index];
729 protected override void ZeroOut (int index)
734 protected override void SetValue (int index, object value)
736 _values [index] = (ulong) GetContainerData (value);
739 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
741 _values [index] = (ulong) record.GetInt64Safe (field);
744 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
746 _values [to_index] = ((UInt64DataContainer) from)._values [from_index];
749 protected override int DoCompareValues (int index1, int index2)
751 ulong val1 = _values [index1];
752 ulong val2 = _values [index2];
753 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
756 protected override void Resize (int size)
758 if (_values == null) {
759 _values = new ulong [size];
763 ulong[] tmp = new ulong [size];
764 Array.Copy (_values, 0, tmp, 0, _values.Length);
768 internal override long GetInt64 (int index)
770 return Convert.ToInt64 (_values [index]);
774 sealed class SingleDataContainer : DataContainer {
777 protected override object GetValue (int index)
779 return _values [index];
782 protected override void ZeroOut (int index)
787 protected override void SetValue (int index, object value)
789 _values [index] = (float) GetContainerData (value);
792 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
794 _values [index] = record.GetFloatSafe (field);
797 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
799 _values [to_index] = ((SingleDataContainer) from)._values [from_index];
802 protected override int DoCompareValues (int index1, int index2)
804 float val1 = _values [index1];
805 float val2 = _values [index2];
806 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
809 protected override void Resize (int size)
811 if (_values == null) {
812 _values = new float [size];
816 float[] tmp = new float [size];
817 Array.Copy (_values, 0, tmp, 0, _values.Length);
821 internal override long GetInt64 (int index)
823 return Convert.ToInt64 (_values [index]);
827 sealed class DoubleDataContainer : DataContainer {
830 protected override object GetValue (int index)
832 return _values [index];
835 protected override void ZeroOut (int index)
840 protected override void SetValue (int index, object value)
842 _values [index] = (double) GetContainerData (value);
845 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
847 _values [index] = record.GetDoubleSafe (field);
850 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
852 _values [to_index] = ((DoubleDataContainer) from)._values [from_index];
855 protected override int DoCompareValues (int index1, int index2)
857 double val1 = _values [index1];
858 double val2 = _values [index2];
859 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
862 protected override void Resize (int size)
864 if (_values == null) {
865 _values = new double [size];
869 double[] tmp = new double [size];
870 Array.Copy (_values, 0, tmp, 0, _values.Length);
874 internal override long GetInt64 (int index)
876 return Convert.ToInt64 (_values[index]);
880 class ObjectDataContainer : DataContainer {
883 protected override object GetValue (int index)
885 return _values [index];
888 protected override void ZeroOut (int index)
890 _values [index] = null;
893 protected override void SetValue (int index, object value)
895 _values [index] = value;
898 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
900 _values [index] = record.GetValue (field);
903 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
905 _values [to_index] = ((ObjectDataContainer) from)._values [from_index];
908 protected override int DoCompareValues (int index1, int index2)
910 object obj1 = _values [index1];
911 object obj2 = _values [index2];
916 if (obj1 is IComparable) {
918 return ((IComparable)obj1).CompareTo (obj2);
920 if (obj2 is IComparable) {
921 obj2 = Convert.ChangeType (obj2, Type.GetTypeCode (obj1.GetType ()));
922 return ((IComparable)obj1).CompareTo (obj2);
927 return String.Compare (obj1.ToString (), obj2.ToString ());
930 protected override void Resize (int size)
932 if (_values == null) {
933 _values = new object [size];
937 object[] tmp = new object [size];
938 Array.Copy (_values, 0, tmp, 0, _values.Length);
942 internal override long GetInt64 (int index)
944 return Convert.ToInt64 (_values [index]);
948 sealed class DateTimeDataContainer : ObjectDataContainer {
949 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
951 base.SetValue (index, record.GetDateTimeSafe (field));
954 protected override void SetValue (int index, object value)
956 base.SetValue (index, GetContainerData (value));
960 sealed class DecimalDataContainer : ObjectDataContainer {
961 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
963 base.SetValue (index, record.GetDecimalSafe (field));
966 protected override void SetValue (int index, object value)
968 base.SetValue (index, GetContainerData (value));
972 sealed class StringDataContainer : ObjectDataContainer {
973 private void SetValue (int index, string value)
975 if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length)
976 throw new ArgumentException ("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column.");
977 base.SetValue (index, value);
980 protected override void SetValue (int index, object value)
982 SetValue (index, (string) GetContainerData (value));
985 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
987 SetValue (index, record.GetStringSafe (field));
990 protected override int DoCompareValues (int index1, int index2)
992 DataTable table = Column.Table;
993 return String.Compare ((string) this [index1], (string) this [index2], !table.CaseSensitive, table.Locale);