In Test/System.Data:
[mono.git] / mcs / class / System.Data / System.Data / DataRow.cs
index 00bb0d1bdbdcca71528716438e14b14ba014abaa..cbc95c861ae1b5836f75fb6277d032ffd4e338ab 100644 (file)
@@ -7,6 +7,7 @@
 //   Tim Coleman <tim@timcoleman.com>
 //   Ville Palo <vi64pa@koti.soon.fi>
 //   Alan Tam Siu Lung <Tam@SiuLung.com>
+//   Sureshkumar T <tsureshkumar@novell.com>
 //
 // (C) Ximian, Inc 2002
 // (C) Daniel Morgan 2002, 2003
@@ -37,6 +38,7 @@
 //
 
 using System;
+using System.Data.Common;
 using System.Collections;
 using System.Globalization;
 using System.Xml;
@@ -233,6 +235,82 @@ namespace System.Data {
                        }
                }
 
+                /// <summary>
+                /// Sets the index into the container records for the original version. Apart
+                /// from that, it makes sure it pools the record used earlier if they are not
+                /// used by other versions.
+                /// </summary>
+                internal int Original 
+                {
+                        get { return _original;}
+                        set {
+                                if (_original == value) 
+                                        return;
+                                
+                                if (_original >= 0 
+                                    && _current != _original
+                                    && _proposed != _original)
+                                        Table.RecordCache.DisposeRecord (_original);
+                                _original = value;
+                        }
+                }
+
+                /// <summary>
+                /// Sets the index into the container records for the proposed version. Apart
+                /// from that, it makes sure it pools the record used earlier if they are not
+                /// used by other versions.
+                internal int Proposed
+                {
+                        get { return _proposed;}
+                        set {
+                                if (_proposed == value)
+                                        return;
+                                if (_proposed >= 0
+                                    && _proposed != _current
+                                    && _proposed != _original)
+                                        Table.RecordCache.DisposeRecord (_proposed);
+                                _proposed = value;
+                        }
+                }
+
+                /// <summary>
+                /// Sets the index into the container records for the current version. Apart
+                /// from that, it makes sure it pools the record used earlier if they are not
+                /// used by other versions.
+                internal int Current 
+                {
+                        get { return _current;}
+                        set {
+                                if (_current == value)
+                                        return;
+                                if (_current >= 0
+                                    && _current != _original
+                                    && _current != _proposed)
+                                        Table.RecordCache.DisposeRecord (_current);
+                                _current = value;
+                        }
+                }
+
+                /// <summary>
+                /// Set a value for the column into the offset specified by the version.<br>
+                /// If the value is auto increment or null, necessary auto increment value
+                /// or the default value will be used.
+                /// </summary>
+                internal void SetValue (int column, object value, int version)
+                {
+                        DataColumn dc = Table.Columns[column];
+
+                        if (value == null && ! dc.AutoIncrement) // set default value / auto increment
+                                value = dc.DefaultValue;
+
+                       Table.ChangingDataColumn (this, dc, value);     
+                        CheckValue (value, dc);
+                        if ( ! dc.AutoIncrement)
+                                dc [version] = value;
+                        else if (_proposed >= 0 && _proposed != version) // proposed holds the AI
+                                dc [version] = dc [_proposed];
+                }
+
                /// <summary>
                /// Gets the data stored in the column, specified by index and version of the data to
                /// retrieve.
@@ -250,15 +328,15 @@ namespace System.Data {
                                        object o = column.CompiledExpression.Eval (this);
                                        return Convert.ChangeType (o, column.DataType);
                                }
+
+                               if (rowState == DataRowState.Detached && version == DataRowVersion.Default && _proposed < 0)
+                                       throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
                                
                                int recordIndex = IndexFromVersion(version);
 
                                if (recordIndex >= 0) {
                                        return column[recordIndex];
                                }
-
-                               if (rowState == DataRowState.Detached && version == DataRowVersion.Default && _proposed < 0)
-                                       throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
                                
                                throw new VersionNotFoundException (Locale.GetText ("There is no " + version.ToString () + " data to access."));
                        }
@@ -310,6 +388,10 @@ namespace System.Data {
                        }
                }
 
+               internal bool IsEditing {
+                       get { return editing; }
+               }
+
                /// <summary>
                /// Gets the current state of the row in regards to its relationship to the
                /// DataRowCollection.
@@ -354,7 +436,7 @@ namespace System.Data {
                        }
                }
 
-               #endregion
+               #endregion // Properties
 
                #region Methods
 
@@ -404,9 +486,6 @@ namespace System.Data {
 
                internal void SetValuesFromDataRecord(IDataRecord record, int[] mapping)
                {
-                       if ( mapping.Length > Table.Columns.Count)
-                               throw new ArgumentException ();
-
 //                     bool orginalEditing = editing;
 //                     if (!orginalEditing) { 
 //                             BeginEdit ();
@@ -417,8 +496,14 @@ namespace System.Data {
                        }
 
                        try {
-                               for(int i=0; i < mapping.Length; i++) {
+                               for(int i=0; i < Table.Columns.Count; i++) {
                                        DataColumn column = Table.Columns[i];
+                                        if (mapping [i] < 0) { // no mapping
+                                                if (! column.AutoIncrement)
+                                                        column.DataContainer [_proposed] = column.DefaultValue;
+                                                continue;
+                                        }
+
                                        column.DataContainer.SetItemFromDataRecord(_proposed, record,mapping[i]);
                                        if ( column.AutoIncrement ) { 
                                                column.UpdateAutoIncrementValue(column.DataContainer.GetInt64(_proposed));
@@ -489,9 +574,8 @@ namespace System.Data {
                        DataColumn column = _table.Columns[columnName];
                        _table.ChangingDataColumn (this, column, val);
                                
-                        if (_original < 0 || _original == _current) { 
-                               // really add a row cache, if _original is not there & 
-                               // make row modified
+                       if (_original < 0 || _original == _current) { 
+                               // This really creates a new record version if one does not exist
                                _original = Table.RecordCache.NewRecord();
                        }
                        CheckValue (val, column);
@@ -521,10 +605,8 @@ namespace System.Data {
                                throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");
                        }
                        // Accept from detached
-                       if (_original >= 0) {
-                               Table.RecordCache.DisposeRecord(_original);
-                       }
-                       _original = _current;
+                       if (_original != _current)
+                               Original = Current;
                }
 
                /// <summary>
@@ -787,7 +869,7 @@ namespace System.Data {
                /// </summary>
                public DataRow[] GetChildRows (DataRelation relation) 
                {
-                       return GetChildRows (relation, DataRowVersion.Current);
+                       return GetChildRows (relation, DataRowVersion.Default);
                }
 
                /// <summary>
@@ -808,12 +890,16 @@ namespace System.Data {
                        if (relation == null)
                                return new DataRow[0];
 
-                       if (this.Table == null || RowState == DataRowState.Detached)
+                       //if (this.Table == null || RowState == DataRowState.Detached)
+                       if (this.Table == null)
                                throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
 
                        if (relation.DataSet != this.Table.DataSet)
                                throw new ArgumentException();
 
+                       if (_table != relation.ParentTable)
+                               throw new InvalidConstraintException ("GetChildRow requires a row whose Table is " + relation.ParentTable + ", but the specified row's table is " + _table);
+
                        if (relation.ChildKeyConstraint != null)
                                return GetChildRows (relation.ChildKeyConstraint, version);
 
@@ -845,7 +931,9 @@ namespace System.Data {
                                        }
                                        if (allColumnsMatch) rows.Add(row);
                                }
-                       }
+                       }else
+                               throw new VersionNotFoundException("There is no " + version + " data to accces.");
+
                        DataRow[] result = relation.ChildTable.NewRowArray(rows.Count);
                        rows.CopyTo(result, 0);
                        return result;
@@ -876,7 +964,7 @@ namespace System.Data {
                                        }
                                }
                                else { // if there is no index we search manualy.
-                                       int curIndex = IndexFromVersion(DataRowVersion.Current);
+                                       int curIndex = IndexFromVersion(DataRowVersion.Default);
                                        int tmpRecord = fkc.Table.RecordCache.NewRecord();
 
                                        try {
@@ -906,7 +994,8 @@ namespace System.Data {
                                                fkc.Table.RecordCache.DisposeRecord(tmpRecord);
                                        }
                                }
-                       }
+                       }else
+                               throw new VersionNotFoundException("There is no " + version + " data to accces.");
 
                        DataRow[] result = fkc.Table.NewRowArray(rows.Count);
                        rows.CopyTo(result, 0);
@@ -967,7 +1056,7 @@ namespace System.Data {
                /// </summary>
                public DataRow GetParentRow (DataRelation relation) 
                {
-                       return GetParentRow (relation, DataRowVersion.Current);
+                       return GetParentRow (relation, DataRowVersion.Default);
                }
 
                /// <summary>
@@ -976,7 +1065,7 @@ namespace System.Data {
                /// </summary>
                public DataRow GetParentRow (string relationName) 
                {
-                       return GetParentRow (relationName, DataRowVersion.Current);
+                       return GetParentRow (relationName, DataRowVersion.Default);
                }
 
                /// <summary>
@@ -1004,7 +1093,7 @@ namespace System.Data {
                /// </summary>
                public DataRow[] GetParentRows (DataRelation relation) 
                {
-                       return GetParentRows (relation, DataRowVersion.Current);
+                       return GetParentRows (relation, DataRowVersion.Default);
                }
 
                /// <summary>
@@ -1013,7 +1102,7 @@ namespace System.Data {
                /// </summary>
                public DataRow[] GetParentRows (string relationName) 
                {
-                       return GetParentRows (relationName, DataRowVersion.Current);
+                       return GetParentRows (relationName, DataRowVersion.Default);
                }
 
                /// <summary>
@@ -1026,28 +1115,32 @@ namespace System.Data {
                        if (relation == null)
                                return new DataRow[0];
 
-                       if (this.Table == null || RowState == DataRowState.Detached)
+                       if (this.Table == null)
                                throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
 
                        if (relation.DataSet != this.Table.DataSet)
                                throw new ArgumentException();
 
+                       if (_table != relation.ChildTable)
+                               throw new InvalidConstraintException ("GetParentRows requires a row whose Table is " + relation.ChildTable + ", but the specified row's table is " + _table);
+
                        ArrayList rows = new ArrayList();
                        DataColumn[] parentColumns = relation.ParentColumns;
                        DataColumn[] childColumns = relation.ChildColumns;
                        int numColumn = parentColumns.Length;
                        if (HasVersion(version)) {
                                Index indx = relation.ParentTable.GetIndexByColumns (parentColumns);
-                               if (indx != null) { // get the child rows from the index
+                               if (indx != null && 
+    (Table == null || Table.DataSet == null || 
+     Table.DataSet.EnforceConstraints)) { // get the child rows from the index
                                        Node[] childNodes = indx.FindAllSimple(childColumns, IndexFromVersion(version));
                                        for (int i = 0; i < childNodes.Length; i++) {
                                                rows.Add (childNodes[i].Row);
                                        }
                                }
                                else { // no index so we have to search manualy.
-                                       int curIndex = IndexFromVersion(DataRowVersion.Current);
+                                       int curIndex = IndexFromVersion(DataRowVersion.Default);
                                        int tmpRecord = relation.ParentTable.RecordCache.NewRecord();
-
                                        try {
                                                for (int i = 0; i < numColumn; i++) {
                                                        // according to MSDN: the DataType value for both columns must be identical.
@@ -1075,7 +1168,8 @@ namespace System.Data {
                                                relation.ParentTable.RecordCache.DisposeRecord(tmpRecord);
                                        }
                                }
-                       }
+                       }else
+                               throw new VersionNotFoundException("There is no " + version + " data to accces.");
 
                        DataRow[] result = relation.ParentTable.NewRowArray(rows.Count);
                        rows.CopyTo(result, 0);
@@ -1096,26 +1190,26 @@ namespace System.Data {
                /// </summary>
                public bool HasVersion (DataRowVersion version) 
                {
-                       switch (version) {
-                               case DataRowVersion.Default:
-                                       if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
-                                               return false;
-                                       if (rowState == DataRowState.Detached)
-                                               return _proposed >= 0;
-                                       return true;
-                               case DataRowVersion.Proposed:
-                                       if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
-                                               return false;
-                                       return _proposed >= 0;
-                               case DataRowVersion.Current:
-                                       if ((rowState == DataRowState.Deleted && !_inExpressionEvaluation) || rowState == DataRowState.Detached)
-                                               return false;
-                                       return _current >= 0;
-                               case DataRowVersion.Original:
-                                       if (rowState == DataRowState.Detached)
-                                               return false;
-                                       return _original >= 0;
-                       }
+                        switch (version) {
+                        case DataRowVersion.Default:
+                                if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
+                                        return false;
+                                if (rowState == DataRowState.Detached)
+                                        return _proposed >= 0;
+                                return true;
+                        case DataRowVersion.Proposed:
+                                if (rowState == DataRowState.Deleted && !_inExpressionEvaluation)
+                                        return false;
+                                return _proposed >= 0;
+                        case DataRowVersion.Current:
+                                if ((rowState == DataRowState.Deleted && !_inExpressionEvaluation) || rowState == DataRowState.Detached)
+                                        return false;
+                                return _current >= 0;
+                        case DataRowVersion.Original:
+                                if (rowState == DataRowState.Detached)
+                                        return false;
+                                return _original >= 0;
+                        }
                        return false;
                }
 
@@ -1274,7 +1368,7 @@ namespace System.Data {
                /// </summary>
                public void SetParentRow (DataRow parentRow, DataRelation relation) 
                {
-                       if (_table == null || parentRow.Table == null || RowState == DataRowState.Detached)
+                       if (_table == null || parentRow.Table == null)
                                throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
 
                        if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)
@@ -1285,8 +1379,8 @@ namespace System.Data {
                        {
                                foreach (DataRelation parentRel in _table.ParentRelations)
                                {
-                                       DataColumn[] childCols = parentRel.ChildKeyConstraint.Columns;
-                                       DataColumn[] parentCols = parentRel.ChildKeyConstraint.RelatedColumns;
+                                       DataColumn[] childCols = parentRel.ChildColumns;
+                                       DataColumn[] parentCols = parentRel.ParentColumns;
                                        
                                        for (int i = 0; i < parentCols.Length; i++)
                                        {
@@ -1300,8 +1394,8 @@ namespace System.Data {
                        }
                        else
                        {
-                               DataColumn[] childCols = relation.ChildKeyConstraint.Columns;
-                               DataColumn[] parentCols = relation.ChildKeyConstraint.RelatedColumns;
+                               DataColumn[] childCols = relation.ChildColumns;
+                               DataColumn[] parentCols = relation.ParentColumns;
                                        
                                for (int i = 0; i < parentCols.Length; i++)
                                {
@@ -1353,8 +1447,8 @@ namespace System.Data {
                                        }
                                        
                                        //Saving the current value as the column value
-                                       row[index] = targetColumn[row._current];
-                                       
+                                       object defaultVal = column [IndexFromVersion (DataRowVersion.Default)];
+                                       row [index] = defaultVal;
                                }
                        }
                        CopyState(row);
@@ -1430,6 +1524,71 @@ namespace System.Data {
                 }
        
                #endregion // Methods
+
+#if NET_2_0
+                /// <summary>
+                ///    This method loads a given value into the existing row affecting versions,
+                ///    state based on the LoadOption.  The matrix of changes for this method are as
+                ///    mentioned in the DataTable.Load (IDataReader, LoadOption) method.
+                /// </summary>
+                [MonoTODO ("Raise necessary Events")]
+                internal void Load (object [] values, LoadOption loadOption, bool is_new)
+                {
+                        DataRowAction action = DataRowAction.Change;
+
+                        int temp = Table.RecordCache.NewRecord ();
+                        for (int i = 0 ; i < Table.Columns.Count; i++)
+                                SetValue (i, values [i], temp);
+
+                        if (is_new) { // new row
+                                if (editing || RowState == DataRowState.Detached)
+                                        Proposed = temp;
+                                else
+                                        Current = temp;
+                                return;
+                        }
+
+                        if (loadOption == LoadOption.OverwriteChanges 
+                            || (loadOption == LoadOption.PreserveChanges
+                                && rowState == DataRowState.Unchanged)) {
+                                Original = temp;
+                                if (editing)
+                                        Proposed = temp;
+                                else
+                                        Current = temp;
+                                rowState = DataRowState.Unchanged;
+                                action = DataRowAction.ChangeCurrentAndOriginal;
+                                return;
+                        }
+
+                        if (loadOption == LoadOption.PreserveChanges) {
+                                if (rowState != DataRowState.Deleted) {
+                                        Original = temp;
+                                        rowState = DataRowState.Modified;
+                                        action   = DataRowAction.ChangeOriginal;
+                                }
+                                return;
+                        }
+                                
+                        bool not_used = true;
+                        // Upsert
+                        if (rowState != DataRowState.Deleted) {
+                                int index = editing ? _proposed : _current;
+                                if (! RecordCache.CompareRecords (Table, index, temp)) {
+                                        if (editing)
+                                                Proposed = temp;
+                                        else
+                                                Current = temp;
+                                        not_used = false;
+                                        if (rowState == DataRowState.Unchanged)
+                                                rowState = DataRowState.Modified;
+                                }
+                        }
+                                
+                        if (not_used)
+                                Table.RecordCache.DisposeRecord (temp);
+                }
+#endif // NET_2_0
        }