2 // System.Data.DataTable.cs
5 // Franklin Wise <gracenote@earthlink.net>
6 // Christopher Podurgiel (cpodurgiel@msn.com)
7 // Daniel Morgan <danmorg@sc.rr.com>
8 // Rodrigo Moya <rodrigo@ximian.com>
9 // Tim Coleman (tim@timcoleman.com)
10 // Ville Palo <vi64pa@koti.soon.fi>
12 // (C) Chris Podurgiel
13 // (C) Ximian, Inc 2002
14 // Copyright (C) Tim Coleman, 2002-2003
15 // Copyright (C) Daniel Morgan, 2002-2003
19 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
21 // Permission is hereby granted, free of charge, to any person obtaining
22 // a copy of this software and associated documentation files (the
23 // "Software"), to deal in the Software without restriction, including
24 // without limitation the rights to use, copy, modify, merge, publish,
25 // distribute, sublicense, and/or sell copies of the Software, and to
26 // permit persons to whom the Software is furnished to do so, subject to
27 // the following conditions:
29 // The above copyright notice and this permission notice shall be
30 // included in all copies or substantial portions of the Software.
32 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 using System.Data.Common;
43 using System.Collections;
44 using System.ComponentModel;
45 using System.Globalization;
47 using System.Runtime.Serialization;
49 using System.Xml.Schema;
50 using Mono.Data.SqlExpressions;
52 namespace System.Data {
55 [DefaultEvent ("RowChanging")]
56 [DefaultProperty ("TableName")]
57 [DesignTimeVisible (false)]
58 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DataTableEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
60 public class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable
64 internal DataSet dataSet;
66 private bool _caseSensitive;
67 private DataColumnCollection _columnCollection;
68 private ConstraintCollection _constraintCollection;
69 private DataView _defaultView;
71 private string _displayExpression;
72 private PropertyCollection _extendedProperties;
73 private bool _hasErrors;
74 private CultureInfo _locale;
75 private int _minimumCapacity;
76 private string _nameSpace;
77 private DataRelationCollection _childRelations;
78 private DataRelationCollection _parentRelations;
79 private string _prefix;
80 private DataColumn[] _primaryKey;
81 private DataRowCollection _rows;
83 private string _tableName;
84 private bool _containsListCollection;
85 private string _encodedTableName;
86 internal bool _duringDataLoad;
87 internal bool _nullConstraintViolationDuringDataLoad;
88 private bool dataSetPrevEnforceConstraints;
89 private bool dataTablePrevEnforceConstraints;
90 private bool enforceConstraints = true;
91 private DataRowBuilder _rowBuilder;
92 private ArrayList _indexes;
93 private RecordCache _recordCache;
94 private int _defaultValuesRowIndex = -1;
95 protected internal bool fInitInProgress;
97 // If CaseSensitive property is changed once it does not anymore follow owner DataSet's
98 // CaseSensitive property. So when you lost you virginity it's gone for ever
99 private bool _virginCaseSensitive = true;
103 private delegate void PostEndInit();
106 /// Initializes a new instance of the DataTable class with no arguments.
111 _columnCollection = new DataColumnCollection(this);
112 _constraintCollection = new ConstraintCollection(this);
113 _extendedProperties = new PropertyCollection();
116 _caseSensitive = false; //default value
117 _displayExpression = null;
120 _rows = new DataRowCollection (this);
121 _indexes = new ArrayList();
122 _recordCache = new RecordCache(this);
124 //LAMESPEC: spec says 25 impl does 50
125 _minimumCapacity = 50;
127 _childRelations = new DataRelationCollection.DataTableRelationCollection (this);
128 _parentRelations = new DataRelationCollection.DataTableRelationCollection (this);
130 _defaultView = new DataView(this);
134 /// Intitalizes a new instance of the DataTable class with the specified table name.
136 public DataTable (string tableName) : this ()
138 _tableName = tableName;
142 /// Initializes a new instance of the DataTable class with the SerializationInfo and the StreamingContext.
145 protected DataTable (SerializationInfo info, StreamingContext context)
148 string schema = info.GetString ("XmlSchema");
149 string data = info.GetString ("XmlDiffGram");
151 DataSet ds = new DataSet ();
152 ds.ReadXmlSchema (new StringReader (schema));
153 ds.Tables [0].CopyProperties (this);
155 ds.Tables.Add (this);
156 ds.ReadXml (new StringReader (data), XmlReadMode.DiffGram);
157 ds.Tables.Remove (this);
158 /* keeping for a while. With the change above, we shouldn't have to consider
159 * DataTable mode in schema inference/read.
160 XmlSchemaMapper mapper = new XmlSchemaMapper (this);
161 XmlTextReader xtr = new XmlTextReader(new StringReader (schema));
164 XmlDiffLoader loader = new XmlDiffLoader (this);
165 xtr = new XmlTextReader(new StringReader (data));
171 public DataTable (string tableName, string tbNamespace)
174 _nameSpace = tbNamespace;
179 /// Indicates whether string comparisons within the table are case-sensitive.
181 [DataSysDescription ("Indicates whether comparing strings within the table is case sensitive.")]
182 public bool CaseSensitive {
184 if (_virginCaseSensitive && dataSet != null)
185 return dataSet.CaseSensitive;
187 return _caseSensitive;
190 if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
191 throw new ArgumentException ("Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.");
193 _virginCaseSensitive = false;
194 _caseSensitive = value;
198 internal bool VirginCaseSensitive {
199 get { return _virginCaseSensitive; }
200 set { _virginCaseSensitive = value; }
203 internal ArrayList Indexes{
204 get { return _indexes; }
207 internal void ChangedDataColumn (DataRow dr, DataColumn dc, object pv)
209 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
213 internal void ChangingDataColumn (DataRow dr, DataColumn dc, object pv)
215 DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
216 OnColumnChanging (e);
219 internal void DeletedDataRow (DataRow dr, DataRowAction action)
221 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
225 internal void DeletingDataRow (DataRow dr, DataRowAction action)
227 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
231 internal void ChangedDataRow (DataRow dr, DataRowAction action)
233 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
237 internal void ChangingDataRow (DataRow dr, DataRowAction action)
239 DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
244 /// Gets the collection of child relations for this DataTable.
247 [DataSysDescription ("Returns the child relations for this table.")]
248 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
249 public DataRelationCollection ChildRelations {
251 return _childRelations;
256 /// Gets the collection of columns that belong to this table.
258 [DataCategory ("Data")]
259 [DataSysDescription ("The collection that holds the columns for this table.")]
260 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
261 public DataColumnCollection Columns {
262 get { return _columnCollection; }
266 /// Gets the collection of constraints maintained by this table.
268 [DataCategory ("Data")]
269 [DataSysDescription ("The collection that holds the constraints for this table.")]
270 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
271 public ConstraintCollection Constraints {
272 get { return _constraintCollection; }
276 /// Gets the DataSet that this table belongs to.
279 [DataSysDescription ("Indicates the DataSet to which this table belongs.")]
280 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
281 public DataSet DataSet {
282 get { return dataSet; }
288 /// Gets a customized view of the table which may
289 /// include a filtered view, or a cursor position.
293 [DataSysDescription ("This is the default DataView for the table.")]
294 public DataView DefaultView {
295 get { return _defaultView; }
300 /// Gets or sets the expression that will return
301 /// a value used to represent this table in the user interface.
303 [DataCategory ("Data")]
304 [DataSysDescription ("The expression used to compute the data-bound value of this row.")]
306 public string DisplayExpression {
307 get { return _displayExpression == null ? "" : _displayExpression; }
308 set { _displayExpression = value; }
312 /// Gets the collection of customized user information.
315 [DataCategory ("Data")]
316 [DataSysDescription ("The collection that holds custom user information.")]
317 public PropertyCollection ExtendedProperties {
318 get { return _extendedProperties; }
322 /// Gets a value indicating whether there are errors in
323 /// any of the_rows in any of the tables of the DataSet to
324 /// which the table belongs.
327 [DataSysDescription ("Returns whether the table has errors.")]
328 public bool HasErrors {
330 // we can not use the _hasError flag because we do not know when to turn it off!
331 for (int i = 0; i < _rows.Count; i++)
333 if (_rows[i].HasErrors)
341 /// Gets or sets the locale information used to
342 /// compare strings within the table.
344 [DataSysDescription ("Indicates a locale under which to compare strings within the table.")]
345 public CultureInfo Locale {
347 // if the locale is null, we check for the DataSet locale
348 // and if the DataSet is null we return the current culture.
349 // this way if DataSet locale is changed, only if there is no locale for
350 // the DataTable it influece the Locale get;
354 return DataSet.Locale;
355 return CultureInfo.CurrentCulture;
358 if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
359 throw new ArgumentException ("Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.");
361 if (_locale == null || !_locale.Equals(value))
367 /// Gets or sets the initial starting size for this table.
369 [DataCategory ("Data")]
370 [DataSysDescription ("Indicates an initial starting size for this table.")]
372 public int MinimumCapacity {
373 get { return _minimumCapacity; }
374 set { _minimumCapacity = value; }
378 /// Gets or sets the namespace for the XML represenation
379 /// of the data stored in the DataTable.
381 [DataCategory ("Data")]
382 [DataSysDescription ("Indicates the XML uri namespace for the elements contained in this table.")]
383 public string Namespace {
385 if (_nameSpace != null)
387 else if (dataSet != null)
388 return dataSet.Namespace;
391 set { _nameSpace = value; }
395 /// Gets the collection of parent relations for
399 [DataSysDescription ("Returns the parent relations for this table.")]
400 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
401 public DataRelationCollection ParentRelations {
403 return _parentRelations;
408 /// Gets or sets the namespace for the XML represenation
409 /// of the data stored in the DataTable.
411 [DataCategory ("Data")]
412 [DataSysDescription ("Indicates the Prefix of the namespace used for this table in XML representation.")]
414 public string Prefix {
415 get { return _prefix == null ? "" : _prefix; }
417 // Prefix cannot contain any special characters other than '_' and ':'
418 for (int i = 0; i < value.Length; i++) {
419 if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
420 throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
427 /// Gets or sets an array of columns that function as
428 /// primary keys for the data table.
430 [DataCategory ("Data")]
431 [DataSysDescription ("Indicates the column(s) that represent the primary key for this table.")]
432 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.PrimaryKeyEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
433 [TypeConverterAttribute ("System.Data.PrimaryKeyTypeConverter, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
434 public DataColumn[] PrimaryKey {
436 UniqueConstraint uc = UniqueConstraint.GetPrimaryKeyConstraint( Constraints);
437 if (null == uc) return new DataColumn[] {};
441 UniqueConstraint oldPKConstraint = UniqueConstraint.GetPrimaryKeyConstraint( Constraints);
443 // first check if value is the same as current PK.
444 if (oldPKConstraint != null && DataColumn.AreColumnSetsTheSame(value, oldPKConstraint.Columns))
447 // remove PK Constraint
448 if(oldPKConstraint != null) {
449 Constraints.Remove(oldPKConstraint);
453 //Does constraint exist for these columns
454 UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet(
455 this.Constraints, (DataColumn[]) value);
457 //if constraint doesn't exist for columns
458 //create new unique primary key constraint
460 foreach (DataColumn Col in (DataColumn[]) value) {
462 if (Col.Table == null)
465 if (Columns.IndexOf (Col) < 0)
466 throw new ArgumentException ("PrimaryKey columns do not belong to this table.");
470 uc = new UniqueConstraint( (DataColumn[]) value, true);
472 Constraints.Add (uc);
475 //set existing constraint as the new primary key
476 UniqueConstraint.SetAsPrimaryKey(this.Constraints, uc);
479 // if we really supplied some columns fo primary key -
480 // rebuild indexes fo all foreign key constraints
481 if(value.Length > 0) {
482 foreach(ForeignKeyConstraint constraint in this.Constraints.ForeignKeyConstraints){
483 constraint.AssertConstraint();
488 // if primary key is null now - drop all the indexes for foreign key constraints
489 foreach(ForeignKeyConstraint constraint in this.Constraints.ForeignKeyConstraints){
490 Index index = constraint.Index;
491 constraint.Index = null;
492 this.DropIndex(index);
500 /// Gets the collection of_rows that belong to this table.
503 [DataSysDescription ("Indicates the collection that holds the rows of data for this table.")]
504 public DataRowCollection Rows {
505 get { return _rows; }
509 /// Gets or sets an System.ComponentModel.ISite
510 /// for the DataTable.
513 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
514 public override ISite Site {
515 get { return _site; }
516 set { _site = value; }
520 /// Gets or sets the name of the the DataTable.
522 [DataCategory ("Data")]
523 [DataSysDescription ("Indicates the name used to look up this table in the Tables collection of a DataSet.")]
525 [RefreshProperties (RefreshProperties.All)]
526 public string TableName {
527 get { return _tableName == null ? "" : _tableName; }
528 set { _tableName = value; }
531 bool IListSource.ContainsListCollection {
533 // the collection is a DataView
538 internal RecordCache RecordCache {
544 private bool EnforceConstraints {
545 get { return enforceConstraints; }
547 if (value != enforceConstraints) {
549 // first assert all unique constraints
550 foreach (UniqueConstraint uc in this.Constraints.UniqueConstraints)
551 uc.AssertConstraint ();
552 // then assert all foreign keys
553 foreach (ForeignKeyConstraint fk in this.Constraints.ForeignKeyConstraints)
554 fk.AssertConstraint ();
556 enforceConstraints = value;
561 internal bool RowsExist(DataColumn[] columns, DataColumn[] relatedColumns,DataRow row)
563 int curIndex = row.IndexFromVersion(DataRowVersion.Default);
564 int tmpRecord = RecordCache.NewRecord();
567 for (int i = 0; i < relatedColumns.Length; i++) {
568 // according to MSDN: the DataType value for both columns must be identical.
569 columns[i].DataContainer.CopyValue(relatedColumns[i].DataContainer, curIndex, tmpRecord);
572 return RowsExist(columns, tmpRecord, relatedColumns.Length);
575 RecordCache.DisposeRecord(tmpRecord);
579 bool RowsExist(DataColumn[] columns, int index, int length)
581 bool rowsExist = false;
582 Index indx = this.GetIndexByColumns (columns);
584 if (indx != null) { // lookup for a row in index
585 rowsExist = (indx.FindSimple (index, length, false) != null);
588 if(indx == null || rowsExist == false) {
589 // no index or rowExist= false, we have to perform full-table scan
590 // check that there is a parent for this row.
591 foreach (DataRow thisRow in this.Rows) {
592 if (thisRow.RowState != DataRowState.Deleted) {
594 // check if the values in the columns are equal
595 int thisIndex = thisRow.IndexFromVersion(DataRowVersion.Current);
596 foreach (DataColumn column in columns) {
597 if (column.DataContainer.CompareValues(thisIndex, index) != 0) {
602 if (match) {// there is a row with columns values equals to those supplied.
613 /// Commits all the changes made to this table since the
614 /// last time AcceptChanges was called.
616 public void AcceptChanges ()
618 //FIXME: Do we need to validate anything here or
619 //try to catch any errors to deal with them?
621 // we do not use foreach because if one of the rows is in Delete state
622 // it will be romeved from Rows and we get an exception.
624 for (int i = 0; i < Rows.Count; )
627 myRow.AcceptChanges();
629 // if the row state is Detached it meens that it was removed from row list (Rows)
630 // so we should not increase 'i'.
631 if (myRow.RowState != DataRowState.Detached)
637 /// Begins the initialization of a DataTable that is used
638 /// on a form or used by another component. The initialization
639 /// occurs at runtime.
641 public virtual void BeginInit ()
643 fInitInProgress = true;
647 /// Turns off notifications, index maintenance, and
648 /// constraints while loading data.
651 public void BeginLoadData ()
653 if (!this._duringDataLoad)
655 //duringDataLoad is important to EndLoadData and
656 //for not throwing unexpected exceptions.
657 this._duringDataLoad = true;
658 this._nullConstraintViolationDuringDataLoad = false;
660 if (this.dataSet != null)
662 //Saving old Enforce constraints state for later
663 //use in the EndLoadData.
664 this.dataSetPrevEnforceConstraints = this.dataSet.EnforceConstraints;
665 this.dataSet.EnforceConstraints = false;
668 //if table does not belong to any data set use EnforceConstraints of the table
669 this.dataTablePrevEnforceConstraints = this.EnforceConstraints;
670 this.EnforceConstraints = false;
677 /// Clears the DataTable of all data.
679 public void Clear () {
680 // TODO: thow an exception if any rows that
681 // have enforced child relations
682 // that would result in child rows being orphaned
683 // now we check if any ForeignKeyConstraint is referncing 'table'.
686 if (DataSet._xmlDataDocument != null)
687 throw new NotSupportedException ("Clear function on dataset and datatable is not supported on XmlDataDocument.");
689 IEnumerator tableEnumerator = DataSet.Tables.GetEnumerator();
691 // loop on all tables in dataset
692 while (tableEnumerator.MoveNext())
694 IEnumerator constraintEnumerator = ((DataTable) tableEnumerator.Current).Constraints.GetEnumerator();
695 // loop on all constrains in the current table
696 while (constraintEnumerator.MoveNext())
698 Object o = constraintEnumerator.Current;
699 // we only check ForeignKeyConstraint
700 if (o is ForeignKeyConstraint)
702 ForeignKeyConstraint fc = (ForeignKeyConstraint) o;
703 if(fc.RelatedTable == this && fc.Table.Rows.Count > 0)
704 throw new InvalidConstraintException("Cannot clear table " + fc.RelatedTable + " because ForeignKeyConstraint " + fc.ConstraintName + " enforces constraints and there are child rows in " + fc.Table);
715 /// Clones the structure of the DataTable, including
716 /// all DataTable schemas and constraints.
718 public virtual DataTable Clone ()
720 DataTable Copy = new DataTable ();
722 CopyProperties (Copy);
727 /// Computes the given expression on the current_rows that
728 /// pass the filter criteria.
731 public object Compute (string expression, string filter)
733 // expression is an aggregate function
734 // filter is an expression used to limit rows
736 DataRow[] rows = Select(filter);
738 Parser parser = new Parser (rows);
739 IExpression expr = parser.Compile (expression);
740 object obj = expr.Eval (rows[0]);
746 /// Copies both the structure and data for this DataTable.
748 public DataTable Copy ()
750 DataTable copy = Clone();
752 copy._duringDataLoad = true;
753 foreach (DataRow row in Rows) {
754 DataRow newRow = copy.NewNotInitializedRow();
755 copy.Rows.Add(newRow);
758 copy._duringDataLoad = false;
762 internal void CopyRow(DataRow fromRow,DataRow toRow)
764 fromRow.CopyState(toRow);
766 if (fromRow.HasVersion(DataRowVersion.Original)) {
767 toRow._original = toRow.Table.RecordCache.CopyRecord(this,fromRow._original,-1);
770 if (fromRow.HasVersion(DataRowVersion.Current)) {
771 toRow._current = toRow.Table.RecordCache.CopyRecord(this,fromRow._current,-1);
775 private void CopyProperties (DataTable Copy)
778 Copy.CaseSensitive = CaseSensitive;
779 Copy.VirginCaseSensitive = VirginCaseSensitive;
781 // Copy.ChildRelations
786 Copy.DisplayExpression = DisplayExpression;
787 if(ExtendedProperties.Count > 0) {
788 // Cannot copy extended properties directly as the property does not have a set accessor
789 Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
790 ExtendedProperties.Keys.CopyTo (tgtArray, 0);
791 for (int i=0; i < ExtendedProperties.Count; i++)
792 Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
794 Copy.Locale = Locale;
795 Copy.MinimumCapacity = MinimumCapacity;
796 Copy.Namespace = Namespace;
797 // Copy.ParentRelations
798 Copy.Prefix = Prefix;
800 Copy.TableName = TableName;
805 foreach (DataColumn Column in Columns) {
807 Copy.Columns.Add (CopyColumn (Column));
810 CopyConstraints(Copy);
811 // add primary key to the copy
812 if (PrimaryKey.Length > 0)
814 DataColumn[] pColumns = new DataColumn[PrimaryKey.Length];
815 for (int i = 0; i < pColumns.Length; i++)
816 pColumns[i] = Copy.Columns[PrimaryKey[i].ColumnName];
818 Copy.PrimaryKey = pColumns;
822 private void CopyConstraints(DataTable copy)
824 UniqueConstraint origUc;
825 UniqueConstraint copyUc;
826 for (int i = 0; i < this.Constraints.Count; i++)
828 if (this.Constraints[i] is UniqueConstraint)
830 origUc = (UniqueConstraint)this.Constraints[i];
831 DataColumn[] columns = new DataColumn[origUc.Columns.Length];
832 for (int j = 0; j < columns.Length; j++)
833 columns[j] = copy.Columns[origUc.Columns[j].ColumnName];
835 copyUc = new UniqueConstraint(origUc.ConstraintName, columns, origUc.IsPrimaryKey);
836 copy.Constraints.Add(copyUc);
841 /// Ends the initialization of a DataTable that is used
842 /// on a form or used by another component. The
843 /// initialization occurs at runtime.
846 public virtual void EndInit ()
848 fInitInProgress = false;
849 // Add the constraints
850 PostEndInit _postEndInit = new PostEndInit (_constraintCollection.PostEndInit);
855 /// Turns on notifications, index maintenance, and
856 /// constraints after loading data.
858 public void EndLoadData()
861 if (this._duringDataLoad)
864 if (this.dataSet !=null)
866 //Getting back to previous EnforceConstraint state
867 this.dataSet.EnforceConstraints = this.dataSetPrevEnforceConstraints;
870 //Getting back to the table's previous EnforceConstraint state
871 this.EnforceConstraints = this.dataTablePrevEnforceConstraints;
874 if(this._nullConstraintViolationDuringDataLoad) {
875 this._nullConstraintViolationDuringDataLoad = false;
876 throw new ConstraintException ("Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.");
879 //Returning from loading mode, raising exceptions as usual
880 this._duringDataLoad = false;
887 /// Gets a copy of the DataTable that contains all
888 /// changes made to it since it was loaded or
889 /// AcceptChanges was last called.
891 public DataTable GetChanges()
893 return GetChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
897 /// Gets a copy of the DataTable containing all
898 /// changes made to it since it was last loaded, or
899 /// since AcceptChanges was called, filtered by DataRowState.
901 public DataTable GetChanges(DataRowState rowStates)
903 DataTable copyTable = null;
905 IEnumerator rowEnumerator = Rows.GetEnumerator();
906 while (rowEnumerator.MoveNext()) {
907 DataRow row = (DataRow)rowEnumerator.Current;
908 // The spec says relationship constraints may cause Unchanged parent rows to be included but
909 // MS .NET 1.1 does not include Unchanged rows even if their child rows are changed.
910 if (row.IsRowChanged(rowStates)) {
911 if (copyTable == null)
913 DataRow newRow = copyTable.NewRow();
914 row.CopyValuesToRow(newRow);
915 copyTable.Rows.Add (newRow);
924 public DataTableReader GetDataReader ()
926 throw new NotImplementedException ();
931 /// Gets an array of DataRow objects that contain errors.
933 public DataRow[] GetErrors ()
935 ArrayList errors = new ArrayList();
936 for (int i = 0; i < _rows.Count; i++)
938 if (_rows[i].HasErrors)
939 errors.Add(_rows[i]);
942 return (DataRow[]) errors.ToArray(typeof(DataRow));
946 /// This member is only meant to support Mono's infrastructure
948 protected virtual DataTable CreateInstance ()
950 return Activator.CreateInstance (this.GetType (), true) as DataTable;
954 /// This member is only meant to support Mono's infrastructure
956 protected virtual Type GetRowType ()
958 return typeof (DataRow);
962 /// This member is only meant to support Mono's infrastructure
964 /// Used for Data Binding between System.Web.UI. controls
967 /// System.Windows.Forms controls like a DataGrid
969 IList IListSource.GetList ()
971 IList list = (IList) _defaultView;
976 /// Copies a DataRow into a DataTable, preserving any
977 /// property settings, as well as original and current values.
979 public void ImportRow (DataRow row)
981 DataRow newRow = NewRow();
983 row.CopyValuesToRow(newRow);
987 internal int DefaultValuesRowIndex
990 return _defaultValuesRowIndex;
995 /// This member is only meant to support Mono's infrastructure
997 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
1000 if (dataSet != null)
1003 dset = new DataSet ("tmpDataSet");
1004 dset.Tables.Add (this);
1007 StringWriter sw = new StringWriter ();
1008 XmlTextWriter tw = new XmlTextWriter (sw);
1009 dset.WriteIndividualTableContent (tw, this, XmlWriteMode.DiffGram);
1012 StringWriter sw2 = new StringWriter ();
1013 DataTableCollection tables = new DataTableCollection (dset);
1015 XmlSchema schema = dset.BuildSchema (tables, null);
1019 info.AddValue ("XmlSchema", sw2.ToString(), typeof(string));
1020 info.AddValue ("XmlDiffGram", sw.ToString(), typeof(string));
1025 public void Load (IDataReader reader)
1027 throw new NotImplementedException ();
1031 public void Load (IDataReader reader, LoadOption loadOption)
1033 throw new NotImplementedException ();
1038 /// Finds and updates a specific row. If no matching row
1039 /// is found, a new row is created using the given values.
1041 public DataRow LoadDataRow (object[] values, bool fAcceptChanges)
1044 if (PrimaryKey.Length == 0) {
1045 row = Rows.Add (values);
1047 row.AcceptChanges ();
1050 bool hasPrimaryValues = true;
1051 // initiate an array that has the values of the primary keys.
1052 object[] keyValues = new object[PrimaryKey.Length];
1053 for (int i = 0; i < keyValues.Length && hasPrimaryValues; i++)
1055 if(PrimaryKey[i].Ordinal < values.Length)
1056 keyValues[i] = values[PrimaryKey[i].Ordinal];
1058 hasPrimaryValues = false;
1061 if (hasPrimaryValues){
1062 // find the row in the table.
1063 row = Rows.Find(keyValues);
1067 row = Rows.Add (values);
1069 row.ItemArray = values;
1072 row.AcceptChanges ();
1078 internal DataRow LoadDataRow(IDataRecord record, int[] mapping, bool fAcceptChanges)
1081 if (PrimaryKey.Length == 0) {
1083 row.SetValuesFromDataRecord(record, mapping);
1086 if (fAcceptChanges) {
1087 row.AcceptChanges();
1091 bool hasPrimaryValues = true;
1092 int tmpRecord = this.RecordCache.NewRecord();
1094 for (int i = 0; i < PrimaryKey.Length && hasPrimaryValues; i++) {
1095 DataColumn primaryKeyColumn = PrimaryKey[i];
1096 int ordinal = primaryKeyColumn.Ordinal;
1097 if(ordinal < mapping.Length) {
1098 primaryKeyColumn.DataContainer.SetItemFromDataRecord(tmpRecord,record,mapping[ordinal]);
1101 hasPrimaryValues = false;
1105 if (hasPrimaryValues) {
1106 // find the row in the table.
1107 row = Rows.Find(tmpRecord,PrimaryKey.Length);
1111 this.RecordCache.DisposeRecord(tmpRecord);
1116 row.SetValuesFromDataRecord(record, mapping);
1120 row.SetValuesFromDataRecord(record, mapping);
1123 if (fAcceptChanges) {
1124 row.AcceptChanges();
1132 public DataRow LoadDataRow (object[] values, LoadOption loadOption)
1134 throw new NotImplementedException ();
1138 public void Merge (DataTable table)
1140 throw new NotImplementedException ();
1144 public void Merge (DataTable table, bool preserveChanges)
1146 throw new NotImplementedException ();
1150 public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
1152 throw new NotImplementedException ();
1157 /// Creates a new DataRow with the same schema as the table.
1159 public DataRow NewRow ()
1161 // initiate only one row builder.
1162 if (_rowBuilder == null)
1163 _rowBuilder = new DataRowBuilder (this, 0, 0);
1165 // new row get id -1.
1166 _rowBuilder._rowId = -1;
1168 // initialize default values row for the first time
1169 if ( _defaultValuesRowIndex == -1 ) {
1170 _defaultValuesRowIndex = RecordCache.NewRecord();
1171 foreach(DataColumn column in Columns) {
1172 column.DataContainer[_defaultValuesRowIndex] = column.DefaultValue;
1176 return this.NewRowFromBuilder (_rowBuilder);
1180 /// This member supports the .NET Framework infrastructure
1181 /// and is not intended to be used directly from your code.
1183 protected internal DataRow[] NewRowArray (int size)
1185 return (DataRow[]) Array.CreateInstance (GetRowType (), size);
1189 /// Creates a new row from an existing row.
1191 protected virtual DataRow NewRowFromBuilder (DataRowBuilder builder)
1193 return new DataRow (builder);
1196 internal DataRow NewNotInitializedRow()
1198 return new DataRow(this,-1);
1203 XmlReadMode ReadXml (Stream stream)
1205 throw new NotImplementedException ();
1208 public void ReadXmlSchema (Stream stream)
1210 XmlSchemaMapper mapper = new XmlSchemaMapper (this);
1211 mapper.Read (new XmlTextReader(stream));
1214 public void ReadXmlSchema (TextReader reader)
1216 XmlSchemaMapper mapper = new XmlSchemaMapper (this);
1217 mapper.Read (new XmlTextReader(reader));
1220 public void ReadXmlSchema (string fileName)
1222 StreamReader reader = new StreamReader (fileName);
1223 ReadXmlSchema (reader);
1227 public void ReadXmlSchema (XmlReader reader)
1229 XmlSchemaMapper mapper = new XmlSchemaMapper (this);
1230 mapper.Read (reader);
1235 /// Rolls back all changes that have been made to the
1236 /// table since it was loaded, or the last time AcceptChanges
1239 public void RejectChanges ()
1241 for (int i = _rows.Count - 1; i >= 0; i--) {
1242 DataRow row = _rows [i];
1243 if (row.RowState != DataRowState.Unchanged)
1244 _rows [i].RejectChanges ();
1249 /// Resets the DataTable to its original state.
1251 public virtual void Reset ()
1254 while (ParentRelations.Count > 0)
1256 if (dataSet.Relations.Contains(ParentRelations[ParentRelations.Count - 1].RelationName))
1257 dataSet.Relations.Remove(ParentRelations[ParentRelations.Count - 1]);
1260 while (ChildRelations.Count > 0)
1262 if (dataSet.Relations.Contains(ChildRelations[ChildRelations.Count - 1].RelationName))
1263 dataSet.Relations.Remove(ChildRelations[ChildRelations.Count - 1]);
1265 Constraints.Clear();
1270 /// Gets an array of all DataRow objects.
1272 public DataRow[] Select ()
1274 return Select(String.Empty, String.Empty, DataViewRowState.CurrentRows);
1278 /// Gets an array of all DataRow objects that match
1279 /// the filter criteria in order of primary key (or
1280 /// lacking one, order of addition.)
1282 public DataRow[] Select (string filterExpression)
1284 return Select(filterExpression, String.Empty, DataViewRowState.CurrentRows);
1288 /// Gets an array of all DataRow objects that
1289 /// match the filter criteria, in the the
1290 /// specified sort order.
1292 public DataRow[] Select (string filterExpression, string sort)
1294 return Select(filterExpression, sort, DataViewRowState.CurrentRows);
1298 /// Gets an array of all DataRow objects that match
1299 /// the filter in the order of the sort, that match
1300 /// the specified state.
1303 public DataRow[] Select(string filterExpression, string sort, DataViewRowState recordStates)
1305 if (filterExpression == null)
1306 filterExpression = String.Empty;
1308 IExpression filter = null;
1309 if (filterExpression != String.Empty) {
1310 Parser parser = new Parser ();
1311 filter = parser.Compile (filterExpression);
1314 ArrayList rowList = new ArrayList();
1315 int recordStateFilter = GetRowStateFilter(recordStates);
1316 foreach (DataRow row in Rows) {
1317 if (((int)row.RowState & recordStateFilter) != 0) {
1318 if (filter != null && !(bool)filter.Eval (row))
1324 DataRow[] dataRows = (DataRow[])rowList.ToArray(typeof(DataRow));
1326 if (sort != null && !sort.Equals(String.Empty))
1328 SortableColumn[] sortableColumns = null;
1330 sortableColumns = ParseTheSortString (sort);
1331 if (sortableColumns == null)
1332 throw new Exception ("sort expression result is null");
1333 if (sortableColumns.Length == 0)
1334 throw new Exception("sort expression result is 0");
1336 RowSorter rowSorter = new RowSorter (this, dataRows, sortableColumns);
1337 dataRows = rowSorter.SortRows ();
1339 sortableColumns = null;
1347 internal void AddIndex (Index index)
1349 if (_indexes == null)
1350 _indexes = new ArrayList();
1352 _indexes.Add (index);
1355 internal void RemoveIndex (Index indx)
1357 _indexes.Remove (indx);
1360 internal Index GetIndexByColumns (DataColumn[] columns)
1362 return GetIndexByColumns(columns,false,false);
1365 // internal Index GetIndexByColumnsExtended(DataColumn[] columns)
1367 // DataColumn[] pkColumns = this.PrimaryKey;
1368 // if((pkColumns != null) && (pkColumns.Length > 0)) {
1369 // DataColumn[] cols = new DataColumn[columns.Length + pkColumns.Length];
1370 // Array.Copy(columns,0,cols,0,columns.Length);
1371 // Array.Copy(pkColumns,0,cols,columns.Length,pkColumns.Length);
1373 // return _getIndexByColumns(cols,false,false);
1379 internal Index GetIndexByColumns (DataColumn[] columns, bool unique)
1381 return GetIndexByColumns(columns,unique,true);
1384 // internal Index GetIndexByColumnsExtended(DataColumn[] columns, bool unique)
1386 // DataColumn[] pkColumns = this.PrimaryKey;
1387 // if((pkColumns != null) && (pkColumns.Length > 0)) {
1388 // DataColumn[] cols = new DataColumn[columns.Length + pkColumns.Length];
1389 // Array.Copy(columns,0,cols,0,columns.Length);
1390 // Array.Copy(pkColumns,0,cols,columns.Length,pkColumns.Length);
1392 // return _getIndexByColumns(cols,unique,true);
1398 internal Index GetIndexByColumns(DataColumn[] columns, bool unique, bool useUnique)
1400 if (_indexes != null) {
1401 foreach (Index indx in _indexes) {
1403 if ((!useUnique) || ((useUnique)&& (indx.IsUnique))) {
1404 found = DataColumn.AreColumnSetsTheSame (indx.Columns, columns);
1414 internal void DeleteRowFromIndexes (DataRow row)
1416 if (_indexes != null) {
1417 foreach (Index indx in _indexes) {
1423 private static int GetRowStateFilter(DataViewRowState recordStates)
1427 if ((recordStates & DataViewRowState.Added) != 0)
1428 flag |= (int)DataRowState.Added;
1429 if ((recordStates & DataViewRowState.Deleted) != 0)
1430 flag |= (int)DataRowState.Deleted;
1431 if ((recordStates & DataViewRowState.ModifiedCurrent) != 0)
1432 flag |= (int)DataRowState.Modified;
1433 if ((recordStates & DataViewRowState.ModifiedOriginal) != 0)
1434 flag |= (int)DataRowState.Modified;
1435 if ((recordStates & DataViewRowState.Unchanged) != 0)
1436 flag |= (int)DataRowState.Unchanged;
1442 /// Gets the TableName and DisplayExpression, if
1443 /// there is one as a concatenated string.
1445 public override string ToString()
1447 //LAMESPEC: spec says concat the two. impl puts a
1448 //plus sign infront of DisplayExpression
1449 string retVal = TableName;
1450 if(DisplayExpression != null && DisplayExpression != "")
1451 retVal += " + " + DisplayExpression;
1457 public void WriteXml (Stream stream)
1459 throw new NotImplementedException ();
1463 public void WriteXml (TextWriter writer)
1465 throw new NotImplementedException ();
1469 public void WriteXml (XmlWriter writer)
1471 throw new NotImplementedException ();
1475 public void WriteXml (string fileName)
1477 throw new NotImplementedException ();
1481 public void WriteXml (Stream stream, XmlWriteMode mode)
1483 throw new NotImplementedException ();
1487 public void WriteXml (TextWriter writer, XmlWriteMode mode)
1489 throw new NotImplementedException ();
1493 public void WriteXml (XmlWriter writer, XmlWriteMode mode)
1495 throw new NotImplementedException ();
1499 public void WriteXml (string fileName, XmlWriteMode mode)
1501 throw new NotImplementedException ();
1505 public void WriteXmlSchema (Stream stream)
1507 throw new NotImplementedException ();
1511 public void WriteXmlSchema (TextWriter writer)
1513 throw new NotImplementedException ();
1517 public void WriteXmlSchema (XmlWriter writer)
1519 throw new NotImplementedException ();
1523 public void WriteXmlSchema (string fileName)
1525 throw new NotImplementedException ();
1532 /// Raises the ColumnChanged event.
1534 protected virtual void OnColumnChanged (DataColumnChangeEventArgs e) {
1535 if (null != ColumnChanged) {
1536 ColumnChanged (this, e);
1540 internal void RaiseOnColumnChanged (DataColumnChangeEventArgs e) {
1545 /// Raises the ColumnChanging event.
1547 protected virtual void OnColumnChanging (DataColumnChangeEventArgs e) {
1548 if (null != ColumnChanging) {
1549 ColumnChanging (this, e);
1554 /// Raises the PropertyChanging event.
1557 protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent) {
1558 // if (null != PropertyChanging)
1560 // PropertyChanging (this, e);
1565 /// Notifies the DataTable that a DataColumn is being removed.
1568 protected internal virtual void OnRemoveColumn (DataColumn column) {
1573 /// Raises the RowChanged event.
1575 protected virtual void OnRowChanged (DataRowChangeEventArgs e) {
1576 if (null != RowChanged) {
1577 RowChanged(this, e);
1583 /// Raises the RowChanging event.
1585 protected virtual void OnRowChanging (DataRowChangeEventArgs e) {
1586 if (null != RowChanging) {
1587 RowChanging(this, e);
1592 /// Raises the RowDeleted event.
1594 protected virtual void OnRowDeleted (DataRowChangeEventArgs e) {
1595 if (null != RowDeleted) {
1596 RowDeleted(this, e);
1601 /// Raises the RowDeleting event.
1603 protected virtual void OnRowDeleting (DataRowChangeEventArgs e) {
1604 if (null != RowDeleting) {
1605 RowDeleting(this, e);
1610 private DataColumn CopyColumn (DataColumn Column) {
1611 DataColumn Copy = new DataColumn ();
1613 // Copy all the properties of column
1614 Copy.AllowDBNull = Column.AllowDBNull;
1615 Copy.AutoIncrement = Column.AutoIncrement;
1616 Copy.AutoIncrementSeed = Column.AutoIncrementSeed;
1617 Copy.AutoIncrementStep = Column.AutoIncrementStep;
1618 Copy.Caption = Column.Caption;
1619 Copy.ColumnMapping = Column.ColumnMapping;
1620 Copy.ColumnName = Column.ColumnName;
1622 Copy.DataType = Column.DataType;
1623 Copy.DefaultValue = Column.DefaultValue;
1624 Copy.Expression = Column.Expression;
1625 //Copy.ExtendedProperties
1626 Copy.MaxLength = Column.MaxLength;
1627 Copy.Namespace = Column.Namespace;
1628 Copy.Prefix = Column.Prefix;
1629 Copy.ReadOnly = Column.ReadOnly;
1631 //we do not copy the unique value - it will be copyied when copying the constraints.
1632 //Copy.Unique = Column.Unique;
1638 /// Occurs when after a value has been changed for
1639 /// the specified DataColumn in a DataRow.
1641 [DataCategory ("Data")]
1642 [DataSysDescription ("Occurs when a value has been changed for this column.")]
1643 public event DataColumnChangeEventHandler ColumnChanged;
1646 /// Occurs when a value is being changed for the specified
1647 /// DataColumn in a DataRow.
1649 [DataCategory ("Data")]
1650 [DataSysDescription ("Occurs when a value has been submitted for this column. The user can modify the proposed value and should throw an exception to cancel the edit.")]
1651 public event DataColumnChangeEventHandler ColumnChanging;
1654 /// Occurs after a DataRow has been changed successfully.
1656 [DataCategory ("Data")]
1657 [DataSysDescription ("Occurs after a row in the table has been successfully edited.")]
1658 public event DataRowChangeEventHandler RowChanged;
1661 /// Occurs when a DataRow is changing.
1663 [DataCategory ("Data")]
1664 [DataSysDescription ("Occurs when the row is being changed so that the event handler can modify or cancel the change. The user can modify values in the row and should throw an exception to cancel the edit.")]
1665 public event DataRowChangeEventHandler RowChanging;
1668 /// Occurs after a row in the table has been deleted.
1670 [DataCategory ("Data")]
1671 [DataSysDescription ("Occurs after a row in the table has been successfully deleted.")]
1672 public event DataRowChangeEventHandler RowDeleted;
1675 /// Occurs before a row in the table is about to be deleted.
1677 [DataCategory ("Data")]
1678 [DataSysDescription ("Occurs when a row in the table marked for deletion. Throw an exception to cancel the deletion.")]
1679 public event DataRowChangeEventHandler RowDeleting;
1681 #endregion // Events
1684 /// Removes all UniqueConstraints
1686 private void RemoveUniqueConstraints ()
1688 foreach (Constraint Cons in Constraints) {
1690 if (Cons is UniqueConstraint) {
1691 Constraints.Remove (Cons);
1696 UniqueConstraint.SetAsPrimaryKey(this.Constraints, null);
1699 // to parse the sort string for DataTable:Select(expression,sort)
1700 // into sortable columns (think ORDER BY,
1701 // such as, "customer ASC, price DESC" )
1702 private SortableColumn[] ParseTheSortString (string sort)
1704 SortableColumn[] sortColumns = null;
1705 ArrayList columns = null;
1707 if (sort != null && !sort.Equals ("")) {
1708 columns = new ArrayList ();
1709 string[] columnExpression = sort.Trim ().Split (new char[1] {','});
1711 for (int c = 0; c < columnExpression.Length; c++) {
1712 string[] columnSortInfo = columnExpression[c].Trim ().Split (new char[1] {' '});
1714 string columnName = columnSortInfo[0].Trim ();
1715 string sortOrder = "ASC";
1716 if (columnSortInfo.Length > 1)
1717 sortOrder = columnSortInfo[1].Trim ().ToUpper (Locale);
1719 ListSortDirection sortDirection = ListSortDirection.Ascending;
1720 switch (sortOrder) {
1722 sortDirection = ListSortDirection.Ascending;
1725 sortDirection = ListSortDirection.Descending;
1728 throw new IndexOutOfRangeException ("Could not find column: " + columnExpression[c]);
1732 ord = Int32.Parse (columnName);
1734 catch (FormatException) {
1737 DataColumn dc = null;
1739 dc = _columnCollection[columnName];
1741 dc = _columnCollection[ord];
1742 SortableColumn sortCol = new SortableColumn (dc,sortDirection);
1743 columns.Add (sortCol);
1745 sortColumns = (SortableColumn[]) columns.ToArray (typeof (SortableColumn));
1750 private class SortableColumn
1752 private DataColumn col;
1753 private ListSortDirection dir;
1755 internal SortableColumn (DataColumn column,
1756 ListSortDirection direction)
1762 public DataColumn Column {
1768 public ListSortDirection SortDirection {
1775 private class RowSorter : IComparer
1777 private DataTable table;
1778 private SortableColumn[] sortColumns;
1779 private DataRow[] rowsToSort;
1781 internal RowSorter(DataTable table,
1782 DataRow[] unsortedRows,
1783 SortableColumn[] sortColumns)
1786 this.sortColumns = sortColumns;
1787 this.rowsToSort = unsortedRows;
1790 public SortableColumn[] SortColumns {
1796 public DataRow[] SortRows ()
1798 Array.Sort (rowsToSort, this);
1802 int IComparer.Compare (object x, object y)
1805 throw new Exception ("Object to compare is null: x");
1807 throw new Exception ("Object to compare is null: y");
1809 throw new Exception ("Object to compare is not DataRow: x is " + x.GetType().ToString());
1811 throw new Exception ("Object to compare is not DataRow: y is " + x.GetType().ToString());
1813 DataRow rowx = (DataRow) x;
1814 DataRow rowy = (DataRow) y;
1816 for(int i = 0; i < sortColumns.Length; i++) {
1817 SortableColumn sortColumn = sortColumns[i];
1818 DataColumn dc = sortColumn.Column;
1820 int result = dc.CompareValues(
1821 rowx.IndexFromVersion(DataRowVersion.Default),
1822 rowy.IndexFromVersion(DataRowVersion.Default));
1825 if (sortColumn.SortDirection == ListSortDirection.Ascending) {
1838 /// Creates new index for a table
1840 internal Index CreateIndex(string name, DataColumn[] columns, bool unique)
1842 // first check whenever index exists on the columns
1843 Index idx = this.GetIndexByColumns(columns);
1845 // if index on this columns already exists - return it
1850 Index newIndex = new Index(name,this,columns,unique);
1852 //InitializeIndex (newIndex);
1854 // add new index to table indexes
1855 this.AddIndex(newIndex);
1860 // /// Creates new extended index for a table
1862 // internal Index CreateIndexExtended(string name, DataColumn[] columns, bool unique)
1864 // // first check whenever extended index exists on the columns
1865 // Index idx = this.GetIndexByColumnsExtended(columns);
1866 // if(idx != null) {
1867 // // if extended index on this columns already exists - return it
1871 // DataColumn[] pkColumns = this.PrimaryKey;
1872 // if((pkColumns != null) && (pkColumns.Length > 0)) {
1873 // DataColumn[] cols = new DataColumn[columns.Length + pkColumns.Length];
1874 // Array.Copy(columns,0,cols,0,columns.Length);
1875 // Array.Copy(pkColumns,0,cols,columns.Length,pkColumns.Length);
1876 // return this.CreateIndex(name, cols, unique);
1879 // throw new InvalidOperationException("Can not create extended index if the primary key is null or primary key does not contains any row");
1884 // /// Drops extended index if it is not referenced anymore
1885 // /// by any of table constraints
1887 // internal void DropIndexExtended(DataColumn[] columns)
1889 // // first check whenever extended index exists on the columns
1890 // Index index = this.GetIndexByColumnsExtended(columns);
1891 // if(index == null) {
1892 // // if no extended index on this columns exists - do nothing
1895 // this.DropIndex(index);
1899 /// Drops index specified by columns if it is not referenced anymore
1900 /// by any of table constraints
1902 internal void DropIndex(DataColumn[] columns)
1904 // first check whenever index exists for the columns
1905 Index index = this.GetIndexByColumns(columns);
1907 // if no index on this columns already exists - do nothing
1910 this.DropIndex(index);
1913 internal void DropIndex(Index index)
1915 // loop through table constraints and checks
1916 foreach(Constraint constraint in Constraints) {
1917 // if we found another reference to the index we do not remove the index.
1918 if (index == constraint.Index)
1922 this.RemoveIndex(index);
1925 internal void InitializeIndex (Index indx)
1927 DataRow[] rows = new DataRow[this.Rows.Count];
1928 this.Rows.CopyTo (rows, 0);
1930 // fill index with table rows
1931 foreach(DataRow row in this.Rows) {
1932 if(row.RowState != DataRowState.Deleted) {
1933 indx.Insert(new Node(row), DataRowVersion.Default);