1 //------------------------------------------------------------------------------
2 // <copyright file="DataColumn.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
9 namespace System.Data {
12 using System.Data.Common;
13 using System.ComponentModel;
14 using System.Diagnostics;
15 using System.Collections;
16 using System.Globalization;
17 using System.Data.SqlTypes;
18 using System.Xml.Serialization;
19 using System.Collections.Generic;
20 using System.Runtime.CompilerServices;
24 /// Represents one column of data in a <see cref='System.Data.DataTable'/>.
29 DesignTimeVisible(false),
30 DefaultProperty("ColumnName"),
31 Editor("Microsoft.VSDesigner.Data.Design.DataColumnEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
33 public class DataColumn : MarshalByValueComponent {
36 private bool allowNull = true;
37 private string caption = null;
38 private string _columnName = null;
39 private Type dataType = null;
40 private StorageType _storageType;
41 internal object defaultValue = DBNull.Value; // DefaultValue Converter
42 private DataSetDateTime _dateTimeMode = DataSetDateTime.UnspecifiedLocal;
43 private DataExpression expression = null;
44 private int maxLength = -1;
45 private int _ordinal = -1;
46 private bool readOnly = false;
47 internal Index sortIndex = null;
48 internal DataTable table = null;
49 private bool unique = false;
50 internal MappingType columnMapping = MappingType.Element;
51 internal int _hashCode;
54 private bool isSqlType = false;
55 private bool implementsINullable = false;
56 private bool implementsIChangeTracking = false;
57 private bool implementsIRevertibleChangeTracking = false;
58 private bool implementsIXMLSerializable = false;
60 private bool defaultValueIsNull = true;
62 // list of columns whose expression consume values from this column
63 internal List<DataColumn> dependentColumns = null;
66 internal PropertyCollection extendedProperties = null;
69 private PropertyChangedEventHandler onPropertyChangingDelegate = null;
72 private DataStorage _storage;
74 /// <summary>represents current value to return, usage pattern is .get_Current then MoveAfter</summary>
75 private AutoIncrementValue autoInc;
78 // The _columnClass member is the class for the unfoliated virtual nodes in the XML.
80 internal string _columnUri = null;
81 private string _columnPrefix = "";
82 internal string encodedColumnName = null;
85 internal string dttype = ""; // The type specified in dt:type attribute
86 internal SimpleType simpleType = null;
88 private static int _objectTypeCount; // Bid counter
89 private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
93 /// Initializes a new instance of a <see cref='System.Data.DataColumn'/>
97 public DataColumn() : this(null, typeof(string), null, MappingType.Element) {
102 /// Inititalizes a new instance of the <see cref='System.Data.DataColumn'/> class
103 /// using the specified column name.
106 public DataColumn(string columnName) : this(columnName, typeof(string), null, MappingType.Element) {
111 /// Inititalizes a new instance of the <see cref='System.Data.DataColumn'/> class
112 /// using the specified column name and data type.
115 public DataColumn(string columnName, Type dataType) : this(columnName, dataType, null, MappingType.Element) {
120 /// Initializes a new instance
121 /// of the <see cref='System.Data.DataColumn'/> class
122 /// using the specified name, data type, and expression.
125 public DataColumn(string columnName, Type dataType, string expr) : this(columnName, dataType, expr, MappingType.Element) {
130 /// Initializes a new instance of the <see cref='System.Data.DataColumn'/> class
132 /// the specified name, data type, expression, and value that determines whether the
133 /// column is an attribute.
136 public DataColumn(string columnName, Type dataType, string expr, MappingType type) {
137 GC.SuppressFinalize(this);
138 Bid.Trace("<ds.DataColumn.DataColumn|API> %d#, columnName='%ls', expr='%ls', type=%d{ds.MappingType}\n",
139 ObjectID, columnName, expr, (int)type);
141 if (dataType == null) {
142 throw ExceptionBuilder.ArgumentNull("dataType");
145 StorageType typeCode = DataStorage.GetStorageType(dataType);
146 if (DataStorage.ImplementsINullableValue(typeCode, dataType)) {
147 throw ExceptionBuilder.ColumnTypeNotSupported();
149 _columnName = columnName ?? string.Empty;
151 SimpleType stype = SimpleType.CreateSimpleType(typeCode, dataType);
153 this.SimpleType = stype;
155 UpdateColumnType(dataType, typeCode);
157 if ((null != expr) && (0 < expr.Length)) {
158 // @perfnote: its a performance hit to set Expression to the empty str when we know it will come out null
159 this.Expression = expr;
161 this.columnMapping = type;
165 private void UpdateColumnType(Type type, StorageType typeCode) {
167 _storageType = typeCode;
168 if (StorageType.DateTime != typeCode) { // revert _dateTimeMode back to default, when column type is changed
169 _dateTimeMode = DataSetDateTime.UnspecifiedLocal;
171 DataStorage.ImplementsInterfaces(
174 out implementsINullable,
175 out implementsIXMLSerializable,
176 out implementsIChangeTracking,
177 out implementsIRevertibleChangeTracking);
179 if (!isSqlType && implementsINullable) {
180 SqlUdtStorage.GetStaticNullForUdtType(type);
188 /// Gets or sets a value indicating whether null
190 /// allowed in this column for rows belonging to the table.
194 ResCategoryAttribute(Res.DataCategory_Data),
196 ResDescriptionAttribute(Res.DataColumnAllowNullDescr)
198 public bool AllowDBNull {
204 Bid.ScopeEnter(out hscp, "<ds.DataColumn.set_AllowDBNull|API> %d#, %d{bool}\n", ObjectID, value);
206 if (allowNull != value) {
208 if (!value && table.EnforceConstraints)
211 this.allowNull = value;
216 Bid.ScopeLeave(ref hscp);
224 /// sets a value indicating whether the column automatically increments the value of the column for new
225 /// rows added to the table.
229 ResCategoryAttribute(Res.DataCategory_Data),
230 RefreshProperties(RefreshProperties.All),
232 ResDescriptionAttribute(Res.DataColumnAutoIncrementDescr)
234 public bool AutoIncrement {
236 return ((null != autoInc) && (autoInc.Auto));
239 Bid.Trace("<ds.DataColumn.set_AutoIncrement|API> %d#, %d{bool}\n", ObjectID, value);
240 if (this.AutoIncrement != value) {
242 if (expression != null) {
243 throw ExceptionBuilder.AutoIncrementAndExpression();
245 // if (defaultValue != null && defaultValue != DBNull.Value) {
246 if (!DefaultValueIsNull) {
247 throw ExceptionBuilder.AutoIncrementAndDefaultValue();
249 if (!IsAutoIncrementType(DataType)) {
251 throw ExceptionBuilder.AutoIncrementCannotSetIfHasData(DataType.Name);
253 DataType = typeof(int);
257 this.AutoInc.Auto = value;
262 internal object AutoIncrementCurrent {
263 get { return ((null != this.autoInc) ? this.autoInc.Current : this.AutoIncrementSeed); }
265 if ((System.Numerics.BigInteger)this.AutoIncrementSeed != BigIntegerStorage.ConvertToBigInteger(value, this.FormatProvider)) {
266 this.AutoInc.SetCurrent(value, this.FormatProvider);
271 internal AutoIncrementValue AutoInc {
273 return (this.autoInc ?? (this.autoInc = ((this.DataType == typeof(System.Numerics.BigInteger))
274 ? (AutoIncrementValue)new AutoIncrementBigInteger()
275 : new AutoIncrementInt64())));
283 /// or sets the starting value for a column that has its
284 /// <see cref='System.Data.DataColumn.AutoIncrement'/> property
285 /// set to <see langword='true'/>
290 ResCategoryAttribute(Res.DataCategory_Data),
291 DefaultValue((Int64)0),
292 ResDescriptionAttribute(Res.DataColumnAutoIncrementSeedDescr)
294 public Int64 AutoIncrementSeed {
296 return ((null != this.autoInc) ? this.autoInc.Seed : 0L);
299 Bid.Trace("<ds.DataColumn.set_AutoIncrementSeed|API> %d#, %I64d\n", ObjectID, value);
300 if (this.AutoIncrementSeed != value) {
301 this.AutoInc.Seed = value;
308 /// Gets or sets the increment used by a column with its <see cref='System.Data.DataColumn.AutoIncrement'/>
309 /// property set to <see langword='true'/>
314 ResCategoryAttribute(Res.DataCategory_Data),
315 DefaultValue((Int64)1),
316 ResDescriptionAttribute(Res.DataColumnAutoIncrementStepDescr)
318 public Int64 AutoIncrementStep {
320 return ((null != this.autoInc) ? this.autoInc.Step : 1L);
323 Bid.Trace("<ds.DataColumn.set_AutoIncrementStep|API> %d#, %I64d\n", ObjectID, value);
324 if (this.AutoIncrementStep != value) {
325 this.AutoInc.Step = value;
333 /// the caption for this column.
337 ResCategoryAttribute(Res.DataCategory_Data),
338 ResDescriptionAttribute(Res.DataColumnCaptionDescr)
340 public string Caption {
342 return (caption != null) ? caption : _columnName;
348 if (caption == null || String.Compare(caption, value, true, Locale) != 0) {
356 /// Resets the <see cref='System.Data.DataColumn.Caption'/> property to its previous value, or
357 /// to <see langword='null'/> .
360 private void ResetCaption() {
361 if (caption != null) {
368 /// Gets a value indicating whether the <see cref='System.Data.DataColumn.Caption'/> has been explicitly set.
371 private bool ShouldSerializeCaption() {
372 return (caption != null);
377 /// Gets or sets the name of the column within the <see cref='System.Data.DataColumnCollection'/>.
381 RefreshProperties(RefreshProperties.All),
382 ResCategoryAttribute(Res.DataCategory_Data),
384 ResDescriptionAttribute(Res.DataColumnColumnNameDescr)
386 public string ColumnName {
392 Bid.ScopeEnter(out hscp, "<ds.DataColumn.set_ColumnName|API> %d#, '%ls'\n", ObjectID, value);
398 if (String.Compare(_columnName, value, true, Locale) != 0) {
400 if (value.Length == 0)
401 throw ExceptionBuilder.ColumnNameRequired();
403 table.Columns.RegisterColumnName(value, this);
404 if (_columnName.Length != 0)
405 table.Columns.UnregisterName(_columnName);
408 RaisePropertyChanging("ColumnName");
410 encodedColumnName = null;
412 table.Columns.OnColumnPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this));
415 else if (_columnName != value) {
416 RaisePropertyChanging("ColumnName");
418 encodedColumnName = null;
420 table.Columns.OnColumnPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this));
425 Bid.ScopeLeave(ref hscp);
430 internal string EncodedColumnName {
432 if (this.encodedColumnName == null) {
433 this.encodedColumnName = XmlConvert.EncodeLocalName(this.ColumnName);
435 Debug.Assert(this.encodedColumnName != null && this.encodedColumnName.Length != 0);
436 return this.encodedColumnName;
440 internal IFormatProvider FormatProvider {
442 // used for formating/parsing not comparing
443 return ((null != table) ? table.FormatProvider : CultureInfo.CurrentCulture);
447 internal CultureInfo Locale {
449 // used for comparing not formating/parsing
450 return ((null != table) ? table.Locale : CultureInfo.CurrentCulture);
454 internal int ObjectID {
461 ResCategoryAttribute(Res.DataCategory_Data),
463 ResDescriptionAttribute(Res.DataColumnPrefixDescr)
465 public string Prefix {
466 get { return _columnPrefix; }
470 Bid.Trace("<ds.DataColumn.set_Prefix|API> %d#, '%ls'\n", ObjectID, value);
472 if ((XmlConvert.DecodeName(value) == value) && (XmlConvert.EncodeName(value) != value))
473 throw ExceptionBuilder.InvalidPrefix(value);
475 _columnPrefix = value;
480 // Return the field value as a string. If the field value is NULL, then NULL is return.
481 // If the column type is string and it's value is empty, then the empty string is returned.
482 // If the column type is not string, or the column type is string and the value is not empty string, then a non-empty string is returned
483 // This method does not throw any formatting exceptions, since we can always format the field value to a string.
484 internal string GetColumnValueAsString(DataRow row, DataRowVersion version) {
486 object objValue = this[row.GetRecordFromVersion(version)];
488 if (DataStorage.IsObjectNull(objValue)) {
492 string value = ConvertObjectToXml(objValue);
493 Debug.Assert(value != null);
499 /// Whether this column computes values.
501 internal bool Computed {
503 return this.expression != null;
508 /// The internal expression object that computes the values.
510 internal DataExpression DataExpression {
512 return this.expression;
519 /// of data stored in thecolumn.
523 ResCategoryAttribute(Res.DataCategory_Data),
524 DefaultValue(typeof(string)),
525 RefreshProperties(RefreshProperties.All),
526 TypeConverter(typeof(ColumnTypeConverter)),
527 ResDescriptionAttribute(Res.DataColumnDataTypeDescr)
529 public Type DataType {
534 if (dataType != value) {
536 throw ExceptionBuilder.CantChangeDataType();
539 throw ExceptionBuilder.NullDataType();
541 StorageType typeCode = DataStorage.GetStorageType(value);
542 if (DataStorage.ImplementsINullableValue(typeCode, value)) {
543 throw ExceptionBuilder.ColumnTypeNotSupported();
545 if (table != null && IsInRelation()) {
546 throw ExceptionBuilder.ColumnsTypeMismatch();
548 if (typeCode == StorageType.BigInteger && this.expression != null)
550 throw ExprException.UnsupportedDataType(value);
553 // If the DefualtValue is different from the Column DataType, we will coerce the value to the DataType
554 if (!DefaultValueIsNull) {
556 if (this.defaultValue is System.Numerics.BigInteger) {
557 this.defaultValue = BigIntegerStorage.ConvertFromBigInteger((System.Numerics.BigInteger)this.defaultValue, value, this.FormatProvider);
559 else if (typeof(System.Numerics.BigInteger) == value) {
560 this.defaultValue = BigIntegerStorage.ConvertToBigInteger(this.defaultValue, this.FormatProvider);
562 else if (typeof(string) == value) { // since string types can be null in value! DO NOT REMOVE THIS
563 defaultValue = DefaultValue.ToString();
565 else if (typeof(SqlString) == value) { // since string types can be null in value! DO NOT REMOVE THIS
566 defaultValue = SqlConvert.ConvertToSqlString(DefaultValue);
568 else if (typeof(object) != value) {
569 DefaultValue = SqlConvert.ChangeTypeForDefaultValue(DefaultValue, value, FormatProvider);
572 catch (InvalidCastException ex) {
573 throw ExceptionBuilder.DefaultValueDataType(ColumnName, DefaultValue.GetType(), value, ex);
575 catch (FormatException ex) {
576 throw ExceptionBuilder.DefaultValueDataType(ColumnName, DefaultValue.GetType(), value, ex);
580 if (this.ColumnMapping == MappingType.SimpleContent)
581 if (value == typeof(Char))
582 throw ExceptionBuilder.CannotSetSimpleContentType(ColumnName, value);
584 SimpleType = SimpleType.CreateSimpleType(typeCode, value);
585 if (StorageType.String == typeCode) {
588 UpdateColumnType(value, typeCode);
592 if (!IsAutoIncrementType(value)) {
593 AutoIncrement = false;
596 if (null != this.autoInc) {
597 // if you already have data you can't change the data type
598 // if you don't have data - you wouldn't have incremented AutoIncrementCurrent.
599 AutoIncrementValue inc = this.autoInc;
601 this.AutoInc.Auto = inc.Auto; // recreate with correct datatype
602 this.AutoInc.Seed = inc.Seed;
603 this.AutoInc.Step = inc.Step;
604 if (this.autoInc.DataType == inc.DataType) {
605 this.autoInc.Current = inc.Current;
607 else if (inc.DataType == typeof(Int64)) {
608 this.AutoInc.Current = (System.Numerics.BigInteger)(long)inc.Current;
611 this.AutoInc.Current = checked((long)(System.Numerics.BigInteger)inc.Current);
620 ResCategoryAttribute(Res.DataCategory_Data),
621 DefaultValue(DataSetDateTime.UnspecifiedLocal),
622 RefreshProperties(RefreshProperties.All),
623 ResDescriptionAttribute(Res.DataColumnDateTimeModeDescr)
625 public DataSetDateTime DateTimeMode {
627 return _dateTimeMode;
630 if (_dateTimeMode != value) {
631 if (DataType != typeof(DateTime) && value != DataSetDateTime.UnspecifiedLocal) { //Check for column being DateTime. If the column is not DateTime make sure the value that is being is only the default[UnspecifiedLocal].
632 throw ExceptionBuilder.CannotSetDateTimeModeForNonDateTimeColumns();
635 case DataSetDateTime.Utc:
636 case DataSetDateTime.Local:
638 throw ExceptionBuilder.CantChangeDateTimeMode(_dateTimeMode, value);
641 case DataSetDateTime.Unspecified:
642 case DataSetDateTime.UnspecifiedLocal:
643 if (_dateTimeMode == DataSetDateTime.Unspecified || _dateTimeMode == DataSetDateTime.UnspecifiedLocal) {
647 throw ExceptionBuilder.CantChangeDateTimeMode(_dateTimeMode, value);
651 throw ExceptionBuilder.InvalidDateTimeMode(value);
653 _dateTimeMode = value;
659 /// <para>Gets or sets the default value for the
660 /// column when creating new rows.</para>
663 ResCategoryAttribute(Res.DataCategory_Data),
664 ResDescriptionAttribute(Res.DataColumnDefaultValueDescr),
665 TypeConverter(typeof(DefaultValueTypeConverter))
667 public object DefaultValue {
669 Debug.Assert(defaultValue != null, "It should not have been set to null.");
670 if (defaultValue == DBNull.Value && this.implementsINullable) { // for perf I dont access property
671 if (_storage != null)
672 defaultValue = _storage._nullValue;
673 else if (this.isSqlType)
674 defaultValue = SqlConvert.ChangeTypeForDefaultValue(defaultValue, this.dataType, FormatProvider);
675 else if (this.implementsINullable) {
676 System.Reflection.PropertyInfo propInfo = this.dataType.GetProperty("Null", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
677 if (propInfo != null)
678 defaultValue = propInfo.GetValue(null, null);
685 Bid.Trace("<ds.DataColumn.set_DefaultValue|API> %d#\n", ObjectID);
686 if (defaultValue == null || !DefaultValue.Equals(value)) {
688 throw ExceptionBuilder.DefaultValueAndAutoIncrement();
691 object newDefaultValue = (value == null) ? DBNull.Value : value;
692 if (newDefaultValue != DBNull.Value && DataType != typeof(Object)) {
693 // If the DefualtValue is different from the Column DataType, we will coerce the value to the DataType
695 newDefaultValue = SqlConvert.ChangeTypeForDefaultValue(newDefaultValue, DataType, FormatProvider);
697 catch (InvalidCastException ex) {
698 throw ExceptionBuilder.DefaultValueColumnDataType(ColumnName, newDefaultValue.GetType(), DataType, ex);
701 defaultValue = newDefaultValue;
702 // SQL BU Defect Tracking 401640: should not assign any value until conversion is successful.
703 defaultValueIsNull = ((newDefaultValue == DBNull.Value) || (this.ImplementsINullable && DataStorage.IsObjectSqlNull(newDefaultValue))) ? true : false;
708 internal bool DefaultValueIsNull {
710 return defaultValueIsNull;
714 internal void BindExpression() {
715 this.DataExpression.Bind(this.table);
720 /// or sets the expresssion used to either filter rows, calculate the column's
721 /// value, or create an aggregate column.</para>
724 ResCategoryAttribute(Res.DataCategory_Data),
725 RefreshProperties(RefreshProperties.All),
727 ResDescriptionAttribute(Res.DataColumnExpressionDescr)
729 public string Expression {
731 return (this.expression == null ? "" : this.expression.Expression);
735 Bid.ScopeEnter(out hscp, "<ds.DataColumn.set_Expression|API> %d#, '%ls'\n", ObjectID, value);
742 DataExpression newExpression = null;
743 if (value.Length > 0) {
744 DataExpression testExpression = new DataExpression(this.table, value, this.dataType);
745 if (testExpression.HasValue) {
746 newExpression = testExpression;
750 if (expression == null && newExpression != null) {
751 if (AutoIncrement || Unique) {
752 throw ExceptionBuilder.ExpressionAndUnique();
755 // We need to make sure the column is not involved in any Constriants
757 for (int i = 0; i < table.Constraints.Count; i++) {
758 if (table.Constraints[i].ContainsColumn(this)) {
759 throw ExceptionBuilder.ExpressionAndConstraint(this, table.Constraints[i]);
764 bool oldReadOnly = ReadOnly;
768 catch (ReadOnlyException e) {
769 ExceptionBuilder.TraceExceptionForCapture(e);
770 ReadOnly = oldReadOnly;
771 throw ExceptionBuilder.ExpressionAndReadOnly();
775 // re-calculate the evaluation queue
776 if (this.table != null) {
777 if (newExpression != null && newExpression.DependsOn(this)) {
778 throw ExceptionBuilder.ExpressionCircular();
780 HandleDependentColumnList(expression, newExpression);
781 //hold onto oldExpression in case of error applying new Expression.
782 DataExpression oldExpression = this.expression;
783 this.expression = newExpression;
785 // because the column is attached to a table we need to re-calc values
787 if (newExpression == null) {
788 for (int i = 0; i < table.RecordCapacity; i++) {
793 this.table.EvaluateExpressions(this);
795 // SQLBU 501916: DataTable internal index is corrupted:'5'
796 this.table.ResetInternalIndexes(this);
797 this.table.EvaluateDependentExpressions(this);
799 catch (Exception e1) {
801 if (!ADP.IsCatchableExceptionType(e1)) {
804 ExceptionBuilder.TraceExceptionForCapture(e1);
806 // in the case of error we need to set the column expression to the old value
807 this.expression = oldExpression;
808 HandleDependentColumnList(newExpression, expression);
809 if (oldExpression == null) {
810 for (int i = 0; i < table.RecordCapacity; i++) {
815 this.table.EvaluateExpressions(this);
817 this.table.ResetInternalIndexes(this);
818 this.table.EvaluateDependentExpressions(this);
820 catch (Exception e2) {
822 if (!ADP.IsCatchableExceptionType(e2)) {
825 ExceptionBuilder.TraceExceptionWithoutRethrow(e2);
831 //if column is not attached to a table, just set.
832 this.expression = newExpression;
836 Bid.ScopeLeave(ref hscp);
842 /// <para>Gets the collection of custom user information.</para>
845 ResCategoryAttribute(Res.DataCategory_Data),
847 ResDescriptionAttribute(Res.ExtendedPropertiesDescr)
849 public PropertyCollection ExtendedProperties {
851 if (extendedProperties == null) {
852 extendedProperties = new PropertyCollection();
854 return extendedProperties;
859 /// Indicates whether this column is now storing data.
861 internal bool HasData {
863 return (_storage != null);
867 internal bool ImplementsINullable {
869 return implementsINullable;
873 internal bool ImplementsIChangeTracking {
875 return implementsIChangeTracking;
879 internal bool ImplementsIRevertibleChangeTracking {
881 return implementsIRevertibleChangeTracking;
885 internal bool IsCloneable {
887 Debug.Assert(null != _storage, "no storage");
888 return _storage._isCloneable;
892 internal bool IsStringType {
894 Debug.Assert(null != _storage, "no storage");
895 return _storage._isStringType;
899 internal bool IsValueType {
901 Debug.Assert(null != _storage, "no storage");
902 return _storage._isValueType;
906 internal bool IsSqlType {
912 private void SetMaxLengthSimpleType() {
913 if (this.simpleType != null) {
914 Debug.Assert(this.simpleType.CanHaveMaxLength(), "expected simpleType to be string");
916 this.simpleType.MaxLength = maxLength;
917 // check if we reset the simpleType back to plain string
918 if (this.simpleType.IsPlainString()) {
919 this.simpleType = null;
922 // Named Simple Type's Name should not be null
923 if (this.simpleType.Name != null && this.dttype != null) {
924 // if MaxLength is changed, we need to make namedsimpletype annonymous simpletype
925 this.simpleType.ConvertToAnnonymousSimpleType();
930 else if (-1 < maxLength) {
931 this.SimpleType = SimpleType.CreateLimitedStringType(maxLength);
935 ResCategoryAttribute(Res.DataCategory_Data),
936 ResDescriptionAttribute(Res.DataColumnMaxLengthDescr),
939 public int MaxLength {
945 Bid.ScopeEnter(out hscp, "<ds.DataColumn.set_MaxLength|API> %d#, %d\n", ObjectID, value);
948 if (maxLength != value) {
949 if (this.ColumnMapping == MappingType.SimpleContent) {
950 throw ExceptionBuilder.CannotSetMaxLength2(this);
952 if ((DataType != typeof(string)) && (DataType != typeof(SqlString))) {
953 throw ExceptionBuilder.HasToBeStringType(this);
955 int oldValue = maxLength;
956 maxLength = Math.Max(value, -1);
958 if (((oldValue < 0) || (value < oldValue)) && (null != table) && table.EnforceConstraints) {
959 if (!CheckMaxLength()) {
960 maxLength = oldValue;
961 throw ExceptionBuilder.CannotSetMaxLength(this, value);
964 SetMaxLengthSimpleType();
968 Bid.ScopeLeave(ref hscp);
974 ResCategoryAttribute(Res.DataCategory_Data),
975 ResDescriptionAttribute(Res.DataColumnNamespaceDescr)
977 public string Namespace {
979 if (_columnUri == null) {
980 if (Table != null && columnMapping != MappingType.Attribute) {
981 return Table.Namespace;
988 Bid.Trace("<ds.DataColumn.set_Namespace|API> %d#, '%ls'\n", ObjectID, value);
990 if (_columnUri != value) {
991 if (columnMapping != MappingType.SimpleContent) {
992 RaisePropertyChanging("Namespace");
995 else if (value != this.Namespace) {
996 throw ExceptionBuilder.CannotChangeNamespace(this.ColumnName);
1002 private bool ShouldSerializeNamespace() {
1003 return (_columnUri != null);
1006 private void ResetNamespace() {
1007 this.Namespace = null;
1012 /// Gets the position of the column in the <see cref='System.Data.DataColumnCollection'/>
1017 ResCategoryAttribute(Res.DataCategory_Data),
1019 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
1020 ResDescriptionAttribute(Res.DataColumnOrdinalDescr)
1022 public int Ordinal {
1028 public void SetOrdinal(int ordinal) {
1029 if (_ordinal == -1) {
1030 throw ExceptionBuilder.ColumnNotInAnyTable();
1033 if (this._ordinal != ordinal) {
1034 table.Columns.MoveTo(this, ordinal);
1038 internal void SetOrdinalInternal(int ordinal) {
1040 if (this._ordinal != ordinal) {
1041 if (Unique && this._ordinal != -1 && ordinal == -1) {
1042 UniqueConstraint key = table.Constraints.FindKeyConstraint(this);
1044 table.Constraints.Remove(key);
1046 // SQLBU 429176: remove the sortIndex when DataColumn is removed
1047 if ((null != sortIndex) && (-1 == ordinal)) {
1048 Debug.Assert(2 <= sortIndex.RefCount, "bad sortIndex refcount");
1049 sortIndex.RemoveRef();
1050 sortIndex.RemoveRef(); // second should remove it from index collection
1053 int originalOrdinal = this._ordinal;
1054 this._ordinal = ordinal;
1055 if (originalOrdinal == -1 && this._ordinal != -1) {
1057 UniqueConstraint key = new UniqueConstraint(this);
1058 table.Constraints.Add(key);
1066 /// Gets or sets a value
1067 /// indicating whether the column allows changes once a row has been added to the table.
1071 ResCategoryAttribute(Res.DataCategory_Data),
1072 DefaultValue(false),
1073 ResDescriptionAttribute(Res.DataColumnReadOnlyDescr)
1075 public bool ReadOnly {
1080 Bid.Trace("<ds.DataColumn.set_ReadOnly|API> %d#, %d{bool}\n", ObjectID, value);
1081 if (readOnly != value) {
1082 if (!value && expression != null) {
1083 throw ExceptionBuilder.ReadOnlyAndExpression();
1085 this.readOnly = value;
1090 [DebuggerBrowsable(DebuggerBrowsableState.Never)] // don't have debugger view expand this
1091 private Index SortIndex {
1093 if (sortIndex == null) {
1094 IndexField[] indexDesc = new IndexField[] { new IndexField(this, false) };
1095 sortIndex = table.GetIndex(indexDesc, DataViewRowState.CurrentRows, (IFilter)null);
1104 /// Gets the <see cref='System.Data.DataTable'/> to which the column belongs to.
1108 ResCategoryAttribute(Res.DataCategory_Data),
1110 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
1111 ResDescriptionAttribute(Res.DataColumnDataTableDescr)
1113 public DataTable Table {
1120 /// Internal mechanism for changing the table pointer.
1122 internal void SetTable(DataTable table) {
1123 if (this.table != table) {
1125 if ((table == null) ||
1126 (!table.fInitInProgress && ((table.DataSet == null) || (!table.DataSet.fIsSchemaLoading && !table.DataSet.fInitInProgress)))) {
1127 // We need to re-bind all expression columns.
1128 this.DataExpression.Bind(table);
1131 if (Unique && this.table != null) {
1132 UniqueConstraint constraint = table.Constraints.FindKeyConstraint(this);
1133 if (constraint != null)
1134 table.Constraints.CanRemove(constraint, true);
1137 _storage = null; // empty out storage for reuse.
1141 private DataRow GetDataRow(int index) {
1142 return table.recordManager[index];
1146 /// This is how data is pushed in and out of the column.
1148 internal object this[int record] {
1150 table.recordManager.VerifyRecord(record);
1151 Debug.Assert(null != _storage, "null storage");
1152 return _storage.Get(record);
1156 table.recordManager.VerifyRecord(record);
1157 Debug.Assert(null != _storage, "no storage");
1158 Debug.Assert(null != value, "setting null, expecting dbnull");
1159 _storage.Set(record, value);
1160 Debug.Assert(null != this.table, "storage with no DataTable on column");
1162 catch (Exception e) {
1163 ExceptionBuilder.TraceExceptionForCapture(e);
1164 throw ExceptionBuilder.SetFailed(value, this, DataType, e);
1167 if (AutoIncrement) {
1168 if (!_storage.IsNull(record)) {
1169 this.AutoInc.SetCurrentAndIncrement(_storage.Get(record));
1172 if (Computed) {// if and only if it is Expression column, we will cache LastChangedColumn, otherwise DO NOT
1173 DataRow dr = GetDataRow(record);
1175 // at initialization time (datatable.NewRow(), we would fill the storage with default value, but at that time we wont have datarow)
1176 dr.LastChangedColumn = this;
1182 internal void InitializeRecord(int record) {
1183 Debug.Assert(null != _storage, "no storage");
1184 _storage.Set(record, DefaultValue);
1187 internal void SetValue(int record, object value) { // just silently set the value
1189 Debug.Assert(null != value, "setting null, expecting dbnull");
1190 Debug.Assert(null != this.table, "storage with no DataTable on column");
1191 Debug.Assert(null != _storage, "no storage");
1192 _storage.Set(record, value);
1194 catch (Exception e) {
1195 ExceptionBuilder.TraceExceptionForCapture(e);
1196 throw ExceptionBuilder.SetFailed(value, this, DataType, e);
1199 DataRow dr = GetDataRow(record);
1200 if (dr != null) { // at initialization time (datatable.NewRow(), we would fill the storage with default value, but at that time we wont have datarow)
1201 dr.LastChangedColumn = this;
1205 internal void FreeRecord(int record) {
1206 Debug.Assert(null != _storage, "no storage");
1207 _storage.Set(record, _storage._nullValue);
1212 /// Gets or sets a value indicating whether the values in each row of the column must be unique.
1216 ResCategoryAttribute(Res.DataCategory_Data),
1217 DefaultValue(false),
1218 ResDescriptionAttribute(Res.DataColumnUniqueDescr),
1219 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1221 public bool Unique {
1227 Bid.ScopeEnter(out hscp, "<ds.DataColumn.set_Unique|API> %d#, %d{bool}\n", ObjectID, value);
1229 if (unique != value) {
1230 if (value && expression != null) {
1231 throw ExceptionBuilder.UniqueAndExpression();
1233 UniqueConstraint oldConstraint = null;
1234 if (table != null) {
1238 for (System.Collections.IEnumerator e = Table.Constraints.GetEnumerator(); e.MoveNext(); ) {
1239 UniqueConstraint o = (e.Current as UniqueConstraint);
1240 if ((null != o) && (o.ColumnsReference.Length == 1) && (o.ColumnsReference[0] == this))
1243 Debug.Assert(oldConstraint != null, "Should have found a column to remove from the collection.");
1244 table.Constraints.CanRemove(oldConstraint, true);
1248 this.unique = value;
1250 if (table != null) {
1252 // This should not fail due to a duplicate constraint. unique would have
1253 // already been true if there was an existed UniqueConstraint for this column
1255 UniqueConstraint constraint = new UniqueConstraint(this);
1256 Debug.Assert(table.Constraints.FindKeyConstraint(this) == null, "Should not be a duplication constraint in collection");
1257 table.Constraints.Add(constraint);
1261 table.Constraints.Remove(oldConstraint);
1268 Bid.ScopeLeave(ref hscp);
1274 // FxCop Rule; getter not used! WebData 101301; so changing from Property to method
1275 internal void InternalUnique(bool value) {
1276 this.unique = value;
1279 internal string XmlDataType {
1288 internal SimpleType SimpleType {
1294 // there is a change, since we are supporting hierarchy(bacause of Names Simple Type) old check (just one leel base check) is wrong
1295 if (value != null && value.CanHaveMaxLength())
1296 maxLength = simpleType.MaxLength;// this is temp solution, since we dont let simple content to have
1297 //maxlength set but for simple type we want to set it, after coming to decision about it , we should
1298 // use MaxLength property
1303 /// <para>Gets the <see cref='System.Data.MappingType'/> of the column.</para>
1306 DefaultValue(MappingType.Element),
1307 ResDescriptionAttribute(Res.DataColumnMappingDescr)
1309 public virtual MappingType ColumnMapping {
1311 return columnMapping;
1314 Bid.Trace("<ds.DataColumn.set_ColumnMapping|API> %d#, %d{ds.MappingType}\n", ObjectID, (int)value);
1315 if (value != columnMapping) {
1317 if (value == MappingType.SimpleContent && table != null) {
1319 if (columnMapping == MappingType.Element)
1321 if (this.dataType == typeof(Char))
1322 throw ExceptionBuilder.CannotSetSimpleContent(ColumnName, this.dataType);
1324 if (table.XmlText != null && table.XmlText != this)
1325 throw ExceptionBuilder.CannotAddColumn3();
1326 if (table.ElementColumnCount > threshold)
1327 throw ExceptionBuilder.CannotAddColumn4(this.ColumnName);
1330 RaisePropertyChanging("ColumnMapping");
1332 if (table != null) {
1333 if (columnMapping == MappingType.SimpleContent)
1334 table.xmlText = null;
1336 if (value == MappingType.Element)
1337 table.ElementColumnCount++;
1338 else if (columnMapping == MappingType.Element)
1339 table.ElementColumnCount--;
1342 columnMapping = value;
1343 if (value == MappingType.SimpleContent) {
1345 if (table != null) {
1346 table.XmlText = this;
1348 this.SimpleType = null;
1354 internal event PropertyChangedEventHandler PropertyChanging {
1356 onPropertyChangingDelegate += value;
1359 onPropertyChangingDelegate -= value;
1363 internal void CheckColumnConstraint(DataRow row, DataRowAction action) {
1364 if (table.UpdatingCurrent(row, action)) {
1366 CheckMaxLength(row);
1370 internal bool CheckMaxLength() {
1371 if ((0 <= maxLength) && (null != Table) && (0 < Table.Rows.Count)) {
1372 Debug.Assert(IsStringType, "not a String or SqlString column");
1373 foreach (DataRow dr in Table.Rows) {
1374 if (dr.HasVersion(DataRowVersion.Current)) {
1375 if (maxLength < GetStringLength(dr.GetCurrentRecordNo())) {
1384 internal void CheckMaxLength(DataRow dr) {
1385 if (0 <= maxLength) {
1386 Debug.Assert(IsStringType, "not a String or SqlString column");
1387 if (maxLength < GetStringLength(dr.GetDefaultRecord())) {
1388 throw ExceptionBuilder.LongerThanMaxLength(this);
1393 internal protected void CheckNotAllowNull() {
1394 if (_storage == null)
1397 if (sortIndex != null) {
1398 if (sortIndex.IsKeyInIndex(_storage._nullValue)) {// here we do use strong typed NULL for Sql types
1399 throw ExceptionBuilder.NullKeyValues(ColumnName);
1402 else { // since we do not have index, we so sequential search
1403 foreach (DataRow dr in this.table.Rows) {
1404 if (dr.RowState == DataRowState.Deleted)
1406 if (!implementsINullable) {
1407 if (dr[this] == DBNull.Value) {
1408 throw ExceptionBuilder.NullKeyValues(ColumnName);
1412 if (DataStorage.IsObjectNull(dr[this])) {
1413 throw ExceptionBuilder.NullKeyValues(ColumnName);
1420 internal void CheckNullable(DataRow row) {
1422 Debug.Assert(null != _storage, "no storage");
1423 if (_storage.IsNull(row.GetDefaultRecord())) {
1424 throw ExceptionBuilder.NullValues(ColumnName);
1429 protected void CheckUnique() {
1430 if (!SortIndex.CheckUnique()) {
1431 // Throws an exception and the name of any column if its Unique property set to
1432 // True and non-unique values are found in the column.
1433 throw ExceptionBuilder.NonUniqueValues(ColumnName);
1437 internal int Compare(int record1, int record2) {
1438 Debug.Assert(null != _storage, "null storage");
1439 return _storage.Compare(record1, record2);
1442 internal bool CompareValueTo(int record1, object value, bool checkType) {
1443 // this method is used to make sure value and exact type match.
1444 int valuesMatch = CompareValueTo(record1, value);
1445 // if values match according to storage, do extra checks for exact compare
1446 if (valuesMatch == 0) {
1447 Type leftType = value.GetType();
1448 Type rightType = _storage.Get(record1).GetType();
1449 // if strings, then do exact character by character check
1450 if (leftType == typeof(System.String) && rightType == typeof(System.String)) {
1451 return String.CompareOrdinal((string)_storage.Get(record1), (string)value) == 0 ? true : false;
1453 // make sure same type
1454 else if (leftType == rightType) {
1461 internal int CompareValueTo(int record1, object value) {
1462 Debug.Assert(null != _storage, "null storage");
1463 return _storage.CompareValueTo(record1, value);
1466 internal object ConvertValue(object value) {
1467 Debug.Assert(null != _storage, "null storage");
1468 return _storage.ConvertValue(value);
1471 internal void Copy(int srcRecordNo, int dstRecordNo) {
1472 Debug.Assert(null != _storage, "null storage");
1473 _storage.Copy(srcRecordNo, dstRecordNo);
1476 // Prevent inlining so that reflection calls are not moved to caller that may be in a different assembly that may have a different grant set.
1477 [MethodImpl(MethodImplOptions.NoInlining)]
1478 internal DataColumn Clone() {
1479 DataColumn clone = (DataColumn)Activator.CreateInstance(this.GetType());
1480 // set All properties
1481 // clone.columnMapping = columnMapping;
1483 clone.SimpleType = SimpleType;
1485 clone.allowNull = allowNull;
1486 if (null != this.autoInc) {
1487 clone.autoInc = this.autoInc.Clone();
1489 clone.caption = caption;
1490 clone.ColumnName = ColumnName;
1491 clone._columnUri = _columnUri;
1492 clone._columnPrefix = _columnPrefix;
1493 clone.DataType = DataType;
1494 clone.defaultValue = defaultValue;
1495 clone.defaultValueIsNull = ((defaultValue == DBNull.Value) || (clone.ImplementsINullable && DataStorage.IsObjectSqlNull(defaultValue))) ? true : false;
1496 clone.columnMapping = columnMapping;// clone column Mapping since we dont let MaxLength to be set throu API
1498 clone.readOnly = readOnly;
1499 clone.MaxLength = MaxLength;
1500 clone.dttype = dttype;
1501 clone._dateTimeMode = _dateTimeMode;
1504 // so if we have set it, we should continue preserving the information
1506 // ...Extended Properties
1507 if (this.extendedProperties != null) {
1508 foreach (Object key in this.extendedProperties.Keys) {
1509 clone.ExtendedProperties[key] = this.extendedProperties[key];
1517 /// <para>Finds a relation that this column is the sole child of or null.</para>
1519 internal DataRelation FindParentRelation() {
1520 DataRelation[] parentRelations = new DataRelation[Table.ParentRelations.Count];
1521 Table.ParentRelations.CopyTo(parentRelations, 0);
1523 for (int i = 0; i < parentRelations.Length; i++) {
1524 DataRelation relation = parentRelations[i];
1525 DataKey key = relation.ChildKey;
1526 if (key.ColumnsReference.Length == 1 && key.ColumnsReference[0] == this) {
1530 // should we throw an exception?
1535 internal object GetAggregateValue(int[] records, AggregateType kind) {
1536 if (_storage == null) {
1537 if (kind == AggregateType.Count)
1540 return DBNull.Value;
1542 return _storage.Aggregate(records, kind);
1545 private int GetStringLength(int record) {
1546 Debug.Assert(null != _storage, "no storage");
1547 return _storage.GetStringLength(record);
1550 internal void Init(int record) {
1551 if (AutoIncrement) {
1552 object value = this.autoInc.Current;
1553 this.autoInc.MoveAfter();
1554 Debug.Assert(null != _storage, "no storage");
1555 _storage.Set(record, value);
1558 this[record] = defaultValue;
1561 internal static bool IsAutoIncrementType(Type dataType) {
1562 return ((dataType == typeof(Int32)) || (dataType == typeof(Int64)) || (dataType == typeof(Int16)) || (dataType == typeof(Decimal)) || (dataType == typeof(System.Numerics.BigInteger)) ||
1563 (dataType == typeof(SqlInt32)) || (dataType == typeof(SqlInt64)) || (dataType == typeof(SqlInt16)) || (dataType == typeof(SqlDecimal)));
1566 private bool IsColumnMappingValid(StorageType typeCode, MappingType mapping) {
1567 if ((mapping != MappingType.Element) && DataStorage.IsTypeCustomType(typeCode)) {
1573 internal bool IsCustomType {
1575 if (null != _storage)
1576 return _storage._isCustomDefinedType;
1577 return DataStorage.IsTypeCustomType(DataType);
1581 internal bool IsValueCustomTypeInstance(object value) {
1582 // if instance is not a storage supported type (built in or SQL types)
1583 return (DataStorage.IsTypeCustomType(value.GetType()) && !(value is Type));
1586 internal bool ImplementsIXMLSerializable {
1588 return implementsIXMLSerializable;
1592 internal bool IsNull(int record) {
1593 Debug.Assert(null != _storage, "no storage");
1594 return _storage.IsNull(record);
1598 /// Returns true if this column is a part of a Parent or Child key for a relation.
1600 internal bool IsInRelation() {
1602 DataRelationCollection rels = table.ParentRelations;
1604 Debug.Assert(rels != null, "Invalid ParentRelations");
1605 for (int i = 0; i < rels.Count; i++) {
1606 key = rels[i].ChildKey;
1607 Debug.Assert(key.HasValue, "Invalid child key (null)");
1608 if (key.ContainsColumn(this)) {
1612 rels = table.ChildRelations;
1613 Debug.Assert(rels != null, "Invalid ChildRelations");
1614 for (int i = 0; i < rels.Count; i++) {
1615 key = rels[i].ParentKey;
1616 Debug.Assert(key.HasValue, "Invalid parent key (null)");
1617 if (key.ContainsColumn(this)) {
1624 internal bool IsMaxLengthViolated() {
1630 string errorText = null;
1632 foreach (DataRow dr in Table.Rows) {
1633 if (dr.HasVersion(DataRowVersion.Current)) {
1635 if (!this.isSqlType) {
1636 if (value != null && value != DBNull.Value && ((string)value).Length > MaxLength) {
1637 if (errorText == null) {
1638 errorText = ExceptionBuilder.MaxLengthViolationText(this.ColumnName);
1640 dr.RowError = errorText;
1641 dr.SetColumnError(this, errorText);
1646 if (!DataStorage.IsObjectNull(value) && ((SqlString)value).Value.Length > MaxLength) {
1647 if (errorText == null) {
1648 errorText = ExceptionBuilder.MaxLengthViolationText(this.ColumnName);
1650 dr.RowError = errorText;
1651 dr.SetColumnError(this, errorText);
1660 internal bool IsNotAllowDBNullViolated() {//
1661 Index index = this.SortIndex;
1662 DataRow[] rows = index.GetRows(index.FindRecords(DBNull.Value));
1663 for (int i = 0; i < rows.Length; i++) {
1664 string errorText = ExceptionBuilder.NotAllowDBNullViolationText(this.ColumnName);
1665 rows[i].RowError = errorText;
1666 rows[i].SetColumnError(this, errorText);
1668 return (rows.Length > 0);
1671 internal void FinishInitInProgress() {
1676 protected virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent) {
1677 if (onPropertyChangingDelegate != null)
1678 onPropertyChangingDelegate(this, pcevent);
1681 protected internal void RaisePropertyChanging(string name) {
1682 OnPropertyChanging(new PropertyChangedEventArgs(name));
1685 private void InsureStorage() {
1686 if (_storage == null) {
1687 _storage = DataStorage.CreateStorage(this, dataType, _storageType);
1691 internal void SetCapacity(int capacity) {
1693 _storage.SetCapacity(capacity);
1696 private bool ShouldSerializeDefaultValue() {
1697 return (!DefaultValueIsNull);
1700 internal void OnSetDataSet() {
1703 // Returns the <see cref='System.Data.DataColumn.Expression'/> of the column, if one exists.
1704 public override string ToString() {
1705 if (this.expression == null)
1706 return this.ColumnName;
1708 return this.ColumnName + " + " + this.Expression;
1713 internal object ConvertXmlToObject(string s) {
1714 Debug.Assert(s != null, "Caller is resposible for missing element/attribure case");
1716 return _storage.ConvertXmlToObject(s);
1719 internal object ConvertXmlToObject(XmlReader xmlReader, XmlRootAttribute xmlAttrib) {
1721 return _storage.ConvertXmlToObject(xmlReader, xmlAttrib);
1725 internal string ConvertObjectToXml(object value) {
1726 Debug.Assert(value != null && (value != DBNull.Value), "Caller is resposible for checking on DBNull");
1728 return _storage.ConvertObjectToXml(value);
1731 internal void ConvertObjectToXml(object value, XmlWriter xmlWriter, XmlRootAttribute xmlAttrib) {
1732 Debug.Assert(value != null && (value != DBNull.Value), "Caller is resposible for checking on DBNull");
1734 _storage.ConvertObjectToXml(value, xmlWriter, xmlAttrib);
1737 internal object GetEmptyColumnStore(int recordCount) {
1739 return _storage.GetEmptyStorageInternal(recordCount);
1742 internal void CopyValueIntoStore(int record, object store, BitArray nullbits, int storeIndex) {
1743 Debug.Assert(null != _storage, "no storage");
1744 _storage.CopyValueInternal(record, store, nullbits, storeIndex);
1747 internal void SetStorage(object store, BitArray nullbits) {
1749 _storage.SetStorageInternal(store, nullbits);
1752 internal void AddDependentColumn(DataColumn expressionColumn) {
1753 if (dependentColumns == null) {
1754 dependentColumns = new List<DataColumn>();
1756 Debug.Assert(!dependentColumns.Contains(expressionColumn), "duplicate column - expected to be unique");
1757 dependentColumns.Add(expressionColumn);
1758 this.table.AddDependentColumn(expressionColumn);
1761 internal void RemoveDependentColumn(DataColumn expressionColumn) {
1762 if (dependentColumns != null && dependentColumns.Contains(expressionColumn)) {
1763 dependentColumns.Remove(expressionColumn);
1765 this.table.RemoveDependentColumn(expressionColumn);
1768 internal void HandleDependentColumnList(DataExpression oldExpression, DataExpression newExpression) {
1769 DataColumn[] dependency;
1770 // remove this column from the dependentColumn list of the columns this column depends on.
1771 if (oldExpression != null) {
1772 dependency = oldExpression.GetDependency();
1773 foreach (DataColumn col in dependency) {
1774 Debug.Assert(null != col, "null datacolumn in expression dependencies");
1775 col.RemoveDependentColumn(this);
1776 if (col.table != this.table) {
1777 this.table.RemoveDependentColumn(this);
1780 this.table.RemoveDependentColumn(this);
1783 if (newExpression != null) {
1784 // get the list of columns that this expression depends on
1785 dependency = newExpression.GetDependency();
1786 // add this column to dependent column list of each column this column depends on
1787 foreach (DataColumn col in dependency) {
1788 col.AddDependentColumn(this);
1789 if (col.table != this.table) {
1790 this.table.AddDependentColumn(this);
1793 this.table.AddDependentColumn(this);
1798 internal abstract class AutoIncrementValue {
1801 internal bool Auto {
1802 get { return this.auto; }
1803 set { this.auto = value; }
1805 internal abstract object Current { get; set; }
1806 internal abstract long Seed { get; set; }
1807 internal abstract long Step { get; set; }
1808 internal abstract Type DataType { get; }
1810 internal abstract void SetCurrent(object value, IFormatProvider formatProvider);
1811 internal abstract void SetCurrentAndIncrement(object value);
1812 internal abstract void MoveAfter();
1814 internal AutoIncrementValue Clone() {
1815 AutoIncrementValue clone = (this is AutoIncrementInt64) ? (AutoIncrementValue)new AutoIncrementInt64() : (AutoIncrementValue)new AutoIncrementBigInteger();
1816 clone.Auto = this.Auto;
1817 clone.Seed = this.Seed;
1818 clone.Step = this.Step;
1819 clone.Current = this.Current;
1824 /// <summary>the auto stepped value with Int64 representation</summary>
1825 /// <remarks>use unchecked behavior for Dev10 Bug 568510</remarks>
1826 internal sealed class AutoIncrementInt64 : AutoIncrementValue {
1827 /// <summary>the last returned auto incremented value</summary>
1828 private System.Int64 current;
1830 /// <summary>the initial value use to set current</summary>
1831 private System.Int64 seed;
1833 /// <summary>the value by which to offset the next value</summary>
1834 private System.Int64 step = 1;
1836 /// <summary>Gets and sets the current auto incremented value to use</summary>
1837 internal override object Current {
1838 get { return this.current; }
1839 set { this.current = (Int64)value; }
1842 internal override Type DataType { get { return typeof(System.Int64); } }
1844 /// <summary>Get and sets the initial seed value.</summary>
1845 internal override long Seed {
1846 get { return this.seed; }
1848 if ((this.current == this.seed) || this.BoundaryCheck(value)) {
1849 this.current = value;
1855 /// <summary>Get and sets the stepping value.</summary>
1856 /// <exception cref="ArugmentException">if value is 0</exception>
1857 internal override long Step {
1858 get { return this.step; }
1861 throw ExceptionBuilder.AutoIncrementSeed();
1863 if (this.step != value) {
1864 if (this.current != this.Seed) {
1865 this.current = unchecked(this.current - this.step + value);
1872 internal override void MoveAfter() {
1873 this.current = unchecked(this.current + this.step);
1876 internal override void SetCurrent(object value, IFormatProvider formatProvider) {
1877 this.current = Convert.ToInt64(value, formatProvider);
1880 internal override void SetCurrentAndIncrement(object value) {
1881 Debug.Assert(null != value && DataColumn.IsAutoIncrementType(value.GetType()) && !(value is System.Numerics.BigInteger), "unexpected value for autoincrement");
1882 System.Int64 v = (Int64)SqlConvert.ChangeType2(value, StorageType.Int64, typeof(Int64), CultureInfo.InvariantCulture);
1883 if (this.BoundaryCheck(v)) {
1884 this.current = unchecked(v + this.step);
1888 private bool BoundaryCheck(System.Numerics.BigInteger value) {
1889 return (((this.step < 0) && (value <= this.current)) || ((0 < this.step) && (this.current <= value)));
1893 /// <summary>the auto stepped value with BigInteger representation</summary>
1894 internal sealed class AutoIncrementBigInteger : AutoIncrementValue {
1895 /// <summary>the current auto incremented value to use</summary>
1896 private System.Numerics.BigInteger current;
1898 /// <summary>the initial value use to set current</summary>
1899 private System.Int64 seed;
1901 /// <summary>the value by which to offset the next value</summary>
1902 private System.Numerics.BigInteger step = 1;
1904 /// <summary>Gets and sets the current auto incremented value to use</summary>
1905 internal override object Current {
1906 get { return this.current; }
1907 set { this.current = (System.Numerics.BigInteger)value; }
1910 internal override Type DataType { get { return typeof(System.Numerics.BigInteger); } }
1912 /// <summary>Get and sets the initial seed value.</summary>
1913 internal override long Seed {
1914 get { return this.seed; }
1916 if ((this.current == this.seed) || this.BoundaryCheck(value)) {
1917 this.current = value;
1923 /// <summary>Get and sets the stepping value.</summary>
1924 /// <exception cref="ArugmentException">if value is 0</exception>
1925 internal override long Step {
1926 get { return (long)this.step; }
1929 throw ExceptionBuilder.AutoIncrementSeed();
1931 if (this.step != value) {
1932 if (this.current != this.Seed) {
1933 this.current = checked(this.current - this.step + value);
1940 internal override void MoveAfter() {
1941 this.current = checked(this.current + this.step);
1944 internal override void SetCurrent(object value, IFormatProvider formatProvider) {
1945 this.current = BigIntegerStorage.ConvertToBigInteger(value, formatProvider);
1948 internal override void SetCurrentAndIncrement(object value) {
1949 System.Numerics.BigInteger v = (System.Numerics.BigInteger)value;
1950 if (this.BoundaryCheck(v)) {
1951 this.current = v + this.step;
1955 private bool BoundaryCheck(System.Numerics.BigInteger value) {
1956 return (((this.step < 0) && (value <= this.current)) || ((0 < this.step) && (this.current <= value)));