PageRenderTime 75ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Data/System.Data/DataTable.cs

https://bitbucket.org/danipen/mono
C# | 3009 lines | 2173 code | 329 blank | 507 comment | 528 complexity | 998048b146804016d6ee20c7946dd11a MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Data.DataTable.cs
  3. //
  4. // Author:
  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>
  11. // Sureshkumar T <tsureshkumar@novell.com>
  12. // Konstantin Triger <kostat@mainsoft.com>
  13. //
  14. // (C) Chris Podurgiel
  15. // (C) Ximian, Inc 2002
  16. // Copyright (C) Tim Coleman, 2002-2003
  17. // Copyright (C) Daniel Morgan, 2002-2003
  18. //
  19. //
  20. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  21. //
  22. // Permission is hereby granted, free of charge, to any person obtaining
  23. // a copy of this software and associated documentation files (the
  24. // "Software"), to deal in the Software without restriction, including
  25. // without limitation the rights to use, copy, modify, merge, publish,
  26. // distribute, sublicense, and/or sell copies of the Software, and to
  27. // permit persons to whom the Software is furnished to do so, subject to
  28. // the following conditions:
  29. //
  30. // The above copyright notice and this permission notice shall be
  31. // included in all copies or substantial portions of the Software.
  32. //
  33. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  34. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  35. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  36. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  37. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  38. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  39. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  40. //
  41. using System;
  42. using System.Data.Common;
  43. using System.Collections;
  44. #if NET_2_0
  45. using System.Collections.Generic;
  46. #endif
  47. using System.ComponentModel;
  48. using System.Globalization;
  49. using System.IO;
  50. using System.Runtime.Serialization;
  51. using System.Xml;
  52. using System.Xml.Schema;
  53. using System.Xml.Serialization;
  54. using System.Text.RegularExpressions;
  55. using Mono.Data.SqlExpressions;
  56. namespace System.Data {
  57. //[Designer]
  58. [ToolboxItem (false)]
  59. [DefaultEvent ("RowChanging")]
  60. [DefaultProperty ("TableName")]
  61. [DesignTimeVisible (false)]
  62. [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DataTableEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
  63. [Serializable]
  64. public partial class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable {
  65. #region Fields
  66. internal DataSet dataSet;
  67. private bool _caseSensitive;
  68. private DataColumnCollection _columnCollection;
  69. private ConstraintCollection _constraintCollection;
  70. // never access it. Use DefaultView.
  71. private DataView _defaultView = null;
  72. private string _displayExpression;
  73. private PropertyCollection _extendedProperties;
  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 UniqueConstraint _primaryKeyConstraint;
  81. private DataRowCollection _rows;
  82. private ISite _site;
  83. private string _tableName;
  84. internal bool _duringDataLoad;
  85. internal bool _nullConstraintViolationDuringDataLoad;
  86. private bool dataSetPrevEnforceConstraints;
  87. private bool enforceConstraints = true;
  88. private DataRowBuilder _rowBuilder;
  89. private ArrayList _indexes;
  90. private RecordCache _recordCache;
  91. private int _defaultValuesRowIndex = -1;
  92. protected internal bool fInitInProgress;
  93. // If CaseSensitive property is changed once it does not anymore follow owner DataSet's
  94. // CaseSensitive property. So when you lost you virginity it's gone for ever
  95. private bool _virginCaseSensitive = true;
  96. private PropertyDescriptorCollection _propertyDescriptorsCache;
  97. static DataColumn[] _emptyColumnArray = new DataColumn[0];
  98. // Regex to parse the Sort string.
  99. static Regex SortRegex = new Regex ( @"^((\[(?<ColName>.+)\])|(?<ColName>\S+))([ ]+(?<Order>ASC|DESC))?$",
  100. RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture);
  101. DataColumn [] _latestPrimaryKeyCols;
  102. #endregion //Fields
  103. /// <summary>
  104. /// Initializes a new instance of the DataTable class with no arguments.
  105. /// </summary>
  106. public DataTable ()
  107. {
  108. dataSet = null;
  109. _columnCollection = new DataColumnCollection(this);
  110. _constraintCollection = new ConstraintCollection(this);
  111. _extendedProperties = new PropertyCollection();
  112. _tableName = "";
  113. _nameSpace = null;
  114. _caseSensitive = false; //default value
  115. _displayExpression = null;
  116. _primaryKeyConstraint = null;
  117. _site = null;
  118. _rows = new DataRowCollection (this);
  119. _indexes = new ArrayList();
  120. _recordCache = new RecordCache(this);
  121. //LAMESPEC: spec says 25 impl does 50
  122. _minimumCapacity = 50;
  123. _childRelations = new DataRelationCollection.DataTableRelationCollection (this);
  124. _parentRelations = new DataRelationCollection.DataTableRelationCollection (this);
  125. }
  126. /// <summary>
  127. /// Intitalizes a new instance of the DataTable class with the specified table name.
  128. /// </summary>
  129. public DataTable (string tableName)
  130. : this ()
  131. {
  132. _tableName = tableName;
  133. }
  134. /// <summary>
  135. /// Initializes a new instance of the DataTable class with the SerializationInfo and the StreamingContext.
  136. /// </summary>
  137. protected DataTable (SerializationInfo info, StreamingContext context)
  138. : this ()
  139. {
  140. #if NET_2_0
  141. SerializationInfoEnumerator e = info.GetEnumerator ();
  142. SerializationFormat serializationFormat = SerializationFormat.Xml;
  143. while (e.MoveNext()) {
  144. if (e.ObjectType == typeof(System.Data.SerializationFormat)) {
  145. serializationFormat = (SerializationFormat) e.Value;
  146. break;
  147. }
  148. }
  149. if (serializationFormat == SerializationFormat.Xml) {
  150. #endif
  151. string schema = info.GetString ("XmlSchema");
  152. string data = info.GetString ("XmlDiffGram");
  153. DataSet ds = new DataSet ();
  154. ds.ReadXmlSchema (new StringReader (schema));
  155. ds.Tables [0].CopyProperties (this);
  156. ds = new DataSet ();
  157. ds.Tables.Add (this);
  158. ds.ReadXml (new StringReader (data), XmlReadMode.DiffGram);
  159. ds.Tables.Remove (this);
  160. /* keeping for a while. With the change above, we shouldn't have to consider
  161. * DataTable mode in schema inference/read.
  162. XmlSchemaMapper mapper = new XmlSchemaMapper (this);
  163. XmlTextReader xtr = new XmlTextReader(new StringReader (schema));
  164. mapper.Read (xtr);
  165. XmlDiffLoader loader = new XmlDiffLoader (this);
  166. xtr = new XmlTextReader(new StringReader (data));
  167. loader.Load (xtr);
  168. */
  169. #if NET_2_0
  170. } else /*if (Tables.RemotingFormat == SerializationFormat.Binary)*/ {
  171. BinaryDeserializeTable (info);
  172. }
  173. #endif
  174. }
  175. /// <summary>
  176. /// Indicates whether string comparisons within the table are case-sensitive.
  177. /// </summary>
  178. #if !NET_2_0
  179. [DataSysDescription ("Indicates whether comparing strings within the table is case sensitive.")]
  180. #endif
  181. public bool CaseSensitive {
  182. get {
  183. if (_virginCaseSensitive && dataSet != null)
  184. return dataSet.CaseSensitive;
  185. else
  186. return _caseSensitive;
  187. }
  188. set {
  189. if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
  190. 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.");
  191. }
  192. _virginCaseSensitive = false;
  193. _caseSensitive = value;
  194. ResetCaseSensitiveIndexes();
  195. }
  196. }
  197. internal ArrayList Indexes {
  198. get { return _indexes; }
  199. }
  200. internal void ChangedDataColumn (DataRow dr, DataColumn dc, object pv)
  201. {
  202. DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
  203. OnColumnChanged (e);
  204. }
  205. internal void ChangingDataColumn (DataRow dr, DataColumn dc, object pv)
  206. {
  207. DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
  208. OnColumnChanging (e);
  209. }
  210. internal void DeletedDataRow (DataRow dr, DataRowAction action)
  211. {
  212. DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
  213. OnRowDeleted (e);
  214. }
  215. internal void DeletingDataRow (DataRow dr, DataRowAction action)
  216. {
  217. DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
  218. OnRowDeleting (e);
  219. }
  220. internal void ChangedDataRow (DataRow dr, DataRowAction action)
  221. {
  222. DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
  223. OnRowChanged (e);
  224. }
  225. internal void ChangingDataRow (DataRow dr, DataRowAction action)
  226. {
  227. DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
  228. OnRowChanging (e);
  229. }
  230. /// <summary>
  231. /// Gets the collection of child relations for this DataTable.
  232. /// </summary>
  233. [Browsable (false)]
  234. #if !NET_2_0
  235. [DataSysDescription ("Returns the child relations for this table.")]
  236. #endif
  237. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  238. public DataRelationCollection ChildRelations {
  239. get { return _childRelations; }
  240. }
  241. /// <summary>
  242. /// Gets the collection of columns that belong to this table.
  243. /// </summary>
  244. [DataCategory ("Data")]
  245. #if !NET_2_0
  246. [DataSysDescription ("The collection that holds the columns for this table.")]
  247. #endif
  248. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  249. public DataColumnCollection Columns {
  250. get { return _columnCollection; }
  251. }
  252. /// <summary>
  253. /// Gets the collection of constraints maintained by this table.
  254. /// </summary>
  255. [DataCategory ("Data")]
  256. #if !NET_2_0
  257. [DataSysDescription ("The collection that holds the constraints for this table.")]
  258. #endif
  259. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  260. public ConstraintCollection Constraints {
  261. get { return _constraintCollection; }
  262. #if NET_2_0
  263. internal set { _constraintCollection = value; }
  264. #endif
  265. }
  266. /// <summary>
  267. /// Gets the DataSet that this table belongs to.
  268. /// </summary>
  269. [Browsable (false)]
  270. #if !NET_2_0
  271. [DataSysDescription ("Indicates the DataSet to which this table belongs.")]
  272. #endif
  273. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  274. public DataSet DataSet {
  275. get { return dataSet; }
  276. }
  277. /// <summary>
  278. /// Gets a customized view of the table which may
  279. /// include a filtered view, or a cursor position.
  280. /// </summary>
  281. [Browsable (false)]
  282. #if !NET_2_0
  283. [DataSysDescription ("This is the default DataView for the table.")]
  284. #endif
  285. public DataView DefaultView {
  286. get {
  287. if (_defaultView == null) {
  288. lock(this){
  289. if (_defaultView == null){
  290. if (dataSet != null)
  291. _defaultView = dataSet.DefaultViewManager.CreateDataView(this);
  292. else
  293. _defaultView = new DataView(this);
  294. }
  295. }
  296. }
  297. return _defaultView;
  298. }
  299. }
  300. /// <summary>
  301. /// Gets or sets the expression that will return
  302. /// a value used to represent this table in the user interface.
  303. /// </summary>
  304. [DataCategory ("Data")]
  305. #if !NET_2_0
  306. [DataSysDescription ("The expression used to compute the data-bound value of this row.")]
  307. #endif
  308. [DefaultValue ("")]
  309. public string DisplayExpression {
  310. get { return _displayExpression == null ? "" : _displayExpression; }
  311. set { _displayExpression = value; }
  312. }
  313. /// <summary>
  314. /// Gets the collection of customized user information.
  315. /// </summary>
  316. [Browsable (false)]
  317. [DataCategory ("Data")]
  318. #if !NET_2_0
  319. [DataSysDescription ("The collection that holds custom user information.")]
  320. #endif
  321. public PropertyCollection ExtendedProperties {
  322. get { return _extendedProperties; }
  323. }
  324. /// <summary>
  325. /// Gets a value indicating whether there are errors in
  326. /// any of the_rows in any of the tables of the DataSet to
  327. /// which the table belongs.
  328. /// </summary>
  329. [Browsable (false)]
  330. #if !NET_2_0
  331. [DataSysDescription ("Returns whether the table has errors.")]
  332. #endif
  333. public bool HasErrors {
  334. get {
  335. // we can not use the _hasError flag because we do not know when to turn it off!
  336. for (int i = 0; i < _rows.Count; i++) {
  337. if (_rows[i].HasErrors)
  338. return true;
  339. }
  340. return false;
  341. }
  342. }
  343. /// <summary>
  344. /// Gets or sets the locale information used to
  345. /// compare strings within the table.
  346. /// </summary>
  347. #if !NET_2_0
  348. [DataSysDescription ("Indicates a locale under which to compare strings within the table.")]
  349. #endif
  350. public CultureInfo Locale {
  351. get {
  352. // if the locale is null, we check for the DataSet locale
  353. // and if the DataSet is null we return the current culture.
  354. // this way if DataSet locale is changed, only if there is no locale for
  355. // the DataTable it influece the Locale get;
  356. if (_locale != null)
  357. return _locale;
  358. if (DataSet != null)
  359. return DataSet.Locale;
  360. return CultureInfo.CurrentCulture;
  361. }
  362. set {
  363. if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
  364. 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.");
  365. }
  366. if (_locale == null || !_locale.Equals(value))
  367. _locale = value;
  368. }
  369. }
  370. internal bool LocaleSpecified {
  371. get { return _locale != null; }
  372. }
  373. /// <summary>
  374. /// Gets or sets the initial starting size for this table.
  375. /// </summary>
  376. [DataCategory ("Data")]
  377. #if !NET_2_0
  378. [DataSysDescription ("Indicates an initial starting size for this table.")]
  379. #endif
  380. [DefaultValue (50)]
  381. public int MinimumCapacity {
  382. get { return _minimumCapacity; }
  383. set { _minimumCapacity = value; }
  384. }
  385. /// <summary>
  386. /// Gets or sets the namespace for the XML represenation
  387. /// of the data stored in the DataTable.
  388. /// </summary>
  389. [DataCategory ("Data")]
  390. #if !NET_2_0
  391. [DataSysDescription ("Indicates the XML uri namespace for the elements contained in this table.")]
  392. #endif
  393. public string Namespace {
  394. get {
  395. if (_nameSpace != null)
  396. return _nameSpace;
  397. if (DataSet != null)
  398. return DataSet.Namespace;
  399. return String.Empty;
  400. }
  401. set { _nameSpace = value; }
  402. }
  403. /// <summary>
  404. /// Gets the collection of parent relations for
  405. /// this DataTable.
  406. /// </summary>
  407. [Browsable (false)]
  408. #if !NET_2_0
  409. [DataSysDescription ("Returns the parent relations for this table.")]
  410. #endif
  411. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  412. public DataRelationCollection ParentRelations {
  413. get { return _parentRelations; }
  414. }
  415. /// <summary>
  416. /// Gets or sets the namespace for the XML represenation
  417. /// of the data stored in the DataTable.
  418. /// </summary>
  419. [DataCategory ("Data")]
  420. #if !NET_2_0
  421. [DataSysDescription ("Indicates the Prefix of the namespace used for this table in XML representation.")]
  422. #endif
  423. [DefaultValue ("")]
  424. public string Prefix {
  425. get { return _prefix == null ? "" : _prefix; }
  426. set {
  427. // Prefix cannot contain any special characters other than '_' and ':'
  428. for (int i = 0; i < value.Length; i++) {
  429. if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
  430. throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
  431. }
  432. _prefix = value;
  433. }
  434. }
  435. /// <summary>
  436. /// Gets or sets an array of columns that function as
  437. /// primary keys for the data table.
  438. /// </summary>
  439. [DataCategory ("Data")]
  440. #if !NET_2_0
  441. [DataSysDescription ("Indicates the column(s) that represent the primary key for this table.")]
  442. #endif
  443. [EditorAttribute ("Microsoft.VSDesigner.Data.Design.PrimaryKeyEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
  444. [TypeConverterAttribute ("System.Data.PrimaryKeyTypeConverter, " + Consts.AssemblySystem_Data)]
  445. public DataColumn[] PrimaryKey {
  446. get {
  447. if (_primaryKeyConstraint == null)
  448. return new DataColumn[] {};
  449. return _primaryKeyConstraint.Columns;
  450. }
  451. set {
  452. if (value == null || value.Length == 0) {
  453. if (_primaryKeyConstraint != null) {
  454. _primaryKeyConstraint.SetIsPrimaryKey (false);
  455. Constraints.Remove(_primaryKeyConstraint);
  456. _primaryKeyConstraint = null;
  457. }
  458. return;
  459. }
  460. if (InitInProgress) {
  461. _latestPrimaryKeyCols = value;
  462. return;
  463. }
  464. // first check if value is the same as current PK.
  465. if (_primaryKeyConstraint != null &&
  466. DataColumn.AreColumnSetsTheSame (value, _primaryKeyConstraint.Columns))
  467. return;
  468. //Does constraint exist for these columns
  469. UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet (this.Constraints, (DataColumn[]) value);
  470. //if constraint doesn't exist for columns
  471. //create new unique primary key constraint
  472. if (null == uc) {
  473. foreach (DataColumn Col in (DataColumn []) value) {
  474. if (Col.Table == null)
  475. break;
  476. if (Columns.IndexOf (Col) < 0)
  477. throw new ArgumentException ("PrimaryKey columns do not belong to this table.");
  478. }
  479. // create constraint with primary key indication set to false
  480. // to avoid recursion
  481. uc = new UniqueConstraint ((DataColumn []) value, false);
  482. Constraints.Add (uc);
  483. }
  484. //Remove the existing primary key
  485. if (_primaryKeyConstraint != null) {
  486. _primaryKeyConstraint.SetIsPrimaryKey (false);
  487. Constraints.Remove (_primaryKeyConstraint);
  488. _primaryKeyConstraint = null;
  489. }
  490. //set the constraint as the new primary key
  491. UniqueConstraint.SetAsPrimaryKey (Constraints, uc);
  492. _primaryKeyConstraint = uc;
  493. for (int j = 0; j < uc.Columns.Length; ++j)
  494. uc.Columns [j].AllowDBNull = false;
  495. }
  496. }
  497. internal UniqueConstraint PrimaryKeyConstraint {
  498. get { return _primaryKeyConstraint; }
  499. }
  500. /// <summary>
  501. /// Gets the collection of_rows that belong to this table.
  502. /// </summary>
  503. [Browsable (false)]
  504. #if !NET_2_0
  505. [DataSysDescription ("Indicates the collection that holds the rows of data for this table.")]
  506. #endif
  507. public DataRowCollection Rows {
  508. get { return _rows; }
  509. }
  510. /// <summary>
  511. /// Gets or sets an System.ComponentModel.ISite
  512. /// for the DataTable.
  513. /// </summary>
  514. [Browsable (false)]
  515. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  516. public override ISite Site {
  517. get { return _site; }
  518. set { _site = value; }
  519. }
  520. /// <summary>
  521. /// Gets or sets the name of the the DataTable.
  522. /// </summary>
  523. [DataCategory ("Data")]
  524. #if !NET_2_0
  525. [DataSysDescription ("Indicates the name used to look up this table in the Tables collection of a DataSet.")]
  526. #endif
  527. [DefaultValue ("")]
  528. [RefreshProperties (RefreshProperties.All)]
  529. public string TableName {
  530. get { return _tableName == null ? "" : _tableName; }
  531. set { _tableName = value; }
  532. }
  533. bool IListSource.ContainsListCollection {
  534. // the collection is a DataView
  535. get { return false; }
  536. }
  537. internal RecordCache RecordCache {
  538. get { return _recordCache; }
  539. }
  540. private DataRowBuilder RowBuilder {
  541. get {
  542. // initiate only one row builder.
  543. if (_rowBuilder == null)
  544. _rowBuilder = new DataRowBuilder (this, -1, 0);
  545. else
  546. // new row get id -1.
  547. _rowBuilder._rowId = -1;
  548. return _rowBuilder;
  549. }
  550. }
  551. internal bool EnforceConstraints {
  552. get { return enforceConstraints; }
  553. set {
  554. if (value == enforceConstraints)
  555. return;
  556. if (value) {
  557. // reset indexes since they may be outdated
  558. ResetIndexes();
  559. // assert all constraints
  560. foreach (Constraint constraint in Constraints)
  561. constraint.AssertConstraint ();
  562. AssertNotNullConstraints ();
  563. if (HasErrors)
  564. Constraint.ThrowConstraintException ();
  565. }
  566. enforceConstraints = value;
  567. }
  568. }
  569. internal void AssertNotNullConstraints ()
  570. {
  571. if (_duringDataLoad && !_nullConstraintViolationDuringDataLoad)
  572. return;
  573. bool seen = false;
  574. for (int i = 0; i < Columns.Count; i++) {
  575. DataColumn column = Columns [i];
  576. if (column.AllowDBNull)
  577. continue;
  578. for (int j = 0; j < Rows.Count; j++) {
  579. if (Rows [j].HasVersion (DataRowVersion.Default) && Rows[j].IsNull (column)) {
  580. seen = true;
  581. string errMsg = String.Format ("Column '{0}' does not allow DBNull.Value.",
  582. column.ColumnName);
  583. Rows [j].SetColumnError (i, errMsg);
  584. Rows [j].RowError = errMsg;
  585. }
  586. }
  587. }
  588. _nullConstraintViolationDuringDataLoad = seen;
  589. }
  590. internal bool RowsExist (DataColumn [] columns, DataColumn [] relatedColumns, DataRow row)
  591. {
  592. int curIndex = row.IndexFromVersion (DataRowVersion.Default);
  593. int tmpRecord = RecordCache.NewRecord ();
  594. try {
  595. for (int i = 0; i < relatedColumns.Length; i++)
  596. // according to MSDN: the DataType value for both columns must be identical.
  597. columns [i].DataContainer.CopyValue (relatedColumns [i].DataContainer, curIndex, tmpRecord);
  598. return RowsExist (columns, tmpRecord);
  599. } finally {
  600. RecordCache.DisposeRecord (tmpRecord);
  601. }
  602. }
  603. bool RowsExist (DataColumn [] columns, int index)
  604. {
  605. Index indx = this.FindIndex (columns);
  606. if (indx != null)
  607. return indx.Find (index) != -1;
  608. // we have to perform full-table scan
  609. // check that there is a parent for this row.
  610. foreach (DataRow thisRow in this.Rows) {
  611. if (thisRow.RowState == DataRowState.Deleted)
  612. continue;
  613. // check if the values in the columns are equal
  614. int thisIndex = thisRow.IndexFromVersion (
  615. thisRow.RowState == DataRowState.Modified ? DataRowVersion.Original : DataRowVersion.Current);
  616. bool match = true;
  617. foreach (DataColumn column in columns) {
  618. if (column.DataContainer.CompareValues (thisIndex, index) != 0) {
  619. match = false;
  620. break;
  621. }
  622. }
  623. if (match)
  624. return true;
  625. }
  626. return false;
  627. }
  628. /// <summary>
  629. /// Commits all the changes made to this table since the
  630. /// last time AcceptChanges was called.
  631. /// </summary>
  632. public void AcceptChanges ()
  633. {
  634. //FIXME: Do we need to validate anything here or
  635. //try to catch any errors to deal with them?
  636. // we do not use foreach because if one of the rows is in Delete state
  637. // it will be romeved from Rows and we get an exception.
  638. DataRow myRow;
  639. for (int i = 0; i < Rows.Count; ) {
  640. myRow = Rows [i];
  641. myRow.AcceptChanges ();
  642. // if the row state is Detached it meens that it was removed from row list (Rows)
  643. // so we should not increase 'i'.
  644. if (myRow.RowState != DataRowState.Detached)
  645. i++;
  646. }
  647. _rows.OnListChanged (this, new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
  648. }
  649. /// <summary>
  650. /// Begins the initialization of a DataTable that is used
  651. /// on a form or used by another component. The initialization
  652. /// occurs at runtime.
  653. /// </summary>
  654. public
  655. #if NET_2_0
  656. virtual
  657. #endif
  658. void BeginInit ()
  659. {
  660. InitInProgress = true;
  661. #if NET_2_0
  662. tableInitialized = false;
  663. #endif
  664. }
  665. /// <summary>
  666. /// Turns off notifications, index maintenance, and
  667. /// constraints while loading data.
  668. /// </summary>
  669. public void BeginLoadData ()
  670. {
  671. if (this._duringDataLoad)
  672. return;
  673. //duringDataLoad is important to EndLoadData and
  674. //for not throwing unexpected exceptions.
  675. this._duringDataLoad = true;
  676. this._nullConstraintViolationDuringDataLoad = false;
  677. if (this.dataSet != null) {
  678. //Saving old Enforce constraints state for later
  679. //use in the EndLoadData.
  680. this.dataSetPrevEnforceConstraints = this.dataSet.EnforceConstraints;
  681. this.dataSet.EnforceConstraints = false;
  682. } else {
  683. //if table does not belong to any data set use EnforceConstraints of the table
  684. this.EnforceConstraints = false;
  685. }
  686. return;
  687. }
  688. /// <summary>
  689. /// Clears the DataTable of all data.
  690. /// </summary>
  691. public void Clear ()
  692. {
  693. // Foriegn key constraints are checked in _rows.Clear method
  694. _rows.Clear ();
  695. }
  696. /// <summary>
  697. /// Clones the structure of the DataTable, including
  698. /// all DataTable schemas and constraints.
  699. /// </summary>
  700. public virtual DataTable Clone ()
  701. {
  702. // Use Activator so we can use non-public constructors.
  703. DataTable Copy = (DataTable) Activator.CreateInstance (GetType (), true);
  704. CopyProperties (Copy);
  705. return Copy;
  706. }
  707. /// <summary>
  708. /// Computes the given expression on the current_rows that
  709. /// pass the filter criteria.
  710. /// </summary>
  711. public object Compute (string expression, string filter)
  712. {
  713. // expression is an aggregate function
  714. // filter is an expression used to limit rows
  715. DataRow [] rows = Select (filter);
  716. if (rows == null || rows.Length == 0)
  717. return DBNull.Value;
  718. Parser parser = new Parser (rows);
  719. IExpression expr = parser.Compile (expression);
  720. object obj = expr.Eval (rows [0]);
  721. return obj;
  722. }
  723. /// <summary>
  724. /// Copies both the structure and data for this DataTable.
  725. /// </summary>
  726. public DataTable Copy ()
  727. {
  728. DataTable copy = Clone ();
  729. copy._duringDataLoad = true;
  730. foreach (DataRow row in Rows) {
  731. DataRow newRow = copy.NewNotInitializedRow ();
  732. copy.Rows.AddInternal (newRow);
  733. CopyRow (row, newRow);
  734. }
  735. copy._duringDataLoad = false;
  736. // rebuild copy indexes after loading all rows
  737. copy.ResetIndexes ();
  738. return copy;
  739. }
  740. internal void CopyRow (DataRow fromRow, DataRow toRow)
  741. {
  742. if (fromRow.HasErrors)
  743. fromRow.CopyErrors (toRow);
  744. if (fromRow.HasVersion (DataRowVersion.Original))
  745. toRow.Original = toRow.Table.RecordCache.CopyRecord (this, fromRow.Original, -1);
  746. if (fromRow.HasVersion (DataRowVersion.Current)) {
  747. if (fromRow.Original != fromRow.Current)
  748. toRow.Current = toRow.Table.RecordCache.CopyRecord (this, fromRow.Current, -1);
  749. else
  750. toRow.Current = toRow.Original;
  751. }
  752. }
  753. private void CopyProperties (DataTable Copy)
  754. {
  755. Copy.CaseSensitive = CaseSensitive;
  756. Copy._virginCaseSensitive = _virginCaseSensitive;
  757. // Copy.ChildRelations
  758. // Copy.Constraints
  759. // Copy.Container
  760. // Copy.DefaultView
  761. // Copy.DesignMode
  762. Copy.DisplayExpression = DisplayExpression;
  763. if (ExtendedProperties.Count > 0) {
  764. // Cannot copy extended properties directly as the property does not have a set accessor
  765. Array tgtArray = Array.CreateInstance (typeof (object), ExtendedProperties.Count);
  766. ExtendedProperties.Keys.CopyTo (tgtArray, 0);
  767. for (int i=0; i < ExtendedProperties.Count; i++)
  768. Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
  769. }
  770. Copy._locale = _locale;
  771. Copy.MinimumCapacity = MinimumCapacity;
  772. Copy.Namespace = Namespace;
  773. // Copy.ParentRelations
  774. Copy.Prefix = Prefix;
  775. Copy.Site = Site;
  776. Copy.TableName = TableName;
  777. bool isEmpty = Copy.Columns.Count == 0;
  778. // Copy columns
  779. foreach (DataColumn column in Columns) {
  780. // When cloning a table, the columns may be added in the default constructor.
  781. if (isEmpty || !Copy.Columns.Contains (column.ColumnName))
  782. Copy.Columns.Add (column.Clone ());
  783. }
  784. foreach (DataColumn column in Copy.Columns)
  785. column.CompileExpression ();
  786. CopyConstraints (Copy);
  787. // add primary key to the copy
  788. if (PrimaryKey.Length > 0) {
  789. DataColumn[] pColumns = new DataColumn[PrimaryKey.Length];
  790. for (int i = 0; i < pColumns.Length; i++)
  791. pColumns[i] = Copy.Columns[PrimaryKey[i].ColumnName];
  792. Copy.PrimaryKey = pColumns;
  793. }
  794. }
  795. private void CopyConstraints (DataTable copy)
  796. {
  797. UniqueConstraint origUc;
  798. UniqueConstraint copyUc;
  799. for (int i = 0; i < this.Constraints.Count; i++) {
  800. if (this.Constraints[i] is UniqueConstraint) {
  801. // typed ds can already contain the constraints
  802. if (copy.Constraints.Contains (this.Constraints [i].ConstraintName))
  803. continue;
  804. origUc = (UniqueConstraint) this.Constraints [i];
  805. DataColumn [] columns = new DataColumn [origUc.Columns.Length];
  806. for (int j = 0; j < columns.Length; j++)
  807. columns[j] = copy.Columns [origUc.Columns [j].ColumnName];
  808. copyUc = new UniqueConstraint (origUc.ConstraintName, columns, origUc.IsPrimaryKey);
  809. copy.Constraints.Add (copyUc);
  810. }
  811. }
  812. }
  813. /// <summary>
  814. /// Ends the initialization of a DataTable that is used
  815. /// on a form or used by another component. The
  816. /// initialization occurs at runtime.
  817. /// </summary>
  818. public
  819. #if NET_2_0
  820. virtual
  821. #endif
  822. void EndInit ()
  823. {
  824. InitInProgress = false;
  825. DataTableInitialized ();
  826. FinishInit ();
  827. }
  828. // defined in NET_2_0 profile
  829. partial void DataTableInitialized ();
  830. internal bool InitInProgress {
  831. get { return fInitInProgress; }
  832. set { fInitInProgress = value; }
  833. }
  834. internal void FinishInit ()
  835. {
  836. UniqueConstraint oldPK = _primaryKeyConstraint;
  837. // Columns shud be added 'before' the constraints
  838. Columns.PostAddRange ();
  839. // Add the constraints
  840. _constraintCollection.PostAddRange ();
  841. // ms.net behavior : If a PrimaryKey (UniqueConstraint) is added thru AddRange,
  842. // then it takes precedence over an direct assignment of PrimaryKey
  843. if (_primaryKeyConstraint == oldPK)
  844. PrimaryKey = _latestPrimaryKeyCols;
  845. }
  846. /// <summary>
  847. /// Turns on notifications, index maintenance, and
  848. /// constraints after loading data.
  849. /// </summary>
  850. public void EndLoadData ()
  851. {
  852. if (this._duringDataLoad) {
  853. //Getting back to previous EnforceConstraint state
  854. if (this.dataSet != null)
  855. this.dataSet.InternalEnforceConstraints (this.dataSetPrevEnforceConstraints, true);
  856. else
  857. this.EnforceConstraints = true;
  858. this._duringDataLoad = false;
  859. }
  860. }
  861. /// <summary>
  862. /// Gets a copy of the DataTable that contains all
  863. /// changes made to it since it was loaded or
  864. /// AcceptChanges was last called.
  865. /// </summary>
  866. public DataTable GetChanges ()
  867. {
  868. return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
  869. }
  870. /// <summary>
  871. /// Gets a copy of the DataTable containing all
  872. /// changes made to it since it was last loaded, or
  873. /// since AcceptChanges was called, filtered by DataRowState.
  874. /// </summary>
  875. public DataTable GetChanges (DataRowState rowStates)
  876. {
  877. DataTable copyTable = null;
  878. foreach (DataRow row in Rows) {
  879. // The spec says relationship constraints may cause Unchanged parent rows to be included but
  880. // MS .NET 1.1 does not include Unchanged rows even if their child rows are changed.
  881. if (!row.IsRowChanged (rowStates))
  882. continue;
  883. if (copyTable == null)
  884. copyTable = Clone ();
  885. DataRow newRow = copyTable.NewNotInitializedRow ();
  886. // Don't check for ReadOnly, when cloning data to new uninitialized row.
  887. row.CopyValuesToRow (newRow, false);
  888. #if NET_2_0
  889. newRow.XmlRowID = row.XmlRowID;
  890. #endif
  891. copyTable.Rows.AddInternal (newRow);
  892. }
  893. return copyTable;
  894. }
  895. /// <summary>
  896. /// Gets an array of DataRow objects that contain errors.
  897. /// </summary>
  898. public DataRow [] GetErrors ()
  899. {
  900. ArrayList errors = new ArrayList();
  901. for (int i = 0; i < _rows.Count; i++) {
  902. if (_rows[i].HasErrors)
  903. errors.Add (_rows[i]);
  904. }
  905. DataRow[] ret = NewRowArray (errors.Count);
  906. errors.CopyTo (ret, 0);
  907. return ret;
  908. }
  909. /// <summary>
  910. /// This member is only meant to support Mono's infrastructure
  911. /// </summary>
  912. protected virtual DataTable CreateInstance ()
  913. {
  914. return Activator.CreateInstance (this.GetType (), true) as DataTable;
  915. }
  916. /// <summary>
  917. /// This member is only meant to support Mono's infrastructure
  918. /// </summary>
  919. protected virtual Type GetRowType ()
  920. {
  921. return typeof (DataRow);
  922. }
  923. /// <summary>
  924. /// This member is only meant to support Mono's infrastructure
  925. ///
  926. /// Used for Data Binding between System.Web.UI. controls
  927. /// like a DataGrid
  928. /// or
  929. /// System.Windows.Forms controls like a DataGrid
  930. /// </summary>
  931. IList IListSource.GetList ()
  932. {
  933. IList list = (IList) DefaultView;
  934. return list;
  935. }
  936. /// <summary>
  937. /// Copies a DataRow into a DataTable, preserving any
  938. /// property settings, as well as original and current values.
  939. /// </summary>
  940. public void ImportRow (DataRow row)
  941. {
  942. if (row.RowState == DataRowState.Detached)
  943. return;
  944. DataRow newRow = NewNotInitializedRow ();
  945. int original = -1;
  946. if (row.HasVersion (DataRowVersion.Original)) {
  947. original = row.IndexFromVersion (DataRowVersion.Original);
  948. newRow.Original = RecordCache.NewRecord ();
  949. RecordCache.CopyRecord (row.Table, original, newRow.Original);
  950. }
  951. if (row.HasVersion (DataRowVersion.Current)) {
  952. int current = row.IndexFromVersion (DataRowVersion.Current);
  953. if (current == original) {
  954. newRow.Current = newRow.Original;
  955. } else {
  956. newRow.Current = RecordCache.NewRecord ();
  957. RecordCache.CopyRecord (row.Table, current, newRow.Current);
  958. }
  959. }
  960. //Import the row only if RowState is not detached
  961. //Validation for Deleted Rows happens during Accept/RejectChanges
  962. if (row.RowState != DataRowState.Deleted)
  963. newRow.Validate ();
  964. else
  965. AddRowToIndexes (newRow);
  966. Rows.AddInternal(newRow);
  967. if (row.HasErrors)
  968. row.CopyErrors (newRow);
  969. }
  970. internal int DefaultValuesRowIndex {
  971. get { return _defaultValuesRowIndex; }
  972. }
  973. /// <summary>
  974. /// This member is only meant to support Mono's infrastructure
  975. /// </summary>
  976. #if NET_2_0
  977. public virtual
  978. #endif
  979. void
  980. #if !NET_2_0
  981. ISerializable.
  982. #endif
  983. GetObjectData (SerializationInfo info, StreamingContext context)
  984. {
  985. #if NET_2_0
  986. if (RemotingFormat == SerializationFormat.Xml) {
  987. #endif
  988. DataSet dset;
  989. if (dataSet != null)
  990. dset = dataSet;
  991. else {
  992. dset = new DataSet ("tmpDataSet");
  993. dset.Tables.Add (this);
  994. }
  995. StringWriter sw = new StringWriter ();
  996. XmlTextWriter tw = new XmlTextWriter (sw);
  997. tw.Formatting = Formatting.Indented;
  998. dset.WriteIndividualTableContent (tw, this, XmlWriteMode.DiffGram);
  999. tw.Close ();
  1000. StringWriter sw2 = new StringWriter ();
  1001. DataTableCollection tables = new DataTableCollection (dset);
  1002. tables.Add (this);
  1003. XmlSchemaWriter.WriteXmlSchema (dset, new XmlTextWriter (sw2), tables, null);
  1004. sw2.Close ();
  1005. info.AddValue ("XmlSchema", sw2.ToString(), typeof(string));
  1006. info.AddValue ("XmlDiffGram", sw.ToString(), typeof(string));
  1007. #if NET_2_0
  1008. } else /*if (RemotingFormat == SerializationFormat.Binary)*/ {
  1009. BinarySerializeProperty (info);
  1010. if (dataSet == null) {
  1011. for (int i = 0; i < Columns.Count; i++) {
  1012. info.AddValue ("DataTable.DataColumn_" + i + ".Expression",
  1013. Columns[i].Expression);
  1014. }
  1015. BinarySerialize (info, "DataTable_0.");
  1016. }
  1017. }
  1018. #endif
  1019. }
  1020. /// <summary>
  1021. /// Finds and updates a specific row. If no matching row
  1022. /// is found, a new row is created using the given values.
  1023. /// </summary>
  1024. public DataRow LoadDataRow (object [] values, bool fAcceptChanges)
  1025. {
  1026. DataRow row = null;
  1027. if (PrimaryKey.Length == 0) {
  1028. row = Rows.Add (values);
  1029. } else {
  1030. EnsureDefaultValueRowIndex ();
  1031. int newRecord = CreateRecord (values);
  1032. int existingRecord = _primaryKeyConstraint.Index.Find (newRecord);
  1033. if (existingRecord < 0) {
  1034. row = NewRowFromBuilder (RowBuilder);
  1035. row.Proposed = newRecord;
  1036. Rows.AddInternal(row);
  1037. if (!_duringDataLoad)
  1038. AddRowToIndexes (row);
  1039. } else {
  1040. row = RecordCache [existingRecord];
  1041. row.BeginEdit ();
  1042. row.ImportRecord (newRecord);
  1043. row.EndEdit ();
  1044. }
  1045. }
  1046. if (fAcceptChanges)
  1047. row.AcceptChanges ();
  1048. return row;
  1049. }
  1050. internal DataRow LoadDataRow (IDataRecord record, int[] mapping, int length, bool fAcceptChanges)
  1051. {
  1052. DataRow row = null;
  1053. int tmpRecord = this.RecordCache.NewRecord ();
  1054. try {
  1055. RecordCache.ReadIDataRecord (tmpRecord,record,mapping,length);
  1056. if (PrimaryKey.Length != 0) {
  1057. bool hasPrimaryValues = true;
  1058. foreach(DataColumn col in PrimaryKey) {
  1059. if(!(col.Ordinal < mapping.Length)) {
  1060. hasPrimaryValues = false;
  1061. break;
  1062. }
  1063. }
  1064. if (hasPrimaryValues) {
  1065. int existingRecord = _primaryKeyConstraint.Index.Find (tmpRecord);
  1066. if (existingRecord != -1)
  1067. row = RecordCache [existingRecord];
  1068. }
  1069. }
  1070. if (row == null) {
  1071. row = NewNotInitializedRow ();
  1072. row.Proposed = tmpRecord;
  1073. Rows.AddInternal (row);
  1074. } else {
  1075. row.BeginEdit ();
  1076. row.ImportRecord (tmpRecord);
  1077. row.EndEdit ();
  1078. }
  1079. if (fAcceptChanges)
  1080. row.AcceptChanges ();
  1081. } catch {
  1082. this.RecordCache.DisposeRecord (tmpRecord);
  1083. throw;
  1084. }
  1085. return row;
  1086. }
  1087. /// <summary>
  1088. /// Creates a new DataRow with the same schema as the table.
  1089. /// </summary>
  1090. public DataRow NewRow ()
  1091. {
  1092. EnsureDefaultValueRowIndex();
  1093. DataRow newRow = NewRowFromBuilder (RowBuilder);
  1094. newRow.Proposed = CreateRecord (null);
  1095. NewRowAdded (newRow);
  1096. return newRow;
  1097. }
  1098. // defined in the NET_2_0 profile
  1099. partial void NewRowAdded (DataRow dr);
  1100. internal int CreateRecord (object [] values)
  1101. {
  1102. int valCount = values != null ? values.Length : 0;
  1103. if (valCount > Columns.Count)
  1104. throw new ArgumentException ("Input array is longer than the number of columns in this table.");
  1105. int index = RecordCache.NewRecord ();
  1106. try {
  1107. for (int i = 0; i < valCount; i++) {
  1108. object value = values[i];
  1109. if (value == null)
  1110. Columns [i].SetDefaultValue (index);
  1111. else
  1112. Columns [i][index] = values [i];
  1113. }
  1114. for(int i = valCount; i < Columns.Count; i++)
  1115. Columns [i].SetDefaultValue (index);
  1116. return index;
  1117. } catch {
  1118. RecordCache.DisposeRecord (index);
  1119. throw;
  1120. }
  1121. }
  1122. private void EnsureDefaultValueRowIndex ()
  1123. {
  1124. // initialize default values row for the first time
  1125. if (_defaultValuesRowIndex == -1) {
  1126. _defaultValuesRowIndex = RecordCache.NewRecord();
  1127. for (int i = 0; i < Columns.Count; ++i) {
  1128. DataColumn column = Columns [i];
  1129. column.DataContainer [_defaultValuesRowIndex] = column.DefaultValue;
  1130. }
  1131. }
  1132. }
  1133. /// <summary>
  1134. /// This member supports the .NET Framework infrastructure
  1135. /// and is not intended to be used directly from your code.
  1136. /// </summary>
  1137. DataRow [] empty_rows;
  1138. protected internal DataRow [] NewRowArray (int size)
  1139. {
  1140. if (size == 0 && empty_rows != null)
  1141. return empty_rows;
  1142. Type t = GetRowType ();
  1143. /* Avoid reflection if possible */
  1144. DataRow [] rows = t == typeof (DataRow) ? new DataRow [size] : (DataRow []) Array.CreateInstance (t, size);
  1145. if (size == 0)
  1146. empty_rows = rows;
  1147. return rows;
  1148. }
  1149. /// <summary>
  1150. /// Creates a new row from an existing row.
  1151. /// </summary>
  1152. protected virtual DataRow NewRowFromBuilder (DataRowBuilder builder)
  1153. {
  1154. return new DataRow (builder);
  1155. }
  1156. internal DataRow NewNotInitializedRow ()
  1157. {
  1158. EnsureDefaultValueRowIndex ();
  1159. return NewRowFromBuilder (RowBuilder);
  1160. }
  1161. /// <summary>
  1162. /// Rolls back all changes that have been made to the
  1163. /// table since it was loaded, or the last time AcceptChanges
  1164. /// was called.
  1165. /// </summary>
  1166. public void RejectChanges ()
  1167. {
  1168. for (int i = _rows.Count - 1; i >= 0; i--) {
  1169. DataRow row = _rows [i];
  1170. if (row.RowState != DataRowState.Unchanged)
  1171. _rows [i].RejectChanges ();
  1172. }
  1173. }
  1174. /// <summary>
  1175. /// Resets the DataTable to its original state.
  1176. /// </summary>
  1177. public virtual void Reset ()
  1178. {
  1179. Clear ();
  1180. while (ParentRelations.Count > 0) {
  1181. if (dataSet.Relations.Contains (ParentRelations [ParentRelations.Count - 1].RelationName))
  1182. dataSet.Relations.Remove (ParentRelations [ParentRelations.Count - 1]);
  1183. }
  1184. while (ChildRelations.Count > 0) {
  1185. if (dataSet.Relations.Contains (ChildRelations [ChildRelations.Count - 1].RelationName))
  1186. dataSet.Relations.Remove (ChildRelations [ChildRelations.Count - 1]);
  1187. }
  1188. Constraints.Clear ();
  1189. Columns.Clear ();
  1190. }
  1191. /// <summary>
  1192. /// Gets an array of all DataRow objects.
  1193. /// </summary>
  1194. public DataRow[] Select ()
  1195. {
  1196. return Select (String.Empty, String.Empty, DataViewRowState.CurrentRows);
  1197. }
  1198. /// <summary>
  1199. /// Gets an array of all DataRow objects that match
  1200. /// the filter criteria in order of primary key (or
  1201. /// lacking one, order of addition.)
  1202. /// </summary>
  1203. public DataRow[] Select (string filterExpression)
  1204. {
  1205. return Select (filterExpression, String.Empty, DataViewRowState.CurrentRows);
  1206. }
  1207. /// <summary>
  1208. /// Gets an array of all DataRow objects that
  1209. /// match the filter criteria, in the the
  1210. /// specified sort order.
  1211. /// </summary>
  1212. public DataRow[] Select (string filterExpression, string sort)
  1213. {
  1214. return Select (filterExpression, sort, DataViewRowState.CurrentRows);
  1215. }
  1216. /// <summary>
  1217. /// Gets an array of all DataRow objects that match
  1218. /// the filter in the order of the sort, that match
  1219. /// the specified state.
  1220. /// </summary>
  1221. public DataRow [] Select (string filterExpression, string sort, DataViewRowState recordStates)
  1222. {
  1223. if (filterExpression == null)
  1224. filterExpression = String.Empty;
  1225. IExpression filter = null;
  1226. if (filterExpression != String.Empty) {
  1227. Parser parser = new Parser ();
  1228. filter = parser.Compile (filterExpression);
  1229. }
  1230. DataColumn [] columns = _emptyColumnArray;
  1231. ListSortDirection [] sorts = null;
  1232. if (sort != null && !sort.Equals(String.Empty))
  1233. columns = ParseSortString (this, sort, out sorts, false);
  1234. if (Rows.Count == 0)
  1235. return NewRowArray (0);
  1236. //if sort order is not given, sort it in Ascending order of the
  1237. //columns involved in the filter
  1238. if (columns.Length == 0 && filter != null) {
  1239. ArrayList list = new ArrayList ();
  1240. for (int i = 0; i < Columns.Count; ++i) {
  1241. if (!filter.DependsOn (Columns [i]))
  1242. continue;
  1243. list.Add (Columns [i]);
  1244. }
  1245. columns = (DataColumn []) list.ToArray (typeof (DataColumn));
  1246. }
  1247. bool addIndex = true;
  1248. if (filterExpression != String.Empty)
  1249. addIndex = false;
  1250. Index index = GetIndex (columns, sorts, recordStates, filter, false, addIndex);
  1251. int [] records = index.GetAll ();
  1252. DataRow [] dataRows = NewRowArray (index.Size);
  1253. for (int i = 0; i < dataRows.Length; i++)
  1254. dataRows [i] = RecordCache [records [i]];
  1255. return dataRows;
  1256. }
  1257. private void AddIndex (Index index)
  1258. {
  1259. if (_indexes == null)
  1260. _indexes = new ArrayList();
  1261. _indexes.Add (index);
  1262. }
  1263. /// <summary>
  1264. /// Returns index corresponding to columns,sort,row state filter and unique values given.
  1265. /// If such an index not exists, creates a new one.
  1266. /// </summary>
  1267. /// <param name="columns">Columns set of the index to look for.</param>
  1268. /// <param name="sort">Columns sort order of the index to look for.</param>
  1269. /// <param name="rowState">Rpw state filter of the index to look for.</param>
  1270. /// <param name="unique">Uniqueness of the index to look for.</param>
  1271. /// <param name="strict">Indicates whenever the index found should correspond in its uniquness to the value of unique parameter specified.</param>
  1272. /// <param name="reset">Indicates whenever the already existing index should be forced to reset.</param>
  1273. /// <returns></returns>
  1274. internal Index GetIndex (DataColumn[] columns, ListSortDirection[] sort, DataViewRowState rowState, IExpression filter, bool reset)
  1275. {
  1276. return GetIndex (columns, sort, rowState, filter, reset, true);
  1277. }
  1278. internal Index GetIndex (DataColumn[] columns, ListSortDirection[] sort,
  1279. DataViewRowState rowState, IExpression filter,
  1280. bool reset, bool addIndex)
  1281. {
  1282. Index index = FindIndex(columns, sort, rowState, filter);
  1283. if (index == null) {
  1284. index = new Index(new Key (this, columns, sort, rowState, filter));
  1285. if (addIndex)
  1286. AddIndex (index);
  1287. } else if (reset) {
  1288. // reset existing index only if asked for this
  1289. index.Reset ();
  1290. }
  1291. return index;
  1292. }
  1293. internal Index FindIndex (DataColumn[] columns)
  1294. {
  1295. return FindIndex (columns, null, DataViewRowState.None, null);
  1296. }
  1297. internal Index FindIndex (DataColumn[] columns, ListSortDirection[] sort, DataViewRowState rowState, IExpression filter)
  1298. {
  1299. if (Indexes != null) {
  1300. foreach (Index index in Indexes) {
  1301. if (index.Key.Equals (columns,sort,rowState, filter))
  1302. return index;
  1303. }
  1304. }
  1305. return null;
  1306. }
  1307. internal void ResetIndexes ()
  1308. {
  1309. foreach(Index index in Indexes)
  1310. index.Reset ();
  1311. }
  1312. internal void ResetCaseSensitiveIndexes ()
  1313. {
  1314. foreach (Index index in Indexes) {
  1315. bool containsStringcolumns = false;
  1316. foreach(DataColumn column in index.Key.Columns) {
  1317. if (column.DataType == typeof(string)) {
  1318. containsStringcolumns = true;
  1319. break;
  1320. }
  1321. }
  1322. if (!containsStringcolumns && index.Key.HasFilter) {
  1323. foreach (DataColumn column in Columns) {
  1324. if ((column.DataType == DbTypes.TypeOfString) && (index.Key.DependsOn (column))) {
  1325. containsStringcolumns = true;
  1326. break;
  1327. }
  1328. }
  1329. }
  1330. if (containsStringcolumns)
  1331. index.Reset ();
  1332. }
  1333. }
  1334. internal void DropIndex (Index index)
  1335. {
  1336. if (index != null && index.RefCount == 0) {
  1337. _indexes.Remove (index);
  1338. }
  1339. }
  1340. internal void DropReferencedIndexes (DataColumn column)
  1341. {
  1342. if (_indexes != null)
  1343. for (int i = _indexes.Count - 1; i >= 0; i--) {
  1344. Index indx = (Index)_indexes [i];
  1345. if (indx.Key.DependsOn (column))
  1346. _indexes.Remove (indx);
  1347. }
  1348. }
  1349. internal void AddRowToIndexes (DataRow row)
  1350. {
  1351. if (_indexes != null) {
  1352. for (int i = 0; i < _indexes.Count; ++i)
  1353. ((Index)_indexes [i]).Add (row);
  1354. }
  1355. }
  1356. internal void DeleteRowFromIndexes (DataRow row)
  1357. {
  1358. if (_indexes != null) {
  1359. foreach (Index indx in _indexes)
  1360. indx.Delete (row);
  1361. }
  1362. }
  1363. /// <summary>
  1364. /// Gets the TableName and DisplayExpression, if
  1365. /// there is one as a concatenated string.
  1366. /// </summary>
  1367. public override string ToString ()
  1368. {
  1369. //LAMESPEC: spec says concat the two. impl puts a
  1370. //plus sign infront of DisplayExpression
  1371. string retVal = TableName;
  1372. if(DisplayExpression != null && DisplayExpression != "")
  1373. retVal += " + " + DisplayExpression;
  1374. return retVal;
  1375. }
  1376. #region Events
  1377. /// <summary>
  1378. /// Raises the ColumnChanged event.
  1379. /// </summary>
  1380. protected virtual void OnColumnChanged (DataColumnChangeEventArgs e)
  1381. {
  1382. if (null != ColumnChanged)
  1383. ColumnChanged (this, e);
  1384. }
  1385. internal void RaiseOnColumnChanged (DataColumnChangeEventArgs e)
  1386. {
  1387. OnColumnChanged (e);
  1388. }
  1389. /// <summary>
  1390. /// Raises the ColumnChanging event.
  1391. /// </summary>
  1392. protected virtual void OnColumnChanging (DataColumnChangeEventArgs e)
  1393. {
  1394. if (null != ColumnChanging)
  1395. ColumnChanging (this, e);
  1396. }
  1397. internal void RaiseOnColumnChanging (DataColumnChangeEventArgs e)
  1398. {
  1399. OnColumnChanging(e);
  1400. }
  1401. /// <summary>
  1402. /// Raises the PropertyChanging event.
  1403. /// </summary>
  1404. [MonoTODO]
  1405. protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
  1406. {
  1407. //if (null != PropertyChanging)
  1408. //{
  1409. // PropertyChanging (this, pcevent);
  1410. //}
  1411. throw new NotImplementedException ();
  1412. }
  1413. /// <summary>
  1414. /// Notifies the DataTable that a DataColumn is being removed.
  1415. /// </summary>
  1416. protected internal virtual void OnRemoveColumn (DataColumn column)
  1417. {
  1418. DropReferencedIndexes (column);
  1419. }
  1420. /// <summary>
  1421. /// Raises the RowChanged event.
  1422. /// </summary>
  1423. protected virtual void OnRowChanged (DataRowChangeEventArgs e)
  1424. {
  1425. if (null != RowChanged)
  1426. RowChanged (this, e);
  1427. }
  1428. /// <summary>
  1429. /// Raises the RowChanging event.
  1430. /// </summary>
  1431. protected virtual void OnRowChanging (DataRowChangeEventArgs e)
  1432. {
  1433. if (null != RowChanging)
  1434. RowChanging (this, e);
  1435. }
  1436. /// <summary>
  1437. /// Raises the RowDeleted event.
  1438. /// </summary>
  1439. protected virtual void OnRowDeleted (DataRowChangeEventArgs e)
  1440. {
  1441. if (null != RowDeleted)
  1442. RowDeleted (this, e);
  1443. }
  1444. /// <summary>
  1445. /// Raises the RowDeleting event.
  1446. /// </summary>
  1447. protected virtual void OnRowDeleting (DataRowChangeEventArgs e)
  1448. {
  1449. if (null != RowDeleting)
  1450. RowDeleting (this, e);
  1451. }
  1452. /// <summary>
  1453. /// Occurs when after a value has been changed for
  1454. /// the specified DataColumn in a DataRow.
  1455. /// </summary>
  1456. [DataCategory ("Data")]
  1457. #if !NET_2_0
  1458. [DataSysDescription ("Occurs when a value has been changed for this column.")]
  1459. #endif
  1460. public event DataColumnChangeEventHandler ColumnChanged;
  1461. /// <summary>
  1462. /// Occurs when a value is being changed for the specified
  1463. /// DataColumn in a DataRow.
  1464. /// </summary>
  1465. [DataCategory ("Data")]
  1466. #if !NET_2_0
  1467. [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.")]
  1468. #endif
  1469. public event DataColumnChangeEventHandler ColumnChanging;
  1470. /// <summary>
  1471. /// Occurs after a DataRow has been changed successfully.
  1472. /// </summary>
  1473. [DataCategory ("Data")]
  1474. #if !NET_2_0
  1475. [DataSysDescription ("Occurs after a row in the table has been successfully edited.")]
  1476. #endif
  1477. public event DataRowChangeEventHandler RowChanged;
  1478. /// <summary>
  1479. /// Occurs when a DataRow is changing.
  1480. /// </summary>
  1481. [DataCategory ("Data")]
  1482. #if !NET_2_0
  1483. [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.")]
  1484. #endif
  1485. public event DataRowChangeEventHandler RowChanging;
  1486. /// <summary>
  1487. /// Occurs after a row in the table has been deleted.
  1488. /// </summary>
  1489. [DataCategory ("Data")]
  1490. #if !NET_2_0
  1491. [DataSysDescription ("Occurs after a row in the table has been successfully deleted.")]
  1492. #endif
  1493. public event DataRowChangeEventHandler RowDeleted;
  1494. /// <summary>
  1495. /// Occurs before a row in the table is about to be deleted.
  1496. /// </summary>
  1497. [DataCategory ("Data")]
  1498. #if !NET_2_0
  1499. [DataSysDescription ("Occurs when a row in the table marked for deletion. Throw an exception to cancel the deletion.")]
  1500. #endif
  1501. public event DataRowChangeEventHandler RowDeleting;
  1502. #endregion // Events
  1503. internal static DataColumn[] ParseSortString (DataTable table, string sort, out ListSortDirection[] sortDirections, bool rejectNoResult)
  1504. {
  1505. DataColumn[] sortColumns = _emptyColumnArray;
  1506. sortDirections = null;
  1507. ArrayList columns = null;
  1508. ArrayList sorts = null;
  1509. if (sort != null && !sort.Equals ("")) {
  1510. columns = new ArrayList ();
  1511. sorts = new ArrayList();
  1512. string[] columnExpression = sort.Trim ().Split (new char[1] {','});
  1513. for (int c = 0; c < columnExpression.Length; c++) {
  1514. string rawColumnName = columnExpression[c].Trim ();
  1515. Match match = SortRegex.Match (rawColumnName);
  1516. Group g = match.Groups["ColName"] ;
  1517. if (!g.Success)
  1518. throw new IndexOutOfRangeException ("Could not find column: " + rawColumnName);
  1519. string columnName = g.Value;
  1520. DataColumn dc = table.Columns[columnName];
  1521. if (dc == null){
  1522. try {
  1523. dc = table.Columns[Int32.Parse (columnName)];
  1524. } catch (FormatException) {
  1525. throw new IndexOutOfRangeException("Cannot find column " + columnName);
  1526. }
  1527. }
  1528. columns.Add (dc);
  1529. g = match.Groups["Order"];
  1530. if (!g.Success || String.Compare (g.Value, "ASC", true, CultureInfo.InvariantCulture) == 0)
  1531. sorts.Add(ListSortDirection.Ascending);
  1532. else
  1533. sorts.Add (ListSortDirection.Descending);
  1534. }
  1535. sortColumns = (DataColumn[]) columns.ToArray (typeof (DataColumn));
  1536. sortDirections = new ListSortDirection[sorts.Count];
  1537. for (int i = 0; i < sortDirections.Length; i++)
  1538. sortDirections[i] = (ListSortDirection)sorts[i];
  1539. }
  1540. if (rejectNoResult) {
  1541. if (sortColumns == null)
  1542. throw new SystemException ("sort expression result is null");
  1543. if (sortColumns.Length == 0)
  1544. throw new SystemException("sort expression result is 0");
  1545. }
  1546. return sortColumns;
  1547. }
  1548. private void UpdatePropertyDescriptorsCache ()
  1549. {
  1550. PropertyDescriptor[] descriptors = new PropertyDescriptor[Columns.Count + ChildRelations.Count];
  1551. int index = 0;
  1552. foreach (DataColumn col in Columns)
  1553. descriptors [index++] = new DataColumnPropertyDescriptor (col);
  1554. foreach (DataRelation rel in ChildRelations)
  1555. descriptors [index++] = new DataRelationPropertyDescriptor (rel);
  1556. _propertyDescriptorsCache = new PropertyDescriptorCollection (descriptors);
  1557. }
  1558. internal PropertyDescriptorCollection GetPropertyDescriptorCollection()
  1559. {
  1560. if (_propertyDescriptorsCache == null)
  1561. UpdatePropertyDescriptorsCache ();
  1562. return _propertyDescriptorsCache;
  1563. }
  1564. internal void ResetPropertyDescriptorsCache ()
  1565. {
  1566. _propertyDescriptorsCache = null;
  1567. }
  1568. internal void SetRowsID()
  1569. {
  1570. int dataRowID = 0;
  1571. foreach (DataRow row in Rows) {
  1572. row.XmlRowID = dataRowID;
  1573. dataRowID++;
  1574. }
  1575. }
  1576. }
  1577. #if NET_2_0
  1578. [XmlSchemaProvider ("GetDataTableSchema")]
  1579. partial class DataTable : IXmlSerializable {
  1580. [MonoNotSupported ("")]
  1581. XmlSchema IXmlSerializable.GetSchema ()
  1582. {
  1583. return GetSchema ();
  1584. }
  1585. void IXmlSerializable.ReadXml (XmlReader reader)
  1586. {
  1587. ReadXml_internal (reader, true);
  1588. }
  1589. void IXmlSerializable.WriteXml (XmlWriter writer)
  1590. {
  1591. DataSet dset = dataSet;
  1592. bool isPartOfDataSet = true;
  1593. if (dataSet == null) {
  1594. dset = new DataSet ();
  1595. dset.Tables.Add (this);
  1596. isPartOfDataSet = false;
  1597. }
  1598. XmlSchemaWriter.WriteXmlSchema (writer, new DataTable [] { this },
  1599. null, TableName, dset.DataSetName, LocaleSpecified ? Locale : dset.LocaleSpecified ? dset.Locale : null);
  1600. dset.WriteIndividualTableContent (writer, this, XmlWriteMode.DiffGram);
  1601. writer.Flush ();
  1602. if (!isPartOfDataSet)
  1603. dataSet.Tables.Remove(this);
  1604. }
  1605. [MonoTODO]
  1606. protected virtual XmlSchema GetSchema ()
  1607. {
  1608. throw new NotImplementedException ();
  1609. }
  1610. public static XmlSchemaComplexType GetDataTableSchema (XmlSchemaSet schemaSet)
  1611. {
  1612. return new XmlSchemaComplexType ();
  1613. }
  1614. public XmlReadMode ReadXml (Stream stream)
  1615. {
  1616. return ReadXml (new XmlTextReader(stream, null));
  1617. }
  1618. public XmlReadMode ReadXml (string fileName)
  1619. {
  1620. XmlReader reader = new XmlTextReader (fileName);
  1621. try {
  1622. return ReadXml (reader);
  1623. } finally {
  1624. reader.Close();
  1625. }
  1626. }
  1627. public XmlReadMode ReadXml (TextReader reader)
  1628. {
  1629. return ReadXml (new XmlTextReader (reader));
  1630. }
  1631. public XmlReadMode ReadXml (XmlReader reader)
  1632. {
  1633. return ReadXml_internal (reader, false);
  1634. }
  1635. public XmlReadMode ReadXml_internal (XmlReader reader, bool serializable)
  1636. {
  1637. // The documentation from MS for this method is rather
  1638. // poor. The following cases have been observed
  1639. // during testing:
  1640. //
  1641. // Reading a table from XML may create a DataSet to
  1642. // store child tables.
  1643. //
  1644. // If the table has at least one column present,
  1645. // we do not require the schema to be present in
  1646. // the xml. If the table has no columns, neither
  1647. // regular data nor diffgrams will be read, but
  1648. // will throw an error indicating that schema
  1649. // will not be inferred.
  1650. //
  1651. // We will likely need to take advantage of the
  1652. // msdata:MainDataTable attribute added to the
  1653. // schema info to load into the appropriate
  1654. // locations.
  1655. bool isPartOfDataSet = true;
  1656. bool isTableNameBlank = false;
  1657. XmlReadMode mode = XmlReadMode.ReadSchema;
  1658. DataSet dataSet = null;
  1659. DataSet ds = new DataSet ();
  1660. reader.MoveToContent ();
  1661. if (Columns.Count > 0 && reader.LocalName != "diffgram" || serializable)
  1662. mode = ds.ReadXml (reader);
  1663. else if (Columns.Count > 0 && reader.LocalName == "diffgram") {
  1664. try {
  1665. if (TableName == String.Empty)
  1666. isTableNameBlank = true;
  1667. if (DataSet == null) {
  1668. isPartOfDataSet = false;
  1669. ds.Tables.Add (this);
  1670. mode = ds.ReadXml (reader);
  1671. } else
  1672. mode = DataSet.ReadXml (reader);
  1673. } catch (DataException) {
  1674. mode = XmlReadMode.DiffGram;
  1675. if (isTableNameBlank)
  1676. TableName = String.Empty;
  1677. } finally {
  1678. if (!isPartOfDataSet)
  1679. ds.Tables.Remove (this);
  1680. }
  1681. return mode;
  1682. } else {
  1683. mode = ds.ReadXml (reader, XmlReadMode.ReadSchema);
  1684. }
  1685. if (mode == XmlReadMode.InferSchema)
  1686. mode = XmlReadMode.IgnoreSchema;
  1687. if (DataSet == null) {
  1688. isPartOfDataSet = false;
  1689. dataSet = new DataSet ();
  1690. if (TableName == String.Empty)
  1691. isTableNameBlank = true;
  1692. dataSet.Tables.Add (this);
  1693. }
  1694. DenyXmlResolving (this, ds, mode, isTableNameBlank, isPartOfDataSet);
  1695. if (Columns.Count > 0 && TableName != ds.Tables [0].TableName) {
  1696. if (isPartOfDataSet == false)
  1697. dataSet.Tables.Remove (this);
  1698. if (isTableNameBlank && isPartOfDataSet == false)
  1699. TableName = String.Empty;
  1700. return mode;
  1701. }
  1702. else {
  1703. TableName = ds.Tables [0].TableName;
  1704. }
  1705. if (!isPartOfDataSet) {
  1706. if (Columns.Count > 0) {
  1707. dataSet.Merge (ds, true, MissingSchemaAction.Ignore);
  1708. } else {
  1709. dataSet.Merge (ds, true, MissingSchemaAction.AddWithKey);
  1710. }
  1711. if (ChildRelations.Count == 0) {
  1712. dataSet.Tables.Remove (this);
  1713. } else {
  1714. dataSet.DataSetName = ds.DataSetName;
  1715. }
  1716. } else {
  1717. if (Columns.Count > 0) {
  1718. DataSet.Merge (ds, true, MissingSchemaAction.Ignore);
  1719. } else {
  1720. DataSet.Merge (ds, true, MissingSchemaAction.AddWithKey);
  1721. }
  1722. }
  1723. return mode;
  1724. }
  1725. private void DenyXmlResolving (DataTable table, DataSet ds, XmlReadMode mode, bool isTableNameBlank, bool isPartOfDataSet)
  1726. {
  1727. if (ds.Tables.Count == 0 && table.Columns.Count == 0)
  1728. throw new InvalidOperationException ("DataTable does not support schema inference from XML");
  1729. if (table.Columns.Count == 0 && ds.Tables [0].TableName != table.TableName && isTableNameBlank == false)
  1730. throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
  1731. table.TableName));
  1732. if (table.Columns.Count > 0 && ds.Tables [0].TableName != table.TableName &&
  1733. isTableNameBlank == false && mode == XmlReadMode.ReadSchema &&
  1734. isPartOfDataSet == false)
  1735. throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
  1736. table.TableName));
  1737. if (isPartOfDataSet == true && table.Columns.Count > 0 &&
  1738. mode == XmlReadMode.ReadSchema && table.TableName != ds.Tables [0].TableName)
  1739. throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source",
  1740. table.TableName));
  1741. }
  1742. public void ReadXmlSchema (Stream stream)
  1743. {
  1744. ReadXmlSchema (new XmlTextReader (stream));
  1745. }
  1746. public void ReadXmlSchema (TextReader reader)
  1747. {
  1748. ReadXmlSchema (new XmlTextReader (reader));
  1749. }
  1750. public void ReadXmlSchema (string fileName)
  1751. {
  1752. XmlTextReader reader = null;
  1753. try {
  1754. reader = new XmlTextReader (fileName);
  1755. ReadXmlSchema (reader);
  1756. } finally {
  1757. if (reader != null)
  1758. reader.Close ();
  1759. }
  1760. }
  1761. public void ReadXmlSchema (XmlReader reader)
  1762. {
  1763. if (this.Columns.Count > 0)
  1764. return;
  1765. DataSet ds = new DataSet ();
  1766. new XmlSchemaDataImporter (ds, reader, false).Process ();
  1767. DataTable target = null;
  1768. if (TableName == String.Empty) {
  1769. if (ds.Tables.Count > 0)
  1770. target = ds.Tables [0];
  1771. }
  1772. else {
  1773. target = ds.Tables [TableName];
  1774. if (target == null)
  1775. throw new ArgumentException (String.Format ("DataTable '{0}' does not match to any DataTable in source.", TableName));
  1776. }
  1777. if (target != null)
  1778. target.CopyProperties (this);
  1779. }
  1780. [MonoNotSupported ("")]
  1781. protected virtual void ReadXmlSerializable (XmlReader reader)
  1782. {
  1783. throw new NotImplementedException ();
  1784. }
  1785. private XmlWriterSettings GetWriterSettings ()
  1786. {
  1787. XmlWriterSettings s = new XmlWriterSettings ();
  1788. s.Indent = true;
  1789. s.OmitXmlDeclaration = true;
  1790. return s;
  1791. }
  1792. public void WriteXml (Stream stream)
  1793. {
  1794. WriteXml (stream, XmlWriteMode.IgnoreSchema, false);
  1795. }
  1796. public void WriteXml (TextWriter writer)
  1797. {
  1798. WriteXml (writer, XmlWriteMode.IgnoreSchema, false);
  1799. }
  1800. public void WriteXml (XmlWriter writer)
  1801. {
  1802. WriteXml (writer, XmlWriteMode.IgnoreSchema, false);
  1803. }
  1804. public void WriteXml (string fileName)
  1805. {
  1806. WriteXml (fileName, XmlWriteMode.IgnoreSchema, false);
  1807. }
  1808. public void WriteXml (Stream stream, XmlWriteMode mode)
  1809. {
  1810. WriteXml (stream, mode, false);
  1811. }
  1812. public void WriteXml (TextWriter writer, XmlWriteMode mode)
  1813. {
  1814. WriteXml (writer, mode, false);
  1815. }
  1816. public void WriteXml (XmlWriter writer, XmlWriteMode mode)
  1817. {
  1818. WriteXml (writer, mode, false);
  1819. }
  1820. public void WriteXml (string fileName, XmlWriteMode mode)
  1821. {
  1822. WriteXml (fileName, mode, false);
  1823. }
  1824. public void WriteXml (Stream stream, bool writeHierarchy)
  1825. {
  1826. WriteXml (stream, XmlWriteMode.IgnoreSchema, writeHierarchy);
  1827. }
  1828. public void WriteXml (string fileName, bool writeHierarchy)
  1829. {
  1830. WriteXml (fileName, XmlWriteMode.IgnoreSchema, writeHierarchy);
  1831. }
  1832. public void WriteXml (TextWriter writer, bool writeHierarchy)
  1833. {
  1834. WriteXml (writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
  1835. }
  1836. public void WriteXml (XmlWriter writer, bool writeHierarchy)
  1837. {
  1838. WriteXml (writer, XmlWriteMode.IgnoreSchema, writeHierarchy);
  1839. }
  1840. public void WriteXml (Stream stream, XmlWriteMode mode, bool writeHierarchy)
  1841. {
  1842. WriteXml (XmlWriter.Create (stream, GetWriterSettings ()), mode, writeHierarchy);
  1843. }
  1844. public void WriteXml (string fileName, XmlWriteMode mode, bool writeHierarchy)
  1845. {
  1846. XmlWriter xw = null;
  1847. try {
  1848. xw = XmlWriter.Create (fileName, GetWriterSettings ());
  1849. WriteXml (xw, mode, writeHierarchy);
  1850. } finally {
  1851. if (xw != null)
  1852. xw.Close ();
  1853. }
  1854. }
  1855. public void WriteXml (TextWriter writer, XmlWriteMode mode, bool writeHierarchy)
  1856. {
  1857. WriteXml (XmlWriter.Create (writer, GetWriterSettings ()), mode, writeHierarchy);
  1858. }
  1859. public void WriteXml (XmlWriter writer, XmlWriteMode mode, bool writeHierarchy)
  1860. {
  1861. // If we're in mode XmlWriteMode.WriteSchema, we need to output an extra
  1862. // msdata:MainDataTable attribute that wouldn't normally be part of the
  1863. // DataSet WriteXml output.
  1864. //
  1865. // For the writeHierarchy == true case, we write what would be output by
  1866. // a DataSet write, but we limit ourselves to our table and its descendants.
  1867. //
  1868. // For the writeHierarchy == false case, we write what would be output by
  1869. // a DataSet write, but we limit ourselves to this table.
  1870. //
  1871. // If the table is not in a DataSet, we follow the following behaviour:
  1872. // For WriteSchema cases, we do a write as if there is a wrapper
  1873. // dataset called NewDataSet.
  1874. // For IgnoreSchema or DiffGram cases, we do a write as if there
  1875. // is a wrapper dataset called DocumentElement.
  1876. // Generate a list of tables to write.
  1877. List <DataTable> tables = new List <DataTable> ();
  1878. if (writeHierarchy == false)
  1879. tables.Add (this);
  1880. else
  1881. FindAllChildren (tables, this);
  1882. // If we're in a DataSet, generate a list of relations to write.
  1883. List <DataRelation> relations = new List <DataRelation> ();
  1884. if (DataSet != null) {
  1885. foreach (DataRelation relation in DataSet.Relations) {
  1886. if (tables.Contains (relation.ParentTable) &&
  1887. tables.Contains (relation.ChildTable))
  1888. relations.Add (relation);
  1889. }
  1890. }
  1891. // Add the msdata:MainDataTable info if we're writing schema data.
  1892. string mainDataTable = null;
  1893. if (mode == XmlWriteMode.WriteSchema)
  1894. mainDataTable = this.TableName;
  1895. // Figure out the DataSet name.
  1896. string dataSetName = null;
  1897. if (DataSet != null)
  1898. dataSetName = DataSet.DataSetName;
  1899. else if (DataSet == null && mode == XmlWriteMode.WriteSchema)
  1900. dataSetName = "NewDataSet";
  1901. else
  1902. dataSetName = "DocumentElement";
  1903. XmlTableWriter.WriteTables(writer, mode, tables, relations, mainDataTable, dataSetName);
  1904. }
  1905. private void FindAllChildren(List<DataTable> list, DataTable root)
  1906. {
  1907. if (!list.Contains(root))
  1908. {
  1909. list.Add(root);
  1910. foreach (DataRelation relation in root.ChildRelations)
  1911. {
  1912. FindAllChildren(list, relation.ChildTable);
  1913. }
  1914. }
  1915. }
  1916. public void WriteXmlSchema (Stream stream)
  1917. {
  1918. if (TableName == "") {
  1919. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  1920. }
  1921. XmlWriterSettings s = GetWriterSettings ();
  1922. s.OmitXmlDeclaration = false;
  1923. WriteXmlSchema (XmlWriter.Create (stream, s));
  1924. }
  1925. public void WriteXmlSchema (TextWriter writer)
  1926. {
  1927. if (TableName == "") {
  1928. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  1929. }
  1930. XmlWriterSettings s = GetWriterSettings ();
  1931. s.OmitXmlDeclaration = false;
  1932. WriteXmlSchema (XmlWriter.Create (writer, s));
  1933. }
  1934. public void WriteXmlSchema (XmlWriter writer)
  1935. {
  1936. WriteXmlSchema (writer, false);
  1937. /*
  1938. if (TableName == "") {
  1939. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  1940. }
  1941. DataSet ds = DataSet;
  1942. DataSet tmp = null;
  1943. try {
  1944. if (ds == null) {
  1945. tmp = ds = new DataSet ();
  1946. ds.Tables.Add (this);
  1947. }
  1948. writer.WriteStartDocument ();
  1949. DataTableCollection col = new DataTableCollection (ds);
  1950. col.Add (this);
  1951. DataTable [] tables = new DataTable [col.Count];
  1952. for (int i = 0; i < col.Count; i++) tables[i] = col[i];
  1953. string tableName;
  1954. if (ds.Namespace == "")
  1955. tableName = TableName;
  1956. else
  1957. tableName = ds.Namespace + "_x003A_" + TableName;
  1958. XmlSchemaWriter.WriteXmlSchema (writer, tables, null, tableName, ds.DataSetName);
  1959. } finally {
  1960. if (tmp != null)
  1961. ds.Tables.Remove (this);
  1962. }
  1963. */
  1964. }
  1965. public void WriteXmlSchema (string fileName)
  1966. {
  1967. if (fileName == "") {
  1968. throw new ArgumentException ("Empty path name is not legal.");
  1969. }
  1970. if (TableName == "") {
  1971. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  1972. }
  1973. XmlTextWriter writer = null;
  1974. try {
  1975. XmlWriterSettings s = GetWriterSettings ();
  1976. s.OmitXmlDeclaration = false;
  1977. writer = new XmlTextWriter (fileName, null);
  1978. WriteXmlSchema (writer);
  1979. } finally {
  1980. if (writer != null) {
  1981. writer.Close ();
  1982. }
  1983. }
  1984. }
  1985. public void WriteXmlSchema (Stream stream, bool writeHierarchy)
  1986. {
  1987. if (TableName == "") {
  1988. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  1989. }
  1990. XmlWriterSettings s = GetWriterSettings ();
  1991. s.OmitXmlDeclaration = false;
  1992. WriteXmlSchema (XmlWriter.Create (stream, s), writeHierarchy);
  1993. }
  1994. public void WriteXmlSchema (TextWriter writer, bool writeHierarchy)
  1995. {
  1996. if (TableName == "") {
  1997. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  1998. }
  1999. XmlWriterSettings s = GetWriterSettings ();
  2000. s.OmitXmlDeclaration = false;
  2001. WriteXmlSchema (XmlWriter.Create (writer, s), writeHierarchy);
  2002. }
  2003. public void WriteXmlSchema (XmlWriter writer, bool writeHierarchy)
  2004. {
  2005. if (TableName == "") {
  2006. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  2007. }
  2008. // if (writeHierarchy == false) {
  2009. // WriteXmlSchema (writer);
  2010. // }
  2011. // else {
  2012. DataSet ds = DataSet;
  2013. DataSet tmp = null;
  2014. try {
  2015. if (ds == null) {
  2016. tmp = ds = new DataSet ();
  2017. ds.Tables.Add (this);
  2018. }
  2019. writer.WriteStartDocument ();
  2020. //XmlSchemaWriter.WriteXmlSchema (ds, writer);
  2021. //DataTable [] tables = new DataTable [ds.Tables.Count];
  2022. DataTable [] tables = null;
  2023. //DataRelation [] relations = new DataRelation [ds.Relations.Count];
  2024. //for (int i = 0; i < ds.Relations.Count; i++) {
  2025. // relations[i] = ds.Relations[i];
  2026. //}
  2027. DataRelation [] relations = null;
  2028. if (writeHierarchy && ChildRelations.Count > 0) {
  2029. relations = new DataRelation [ChildRelations.Count];
  2030. for (int i = 0; i < ChildRelations.Count; i++) {
  2031. relations [i] = ChildRelations [i];
  2032. }
  2033. tables = new DataTable [ds.Tables.Count];
  2034. for (int i = 0; i < ds.Tables.Count; i++) tables [i] = ds.Tables [i];
  2035. } else {
  2036. tables = new DataTable [1];
  2037. tables [0] = this;
  2038. }
  2039. string tableName;
  2040. if (ds.Namespace == "")
  2041. tableName = TableName;
  2042. else
  2043. tableName = ds.Namespace + "_x003A_" + TableName;
  2044. XmlSchemaWriter.WriteXmlSchema (writer, tables, relations, tableName, ds.DataSetName, LocaleSpecified ? Locale : ds.LocaleSpecified ? ds.Locale : null);
  2045. } finally {
  2046. if (tmp != null)
  2047. ds.Tables.Remove (this);
  2048. }
  2049. // }
  2050. }
  2051. public void WriteXmlSchema (string fileName, bool writeHierarchy)
  2052. {
  2053. if (fileName == "") {
  2054. throw new ArgumentException ("Empty path name is not legal.");
  2055. }
  2056. if (TableName == "") {
  2057. throw new InvalidOperationException ("Cannot serialize the DataTable. DataTable name is not set.");
  2058. }
  2059. XmlTextWriter writer = null;
  2060. try {
  2061. XmlWriterSettings s = GetWriterSettings ();
  2062. s.OmitXmlDeclaration = false;
  2063. writer = new XmlTextWriter (fileName, null);
  2064. WriteXmlSchema (writer, writeHierarchy);
  2065. } finally {
  2066. if (writer != null) {
  2067. writer.Close ();
  2068. }
  2069. }
  2070. }
  2071. }
  2072. partial class DataTable : ISupportInitializeNotification {
  2073. private bool tableInitialized = true;
  2074. [Browsable (false)]
  2075. public bool IsInitialized {
  2076. get { return tableInitialized; }
  2077. }
  2078. public event EventHandler Initialized;
  2079. private void OnTableInitialized (EventArgs e)
  2080. {
  2081. if (null != Initialized)
  2082. Initialized (this, e);
  2083. }
  2084. partial void DataTableInitialized ()
  2085. {
  2086. tableInitialized = true;
  2087. OnTableInitialized (new EventArgs ());
  2088. }
  2089. }
  2090. partial class DataTable {
  2091. public DataTable (string tableName, string tableNamespace)
  2092. : this (tableName)
  2093. {
  2094. _nameSpace = tableNamespace;
  2095. }
  2096. SerializationFormat remotingFormat = SerializationFormat.Xml;
  2097. [DefaultValue (SerializationFormat.Xml)]
  2098. public SerializationFormat RemotingFormat {
  2099. get {
  2100. if (dataSet != null)
  2101. remotingFormat = dataSet.RemotingFormat;
  2102. return remotingFormat;
  2103. }
  2104. set {
  2105. if (dataSet != null)
  2106. throw new ArgumentException ("Cannot have different remoting format property value for DataSet and DataTable");
  2107. remotingFormat = value;
  2108. }
  2109. }
  2110. internal void DeserializeConstraints (ArrayList arrayList)
  2111. {
  2112. bool fKeyNavigate = false;
  2113. for (int i = 0; i < arrayList.Count; i++) {
  2114. ArrayList tmpArrayList = arrayList [i] as ArrayList;
  2115. if (tmpArrayList == null)
  2116. continue;
  2117. if ((string) tmpArrayList [0] == "F") {
  2118. int [] constraintsArray = tmpArrayList [2] as int [];
  2119. if (constraintsArray == null)
  2120. continue;
  2121. ArrayList parentColumns = new ArrayList ();
  2122. DataTable dt = dataSet.Tables [constraintsArray [0]];
  2123. for (int j = 0; j < constraintsArray.Length - 1; j++) {
  2124. parentColumns.Add (dt.Columns [constraintsArray [j + 1]]);
  2125. }
  2126. constraintsArray = tmpArrayList [3] as int [];
  2127. if (constraintsArray == null)
  2128. continue;
  2129. ArrayList childColumns = new ArrayList ();
  2130. dt = dataSet.Tables [constraintsArray [0]];
  2131. for (int j = 0; j < constraintsArray.Length - 1; j++) {
  2132. childColumns.Add (dt.Columns [constraintsArray [j + 1]]);
  2133. }
  2134. ForeignKeyConstraint fKeyConstraint = new
  2135. ForeignKeyConstraint ((string) tmpArrayList [1],
  2136. (DataColumn []) parentColumns.ToArray (typeof (DataColumn)),
  2137. (DataColumn []) childColumns.ToArray (typeof (DataColumn)));
  2138. Array ruleArray = (Array) tmpArrayList [4];
  2139. fKeyConstraint.AcceptRejectRule = (AcceptRejectRule) ruleArray.GetValue (0);
  2140. fKeyConstraint.UpdateRule = (Rule) ruleArray.GetValue (1);
  2141. fKeyConstraint.DeleteRule = (Rule) ruleArray.GetValue (2);
  2142. // FIXME: refactor this deserialization code out to ForeighKeyConstraint
  2143. fKeyConstraint.SetExtendedProperties ((PropertyCollection) tmpArrayList [5]);
  2144. Constraints.Add (fKeyConstraint);
  2145. fKeyNavigate = true;
  2146. } else if (fKeyNavigate == false &&
  2147. (string) tmpArrayList [0] == "U") {
  2148. UniqueConstraint unique = null;
  2149. ArrayList uniqueDataColumns = new ArrayList ();
  2150. int [] constraintsArray = tmpArrayList [2] as int [];
  2151. if (constraintsArray == null)
  2152. continue;
  2153. for (int j = 0; j < constraintsArray.Length; j++) {
  2154. uniqueDataColumns.Add (Columns [constraintsArray [j]]);
  2155. }
  2156. unique = new UniqueConstraint ((string) tmpArrayList[1],
  2157. (DataColumn[]) uniqueDataColumns.
  2158. ToArray (typeof (DataColumn)),
  2159. (bool) tmpArrayList [3]);
  2160. /*
  2161. If UniqueConstraint already exist, don't add them
  2162. */
  2163. if (Constraints.IndexOf (unique) != -1 ||
  2164. Constraints.IndexOf ((string) tmpArrayList[1]) != -1) {
  2165. continue;
  2166. }
  2167. // FIXME: refactor this deserialization code out to UniqueConstraint
  2168. unique.SetExtendedProperties ((PropertyCollection) tmpArrayList [4]);
  2169. Constraints.Add (unique);
  2170. } else {
  2171. fKeyNavigate = false;
  2172. }
  2173. }
  2174. }
  2175. DataRowState GetCurrentRowState (BitArray rowStateBitArray, int i)
  2176. {
  2177. DataRowState currentRowState;
  2178. if (rowStateBitArray[i] == false &&
  2179. rowStateBitArray[i+1] == false &&
  2180. rowStateBitArray[i+2] == true)
  2181. currentRowState = DataRowState.Detached;
  2182. else if (rowStateBitArray[i] == false &&
  2183. rowStateBitArray[i+1] == false &&
  2184. rowStateBitArray[i+2] == false)
  2185. currentRowState = DataRowState.Unchanged;
  2186. else if (rowStateBitArray[i] == false &&
  2187. rowStateBitArray[i+1] == true &&
  2188. rowStateBitArray[i+2] == false)
  2189. currentRowState = DataRowState.Added;
  2190. else if (rowStateBitArray[i] == true &&
  2191. rowStateBitArray[i+1] == true &&
  2192. rowStateBitArray[i+2] == false)
  2193. currentRowState = DataRowState.Deleted;
  2194. else
  2195. currentRowState = DataRowState.Modified;
  2196. return currentRowState;
  2197. }
  2198. internal void DeserializeRecords (ArrayList arrayList, ArrayList nullBits, BitArray rowStateBitArray)
  2199. {
  2200. BitArray nullBit = null;
  2201. if (arrayList == null || arrayList.Count < 1)
  2202. return;
  2203. int len = ((Array) arrayList [0]).Length;
  2204. object [] tmpArray = new object [arrayList.Count];
  2205. int k = 0;
  2206. DataRowState currentRowState;
  2207. for (int l = 0; l < len; l++) { // Columns
  2208. currentRowState = GetCurrentRowState (rowStateBitArray, k *3);
  2209. for (int j = 0; j < arrayList.Count; j++) { // Rows
  2210. Array array = (Array) arrayList [j];
  2211. nullBit = (BitArray) nullBits [j];
  2212. if (nullBit [l] == false) {
  2213. tmpArray [j] = array.GetValue (l);
  2214. } else {
  2215. tmpArray [j] = null;
  2216. }
  2217. }
  2218. LoadDataRow (tmpArray, false);
  2219. if (currentRowState == DataRowState.Modified) {
  2220. Rows[k].AcceptChanges ();
  2221. l++;
  2222. for (int j = 0; j < arrayList.Count; j++) {
  2223. Array array = (Array) arrayList [j];
  2224. nullBit = (BitArray) nullBits[j];
  2225. if (nullBit [l] == false) {
  2226. Rows [k][j] = array.GetValue (l);
  2227. } else {
  2228. Rows [k][j] = null;
  2229. }
  2230. }
  2231. } else if (currentRowState == DataRowState.Unchanged) {
  2232. Rows[k].AcceptChanges ();
  2233. } else if (currentRowState == DataRowState.Deleted) {
  2234. Rows[k].AcceptChanges ();
  2235. Rows[k].Delete ();
  2236. }
  2237. k++;
  2238. }
  2239. }
  2240. void BinaryDeserializeTable (SerializationInfo info)
  2241. {
  2242. ArrayList arrayList = null;
  2243. TableName = info.GetString ("DataTable.TableName");
  2244. Namespace = info.GetString ("DataTable.Namespace");
  2245. Prefix = info.GetString ("DataTable.Prefix");
  2246. CaseSensitive = info.GetBoolean ("DataTable.CaseSensitive");
  2247. /*
  2248. FIXME: Private variable available in SerializationInfo
  2249. this.caseSensitiveAmbientCaseSensitive = info.GetBoolean("DataTable.caseSensitiveAmbientCaseSensitive");
  2250. this.NestedInDataSet = info.GetBoolean("DataTable.NestedInDataSet");
  2251. this.RepeatableElement = info.GetBoolean("DataTable.RepeatableElement");
  2252. this.RemotingVersion = (System.Version) info.GetValue("DataTable.RemotingVersion",
  2253. typeof(System.Version));
  2254. */
  2255. Locale = new CultureInfo (info.GetInt32 ("DataTable.LocaleLCID"));
  2256. _extendedProperties = (PropertyCollection) info.GetValue ("DataTable.ExtendedProperties",
  2257. typeof (PropertyCollection));
  2258. MinimumCapacity = info.GetInt32 ("DataTable.MinimumCapacity");
  2259. int columnsCount = info.GetInt32 ("DataTable.Columns.Count");
  2260. for (int i = 0; i < columnsCount; i++) {
  2261. Columns.Add ();
  2262. string prefix = "DataTable.DataColumn_" + i + ".";
  2263. Columns[i].ColumnName = info.GetString (prefix + "ColumnName");
  2264. Columns[i].Namespace = info.GetString (prefix + "Namespace");
  2265. Columns[i].Caption = info.GetString (prefix + "Caption");
  2266. Columns[i].Prefix = info.GetString (prefix + "Prefix");
  2267. Columns[i].DataType = (Type) info.GetValue (prefix + "DataType",
  2268. typeof (Type));
  2269. Columns[i].DefaultValue = info.GetValue (prefix + "DefaultValue",
  2270. typeof (Object));
  2271. Columns[i].AllowDBNull = info.GetBoolean (prefix + "AllowDBNull");
  2272. Columns[i].AutoIncrement = info.GetBoolean (prefix + "AutoIncrement");
  2273. Columns[i].AutoIncrementStep = info.GetInt64 (prefix + "AutoIncrementStep");
  2274. Columns[i].AutoIncrementSeed = info.GetInt64(prefix + "AutoIncrementSeed");
  2275. Columns[i].ReadOnly = info.GetBoolean (prefix + "ReadOnly");
  2276. Columns[i].MaxLength = info.GetInt32 (prefix + "MaxLength");
  2277. /*
  2278. FIXME: Private variable available in SerializationInfo
  2279. this.Columns[i].SimpleType = info.GetString("DataTable.DataColumn_" +
  2280. i + ".SimpleType");
  2281. this.Columns[i].AutoIncrementCurrent = info.GetInt64("DataTable.DataColumn_" +
  2282. i + ".AutoIncrementCurrent");
  2283. this.Columns[i].XmlDataType = info.GetString("DataTable.DataColumn_" +
  2284. i + ".XmlDataType");
  2285. */
  2286. Columns[i].ExtendedProperties = (PropertyCollection) info.GetValue (prefix + "ExtendedProperties",
  2287. typeof (PropertyCollection));
  2288. if (Columns[i].DataType == typeof (DataSetDateTime)) {
  2289. Columns[i].DateTimeMode = (DataSetDateTime) info.GetValue (prefix + "DateTimeMode",
  2290. typeof (DataSetDateTime));
  2291. }
  2292. Columns[i].ColumnMapping = (MappingType) info.GetValue (prefix + "ColumnMapping",
  2293. typeof (MappingType));
  2294. try {
  2295. Columns[i].Expression = info.GetString (prefix + "Expression");
  2296. prefix = "DataTable_0.";
  2297. arrayList = (ArrayList) info.GetValue (prefix + "Constraints",
  2298. typeof (ArrayList));
  2299. if (Constraints == null)
  2300. Constraints = new ConstraintCollection (this);
  2301. DeserializeConstraints (arrayList);
  2302. } catch (SerializationException) {
  2303. }
  2304. }
  2305. try {
  2306. String prefix = "DataTable_0.";
  2307. ArrayList nullBits = (ArrayList) info.GetValue (prefix + "NullBits",
  2308. typeof (ArrayList));
  2309. arrayList = (ArrayList) info.GetValue (prefix + "Records",
  2310. typeof (ArrayList));
  2311. BitArray rowStateBitArray = (BitArray) info.GetValue (prefix + "RowStates",
  2312. typeof (BitArray));
  2313. Hashtable htRowErrors = (Hashtable) info.GetValue (prefix + "RowErrors",
  2314. typeof (Hashtable));
  2315. DeserializeRecords (arrayList, nullBits, rowStateBitArray);
  2316. } catch (SerializationException) {
  2317. }
  2318. }
  2319. internal void BinarySerializeProperty (SerializationInfo info)
  2320. {
  2321. Version vr = new Version (2, 0);
  2322. info.AddValue ("DataTable.RemotingVersion", vr);
  2323. info.AddValue ("DataTable.RemotingFormat", RemotingFormat);
  2324. info.AddValue ("DataTable.TableName", TableName);
  2325. info.AddValue ("DataTable.Namespace", Namespace);
  2326. info.AddValue ("DataTable.Prefix", Prefix);
  2327. info.AddValue ("DataTable.CaseSensitive", CaseSensitive);
  2328. /*
  2329. FIXME: Required by MS.NET
  2330. caseSensitiveAmbient, NestedInDataSet, RepeatableElement
  2331. */
  2332. info.AddValue ("DataTable.caseSensitiveAmbient", true);
  2333. info.AddValue ("DataTable.NestedInDataSet", true);
  2334. info.AddValue ("DataTable.RepeatableElement", false);
  2335. info.AddValue ("DataTable.LocaleLCID", Locale.LCID);
  2336. info.AddValue ("DataTable.MinimumCapacity", MinimumCapacity);
  2337. info.AddValue ("DataTable.Columns.Count", Columns.Count);
  2338. info.AddValue ("DataTable.ExtendedProperties", _extendedProperties);
  2339. for (int i = 0; i < Columns.Count; i++) {
  2340. info.AddValue ("DataTable.DataColumn_" + i + ".ColumnName",
  2341. Columns[i].ColumnName);
  2342. info.AddValue ("DataTable.DataColumn_" + i + ".Namespace",
  2343. Columns[i].Namespace);
  2344. info.AddValue ("DataTable.DataColumn_" + i + ".Caption",
  2345. Columns[i].Caption);
  2346. info.AddValue ("DataTable.DataColumn_" + i + ".Prefix",
  2347. Columns[i].Prefix);
  2348. info.AddValue ("DataTable.DataColumn_" + i + ".DataType",
  2349. Columns[i].DataType, typeof (Type));
  2350. info.AddValue ("DataTable.DataColumn_" + i + ".DefaultValue",
  2351. Columns[i].DefaultValue, typeof (DBNull));
  2352. info.AddValue ("DataTable.DataColumn_" + i + ".AllowDBNull",
  2353. Columns[i].AllowDBNull);
  2354. info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrement",
  2355. Columns[i].AutoIncrement);
  2356. info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementStep",
  2357. Columns[i].AutoIncrementStep);
  2358. info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementSeed",
  2359. Columns[i].AutoIncrementSeed);
  2360. info.AddValue ("DataTable.DataColumn_" + i + ".ReadOnly",
  2361. Columns[i].ReadOnly);
  2362. info.AddValue ("DataTable.DataColumn_" + i + ".MaxLength",
  2363. Columns[i].MaxLength);
  2364. info.AddValue ("DataTable.DataColumn_" + i + ".ExtendedProperties",
  2365. Columns[i].ExtendedProperties);
  2366. info.AddValue ("DataTable.DataColumn_" + i + ".DateTimeMode",
  2367. Columns[i].DateTimeMode);
  2368. info.AddValue ("DataTable.DataColumn_" + i + ".ColumnMapping",
  2369. Columns[i].ColumnMapping, typeof (MappingType));
  2370. /*
  2371. FIXME: Required by MS.NET
  2372. SimpleType, AutoIncrementCurrent, XmlDataType
  2373. */
  2374. info.AddValue ("DataTable.DataColumn_" + i + ".SimpleType",
  2375. null, typeof (string));
  2376. info.AddValue ("DataTable.DataColumn_" + i + ".AutoIncrementCurrent",
  2377. Columns[i].AutoIncrementValue());
  2378. info.AddValue ("DataTable.DataColumn_" + i + ".XmlDataType",
  2379. null, typeof (string));
  2380. }
  2381. /*
  2382. FIXME: Required by MS.NET
  2383. TypeName
  2384. */
  2385. info.AddValue ("DataTable.TypeName", null, typeof (string));
  2386. }
  2387. internal void SerializeConstraints (SerializationInfo info, string prefix)
  2388. {
  2389. ArrayList constraintArrayList = new ArrayList ();
  2390. for (int j = 0; j < Constraints.Count; j++) {
  2391. ArrayList constraintList = new ArrayList ();
  2392. if (Constraints[j] is UniqueConstraint) {
  2393. constraintList.Add ("U");
  2394. UniqueConstraint unique = (UniqueConstraint) Constraints [j];
  2395. constraintList.Add (unique.ConstraintName);
  2396. DataColumn [] columns = unique.Columns;
  2397. int [] tmpArray = new int [columns.Length];
  2398. for (int k = 0; k < columns.Length; k++)
  2399. tmpArray [k] = unique.Table.Columns.IndexOf (unique.Columns [k]);
  2400. constraintList.Add (tmpArray);
  2401. constraintList.Add (unique.IsPrimaryKey);
  2402. constraintList.Add (unique.ExtendedProperties);
  2403. } else if (Constraints[j] is ForeignKeyConstraint) {
  2404. constraintList.Add ("F");
  2405. ForeignKeyConstraint fKey = (ForeignKeyConstraint) Constraints [j];
  2406. constraintList.Add (fKey.ConstraintName);
  2407. int [] tmpArray = new int [fKey.RelatedColumns.Length + 1];
  2408. tmpArray [0] = DataSet.Tables.IndexOf (fKey.RelatedTable);
  2409. for (int i = 0; i < fKey.Columns.Length; i++) {
  2410. tmpArray [i + 1] = fKey.RelatedColumns [i].Ordinal;
  2411. }
  2412. constraintList.Add (tmpArray);
  2413. tmpArray = new int [fKey.Columns.Length + 1];
  2414. tmpArray [0] = DataSet.Tables.IndexOf (fKey.Table);
  2415. for (int i = 0; i < fKey.Columns.Length; i++) {
  2416. tmpArray [i + 1] = fKey.Columns [i].Ordinal;
  2417. }
  2418. constraintList.Add (tmpArray);
  2419. tmpArray = new int [3];
  2420. tmpArray [0] = (int) fKey.AcceptRejectRule;
  2421. tmpArray [1] = (int) fKey.UpdateRule;
  2422. tmpArray [2] = (int) fKey.DeleteRule;
  2423. constraintList.Add (tmpArray);
  2424. constraintList.Add (fKey.ExtendedProperties);
  2425. }
  2426. else
  2427. continue;
  2428. constraintArrayList.Add (constraintList);
  2429. }
  2430. info.AddValue (prefix, constraintArrayList, typeof (ArrayList));
  2431. }
  2432. internal void BinarySerialize (SerializationInfo info, string prefix)
  2433. {
  2434. int columnsCount = Columns.Count;
  2435. int rowsCount = Rows.Count;
  2436. int recordsCount = Rows.Count;
  2437. ArrayList recordList = new ArrayList ();
  2438. ArrayList bitArrayList = new ArrayList ();
  2439. BitArray rowStateBitArray = new BitArray (rowsCount * 3);
  2440. for (int k = 0; k < Rows.Count; k++) {
  2441. if (Rows[k].RowState == DataRowState.Modified)
  2442. recordsCount++;
  2443. }
  2444. SerializeConstraints (info, prefix + "Constraints");
  2445. for (int j = 0; j < columnsCount; j++) {
  2446. if (rowsCount == 0)
  2447. continue;
  2448. BitArray nullBits = new BitArray (rowsCount);
  2449. DataColumn column = Columns [j];
  2450. Array recordArray = Array.CreateInstance (column.DataType, recordsCount);
  2451. for (int k = 0, l = 0; k < Rows.Count; k++, l++) {
  2452. DataRowVersion version;
  2453. DataRow dr = Rows[k];
  2454. if (dr.RowState == DataRowState.Modified) {
  2455. version = DataRowVersion.Default;
  2456. nullBits.Length = nullBits.Length + 1;
  2457. if (dr.IsNull (column, version) == false) {
  2458. nullBits [l] = false;
  2459. recordArray.SetValue (dr [j, version], l);
  2460. } else {
  2461. nullBits [l] = true;
  2462. }
  2463. l++;
  2464. version = DataRowVersion.Current;
  2465. } else if (dr.RowState == DataRowState.Deleted) {
  2466. version = DataRowVersion.Original;
  2467. } else {
  2468. version = DataRowVersion.Default;
  2469. }
  2470. if (dr.IsNull (column, version) == false) {
  2471. nullBits [l] = false;
  2472. recordArray.SetValue (dr [j, version], l);
  2473. } else {
  2474. nullBits [l] = true;
  2475. }
  2476. }
  2477. recordList.Add (recordArray);
  2478. bitArrayList.Add (nullBits);
  2479. }
  2480. for (int j = 0; j < Rows.Count; j++) {
  2481. int l = j * 3;
  2482. DataRowState rowState = Rows [j].RowState;
  2483. if (rowState == DataRowState.Detached) {
  2484. rowStateBitArray [l] = false;
  2485. rowStateBitArray [l + 1] = false;
  2486. rowStateBitArray [l + 2] = true;
  2487. } else if (rowState == DataRowState.Unchanged) {
  2488. rowStateBitArray [l] = false;
  2489. rowStateBitArray [l + 1] = false;
  2490. rowStateBitArray [l + 2] = false;
  2491. } else if (rowState == DataRowState.Added) {
  2492. rowStateBitArray [l] = false;
  2493. rowStateBitArray [l + 1] = true;
  2494. rowStateBitArray [l + 2] = false;
  2495. } else if (rowState == DataRowState.Deleted) {
  2496. rowStateBitArray [l] = true;
  2497. rowStateBitArray [l + 1] = true;
  2498. rowStateBitArray [l + 2] = false;
  2499. } else {
  2500. rowStateBitArray [l] = true;
  2501. rowStateBitArray [l + 1] = false;
  2502. rowStateBitArray [l + 2] = false;
  2503. }
  2504. }
  2505. info.AddValue (prefix + "Rows.Count", Rows.Count);
  2506. info.AddValue (prefix + "Records.Count", recordsCount);
  2507. info.AddValue (prefix + "Records", recordList, typeof (ArrayList));
  2508. info.AddValue (prefix + "NullBits", bitArrayList, typeof (ArrayList));
  2509. info.AddValue (prefix + "RowStates",
  2510. rowStateBitArray, typeof (BitArray));
  2511. // FIXME: To get row errors
  2512. Hashtable htRowErrors = new Hashtable ();
  2513. info.AddValue (prefix + "RowErrors",
  2514. htRowErrors, typeof (Hashtable));
  2515. // FIXME: To get column errors
  2516. Hashtable htColumnErrors = new Hashtable ();
  2517. info.AddValue (prefix + "ColumnErrors",
  2518. htColumnErrors, typeof (Hashtable));
  2519. }
  2520. public DataTableReader CreateDataReader ()
  2521. {
  2522. return new DataTableReader (this);
  2523. }
  2524. /// <summary>
  2525. /// Loads the table with the values from the reader
  2526. /// </summary>
  2527. public void Load (IDataReader reader)
  2528. {
  2529. if (reader == null)
  2530. throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
  2531. Load (reader, LoadOption.PreserveChanges);
  2532. }
  2533. /// <summary>
  2534. /// Loads the table with the values from the reader and the pattern
  2535. /// of the changes to the existing rows or the new rows are based on
  2536. /// the LoadOption passed.
  2537. /// </summary>
  2538. public void Load (IDataReader reader, LoadOption loadOption)
  2539. {
  2540. if (reader == null)
  2541. throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
  2542. bool prevEnforceConstr = this.EnforceConstraints;
  2543. try {
  2544. this.EnforceConstraints = false;
  2545. int [] mapping = DbDataAdapter.BuildSchema (reader, this, SchemaType.Mapped,
  2546. MissingSchemaAction.AddWithKey,
  2547. MissingMappingAction.Passthrough,
  2548. new DataTableMappingCollection ());
  2549. DbDataAdapter.FillFromReader (this,
  2550. reader,
  2551. 0, // start from
  2552. 0, // all records
  2553. mapping,
  2554. loadOption);
  2555. } finally {
  2556. this.EnforceConstraints = prevEnforceConstr;
  2557. }
  2558. }
  2559. public virtual void Load (IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler)
  2560. {
  2561. if (reader == null)
  2562. throw new ArgumentNullException ("Value cannot be null. Parameter name: reader");
  2563. bool prevEnforceConstr = this.EnforceConstraints;
  2564. try {
  2565. this.EnforceConstraints = false;
  2566. int [] mapping = DbDataAdapter.BuildSchema (reader, this, SchemaType.Mapped,
  2567. MissingSchemaAction.AddWithKey,
  2568. MissingMappingAction.Passthrough,
  2569. new DataTableMappingCollection ());
  2570. DbDataAdapter.FillFromReader (this,
  2571. reader,
  2572. 0, // start from
  2573. 0, // all records
  2574. mapping,
  2575. loadOption,
  2576. errorHandler);
  2577. } finally {
  2578. this.EnforceConstraints = prevEnforceConstr;
  2579. }
  2580. }
  2581. /// <summary>
  2582. /// Loads the given values into an existing row if matches or creates
  2583. /// the new row popluated with the values.
  2584. /// </summary>
  2585. /// <remarks>
  2586. /// This method searches for the values using primary keys and it first
  2587. /// searches using the original values of the rows and if not found, it
  2588. /// searches using the current version of the row.
  2589. /// </remarks>
  2590. public DataRow LoadDataRow (object [] values, LoadOption loadOption)
  2591. {
  2592. DataRow row = null;
  2593. // Find Data DataRow
  2594. if (this.PrimaryKey.Length > 0) {
  2595. object [] keys = new object [PrimaryKey.Length];
  2596. for (int i = 0; i < PrimaryKey.Length; i++)
  2597. keys [i] = values [PrimaryKey [i].Ordinal];
  2598. row = Rows.Find (keys, DataViewRowState.OriginalRows);
  2599. if (row == null)
  2600. row = Rows.Find (keys);
  2601. }
  2602. // If not found, add new row
  2603. if (row == null ||
  2604. (row.RowState == DataRowState.Deleted && loadOption == LoadOption.Upsert)) {
  2605. row = NewNotInitializedRow ();
  2606. row.ImportRecord (CreateRecord (values));
  2607. row.Validate (); // this adds to index ;-)
  2608. if (loadOption == LoadOption.OverwriteChanges ||
  2609. loadOption == LoadOption.PreserveChanges)
  2610. Rows.AddInternal (row, DataRowAction.ChangeCurrentAndOriginal);
  2611. else
  2612. Rows.AddInternal(row);
  2613. return row;
  2614. }
  2615. row.Load (values, loadOption);
  2616. return row;
  2617. }
  2618. public void Merge (DataTable table)
  2619. {
  2620. Merge (table, false, MissingSchemaAction.Add);
  2621. }
  2622. public void Merge (DataTable table, bool preserveChanges)
  2623. {
  2624. Merge (table, preserveChanges, MissingSchemaAction.Add);
  2625. }
  2626. public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
  2627. {
  2628. MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
  2629. }
  2630. internal int CompareRecords (int x, int y)
  2631. {
  2632. for (int col = 0; col < Columns.Count; col++) {
  2633. int res = Columns[col].DataContainer.CompareValues (x, y);
  2634. if (res != 0)
  2635. return res;
  2636. }
  2637. return 0;
  2638. }
  2639. /// <summary>
  2640. /// Occurs after the Clear method is called on the datatable.
  2641. /// </summary>
  2642. [DataCategory ("Data")]
  2643. public event DataTableClearEventHandler TableCleared;
  2644. [DataCategory ("Data")]
  2645. public event DataTableClearEventHandler TableClearing;
  2646. public event DataTableNewRowEventHandler TableNewRow;
  2647. /// <summary>
  2648. /// Raises TableCleared Event and delegates to subscribers
  2649. /// </summary>
  2650. protected virtual void OnTableCleared (DataTableClearEventArgs e)
  2651. {
  2652. if (TableCleared != null)
  2653. TableCleared (this, e);
  2654. }
  2655. internal void DataTableCleared ()
  2656. {
  2657. OnTableCleared (new DataTableClearEventArgs (this));
  2658. }
  2659. protected virtual void OnTableClearing (DataTableClearEventArgs e)
  2660. {
  2661. if (TableClearing != null)
  2662. TableClearing (this, e);
  2663. }
  2664. internal void DataTableClearing ()
  2665. {
  2666. OnTableClearing (new DataTableClearEventArgs (this));
  2667. }
  2668. protected virtual void OnTableNewRow (DataTableNewRowEventArgs e)
  2669. {
  2670. if (null != TableNewRow)
  2671. TableNewRow (this, e);
  2672. }
  2673. partial void NewRowAdded (DataRow dr)
  2674. {
  2675. OnTableNewRow (new DataTableNewRowEventArgs (dr));
  2676. }
  2677. }
  2678. #endif
  2679. }