XMLDiffLoader.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. //------------------------------------------------------------------------------
  2. // <copyright file="XMLDiffLoader.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. // <owner current="false" primary="false">[....]</owner>
  8. //------------------------------------------------------------------------------
  9. namespace System.Data {
  10. using System;
  11. using System.Runtime.Serialization.Formatters;
  12. using System.Configuration.Assemblies;
  13. using System.Runtime.InteropServices;
  14. using System.Diagnostics;
  15. using System.IO;
  16. using System.Collections;
  17. using System.Globalization;
  18. using Microsoft.Win32;
  19. using System.ComponentModel;
  20. using System.Xml;
  21. using System.Xml.Serialization;
  22. internal sealed class XMLDiffLoader {
  23. ArrayList tables;
  24. DataSet dataSet = null;
  25. DataTable dataTable = null;
  26. internal void LoadDiffGram(DataSet ds, XmlReader dataTextReader) {
  27. XmlReader reader = DataTextReader.CreateReader(dataTextReader);
  28. dataSet = ds;
  29. while (reader.LocalName == Keywords.SQL_BEFORE && reader.NamespaceURI==Keywords.DFFNS) {
  30. ProcessDiffs(ds, reader);
  31. reader.Read(); // now the reader points to the error section
  32. }
  33. while (reader.LocalName == Keywords.MSD_ERRORS && reader.NamespaceURI==Keywords.DFFNS) {
  34. ProcessErrors(ds, reader);
  35. Debug.Assert(reader.LocalName == Keywords.MSD_ERRORS && reader.NamespaceURI==Keywords.DFFNS, "something fishy");
  36. reader.Read(); // pass the end of errors tag
  37. }
  38. }
  39. private void CreateTablesHierarchy(DataTable dt) {
  40. foreach( DataRelation r in dt.ChildRelations ) {
  41. if (! tables.Contains((DataTable)r.ChildTable)) {
  42. tables.Add((DataTable)r.ChildTable);
  43. CreateTablesHierarchy(r.ChildTable) ;
  44. }
  45. }
  46. }
  47. internal void LoadDiffGram(DataTable dt, XmlReader dataTextReader) {
  48. XmlReader reader = DataTextReader.CreateReader(dataTextReader);
  49. dataTable = dt;
  50. tables = new ArrayList();
  51. tables.Add(dt);
  52. CreateTablesHierarchy(dt);
  53. while (reader.LocalName == Keywords.SQL_BEFORE && reader.NamespaceURI==Keywords.DFFNS) {
  54. ProcessDiffs(tables, reader);
  55. reader.Read(); // now the reader points to the error section
  56. }
  57. while (reader.LocalName == Keywords.MSD_ERRORS && reader.NamespaceURI==Keywords.DFFNS) {
  58. ProcessErrors(tables, reader);
  59. Debug.Assert(reader.LocalName == Keywords.MSD_ERRORS && reader.NamespaceURI==Keywords.DFFNS, "something fishy");
  60. reader.Read(); // pass the end of errors tag
  61. }
  62. }
  63. internal void ProcessDiffs(DataSet ds, XmlReader ssync) {
  64. DataTable tableBefore;
  65. DataRow row;
  66. int oldRowRecord;
  67. int pos = -1;
  68. int iSsyncDepth = ssync.Depth;
  69. ssync.Read(); // pass the before node.
  70. SkipWhitespaces(ssync);
  71. while (iSsyncDepth < ssync.Depth) {
  72. tableBefore = null;
  73. string diffId = null;
  74. oldRowRecord = -1;
  75. // the diffgramm always contains sql:before and sql:after pairs
  76. int iTempDepth = ssync.Depth;
  77. diffId = ssync.GetAttribute(Keywords.DIFFID, Keywords.DFFNS);
  78. bool hasErrors = (bool) (ssync.GetAttribute(Keywords.HASERRORS, Keywords.DFFNS) == Keywords.TRUE);
  79. oldRowRecord = ReadOldRowData(ds, ref tableBefore, ref pos, ssync);
  80. if (oldRowRecord == -1)
  81. continue;
  82. if (tableBefore == null)
  83. throw ExceptionBuilder.DiffgramMissingSQL();
  84. row = (DataRow)tableBefore.RowDiffId[diffId];
  85. if (row != null) {
  86. row.oldRecord = oldRowRecord ;
  87. tableBefore.recordManager[oldRowRecord] = row;
  88. } else {
  89. row = tableBefore.NewEmptyRow();
  90. tableBefore.recordManager[oldRowRecord] = row;
  91. row.oldRecord = oldRowRecord;
  92. row.newRecord = oldRowRecord;
  93. tableBefore.Rows.DiffInsertAt(row, pos);
  94. row.Delete();
  95. if (hasErrors)
  96. tableBefore.RowDiffId[diffId] = row;
  97. }
  98. }
  99. return;
  100. }
  101. internal void ProcessDiffs(ArrayList tableList, XmlReader ssync) {
  102. DataTable tableBefore;
  103. DataRow row;
  104. int oldRowRecord;
  105. int pos = -1;
  106. int iSsyncDepth = ssync.Depth;
  107. ssync.Read(); // pass the before node.
  108. //SkipWhitespaces(ssync); for given scenario does not require this change, but in fact we should do it.
  109. while (iSsyncDepth < ssync.Depth) {
  110. tableBefore = null;
  111. string diffId = null;
  112. oldRowRecord = -1;
  113. // the diffgramm always contains sql:before and sql:after pairs
  114. int iTempDepth = ssync.Depth;
  115. diffId = ssync.GetAttribute(Keywords.DIFFID, Keywords.DFFNS);
  116. bool hasErrors = (bool) (ssync.GetAttribute(Keywords.HASERRORS, Keywords.DFFNS) == Keywords.TRUE);
  117. oldRowRecord = ReadOldRowData(dataSet, ref tableBefore, ref pos, ssync);
  118. if (oldRowRecord == -1)
  119. continue;
  120. if (tableBefore == null)
  121. throw ExceptionBuilder.DiffgramMissingSQL();
  122. row = (DataRow)tableBefore.RowDiffId[diffId];
  123. if (row != null) {
  124. row.oldRecord = oldRowRecord ;
  125. tableBefore.recordManager[oldRowRecord] = row;
  126. } else {
  127. row = tableBefore.NewEmptyRow();
  128. tableBefore.recordManager[oldRowRecord] = row;
  129. row.oldRecord = oldRowRecord;
  130. row.newRecord = oldRowRecord;
  131. tableBefore.Rows.DiffInsertAt(row, pos);
  132. row.Delete();
  133. if (hasErrors)
  134. tableBefore.RowDiffId[diffId] = row;
  135. }
  136. }
  137. return;
  138. }
  139. internal void ProcessErrors(DataSet ds, XmlReader ssync) {
  140. DataTable table;
  141. int iSsyncDepth = ssync.Depth;
  142. ssync.Read(); // pass the before node.
  143. while (iSsyncDepth < ssync.Depth) {
  144. table = ds.Tables.GetTable(XmlConvert.DecodeName(ssync.LocalName), ssync.NamespaceURI);
  145. if (table == null)
  146. throw ExceptionBuilder.DiffgramMissingSQL();
  147. string diffId = ssync.GetAttribute(Keywords.DIFFID, Keywords.DFFNS);
  148. DataRow row = (DataRow)table.RowDiffId[diffId];
  149. string rowError = ssync.GetAttribute(Keywords.MSD_ERROR, Keywords.DFFNS);
  150. if (rowError != null)
  151. row.RowError = rowError;
  152. int iRowDepth = ssync.Depth;
  153. ssync.Read(); // we may be inside a column
  154. while (iRowDepth < ssync.Depth) {
  155. if (XmlNodeType.Element == ssync.NodeType) {
  156. DataColumn col = table.Columns[XmlConvert.DecodeName(ssync.LocalName), ssync.NamespaceURI];
  157. //if (col == null)
  158. // throw exception here
  159. string colError = ssync.GetAttribute(Keywords.MSD_ERROR, Keywords.DFFNS);
  160. row.SetColumnError(col, colError);
  161. }
  162. ssync.Read();
  163. }
  164. while ((ssync.NodeType == XmlNodeType.EndElement) && (iSsyncDepth < ssync.Depth) )
  165. ssync.Read();
  166. }
  167. return;
  168. }
  169. internal void ProcessErrors(ArrayList dt, XmlReader ssync) {
  170. DataTable table;
  171. int iSsyncDepth = ssync.Depth;
  172. ssync.Read(); // pass the before node.
  173. while (iSsyncDepth < ssync.Depth) {
  174. table = GetTable(XmlConvert.DecodeName(ssync.LocalName), ssync.NamespaceURI);
  175. if (table == null)
  176. throw ExceptionBuilder.DiffgramMissingSQL();
  177. string diffId = ssync.GetAttribute(Keywords.DIFFID, Keywords.DFFNS);
  178. DataRow row = (DataRow)table.RowDiffId[diffId];
  179. if (row == null) {
  180. for(int i = 0; i < dt.Count; i++) {
  181. row = (DataRow)((DataTable)dt[i]).RowDiffId[diffId];
  182. if (row != null) {
  183. table = row.Table;
  184. break;
  185. }
  186. }
  187. }
  188. string rowError = ssync.GetAttribute(Keywords.MSD_ERROR, Keywords.DFFNS);
  189. if (rowError != null)
  190. row.RowError = rowError;
  191. int iRowDepth = ssync.Depth;
  192. ssync.Read(); // we may be inside a column
  193. while (iRowDepth < ssync.Depth) {
  194. if (XmlNodeType.Element == ssync.NodeType) {
  195. DataColumn col = table.Columns[XmlConvert.DecodeName(ssync.LocalName), ssync.NamespaceURI];
  196. //if (col == null)
  197. // throw exception here
  198. string colError = ssync.GetAttribute(Keywords.MSD_ERROR, Keywords.DFFNS);
  199. row.SetColumnError(col, colError);
  200. }
  201. ssync.Read();
  202. }
  203. while ((ssync.NodeType == XmlNodeType.EndElement) && (iSsyncDepth < ssync.Depth) )
  204. ssync.Read();
  205. }
  206. return;
  207. }
  208. private DataTable GetTable(string tableName, string ns) {
  209. if (tables == null)
  210. return dataSet.Tables.GetTable(tableName, ns);
  211. if (tables.Count == 0)
  212. return (DataTable)tables[0];
  213. for(int i = 0; i < tables.Count; i++) {
  214. DataTable dt = (DataTable)tables[i];
  215. if ((string.Compare(dt.TableName, tableName, StringComparison.Ordinal) == 0)
  216. && (string.Compare(dt.Namespace, ns, StringComparison.Ordinal) == 0))
  217. return dt;
  218. }
  219. return null;
  220. }
  221. private int ReadOldRowData(DataSet ds, ref DataTable table, ref int pos, XmlReader row) {
  222. // read table information
  223. if (ds != null) {
  224. table = ds.Tables.GetTable(XmlConvert.DecodeName(row.LocalName), row.NamespaceURI);
  225. }
  226. else {
  227. table = GetTable(XmlConvert.DecodeName(row.LocalName), row.NamespaceURI);
  228. }
  229. if (table == null) {
  230. row.Skip(); // need to skip this element if we dont know about it, before returning -1
  231. return -1;
  232. }
  233. int iRowDepth = row.Depth;
  234. string value = null;
  235. if (table == null)
  236. throw ExceptionBuilder.DiffgramMissingTable(XmlConvert.DecodeName(row.LocalName));
  237. value = row.GetAttribute(Keywords.ROWORDER, Keywords.MSDNS);
  238. if (!Common.ADP.IsEmpty(value)) {
  239. pos = (Int32) Convert.ChangeType(value, typeof(Int32), null);
  240. }
  241. int record = table.NewRecord();
  242. foreach (DataColumn col in table.Columns) {
  243. col[record] = DBNull.Value;
  244. }
  245. foreach (DataColumn col in table.Columns) {
  246. if ((col.ColumnMapping == MappingType.Element) ||
  247. (col.ColumnMapping == MappingType.SimpleContent))
  248. continue;
  249. if (col.ColumnMapping == MappingType.Hidden) {
  250. value = row.GetAttribute("hidden"+col.EncodedColumnName, Keywords.MSDNS);
  251. }
  252. else {
  253. value = row.GetAttribute(col.EncodedColumnName, col.Namespace);
  254. }
  255. if (value == null) {
  256. continue;
  257. }
  258. col[record] = col.ConvertXmlToObject(value);
  259. }
  260. row.Read();
  261. SkipWhitespaces(row);
  262. int currentDepth = row.Depth;
  263. if (currentDepth <= iRowDepth) {
  264. // the node is empty
  265. if (currentDepth == iRowDepth && row.NodeType == XmlNodeType.EndElement) {
  266. // VSTFDEVDIV 764390: read past the EndElement of the current row
  267. // note: (currentDepth == iRowDepth) check is needed so we do not skip elements on parent rows.
  268. row.Read();
  269. SkipWhitespaces(row);
  270. }
  271. return record;
  272. }
  273. if (table.XmlText != null) {
  274. DataColumn col = table.XmlText;
  275. col[record] = col.ConvertXmlToObject(row.ReadString());
  276. }
  277. else {
  278. while (row.Depth > iRowDepth) {
  279. String ln =XmlConvert.DecodeName( row.LocalName) ;
  280. String ns = row.NamespaceURI;
  281. DataColumn column = table.Columns[ln, ns];
  282. if (column == null) {
  283. while((row.NodeType != XmlNodeType.EndElement) && (row.LocalName!=ln) && (row.NamespaceURI!=ns))
  284. row.Read(); // consume the current node
  285. row.Read(); // now points to the next column
  286. //SkipWhitespaces(row); seems no need, just in case if we see other issue , this will be here as hint
  287. continue;// add a read here!
  288. }
  289. if (column.IsCustomType) {
  290. // if column's type is object or column type does not implement IXmlSerializable
  291. bool isPolymorphism = (column.DataType == typeof(Object)|| (row.GetAttribute(Keywords.MSD_INSTANCETYPE, Keywords.MSDNS) != null) ||
  292. (row.GetAttribute(Keywords.TYPE, Keywords.XSINS) != null)) ;
  293. bool skipped = false;
  294. if (column.Table.DataSet != null && column.Table.DataSet.UdtIsWrapped) {
  295. row.Read(); // if UDT is wrapped, skip the wrapper
  296. skipped = true;
  297. }
  298. XmlRootAttribute xmlAttrib = null;
  299. if (!isPolymorphism && !column.ImplementsIXMLSerializable) { // THIS
  300. // if does not implement IXLSerializable, need to go with XmlSerializer: pass XmlRootAttribute
  301. if (skipped) {
  302. xmlAttrib = new XmlRootAttribute(row.LocalName);
  303. xmlAttrib.Namespace = row.NamespaceURI ;
  304. }
  305. else {
  306. xmlAttrib = new XmlRootAttribute(column.EncodedColumnName);
  307. xmlAttrib.Namespace = column.Namespace;
  308. }
  309. }
  310. // for else case xmlAttrib MUST be null
  311. column[record] = column.ConvertXmlToObject(row, xmlAttrib); // you need to pass null XmlAttib here
  312. if (skipped) {
  313. row.Read(); // if Wrapper is skipped, skip its end tag
  314. }
  315. }
  316. else {
  317. int iColumnDepth = row.Depth;
  318. row.Read();
  319. // SkipWhitespaces(row);seems no need, just in case if we see other issue , this will be here as hint
  320. if (row.Depth > iColumnDepth) { //we are inside the column
  321. if (row.NodeType == XmlNodeType.Text || row.NodeType == XmlNodeType.Whitespace || row.NodeType == XmlNodeType.SignificantWhitespace) {
  322. String text = row.ReadString();
  323. column[record] = column.ConvertXmlToObject(text);
  324. row.Read(); // now points to the next column
  325. }
  326. }
  327. else {
  328. // <element></element> case
  329. if (column.DataType == typeof(string))
  330. column[record] = string.Empty;
  331. }
  332. }
  333. }
  334. }
  335. row.Read(); //now it should point to next row
  336. SkipWhitespaces(row);
  337. return record;
  338. }
  339. internal void SkipWhitespaces(XmlReader reader) {
  340. while (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.SignificantWhitespace) {
  341. reader.Read();
  342. }
  343. }
  344. }
  345. }