[runtime] Overwrite stacktrace for exception on re-throw. Fixes #1856.
[mono.git] / mcs / class / System.Data / System.Data / XmlDiffLoader.cs
1 //
2 // mcs/class/System.Data/System.Data/XmlDiffLoader.cs
3 //
4 // Purpose: Loads XmlDiffGrams to DataSet 
5 //
6 // class: XmlDiffLoader
7 // assembly: System.Data.dll
8 // namespace: System.Data
9 //
10 // Author:
11 //     Ville Palo <vi64pa@koti.soon.fi>
12 //     Lluis Sanchez Gual (lluis@ximian.com)
13 //
14 // (c)copyright 2003 Ville Palo
15 // Copyright 2011 Xamarin Inc.
16 //
17
18 //
19 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
20 //
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:
28 // 
29 // The above copyright notice and this permission notice shall be
30 // included in all copies or substantial portions of the Software.
31 // 
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.
39 //
40 using System;
41 using System.Data;
42 using System.Xml;
43 using System.Xml.Schema;
44 using System.Xml.XPath;
45 using System.Collections;
46 using System.Globalization;
47
48 namespace System.Data {
49
50         internal class XmlDiffLoader 
51         {
52
53                 #region Fields
54                 private DataSet DSet;
55                 private DataTable table;
56                 private Hashtable DiffGrRows = new Hashtable ();
57                 private Hashtable ErrorRows = new Hashtable ();
58
59                 #endregion // Fields
60
61                 #region ctors
62
63                 public XmlDiffLoader (DataSet DSet) 
64                 {
65                         this.DSet = DSet;
66                 }
67
68                 public XmlDiffLoader (DataTable table) 
69                 {
70                         this.table = table;
71                 }
72
73                 #endregion //ctors
74
75                 #region Public methods
76
77                 public void Load (XmlReader reader) 
78                 {
79                         bool origEnforceConstraint = false;
80                         if (DSet != null) {
81                                 origEnforceConstraint = DSet.EnforceConstraints;
82                                 DSet.EnforceConstraints = false;
83                         }
84                         
85                         reader.MoveToContent ();
86                         if (reader.IsEmptyElement) {
87                                 reader.Skip ();
88                                 return;
89                         }
90                         
91                         reader.ReadStartElement ("diffgram", XmlConstants.DiffgrNamespace);
92                         reader.MoveToContent ();
93                         
94                         while (reader.NodeType != XmlNodeType.EndElement)
95                         {
96                                 if (reader.NodeType == XmlNodeType.Element)
97                                 {
98                                         if (reader.LocalName == "before" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
99                                                 LoadBefore (reader);
100                                         else if (reader.LocalName == "errors" && reader.NamespaceURI == XmlConstants.DiffgrNamespace)
101                                                 LoadErrors (reader);
102                                         else
103                                                 LoadCurrent (reader);
104                                 }
105                                 else
106                                         reader.Skip ();
107                         }
108                         
109                         reader.ReadEndElement ();
110                         
111                         if (DSet != null)
112                                 DSet.EnforceConstraints = origEnforceConstraint;
113                 }
114
115                 #endregion // Public methods
116
117                 #region Private methods
118
119                 private void LoadCurrent (XmlReader reader) 
120                 {
121                         if (reader.IsEmptyElement) {
122                                 reader.Skip();
123                                 return;
124                         }
125                         reader.ReadStartElement ();             // Dataset root
126                         reader.MoveToContent ();
127
128                         while (reader.NodeType != XmlNodeType.EndElement)
129                         {
130                                 if (reader.NodeType == XmlNodeType.Element)
131                                 {
132                                         DataTable t = GetTable (reader.LocalName);
133                                         if (t != null)
134                                                 LoadCurrentTable (t, reader);
135 #if true
136                                         else
137                                                 reader.Skip ();
138 #else
139                                         else 
140                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));      
141 #endif
142                                 }
143                                 else
144                                         reader.Skip ();
145                         }
146                         
147                         reader.ReadEndElement ();
148                 }
149
150                 private void LoadBefore (XmlReader reader) 
151                 {
152                         if (reader.IsEmptyElement) {
153                                 reader.Skip ();
154                                 return;
155                         }
156                         reader.ReadStartElement ();
157                         reader.MoveToContent ();
158
159                         while (reader.NodeType != XmlNodeType.EndElement)
160                         {
161                                 if (reader.NodeType == XmlNodeType.Element)
162                                 {
163                                         DataTable t = GetTable (reader.LocalName);
164                                         if (t != null)
165                                                 LoadBeforeTable(t, reader);
166                                         else
167                                                 throw new DataException (Locale.GetText ("Cannot load diffGram. Table '" + reader.LocalName + "' is missing in the destination dataset"));
168                                 }
169                                 else
170                                         reader.Skip ();
171                         }
172                         
173                         reader.ReadEndElement ();
174                 }                                
175                                 
176                                            
177                 private void LoadErrors (XmlReader reader) 
178                 {
179                         if (reader.IsEmptyElement) {
180                                 reader.Skip ();
181                                 return;
182                         }
183                         reader.ReadStartElement ();
184                         reader.MoveToContent ();
185
186                         while (reader.NodeType != XmlNodeType.EndElement)
187                         {
188                                 if (reader.NodeType == XmlNodeType.Element)
189                                 {
190                                         DataRow Row = null;
191                 
192                                         // find the row in 'current' section
193                                         
194                                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
195                                         
196                                         if (id != null)
197                                                 Row = (DataRow) ErrorRows [id];
198                 
199                                         if (reader.IsEmptyElement) continue;
200                                         reader.ReadStartElement ();
201                                         while (reader.NodeType != XmlNodeType.EndElement)
202                                         {
203                                                 if (reader.NodeType == XmlNodeType.Element) {
204                                                         string error = reader.GetAttribute ("Error", XmlConstants.DiffgrNamespace);
205                                                         Row.SetColumnError (reader.LocalName, error);
206                                                 }
207                                                 reader.Read ();
208                                         }
209                                 }
210                                 else
211                                         reader.Skip ();
212                         }
213                         reader.ReadEndElement ();
214                 }
215
216                 private void LoadColumns (DataTable Table, DataRow Row, 
217                         XmlReader reader, DataRowVersion loadType)
218                 {
219                         // attributes
220                         LoadColumnAttributes (Table, Row, reader, loadType);
221                         LoadColumnChildren (Table, Row, reader, loadType);
222                 }
223
224                 private void LoadColumnAttributes (DataTable Table, DataRow Row,
225                         XmlReader reader, DataRowVersion loadType)
226                 {
227                         if (!reader.HasAttributes // this check will be faster
228                                 || !reader.MoveToFirstAttribute ())
229                                 return;
230                         do {
231                                 switch (reader.NamespaceURI) {
232                                 case XmlConstants.XmlnsNS:
233                                 case XmlConstants.XmlNS:
234                                 case XmlConstants.DiffgrNamespace:
235                                 case XmlConstants.MsdataNamespace:
236                                 case XmlConstants.MspropNamespace:
237                                 case XmlSchema.Namespace:
238                                         continue;
239                                 }
240                                 DataColumn c = Table.Columns [XmlHelper.Decode (reader.LocalName)];
241                                 if (c == null ||
242                                         c.ColumnMapping != MappingType.Attribute)                                       continue;
243                                 if (c.Namespace == null && reader.NamespaceURI == String.Empty ||
244                                         c.Namespace == reader.NamespaceURI) {
245                                         object data = XmlDataLoader.StringToObject (c.DataType, reader.Value);
246                                         if (loadType == DataRowVersion.Current)
247                                                 Row [c] = data;
248                                         else
249                                                 Row.SetOriginalValue (c.ColumnName, data);
250                                 } // otherwise just ignore as well as unknown elements.
251                         } while (reader.MoveToNextAttribute ());
252                         reader.MoveToElement ();
253                 }
254
255                 private void LoadColumnChildren (DataTable Table, DataRow Row,
256                         XmlReader reader, DataRowVersion loadType) 
257                 {
258                         // children
259                         if (reader.IsEmptyElement) {
260                                 reader.Skip ();
261                                 return;
262                         }
263                         reader.ReadStartElement ();
264                         reader.MoveToContent ();
265                         
266                         while (reader.NodeType != XmlNodeType.EndElement)
267                         {
268                                 if (reader.NodeType != XmlNodeType.Element) { reader.Read (); continue; }
269                                 
270                                 string colName = XmlHelper.Decode (reader.LocalName);
271                                 if (Table.Columns.Contains (colName)) 
272                                 {
273                                         object data = XmlDataLoader.StringToObject (Table.Columns[colName].DataType, reader.ReadString ());
274                                         
275                                         if (loadType == DataRowVersion.Current) Row [colName] = data;
276                                         else Row.SetOriginalValue (colName, data);
277                                         reader.Read ();
278                                 }
279                                 else 
280                                 {
281                                         DataTable t = GetTable (reader.LocalName);
282                                         if (t != null) {
283                                                 if (loadType == DataRowVersion.Original)
284                                                         LoadBeforeTable (t, reader);
285                                                 else if (loadType == DataRowVersion.Current)
286                                                         LoadCurrentTable (t, reader);
287                                         } else
288                                                 reader.Skip ();
289                                 }
290                         }
291                         
292                         reader.ReadEndElement ();
293                 }
294
295                 private void LoadBeforeTable (DataTable Table, XmlReader reader) 
296                 {
297                         string id = reader.GetAttribute ("id", XmlConstants.DiffgrNamespace);
298                         string rowOrder = reader.GetAttribute ("rowOrder", XmlConstants.MsdataNamespace);
299                         DataRow Row = (DataRow) DiffGrRows [id];
300                         
301                         if (Row == null)
302                         {
303                                 // Deleted row
304                                 Row = Table.NewRow ();
305                                 LoadColumns (Table, Row, reader, DataRowVersion.Current);
306                                 Table.Rows.InsertAt (Row, int.Parse (rowOrder));
307                                 Row.AcceptChanges ();
308                                 Row.Delete ();
309                         }
310                         else
311                         {
312                                 LoadColumns (Table, Row, reader, DataRowVersion.Original);
313                         }
314                 }
315
316                 private void LoadCurrentTable (DataTable Table, XmlReader reader) 
317                 {
318                         DataRowState state;
319                         DataRow Row = Table.NewRow ();
320
321                         string id = reader.GetAttribute  ("id", XmlConstants.DiffgrNamespace);
322                         string error = reader.GetAttribute ("hasErrors");
323                         string changes = reader.GetAttribute ("hasChanges", XmlConstants.DiffgrNamespace);
324                         
325                         if (changes != null)
326                         {
327                                 if (string.Compare (changes, "modified", true, CultureInfo.InvariantCulture) == 0) {
328                                         DiffGrRows.Add (id, Row); // for later use
329                                         state = DataRowState.Modified;
330                                 }
331                                 else if (string.Compare (changes, "inserted", true, CultureInfo.InvariantCulture) == 0) {
332                                         state = DataRowState.Added;
333                                 }
334                                 else
335                                         throw new InvalidOperationException ("Invalid row change state");
336                         }
337                         else
338                                 state = DataRowState.Unchanged;
339                         
340                         // If row had errors add row to hashtable for later use
341                         if (error != null && string.Compare (error, "true", true, CultureInfo.InvariantCulture) == 0)
342                                 ErrorRows.Add (id, Row);
343                 
344                         LoadColumns (Table, Row, reader, DataRowVersion.Current);
345                         Table.Rows.Add (Row);
346                         
347                         if (state != DataRowState.Added)
348                                 Row.AcceptChanges ();
349                 }
350
351                 DataTable GetTable (string name)
352                 {
353                         name = XmlConvert.DecodeName (name);
354                         if (DSet != null) 
355                                 return DSet.Tables [name];
356                         else if (name == table.TableName) 
357                                 return table;
358                         else
359                                 return null;
360                 }
361
362
363                 #endregion // Private methods
364         }
365 }