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;
26 namespace System.Data.Common
28 internal abstract class DataContainer {
33 // implementing class protocol
34 protected abstract object GetValue (int index);
35 internal abstract long GetInt64 (int index);
37 // used to set the array value to something neutral when the corresponding item is null (in the database sense)
38 // note: we don't actually ever look at the value written there, but the GC may like us to avoid keeping stale
39 // values in the array.
40 protected abstract void ZeroOut (int index);
41 protected abstract void SetValue (int index, object value);
42 protected abstract void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field);
44 protected abstract void DoCopyValue (DataContainer from, int from_index, int to_index);
45 protected abstract int DoCompareValues (int index1, int index2);
47 protected abstract void Resize (int length);
49 internal object this [int index] {
50 get { return IsNull (index) ? DBNull.Value : GetValue (index); }
53 CopyValue (Column.Table.DefaultValuesRowIndex, index);
57 bool is_dbnull = value == DBNull.Value;
61 SetValue (index, value);
62 null_values [index] = is_dbnull;
66 internal int Capacity {
67 get { return null_values != null ? null_values.Count : 0; }
69 int old_capacity = Capacity;
70 if (value == old_capacity)
72 if (null_values == null)
73 null_values = new BitArray (value);
75 null_values.Length = value;
84 protected DataColumn Column {
85 get { return _column; }
88 internal static DataContainer Create (Type type, DataColumn column)
90 DataContainer container;
91 switch (Type.GetTypeCode(type)) {
93 container = new Int16DataContainer ();
96 container = new Int32DataContainer ();
99 container = new Int64DataContainer ();
101 case TypeCode.String:
102 container = new StringDataContainer ();
104 case TypeCode.Boolean:
105 container = new BitDataContainer ();
108 container = new ByteDataContainer ();
111 container = new CharDataContainer ();
113 case TypeCode.Double:
114 container = new DoubleDataContainer ();
117 container = new SByteDataContainer ();
119 case TypeCode.Single:
120 container = new SingleDataContainer ();
122 case TypeCode.UInt16:
123 container = new UInt16DataContainer ();
125 case TypeCode.UInt32:
126 container = new UInt32DataContainer ();
128 case TypeCode.UInt64:
129 container = new UInt64DataContainer ();
131 case TypeCode.DateTime:
132 container = new DateTimeDataContainer ();
134 case TypeCode.Decimal:
135 container = new DecimalDataContainer ();
138 container = new ObjectDataContainer ();
141 container._type = type;
142 container._column = column;
146 internal bool IsNull (int index)
148 return null_values == null || null_values [index];
151 internal void FillValues (int fromIndex)
153 for (int i = 0; i < Capacity; i++)
154 CopyValue (fromIndex, i);
157 internal void CopyValue (int from_index, int to_index)
159 CopyValue (this, from_index, to_index);
162 internal void CopyValue (DataContainer from, int from_index, int to_index)
164 DoCopyValue (from, from_index, to_index);
165 null_values [to_index] = from.null_values [from_index];
168 internal void SetItemFromDataRecord (int index, IDataRecord record, int field)
170 if (record.IsDBNull (field))
171 this [index] = DBNull.Value;
172 else if (record is ISafeDataRecord)
173 SetValueFromSafeDataRecord (index, (ISafeDataRecord) record, field);
175 this [index] = record.GetValue (field);
178 internal int CompareValues (int index1, int index2)
180 bool null1 = IsNull (index1);
181 bool null2 = IsNull (index2);
184 return null1 ? 0 : DoCompareValues (index1, index2);
185 return null1 ? -1 : 1;
189 sealed class BitDataContainer : DataContainer {
192 protected override object GetValue (int index)
194 return _values [index];
197 protected override void ZeroOut (int index)
199 _values [index] = false;
202 protected override void SetValue (int index, object value)
204 _values [index] = value is bool ? (bool) value : Convert.ToBoolean (value);
207 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
209 _values [index] = record.GetBooleanSafe (field);
212 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
214 _values [to_index] = ((BitDataContainer) from)._values [from_index];
217 protected override int DoCompareValues (int index1, int index2)
219 bool val1 = _values [index1];
220 bool val2 = _values [index2];
221 return val1 == val2 ? 0 : val1 ? 1 : -1;
224 protected override void Resize (int size)
227 _values = new BitArray (size);
229 _values.Length = size;
232 internal override long GetInt64 (int index)
234 return Convert.ToInt64 (_values [index]);
238 sealed class CharDataContainer : DataContainer {
241 protected override object GetValue (int index)
243 return _values [index];
246 protected override void ZeroOut (int index)
248 _values [index] = '\0';
251 protected override void SetValue (int index, object value)
253 _values [index] = value is char ? (char) value : Convert.ToChar (value);
256 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
258 _values [index] = record.GetCharSafe (field);
261 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
263 _values [to_index] = ((CharDataContainer) from)._values [from_index];
266 protected override int DoCompareValues (int index1, int index2)
268 char val1 = _values [index1];
269 char val2 = _values [index2];
270 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
273 protected override void Resize (int size)
275 if (_values == null) {
276 _values = new char [size];
280 char[] tmp = new char [size];
281 Array.Copy (_values, 0, tmp, 0, _values.Length);
285 internal override long GetInt64 (int index)
287 return Convert.ToInt64 (_values [index]);
291 sealed class ByteDataContainer : DataContainer {
294 protected override object GetValue (int index)
296 return _values [index];
299 protected override void ZeroOut (int index)
304 protected override void SetValue (int index, object value)
306 _values [index] = value is byte ? (byte) value : Convert.ToByte (value);
309 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
311 _values [index] = record.GetByteSafe (field);
314 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
316 _values [to_index] = ((ByteDataContainer) from)._values [from_index];
319 protected override int DoCompareValues (int index1, int index2)
321 int val1 = _values [index1];
322 int val2 = _values [index2];
326 protected override void Resize (int size)
328 if (_values == null) {
329 _values = new byte [size];
333 byte[] tmp = new byte [size];
334 Array.Copy (_values, 0, tmp, 0, _values.Length);
338 internal override long GetInt64 (int index)
340 return _values [index];
344 sealed class SByteDataContainer : DataContainer {
347 protected override object GetValue (int index)
349 return _values [index];
352 protected override void ZeroOut (int index)
357 protected override void SetValue (int index, object value)
359 _values [index] = value is sbyte ? (sbyte) value : Convert.ToSByte (value);
362 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
364 _values [index] = (sbyte) record.GetByteSafe (field);
367 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
369 _values [to_index] = ((SByteDataContainer) from)._values [from_index];
372 protected override int DoCompareValues (int index1, int index2)
374 int val1 = _values [index1];
375 int val2 = _values [index2];
379 protected override void Resize (int size)
381 if (_values == null) {
382 _values = new sbyte [size];
386 sbyte[] tmp = new sbyte [size];
387 Array.Copy (_values, 0, tmp, 0, _values.Length);
391 internal override long GetInt64 (int index)
393 return _values [index];
397 sealed class Int16DataContainer : DataContainer {
400 protected override object GetValue (int index)
402 return _values [index];
405 protected override void ZeroOut (int index)
410 protected override void SetValue (int index, object value)
412 _values [index] = value is short ? (short) value : Convert.ToInt16 (value);
415 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
417 _values [index] = record.GetInt16Safe (field);
420 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
422 _values [to_index] = ((Int16DataContainer) from)._values [from_index];
425 protected override int DoCompareValues (int index1, int index2)
427 int val1 = _values [index1];
428 int val2 = _values [index2];
432 protected override void Resize (int size)
434 if (_values == null) {
435 _values = new short [size];
439 short[] tmp = new short [size];
440 Array.Copy (_values, 0, tmp, 0, _values.Length);
444 internal override long GetInt64 (int index)
446 return _values [index];
450 sealed class UInt16DataContainer : DataContainer {
453 protected override object GetValue (int index)
455 return _values [index];
458 protected override void ZeroOut (int index)
463 protected override void SetValue (int index, object value)
465 _values [index] = value is ushort ? (ushort) value : Convert.ToUInt16 (value);
468 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
470 _values [index] = (ushort) record.GetInt16Safe (field);
473 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
475 _values [to_index] = ((UInt16DataContainer) from)._values [from_index];
478 protected override int DoCompareValues (int index1, int index2)
480 int val1 = _values [index1];
481 int val2 = _values [index2];
485 protected override void Resize (int size)
487 if (_values == null) {
488 _values = new ushort [size];
492 ushort[] tmp = new ushort [size];
493 Array.Copy (_values, 0, tmp, 0, _values.Length);
497 internal override long GetInt64 (int index)
499 return _values [index];
503 sealed class Int32DataContainer : DataContainer {
506 protected override object GetValue (int index)
508 return _values [index];
511 protected override void ZeroOut (int index)
516 protected override void SetValue (int index, object value)
518 _values [index] = value is int ? (int) value : Convert.ToInt32 (value);
521 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
523 _values [index] = record.GetInt32Safe (field);
526 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
528 _values [to_index] = ((Int32DataContainer) from)._values [from_index];
531 protected override int DoCompareValues (int index1, int index2)
533 int val1 = _values [index1];
534 int val2 = _values [index2];
535 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
538 protected override void Resize (int size)
540 if (_values == null) {
541 _values = new int [size];
545 int[] tmp = new int [size];
546 Array.Copy (_values, 0, tmp, 0, _values.Length);
550 internal override long GetInt64 (int index)
552 return _values [index];
556 sealed class UInt32DataContainer : DataContainer {
559 protected override object GetValue (int index)
561 return _values [index];
564 protected override void ZeroOut (int index)
569 protected override void SetValue (int index, object value)
571 _values [index] = value is uint ? (uint) value : Convert.ToUInt32 (value);
574 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
576 _values [index] = (uint) record.GetInt32Safe (field);
579 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
581 _values [to_index] = ((UInt32DataContainer) from)._values [from_index];
584 protected override int DoCompareValues (int index1, int index2)
586 uint val1 = _values [index1];
587 uint val2 = _values [index2];
588 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
591 protected override void Resize (int size)
593 if (_values == null) {
594 _values = new uint [size];
598 uint[] tmp = new uint [size];
599 Array.Copy (_values, 0, tmp, 0, _values.Length);
603 internal override long GetInt64 (int index)
605 return _values [index];
609 sealed class Int64DataContainer : DataContainer {
612 protected override object GetValue (int index)
614 return _values [index];
617 protected override void ZeroOut (int index)
622 protected override void SetValue (int index, object value)
624 _values [index] = value is long ? (long) value : Convert.ToInt64 (value);
627 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
629 _values [index] = record.GetInt64Safe (field);
632 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
634 _values [to_index] = ((Int64DataContainer) from)._values [from_index];
637 protected override int DoCompareValues (int index1, int index2)
639 long val1 = _values [index1];
640 long val2 = _values [index2];
641 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
644 protected override void Resize (int size)
646 if (_values == null) {
647 _values = new long [size];
651 long[] tmp = new long [size];
652 Array.Copy (_values, 0, tmp, 0, _values.Length);
656 internal override long GetInt64 (int index)
658 return _values [index];
662 sealed class UInt64DataContainer : DataContainer {
665 protected override object GetValue (int index)
667 return _values [index];
670 protected override void ZeroOut (int index)
675 protected override void SetValue (int index, object value)
677 _values [index] = value is ulong ? (ulong) value : Convert.ToUInt64 (value);
680 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
682 _values [index] = (ulong) record.GetInt64Safe (field);
685 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
687 _values [to_index] = ((UInt64DataContainer) from)._values [from_index];
690 protected override int DoCompareValues (int index1, int index2)
692 ulong val1 = _values [index1];
693 ulong val2 = _values [index2];
694 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
697 protected override void Resize (int size)
699 if (_values == null) {
700 _values = new ulong [size];
704 ulong[] tmp = new ulong [size];
705 Array.Copy (_values, 0, tmp, 0, _values.Length);
709 internal override long GetInt64 (int index)
711 return Convert.ToInt64 (_values [index]);
715 sealed class SingleDataContainer : DataContainer {
718 protected override object GetValue (int index)
720 return _values [index];
723 protected override void ZeroOut (int index)
728 protected override void SetValue (int index, object value)
730 _values [index] = value is float ? (float) value : Convert.ToSingle (value);
733 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
735 _values [index] = record.GetFloatSafe (field);
738 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
740 _values [to_index] = ((SingleDataContainer) from)._values [from_index];
743 protected override int DoCompareValues (int index1, int index2)
745 float val1 = _values [index1];
746 float val2 = _values [index2];
747 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
750 protected override void Resize (int size)
752 if (_values == null) {
753 _values = new float [size];
757 float[] tmp = new float [size];
758 Array.Copy (_values, 0, tmp, 0, _values.Length);
762 internal override long GetInt64 (int index)
764 return Convert.ToInt64 (_values [index]);
768 sealed class DoubleDataContainer : DataContainer {
771 protected override object GetValue (int index)
773 return _values [index];
776 protected override void ZeroOut (int index)
781 protected override void SetValue (int index, object value)
783 _values [index] = value is double ? (double) value : Convert.ToDouble (value);
786 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
788 _values [index] = record.GetDoubleSafe (field);
791 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
793 _values [to_index] = ((DoubleDataContainer) from)._values [from_index];
796 protected override int DoCompareValues (int index1, int index2)
798 double val1 = _values [index1];
799 double val2 = _values [index2];
800 return val1 == val2 ? 0 : val1 < val2 ? -1 : 1;
803 protected override void Resize (int size)
805 if (_values == null) {
806 _values = new double [size];
810 double[] tmp = new double [size];
811 Array.Copy (_values, 0, tmp, 0, _values.Length);
815 internal override long GetInt64 (int index)
817 return Convert.ToInt64 (_values[index]);
821 class ObjectDataContainer : DataContainer {
824 protected override object GetValue (int index)
826 return _values [index];
829 protected override void ZeroOut (int index)
831 _values [index] = null;
834 protected override void SetValue (int index, object value)
836 _values [index] = value;
839 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
841 _values [index] = record.GetValue (field);
844 protected override void DoCopyValue (DataContainer from, int from_index, int to_index)
846 _values [to_index] = ((ObjectDataContainer) from)._values [from_index];
849 protected override int DoCompareValues (int index1, int index2)
851 object obj1 = _values [index1];
852 object obj2 = _values [index2];
857 if (obj1 is IComparable) {
859 return ((IComparable)obj1).CompareTo (obj2);
861 if (obj2 is IComparable) {
862 obj2 = Convert.ChangeType (obj2, Type.GetTypeCode (obj1.GetType ()));
863 return ((IComparable)obj1).CompareTo (obj2);
868 return String.Compare (obj1.ToString (), obj2.ToString ());
871 protected override void Resize (int size)
873 if (_values == null) {
874 _values = new object [size];
878 object[] tmp = new object [size];
879 Array.Copy (_values, 0, tmp, 0, _values.Length);
883 internal override long GetInt64 (int index)
885 return Convert.ToInt64 (_values [index]);
889 sealed class DateTimeDataContainer : ObjectDataContainer {
890 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
892 base.SetValue (index, record.GetDateTimeSafe (field));
895 protected override void SetValue (int index, object value)
897 base.SetValue (index, Convert.ToDateTime (value));
901 sealed class DecimalDataContainer : ObjectDataContainer {
902 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
904 base.SetValue (index, record.GetDecimalSafe (field));
907 protected override void SetValue (int index, object value)
909 base.SetValue (index, Convert.ToDecimal (value));
913 sealed class StringDataContainer : ObjectDataContainer {
914 private void SetValue (int index, string value)
916 if (value != null && Column.MaxLength >= 0 && Column.MaxLength < value.Length)
917 throw new ArgumentException ("Cannot set column '" + Column.ColumnName + "' to '" + value + "'. The value violates the MaxLength limit of this column.");
918 base.SetValue (index, value);
921 protected override void SetValue (int index, object value)
923 SetValue (index, value is string ? (string) value : Convert.ToString (value));
926 protected override void SetValueFromSafeDataRecord (int index, ISafeDataRecord record, int field)
928 SetValue (index, record.GetStringSafe (field));
931 protected override int DoCompareValues (int index1, int index2)
933 DataTable table = Column.Table;
934 return String.Compare ((string) this [index1], (string) this [index2], !table.CaseSensitive, table.Locale);