DbDataAdapter.cs 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. //
  2. // System.Data.Common.DbDataAdapter.cs
  3. //
  4. // Author:
  5. // Rodrigo Moya ([email protected])
  6. // Tim Coleman ([email protected])
  7. // Sureshkumar T <[email protected]>
  8. //
  9. // (C) Ximian, Inc
  10. // Copyright (C) Tim Coleman, 2002-2003
  11. //
  12. //
  13. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  14. //
  15. // Permission is hereby granted, free of charge, to any person obtaining
  16. // a copy of this software and associated documentation files (the
  17. // "Software"), to deal in the Software without restriction, including
  18. // without limitation the rights to use, copy, modify, merge, publish,
  19. // distribute, sublicense, and/or sell copies of the Software, and to
  20. // permit persons to whom the Software is furnished to do so, subject to
  21. // the following conditions:
  22. //
  23. // The above copyright notice and this permission notice shall be
  24. // included in all copies or substantial portions of the Software.
  25. //
  26. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  27. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  28. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  29. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  30. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  31. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  32. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  33. //
  34. using System;
  35. using System.Collections;
  36. using System.ComponentModel;
  37. using System.Data;
  38. using System.Runtime.InteropServices;
  39. namespace System.Data.Common {
  40. #if NET_2_0
  41. public abstract class DbDataAdapter : DataAdapter, IDbDataAdapter, IDataAdapter, ICloneable
  42. #else
  43. public abstract class DbDataAdapter : DataAdapter, ICloneable
  44. #endif
  45. {
  46. #region Fields
  47. public const string DefaultSourceTableName = "Table";
  48. const string DefaultSourceColumnName = "Column";
  49. #if NET_2_0
  50. IDbCommand _selectCommand;
  51. internal IDbCommand _updateCommand;
  52. internal IDbCommand _deleteCommand;
  53. internal IDbCommand _insertCommand;
  54. #endif
  55. #endregion // Fields
  56. #region Constructors
  57. protected DbDataAdapter()
  58. {
  59. }
  60. [MonoTODO]
  61. protected DbDataAdapter(DbDataAdapter adapter) : base(adapter)
  62. {
  63. }
  64. #endregion // Fields
  65. #region Properties
  66. #if NET_2_0
  67. protected internal CommandBehavior FillCommandBehavior {
  68. get { throw new NotImplementedException (); }
  69. set { throw new NotImplementedException (); }
  70. }
  71. IDbCommand IDbDataAdapter.SelectCommand {
  72. get { return _selectCommand; }
  73. set { _selectCommand = value; }
  74. }
  75. IDbCommand IDbDataAdapter.UpdateCommand{
  76. get { return _updateCommand; }
  77. set { _updateCommand = value; }
  78. }
  79. IDbCommand IDbDataAdapter.DeleteCommand{
  80. get { return _deleteCommand; }
  81. set { _deleteCommand = value; }
  82. }
  83. IDbCommand IDbDataAdapter.InsertCommand{
  84. get { return _insertCommand; }
  85. set { _insertCommand = value; }
  86. }
  87. [Browsable (false)]
  88. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  89. public DbCommand SelectCommand {
  90. get { return (DbCommand) ((IDbDataAdapter) this).SelectCommand; }
  91. set { ((IDbDataAdapter) this).SelectCommand = value; }
  92. }
  93. [Browsable (false)]
  94. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  95. public DbCommand DeleteCommand {
  96. get { return (DbCommand) ((IDbDataAdapter) this).DeleteCommand; }
  97. set { ((IDbDataAdapter) this).DeleteCommand = value; }
  98. }
  99. [Browsable (false)]
  100. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  101. public DbCommand InsertCommand {
  102. get { return (DbCommand) ((IDbDataAdapter) this).InsertCommand; }
  103. set { ((IDbDataAdapter) this).InsertCommand = value; }
  104. }
  105. [Browsable (false)]
  106. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  107. public DbCommand UpdateCommand {
  108. get { return (DbCommand) ((IDbDataAdapter) this).UpdateCommand; }
  109. set { ((IDbDataAdapter) this).UpdateCommand = value; }
  110. }
  111. [MonoTODO]
  112. [DefaultValue (1)]
  113. public virtual int UpdateBatchSize {
  114. get { return 1; }
  115. set { throw new NotSupportedException (); }
  116. }
  117. #else
  118. IDbCommand SelectCommand {
  119. get { return ((IDbDataAdapter) this).SelectCommand; }
  120. }
  121. IDbCommand UpdateCommand {
  122. get { return ((IDbDataAdapter) this).UpdateCommand; }
  123. }
  124. IDbCommand DeleteCommand {
  125. get { return ((IDbDataAdapter) this).DeleteCommand; }
  126. }
  127. IDbCommand InsertCommand {
  128. get { return ((IDbDataAdapter) this).InsertCommand; }
  129. }
  130. #endif
  131. #endregion // Properties
  132. #region Events
  133. #if ONLY_1_0 || ONLY_1_1
  134. [DataCategory ("Fill")]
  135. [DataSysDescription ("Event triggered when a recoverable error occurs during Fill.")]
  136. public event FillErrorEventHandler FillError;
  137. #endif
  138. #endregion // Events
  139. #region Methods
  140. #if NET_2_0
  141. protected virtual RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
  142. StatementType statementType,
  143. DataTableMapping tableMapping)
  144. {
  145. return new RowUpdatedEventArgs (dataRow, command, statementType, tableMapping);
  146. }
  147. protected virtual RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
  148. StatementType statementType,
  149. DataTableMapping tableMapping)
  150. {
  151. return new RowUpdatingEventArgs (dataRow, command, statementType, tableMapping);
  152. }
  153. [MonoTODO]
  154. protected virtual void OnRowUpdated (RowUpdatedEventArgs value)
  155. {
  156. throw new NotImplementedException ();
  157. }
  158. [MonoTODO]
  159. protected virtual void OnRowUpdating (RowUpdatingEventArgs value)
  160. {
  161. throw new NotImplementedException ();
  162. }
  163. #else
  164. protected abstract RowUpdatedEventArgs CreateRowUpdatedEvent (DataRow dataRow, IDbCommand command,
  165. StatementType statementType,
  166. DataTableMapping tableMapping);
  167. protected abstract RowUpdatingEventArgs CreateRowUpdatingEvent (DataRow dataRow, IDbCommand command,
  168. StatementType statementType,
  169. DataTableMapping tableMapping);
  170. protected abstract void OnRowUpdated (RowUpdatedEventArgs value);
  171. protected abstract void OnRowUpdating (RowUpdatingEventArgs value);
  172. #endif
  173. private FillErrorEventArgs CreateFillErrorEvent (DataTable dataTable, object[] values, Exception e)
  174. {
  175. FillErrorEventArgs args = new FillErrorEventArgs (dataTable, values);
  176. args.Errors = e;
  177. args.Continue = false;
  178. return args;
  179. }
  180. protected override void Dispose (bool disposing)
  181. {
  182. if (disposing) {
  183. IDbDataAdapter da = (IDbDataAdapter) this;
  184. if (da.SelectCommand != null) {
  185. da.SelectCommand.Dispose();
  186. da.SelectCommand = null;
  187. }
  188. if (da.InsertCommand != null) {
  189. da.InsertCommand.Dispose();
  190. da.InsertCommand = null;
  191. }
  192. if (da.UpdateCommand != null) {
  193. da.UpdateCommand.Dispose();
  194. da.UpdateCommand = null;
  195. }
  196. if (da.DeleteCommand != null) {
  197. da.DeleteCommand.Dispose();
  198. da.DeleteCommand = null;
  199. }
  200. }
  201. }
  202. public override int Fill (DataSet dataSet)
  203. {
  204. return Fill (dataSet, 0, 0, DefaultSourceTableName, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
  205. }
  206. public int Fill (DataTable dataTable)
  207. {
  208. if (dataTable == null)
  209. throw new ArgumentNullException ("DataTable");
  210. return Fill (dataTable, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
  211. }
  212. public int Fill (DataSet dataSet, string srcTable)
  213. {
  214. return Fill (dataSet, 0, 0, srcTable, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
  215. }
  216. #if NET_2_0
  217. [MonoTODO ("This needs to be moved to DataAdapter.For now, just override")]
  218. protected override
  219. #else
  220. protected virtual
  221. #endif
  222. int Fill (DataTable dataTable, IDataReader dataReader)
  223. {
  224. if (dataReader.FieldCount == 0) {
  225. dataReader.Close ();
  226. return 0;
  227. }
  228. int count = 0;
  229. try {
  230. string tableName = SetupSchema (SchemaType.Mapped, dataTable.TableName);
  231. if (tableName != null) {
  232. dataTable.TableName = tableName;
  233. FillTable (dataTable, dataReader, 0, 0, ref count);
  234. }
  235. } finally {
  236. dataReader.Close ();
  237. }
  238. return count;
  239. }
  240. protected virtual int Fill (DataTable dataTable, IDbCommand command, CommandBehavior behavior)
  241. {
  242. CommandBehavior commandBehavior = behavior;
  243. // first see that the connection is not close.
  244. if (command.Connection.State == ConnectionState.Closed)
  245. {
  246. command.Connection.Open ();
  247. commandBehavior |= CommandBehavior.CloseConnection;
  248. }
  249. return Fill (dataTable, command.ExecuteReader (commandBehavior));
  250. }
  251. public int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable)
  252. {
  253. return this.Fill (dataSet, startRecord, maxRecords, srcTable, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
  254. }
  255. #if NET_2_0
  256. [MonoTODO]
  257. public int Fill (int startRecord, int maxRecords, DataTable[] dataTables)
  258. {
  259. throw new NotImplementedException ();
  260. }
  261. [MonoTODO]
  262. protected virtual int Fill (DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior)
  263. {
  264. throw new NotImplementedException ();
  265. }
  266. #endif
  267. #if NET_2_0
  268. [MonoTODO ("This needs to be moved to DataAdapter.For now, just override")]
  269. protected override
  270. #else
  271. protected virtual
  272. #endif
  273. int Fill (DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords)
  274. {
  275. if (dataSet == null)
  276. throw new ArgumentNullException ("DataSet");
  277. if (startRecord < 0)
  278. throw new ArgumentException ("The startRecord parameter was less than 0.");
  279. if (maxRecords < 0)
  280. throw new ArgumentException ("The maxRecords parameter was less than 0.");
  281. DataTable dataTable = null;
  282. int resultIndex = 0;
  283. int count = 0;
  284. try {
  285. string tableName = srcTable;
  286. do {
  287. // Non-resultset queries like insert, delete or update aren't processed.
  288. if (dataReader.FieldCount != -1)
  289. {
  290. tableName = SetupSchema (SchemaType.Mapped, tableName);
  291. if (tableName != null) {
  292. // check if the table exists in the dataset
  293. if (dataSet.Tables.Contains (tableName))
  294. // get the table from the dataset
  295. dataTable = dataSet.Tables [tableName];
  296. else {
  297. // Do not create schema if MissingSchemAction is set to Ignore
  298. if (this.MissingSchemaAction == MissingSchemaAction.Ignore)
  299. continue;
  300. dataTable = dataSet.Tables.Add (tableName);
  301. }
  302. if (!FillTable (dataTable, dataReader, startRecord, maxRecords, ref count)) {
  303. continue;
  304. }
  305. tableName = String.Format ("{0}{1}", srcTable, ++resultIndex);
  306. startRecord = 0;
  307. maxRecords = 0;
  308. }
  309. }
  310. } while (dataReader.NextResult ());
  311. }
  312. finally {
  313. dataReader.Close ();
  314. }
  315. return count;
  316. }
  317. protected virtual int Fill (DataSet dataSet, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
  318. {
  319. if (MissingSchemaAction == MissingSchemaAction.AddWithKey)
  320. behavior |= CommandBehavior.KeyInfo;
  321. CommandBehavior commandBehavior = behavior;
  322. if (command.Connection.State == ConnectionState.Closed) {
  323. command.Connection.Open ();
  324. commandBehavior |= CommandBehavior.CloseConnection;
  325. }
  326. return Fill (dataSet, srcTable, command.ExecuteReader (commandBehavior), startRecord, maxRecords);
  327. }
  328. private bool FillTable (DataTable dataTable, IDataReader dataReader, int startRecord, int maxRecords, ref int counter)
  329. {
  330. if (dataReader.FieldCount == 0)
  331. return false;
  332. int counterStart = counter;
  333. int[] mapping = BuildSchema (dataReader, dataTable, SchemaType.Mapped);
  334. int[] sortedMapping = new int[mapping.Length];
  335. int length = sortedMapping.Length;
  336. for(int i=0; i < sortedMapping.Length; i++) {
  337. if (mapping[i] >= 0)
  338. sortedMapping[mapping[i]] = i;
  339. else
  340. sortedMapping[--length] = i;
  341. }
  342. for (int i = 0; i < startRecord; i++) {
  343. dataReader.Read ();
  344. }
  345. dataTable.BeginLoadData ();
  346. while (dataReader.Read () && (maxRecords == 0 || (counter - counterStart) < maxRecords)) {
  347. try {
  348. dataTable.LoadDataRow (dataReader, sortedMapping, length, AcceptChangesDuringFill);
  349. counter++;
  350. }
  351. catch (Exception e) {
  352. object[] readerArray = new object[dataReader.FieldCount];
  353. object[] tableArray = new object[mapping.Length];
  354. // we get the values from the datareader
  355. dataReader.GetValues (readerArray);
  356. // copy from datareader columns to table columns according to given mapping
  357. for (int i = 0; i < mapping.Length; i++) {
  358. if (mapping[i] >= 0) {
  359. tableArray[i] = readerArray[mapping[i]];
  360. }
  361. }
  362. FillErrorEventArgs args = CreateFillErrorEvent (dataTable, tableArray, e);
  363. OnFillError (args);
  364. // if args.Continue is not set to true or if a handler is not set, rethrow the error..
  365. if(!args.Continue)
  366. throw e;
  367. }
  368. }
  369. dataTable.EndLoadData ();
  370. return true;
  371. }
  372. #if NET_2_0
  373. /// <summary>
  374. /// Fills the given datatable using values from reader. if a value
  375. /// for a column is null, that will be filled with default value.
  376. /// </summary>
  377. /// <returns>No. of rows affected </returns>
  378. internal static int FillFromReader (DataTable table,
  379. IDataReader reader,
  380. int start,
  381. int length,
  382. int [] mapping,
  383. LoadOption loadOption
  384. )
  385. {
  386. if (reader.FieldCount == 0)
  387. return 0 ;
  388. for (int i = 0; i < start; i++)
  389. reader.Read ();
  390. int counter = 0;
  391. object [] values = new object [mapping.Length];
  392. while (reader.Read () &&
  393. (length == 0 || counter < length)) {
  394. for (int i = 0 ; i < mapping.Length; i++)
  395. values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
  396. table.BeginLoadData ();
  397. table.LoadDataRow (values, loadOption);
  398. table.EndLoadData ();
  399. counter++;
  400. }
  401. return counter;
  402. }
  403. internal static int FillFromReader (DataTable table,
  404. IDataReader reader,
  405. int start,
  406. int length,
  407. int [] mapping,
  408. LoadOption loadOption,
  409. FillErrorEventHandler errorHandler)
  410. {
  411. if (reader.FieldCount == 0)
  412. return 0 ;
  413. for (int i = 0; i < start; i++)
  414. reader.Read ();
  415. int counter = 0;
  416. object [] values = new object [mapping.Length];
  417. while (reader.Read () &&
  418. (length == 0 || counter < length)) {
  419. for (int i = 0 ; i < mapping.Length; i++)
  420. values [i] = mapping [i] < 0 ? null : reader [mapping [i]];
  421. table.BeginLoadData ();
  422. try {
  423. table.LoadDataRow (values, loadOption);
  424. } catch (Exception e) {
  425. FillErrorEventArgs args = new FillErrorEventArgs (table, values);
  426. args.Errors = e;
  427. args.Continue = false;
  428. errorHandler (table, args);
  429. // if args.Continue is not set to true or if a handler is not set, rethrow the error..
  430. if(!args.Continue)
  431. throw e;
  432. }
  433. table.EndLoadData ();
  434. counter++;
  435. }
  436. return counter;
  437. }
  438. #endif // NET_2_0
  439. public override DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType)
  440. {
  441. return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, DefaultSourceTableName, CommandBehavior.Default);
  442. }
  443. public DataTable FillSchema (DataTable dataTable, SchemaType schemaType)
  444. {
  445. return FillSchema (dataTable, schemaType, ((IDbDataAdapter) this).SelectCommand, CommandBehavior.Default);
  446. }
  447. public DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, string srcTable)
  448. {
  449. return FillSchema (dataSet, schemaType, ((IDbDataAdapter) this).SelectCommand, srcTable, CommandBehavior.Default);
  450. }
  451. [MonoTODO ("Verify")]
  452. protected virtual DataTable FillSchema (DataTable dataTable, SchemaType schemaType, IDbCommand command, CommandBehavior behavior)
  453. {
  454. if (dataTable == null)
  455. throw new ArgumentNullException ("DataTable");
  456. behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
  457. if (command.Connection.State == ConnectionState.Closed) {
  458. command.Connection.Open ();
  459. behavior |= CommandBehavior.CloseConnection;
  460. }
  461. IDataReader reader = command.ExecuteReader (behavior);
  462. try
  463. {
  464. string tableName = SetupSchema (schemaType, dataTable.TableName);
  465. if (tableName != null)
  466. {
  467. // FillSchema should add the KeyInfo unless MissingSchemaAction
  468. // is set to Ignore or Error.
  469. MissingSchemaAction schemaAction = MissingSchemaAction;
  470. if (!(schemaAction == MissingSchemaAction.Ignore ||
  471. schemaAction == MissingSchemaAction.Error))
  472. schemaAction = MissingSchemaAction.AddWithKey;
  473. BuildSchema (reader, dataTable, schemaType, schemaAction,
  474. MissingMappingAction, TableMappings);
  475. }
  476. }
  477. finally
  478. {
  479. reader.Close ();
  480. }
  481. return dataTable;
  482. }
  483. [MonoTODO ("Verify")]
  484. protected virtual DataTable[] FillSchema (DataSet dataSet, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior)
  485. {
  486. if (dataSet == null)
  487. throw new ArgumentNullException ("DataSet");
  488. behavior |= CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo;
  489. if (command.Connection.State == ConnectionState.Closed) {
  490. command.Connection.Open ();
  491. behavior |= CommandBehavior.CloseConnection;
  492. }
  493. IDataReader reader = command.ExecuteReader (behavior);
  494. ArrayList output = new ArrayList ();
  495. string tableName = srcTable;
  496. int index = 0;
  497. DataTable table;
  498. try
  499. {
  500. // FillSchema should add the KeyInfo unless MissingSchemaAction
  501. // is set to Ignore or Error.
  502. MissingSchemaAction schemaAction = MissingSchemaAction;
  503. if (!(MissingSchemaAction == MissingSchemaAction.Ignore ||
  504. MissingSchemaAction == MissingSchemaAction.Error))
  505. schemaAction = MissingSchemaAction.AddWithKey;
  506. do {
  507. tableName = SetupSchema (schemaType, tableName);
  508. if (tableName != null)
  509. {
  510. if (dataSet.Tables.Contains (tableName))
  511. table = dataSet.Tables [tableName];
  512. else
  513. {
  514. // Do not create schema if MissingSchemAction is set to Ignore
  515. if (this.MissingSchemaAction == MissingSchemaAction.Ignore)
  516. continue;
  517. table = dataSet.Tables.Add (tableName);
  518. }
  519. BuildSchema (reader, table, schemaType, schemaAction,
  520. MissingMappingAction, TableMappings);
  521. output.Add (table);
  522. tableName = String.Format ("{0}{1}", srcTable, ++index);
  523. }
  524. }while (reader.NextResult ());
  525. }
  526. finally
  527. {
  528. reader.Close ();
  529. }
  530. return (DataTable[]) output.ToArray (typeof (DataTable));
  531. }
  532. private string SetupSchema (SchemaType schemaType, string sourceTableName)
  533. {
  534. DataTableMapping tableMapping = null;
  535. if (schemaType == SchemaType.Mapped)
  536. {
  537. tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTableName, sourceTableName, MissingMappingAction);
  538. if (tableMapping != null)
  539. return tableMapping.DataSetTable;
  540. return null;
  541. }
  542. else
  543. return sourceTableName;
  544. }
  545. [EditorBrowsable (EditorBrowsableState.Advanced)]
  546. public override IDataParameter[] GetFillParameters ()
  547. {
  548. IDataParameter[] parameters = new IDataParameter [SelectCommand.Parameters.Count];
  549. SelectCommand.Parameters.CopyTo (parameters, 0);
  550. return parameters;
  551. }
  552. // this method builds the schema for a given datatable. it returns a int array with
  553. // "array[ordinal of datatable column] == index of source column in data reader".
  554. // each column in the datatable has a mapping to a specific column in the datareader,
  555. // the int array represents this match.
  556. [MonoTODO ("Test")]
  557. private int[] BuildSchema (IDataReader reader, DataTable table, SchemaType schemaType)
  558. {
  559. return BuildSchema (reader, table, schemaType, MissingSchemaAction,
  560. MissingMappingAction, TableMappings);
  561. }
  562. /// <summary>
  563. /// Creates or Modifies the schema of the given DataTable based on the schema of
  564. /// the reader and the arguments passed.
  565. /// </summary>
  566. internal static int[] BuildSchema (IDataReader reader,
  567. DataTable table,
  568. SchemaType schemaType,
  569. MissingSchemaAction missingSchAction,
  570. MissingMappingAction missingMapAction,
  571. DataTableMappingCollection dtMapping
  572. )
  573. {
  574. int readerIndex = 0;
  575. // FIXME : this fails if query has fewer columns than a table
  576. int[] mapping = new int[table.Columns.Count]; // mapping the reader indexes to the datatable indexes
  577. for(int i=0; i < mapping.Length; i++) {
  578. mapping[i] = -1;
  579. }
  580. ArrayList primaryKey = new ArrayList ();
  581. ArrayList sourceColumns = new ArrayList ();
  582. bool createPrimaryKey = true;
  583. DataTable schemaTable = reader.GetSchemaTable ();
  584. DataColumn ColumnNameCol = schemaTable.Columns["ColumnName"];
  585. DataColumn DataTypeCol = schemaTable.Columns["DataType"];
  586. DataColumn IsAutoIncrementCol = schemaTable.Columns["IsAutoIncrement"];
  587. DataColumn AllowDBNullCol = schemaTable.Columns["AllowDBNull"];
  588. DataColumn IsReadOnlyCol = schemaTable.Columns["IsReadOnly"];
  589. DataColumn IsKeyCol = schemaTable.Columns["IsKey"];
  590. DataColumn IsUniqueCol = schemaTable.Columns["IsUnique"];
  591. DataColumn ColumnSizeCol = schemaTable.Columns["ColumnSize"];
  592. foreach (DataRow schemaRow in schemaTable.Rows) {
  593. // generate a unique column name in the source table.
  594. string sourceColumnName;
  595. string realSourceColumnName ;
  596. if (ColumnNameCol == null || schemaRow.IsNull(ColumnNameCol) || (string)schemaRow [ColumnNameCol] == String.Empty) {
  597. sourceColumnName = DefaultSourceColumnName;
  598. realSourceColumnName = DefaultSourceColumnName + "1";
  599. }
  600. else {
  601. sourceColumnName = (string) schemaRow [ColumnNameCol];
  602. realSourceColumnName = sourceColumnName;
  603. }
  604. for (int i = 1; sourceColumns.Contains (realSourceColumnName); i += 1)
  605. realSourceColumnName = String.Format ("{0}{1}", sourceColumnName, i);
  606. sourceColumns.Add(realSourceColumnName);
  607. // generate DataSetColumnName from DataTableMapping, if any
  608. string dsColumnName = realSourceColumnName;
  609. DataTableMapping tableMapping = null;
  610. //FIXME : The sourcetable name shud get passed as a parameter..
  611. int index = dtMapping.IndexOfDataSetTable (table.TableName);
  612. string srcTable = (index != -1 ? dtMapping[index].SourceTable : table.TableName);
  613. tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (dtMapping, srcTable, table.TableName, missingMapAction);
  614. if (tableMapping != null)
  615. {
  616. table.TableName = tableMapping.DataSetTable;
  617. // check to see if the column mapping exists
  618. DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, missingMapAction);
  619. if (columnMapping != null)
  620. {
  621. Type columnType = (Type)schemaRow[DataTypeCol];
  622. DataColumn col =
  623. columnMapping.GetDataColumnBySchemaAction(
  624. table ,
  625. columnType,
  626. missingSchAction);
  627. if (col != null)
  628. {
  629. // if the column is not in the table - add it.
  630. if (table.Columns.IndexOf(col) == -1)
  631. {
  632. if (missingSchAction == MissingSchemaAction.Add
  633. || missingSchAction == MissingSchemaAction.AddWithKey)
  634. table.Columns.Add(col);
  635. int[] tmp = new int[mapping.Length + 1];
  636. Array.Copy(mapping,0,tmp,0,col.Ordinal);
  637. Array.Copy(mapping,col.Ordinal,tmp,col.Ordinal + 1,mapping.Length - col.Ordinal);
  638. mapping = tmp;
  639. }
  640. if (missingSchAction == MissingSchemaAction.AddWithKey) {
  641. object value = (AllowDBNullCol != null) ? schemaRow[AllowDBNullCol] : null;
  642. bool allowDBNull = value is bool ? (bool)value : true;
  643. value = (IsKeyCol != null) ? schemaRow[IsKeyCol] : null;
  644. bool isKey = value is bool ? (bool)value : false;
  645. value = (IsAutoIncrementCol != null) ? schemaRow[IsAutoIncrementCol] : null;
  646. bool isAutoIncrement = value is bool ? (bool)value : false;
  647. value = (IsReadOnlyCol != null) ? schemaRow[IsReadOnlyCol] : null;
  648. bool isReadOnly = value is bool ? (bool)value : false;
  649. value = (IsUniqueCol != null) ? schemaRow[IsUniqueCol] : null;
  650. bool isUnique = value is bool ? (bool)value : false;
  651. col.AllowDBNull = allowDBNull;
  652. // fill woth key info
  653. if (isAutoIncrement && DataColumn.CanAutoIncrement(columnType)) {
  654. col.AutoIncrement = true;
  655. if (!allowDBNull)
  656. col.AllowDBNull = false;
  657. }
  658. if (columnType == DbTypes.TypeOfString) {
  659. col.MaxLength = (ColumnSizeCol != null) ? (int)schemaRow[ColumnSizeCol] : 0;
  660. }
  661. if (isReadOnly)
  662. col.ReadOnly = true;
  663. if (!allowDBNull && (!isReadOnly || isKey))
  664. col.AllowDBNull = false;
  665. if (isUnique && !isKey && !columnType.IsArray) {
  666. col.Unique = true;
  667. if (!allowDBNull)
  668. col.AllowDBNull = false;
  669. }
  670. // This might not be set by all DataProviders
  671. bool isHidden = false;
  672. if (schemaTable.Columns.Contains ("IsHidden")) {
  673. value = schemaRow["IsHidden"];
  674. isHidden = ((value is bool) ? (bool)value : false);
  675. }
  676. if (isKey && !isHidden) {
  677. primaryKey.Add (col);
  678. if (allowDBNull)
  679. createPrimaryKey = false;
  680. }
  681. }
  682. // add the ordinal of the column as a key and the index of the column in the datareader as a value.
  683. mapping[col.Ordinal] = readerIndex++;
  684. }
  685. }
  686. }
  687. }
  688. if (primaryKey.Count > 0) {
  689. DataColumn[] colKey = (DataColumn[])(primaryKey.ToArray(typeof (DataColumn)));
  690. if (createPrimaryKey)
  691. table.PrimaryKey = colKey;
  692. else {
  693. UniqueConstraint uConstraint = new UniqueConstraint(colKey);
  694. for (int i = 0; i < table.Constraints.Count; i++) {
  695. if (table.Constraints[i].Equals(uConstraint)) {
  696. uConstraint = null;
  697. break;
  698. }
  699. }
  700. if (uConstraint != null)
  701. table.Constraints.Add(uConstraint);
  702. }
  703. }
  704. return mapping;
  705. }
  706. [MonoTODO]
  707. object ICloneable.Clone ()
  708. {
  709. throw new NotImplementedException ();
  710. }
  711. [MonoTODO]
  712. public int Update (DataRow[] dataRows)
  713. {
  714. if (dataRows == null)
  715. throw new ArgumentNullException("dataRows");
  716. if (dataRows.Length == 0)
  717. return 0;
  718. if (dataRows[0] == null)
  719. throw new ArgumentException("dataRows[0].");
  720. DataTable table = dataRows[0].Table;
  721. if (table == null)
  722. throw new ArgumentException("table is null reference.");
  723. // all rows must be in the same table
  724. for (int i = 0; i < dataRows.Length; i++)
  725. {
  726. if (dataRows[i] == null)
  727. throw new ArgumentException("dataRows[" + i + "].");
  728. if (dataRows[i].Table != table)
  729. throw new ArgumentException(
  730. " DataRow["
  731. + i
  732. + "] is from a different DataTable than DataRow[0].");
  733. }
  734. // get table mapping for this rows
  735. DataTableMapping tableMapping = TableMappings.GetByDataSetTable(table.TableName);
  736. if (tableMapping == null)
  737. {
  738. tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(
  739. TableMappings,
  740. table.TableName,
  741. table.TableName,
  742. MissingMappingAction);
  743. if (tableMapping != null) {
  744. foreach (DataColumn col in table.Columns) {
  745. if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
  746. continue;
  747. DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
  748. if (columnMapping == null)
  749. columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
  750. tableMapping.ColumnMappings.Add (columnMapping);
  751. }
  752. } else {
  753. ArrayList cmc = new ArrayList ();
  754. foreach (DataColumn col in table.Columns)
  755. cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
  756. tableMapping =
  757. new DataTableMapping (
  758. table.TableName,
  759. table.TableName,
  760. cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
  761. }
  762. }
  763. DataRow[] copy = table.NewRowArray(dataRows.Length);
  764. Array.Copy(dataRows, 0, copy, 0, dataRows.Length);
  765. return Update(copy, tableMapping);
  766. }
  767. public override int Update (DataSet dataSet)
  768. {
  769. return Update (dataSet, DefaultSourceTableName);
  770. }
  771. public int Update (DataTable dataTable)
  772. {
  773. /*
  774. int index = TableMappings.IndexOfDataSetTable (dataTable.TableName);
  775. if (index < 0)
  776. throw new ArgumentException ();
  777. return Update (dataTable, TableMappings [index]);
  778. */
  779. DataTableMapping tableMapping = TableMappings.GetByDataSetTable (dataTable.TableName);
  780. if (tableMapping == null)
  781. {
  782. tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (
  783. TableMappings,
  784. dataTable.TableName,
  785. dataTable.TableName,
  786. MissingMappingAction);
  787. if (tableMapping != null) {
  788. foreach (DataColumn col in dataTable.Columns) {
  789. if (tableMapping.ColumnMappings.IndexOf (col.ColumnName) >= 0)
  790. continue;
  791. DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction (tableMapping.ColumnMappings, col.ColumnName, MissingMappingAction);
  792. if (columnMapping == null)
  793. columnMapping = new DataColumnMapping (col.ColumnName, col.ColumnName);
  794. tableMapping.ColumnMappings.Add (columnMapping);
  795. }
  796. } else {
  797. ArrayList cmc = new ArrayList ();
  798. foreach (DataColumn col in dataTable.Columns)
  799. cmc.Add (new DataColumnMapping (col.ColumnName, col.ColumnName));
  800. tableMapping =
  801. new DataTableMapping (
  802. dataTable.TableName,
  803. dataTable.TableName,
  804. cmc.ToArray (typeof (DataColumnMapping)) as DataColumnMapping []);
  805. }
  806. }
  807. return Update (dataTable, tableMapping);
  808. }
  809. private int Update (DataTable dataTable, DataTableMapping tableMapping)
  810. {
  811. DataRow[] rows = dataTable.NewRowArray(dataTable.Rows.Count);
  812. dataTable.Rows.CopyTo (rows, 0);
  813. return Update (rows, tableMapping);
  814. }
  815. [MonoTODO]
  816. protected virtual int Update (DataRow[] dataRows, DataTableMapping tableMapping)
  817. {
  818. int updateCount = 0;
  819. foreach (DataRow row in dataRows) {
  820. StatementType statementType = StatementType.Update;
  821. IDbCommand command = null;
  822. string commandName = String.Empty;
  823. switch (row.RowState) {
  824. case DataRowState.Added:
  825. statementType = StatementType.Insert;
  826. command = ((IDbDataAdapter) this).InsertCommand;
  827. commandName = "Insert";
  828. break;
  829. case DataRowState.Deleted:
  830. statementType = StatementType.Delete;
  831. command = ((IDbDataAdapter) this).DeleteCommand;
  832. commandName = "Delete";
  833. break;
  834. case DataRowState.Modified:
  835. statementType = StatementType.Update;
  836. command = ((IDbDataAdapter) this).UpdateCommand;
  837. commandName = "Update";
  838. break;
  839. case DataRowState.Unchanged:
  840. case DataRowState.Detached:
  841. continue;
  842. }
  843. RowUpdatingEventArgs argsUpdating = CreateRowUpdatingEvent (row, command, statementType, tableMapping);
  844. row.RowError = null;
  845. OnRowUpdating(argsUpdating);
  846. switch(argsUpdating.Status) {
  847. case UpdateStatus.Continue :
  848. //continue in update operation
  849. break;
  850. case UpdateStatus.ErrorsOccurred :
  851. if (argsUpdating.Errors == null) {
  852. argsUpdating.Errors = ExceptionHelper.RowUpdatedError();
  853. }
  854. row.RowError += argsUpdating.Errors.Message;
  855. if (!ContinueUpdateOnError) {
  856. throw argsUpdating.Errors;
  857. }
  858. continue;
  859. case UpdateStatus.SkipAllRemainingRows :
  860. return updateCount;
  861. case UpdateStatus.SkipCurrentRow :
  862. updateCount++;
  863. continue;
  864. default :
  865. throw ExceptionHelper.InvalidUpdateStatus(argsUpdating.Status);
  866. }
  867. command = argsUpdating.Command;
  868. try {
  869. if (command != null) {
  870. DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
  871. IDataParameter nullCheckParam = null;
  872. foreach (IDataParameter parameter in command.Parameters) {
  873. if ((parameter.Direction & ParameterDirection.Input) != 0) {
  874. string dsColumnName = parameter.SourceColumn;
  875. if (columnMappings.Contains(parameter.SourceColumn))
  876. dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
  877. if (dsColumnName == null || dsColumnName.Length <= 0) {
  878. nullCheckParam = parameter;
  879. continue;
  880. }
  881. DataRowVersion rowVersion = parameter.SourceVersion;
  882. // Parameter version is ignored for non-update commands
  883. if (statementType == StatementType.Delete)
  884. rowVersion = DataRowVersion.Original;
  885. parameter.Value = row [dsColumnName, rowVersion];
  886. if (nullCheckParam != null && (parameter.Value != null
  887. && parameter.Value != DBNull.Value)) {
  888. nullCheckParam.Value = 0;
  889. nullCheckParam = null;
  890. }
  891. }
  892. }
  893. }
  894. }
  895. catch (Exception e) {
  896. argsUpdating.Errors = e;
  897. argsUpdating.Status = UpdateStatus.ErrorsOccurred;
  898. }
  899. IDataReader reader = null;
  900. try {
  901. if (command == null) {
  902. throw ExceptionHelper.UpdateRequiresCommand(commandName);
  903. }
  904. CommandBehavior commandBehavior = CommandBehavior.Default;
  905. if (command.Connection.State == ConnectionState.Closed) {
  906. command.Connection.Open ();
  907. commandBehavior |= CommandBehavior.CloseConnection;
  908. }
  909. // use ExecuteReader because we want to use the commandbehavior parameter.
  910. // so the connection will be closed if needed.
  911. reader = command.ExecuteReader (commandBehavior);
  912. // update the current row, if the update command returns any resultset
  913. // ignore other than the first record.
  914. DataColumnMappingCollection columnMappings = tableMapping.ColumnMappings;
  915. if (command.UpdatedRowSource == UpdateRowSource.Both ||
  916. command.UpdatedRowSource == UpdateRowSource.FirstReturnedRecord) {
  917. if (reader.Read ()){
  918. DataTable retSchema = reader.GetSchemaTable ();
  919. foreach (DataRow dr in retSchema.Rows) {
  920. string columnName = dr ["ColumnName"].ToString ();
  921. string dstColumnName = columnName;
  922. if (columnMappings != null &&
  923. columnMappings.Contains(columnName))
  924. dstColumnName = columnMappings [dstColumnName].DataSetColumn;
  925. DataColumn dstColumn = row.Table.Columns [dstColumnName];
  926. if (dstColumn == null
  927. || (dstColumn.Expression != null
  928. && dstColumn.Expression.Length > 0))
  929. continue;
  930. // info from : http://www.error-bank.com/microsoft.public.dotnet.framework.windowsforms.databinding/
  931. // [email protected]_Thread.aspx
  932. // disable readonly for non-expression columns.
  933. bool readOnlyState = dstColumn.ReadOnly;
  934. dstColumn.ReadOnly = false;
  935. try {
  936. row [dstColumnName] = reader [columnName];
  937. } finally {
  938. dstColumn.ReadOnly = readOnlyState;
  939. }
  940. }
  941. }
  942. }
  943. reader.Close ();
  944. int tmp = reader.RecordsAffected; // records affected is valid only after closing reader
  945. // if the execute does not effect any rows we throw an exception.
  946. if (tmp == 0)
  947. throw new DBConcurrencyException("Concurrency violation: the " +
  948. commandName +"Command affected 0 records.");
  949. updateCount += tmp;
  950. if (command.UpdatedRowSource == UpdateRowSource.Both ||
  951. command.UpdatedRowSource == UpdateRowSource.OutputParameters) {
  952. // Update output parameters to row values
  953. foreach (IDataParameter parameter in command.Parameters) {
  954. if (parameter.Direction != ParameterDirection.InputOutput
  955. && parameter.Direction != ParameterDirection.Output
  956. && parameter.Direction != ParameterDirection.ReturnValue)
  957. continue;
  958. string dsColumnName = parameter.SourceColumn;
  959. if (columnMappings != null &&
  960. columnMappings.Contains(parameter.SourceColumn))
  961. dsColumnName = columnMappings [parameter.SourceColumn].DataSetColumn;
  962. DataColumn dstColumn = row.Table.Columns [dsColumnName];
  963. if (dstColumn == null
  964. || (dstColumn.Expression != null
  965. && dstColumn.Expression.Length > 0))
  966. continue;
  967. bool readOnlyState = dstColumn.ReadOnly;
  968. dstColumn.ReadOnly = false;
  969. try {
  970. row [dsColumnName] = parameter.Value;
  971. } finally {
  972. dstColumn.ReadOnly = readOnlyState;
  973. }
  974. }
  975. }
  976. RowUpdatedEventArgs updatedArgs = CreateRowUpdatedEvent(row, command, statementType, tableMapping);
  977. OnRowUpdated(updatedArgs);
  978. switch(updatedArgs.Status) {
  979. case UpdateStatus.Continue:
  980. break;
  981. case UpdateStatus.ErrorsOccurred:
  982. if (updatedArgs.Errors == null) {
  983. updatedArgs.Errors = ExceptionHelper.RowUpdatedError();
  984. }
  985. row.RowError += updatedArgs.Errors.Message;
  986. if (!ContinueUpdateOnError) {
  987. throw updatedArgs.Errors;
  988. }
  989. break;
  990. case UpdateStatus.SkipCurrentRow:
  991. continue;
  992. case UpdateStatus.SkipAllRemainingRows:
  993. return updateCount;
  994. }
  995. #if NET_2_0
  996. if (!AcceptChangesDuringUpdate)
  997. continue;
  998. #endif
  999. row.AcceptChanges ();
  1000. } catch(Exception e) {
  1001. row.RowError = e.Message;
  1002. if (!ContinueUpdateOnError) {
  1003. throw e;
  1004. }
  1005. } finally {
  1006. if (reader != null && ! reader.IsClosed) {
  1007. reader.Close ();
  1008. }
  1009. }
  1010. }
  1011. return updateCount;
  1012. }
  1013. public int Update (DataSet dataSet, string sourceTable)
  1014. {
  1015. MissingMappingAction mappingAction = MissingMappingAction;
  1016. if (mappingAction == MissingMappingAction.Ignore)
  1017. mappingAction = MissingMappingAction.Error;
  1018. DataTableMapping tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction (TableMappings, sourceTable, sourceTable, mappingAction);
  1019. DataTable dataTable = dataSet.Tables[tableMapping.DataSetTable];
  1020. if (dataTable == null)
  1021. throw new ArgumentException (String.Format ("Missing table {0}",
  1022. sourceTable));
  1023. return Update (dataTable, tableMapping);
  1024. }
  1025. #if NET_2_0
  1026. // All the batch methods, should be implemented, if supported,
  1027. // by individual providers
  1028. protected virtual int AddToBatch (IDbCommand cmd)
  1029. {
  1030. throw new NotSupportedException ();
  1031. }
  1032. protected virtual void ClearBatch ()
  1033. {
  1034. throw new NotSupportedException ();
  1035. }
  1036. protected virtual int ExecuteBatch ()
  1037. {
  1038. throw new NotSupportedException ();
  1039. }
  1040. protected virtual IDataParameter GetBatchedParameter (int commandIdentifier, int parameterIdentifer)
  1041. {
  1042. throw new NotSupportedException ();
  1043. }
  1044. protected virtual void InitializeBatching ()
  1045. {
  1046. throw new NotSupportedException ();
  1047. }
  1048. protected virtual void TerminateBatching ()
  1049. {
  1050. throw new NotSupportedException ();
  1051. }
  1052. #endif
  1053. #if ONLY_1_0 || ONLY_1_1
  1054. protected virtual void OnFillError (FillErrorEventArgs value)
  1055. {
  1056. if (FillError != null)
  1057. FillError (this, value);
  1058. }
  1059. #endif
  1060. #endregion // Methods
  1061. }
  1062. }