1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 
7 namespace System.Data
8 {
9     /// <summary>
10     /// Represents an custom error that can be associated with a <see cref='System.Data.DataRow'/>.
11     /// </summary>
12     internal sealed class DataError
13     {
14         private string _rowError = string.Empty;
15 
16         // column-level errors
17         private int _count;
18         private ColumnError[] _errorList;
19         internal const int initialCapacity = 1;
20 
DataError()21         internal DataError() { }
22 
DataError(string rowError)23         internal DataError(string rowError)
24         {
25             SetText(rowError);
26         }
27 
28         internal string Text
29         {
30             get { return _rowError; }
31             set { SetText(value); }
32         }
33 
34         internal bool HasErrors => _rowError.Length != 0 || _count != 0;
35 
36         // this method resets the error to the new value.
SetColumnError(DataColumn column, string error)37         internal void SetColumnError(DataColumn column, string error)
38         {
39             Debug.Assert(column != null, "Invalid (null) argument");
40             Debug.Assert(column.Table != null, "Invalid (loose) column");
41             if (error == null || error.Length == 0)
42             {
43                 // remove error from the collection
44                 Clear(column);
45             }
46             else
47             {
48                 if (_errorList == null)
49                 {
50                     _errorList = new ColumnError[initialCapacity];
51                 }
52                 int i = IndexOf(column);
53                 _errorList[i]._column = column;
54                 _errorList[i]._error = error;
55                 column._errors++;
56                 if (i == _count)
57                 {
58                     _count++;
59                 }
60             }
61         }
62 
GetColumnError(DataColumn column)63         internal string GetColumnError(DataColumn column)
64         {
65             for (int i = 0; i < _count; i++)
66             {
67                 if (_errorList[i]._column == column)
68                 {
69                     return _errorList[i]._error;
70                 }
71             }
72 
73             return string.Empty;
74         }
75 
Clear(DataColumn column)76         internal void Clear(DataColumn column)
77         {
78             if (_count == 0)
79             {
80                 return;
81             }
82 
83             for (int i = 0; i < _count; i++)
84             {
85                 if (_errorList[i]._column == column)
86                 {
87                     Array.Copy(_errorList, i + 1, _errorList, i, _count - i - 1);
88                     _count--;
89                     column._errors--;
90                     Debug.Assert(column._errors >= 0, "missing error counts");
91                 }
92             }
93         }
94 
Clear()95         internal void Clear()
96         {
97             for (int i = 0; i < _count; i++)
98             {
99                 _errorList[i]._column._errors--;
100                 Debug.Assert(_errorList[i]._column._errors >= 0, "missing error counts");
101             }
102             _count = 0;
103             _rowError = string.Empty;
104         }
105 
GetColumnsInError()106         internal DataColumn[] GetColumnsInError()
107         {
108             var cols = new DataColumn[_count];
109 
110             for (int i = 0; i < _count; i++)
111             {
112                 cols[i] = _errorList[i]._column;
113             }
114 
115             return cols;
116         }
117 
118         /// <summary>
119         /// Sets the error message for the <see cref='System.Data.DataError'/>.
120         /// </summary>
SetText(string errorText)121         private void SetText(string errorText)
122         {
123             if (null == errorText)
124             {
125                 errorText = string.Empty;
126             }
127             _rowError = errorText;
128         }
129 
IndexOf(DataColumn column)130         internal int IndexOf(DataColumn column)
131         {
132             // try to find the column
133             for (int i = 0; i < _count; i++)
134             {
135                 if (_errorList[i]._column == column)
136                 {
137                     return i;
138                 }
139             }
140 
141             if (_count >= _errorList.Length)
142             {
143                 int newCapacity = Math.Min(_count * 2, column.Table.Columns.Count);
144                 var biggerList = new ColumnError[newCapacity];
145                 Array.Copy(_errorList, 0, biggerList, 0, _count);
146                 _errorList = biggerList;
147             }
148             return _count;
149         }
150 
151         internal struct ColumnError
152         {
153             internal DataColumn _column;
154             internal string _error;
155         };
156     }
157 }
158