DataAdapter.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. //------------------------------------------------------------------------------
  2. // <copyright file="DataAdapter.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. // <owner current="true" primary="false">Microsoft</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data.Common {
  9. using System;
  10. using System.ComponentModel;
  11. using System.Data;
  12. using System.Data.ProviderBase;
  13. using System.Diagnostics;
  14. using System.Globalization;
  15. using System.Threading;
  16. public class DataAdapter : Component, IDataAdapter { // V1.0.3300
  17. static private readonly object EventFillError = new object();
  18. private bool _acceptChangesDuringUpdate = true;
  19. private bool _acceptChangesDuringUpdateAfterInsert = true;
  20. private bool _continueUpdateOnError = false;
  21. private bool _hasFillErrorHandler = false;
  22. private bool _returnProviderSpecificTypes = false;
  23. private bool _acceptChangesDuringFill = true;
  24. private LoadOption _fillLoadOption;
  25. private MissingMappingAction _missingMappingAction = System.Data.MissingMappingAction.Passthrough;
  26. private MissingSchemaAction _missingSchemaAction = System.Data.MissingSchemaAction.Add;
  27. private DataTableMappingCollection _tableMappings;
  28. private static int _objectTypeCount; // Bid counter
  29. internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
  30. #if DEBUG
  31. // if true, we are asserting that the caller has provided a select command
  32. // which should not return an empty result set
  33. private bool _debugHookNonEmptySelectCommand = false;
  34. #endif
  35. [Conditional("DEBUG")]
  36. void AssertReaderHandleFieldCount(DataReaderContainer readerHandler) {
  37. #if DEBUG
  38. Debug.Assert(!_debugHookNonEmptySelectCommand || readerHandler.FieldCount > 0, "Scenario expects non-empty results but no fields reported by reader");
  39. #endif
  40. }
  41. [Conditional("DEBUG")]
  42. void AssertSchemaMapping(SchemaMapping mapping) {
  43. #if DEBUG
  44. if (_debugHookNonEmptySelectCommand) {
  45. Debug.Assert(mapping != null && mapping.DataValues != null && mapping.DataTable != null, "Debug hook specifies that non-empty results are not expected");
  46. }
  47. #endif
  48. }
  49. protected DataAdapter() : base() { // V1.0.3300
  50. GC.SuppressFinalize(this);
  51. }
  52. protected DataAdapter(DataAdapter from) : base() { // V1.1.3300
  53. CloneFrom(from);
  54. }
  55. [
  56. DefaultValue(true),
  57. ResCategoryAttribute(Res.DataCategory_Fill),
  58. ResDescriptionAttribute(Res.DataAdapter_AcceptChangesDuringFill),
  59. ]
  60. public bool AcceptChangesDuringFill { // V1.0.3300
  61. get {
  62. //Bid.Trace("<comm.DataAdapter.get_AcceptChangesDuringFill|API> %d#\n", ObjectID);
  63. return _acceptChangesDuringFill;
  64. }
  65. set {
  66. _acceptChangesDuringFill = value;
  67. //Bid.Trace("<comm.DataAdapter.set_AcceptChangesDuringFill|API> %d#, %d\n", ObjectID, value);
  68. }
  69. }
  70. [
  71. EditorBrowsableAttribute(EditorBrowsableState.Never)
  72. ]
  73. virtual public bool ShouldSerializeAcceptChangesDuringFill() {
  74. return (0 == _fillLoadOption);
  75. }
  76. [
  77. DefaultValue(true),
  78. ResCategoryAttribute(Res.DataCategory_Update),
  79. ResDescriptionAttribute(Res.DataAdapter_AcceptChangesDuringUpdate),
  80. ]
  81. public bool AcceptChangesDuringUpdate { // V1.2.3300, MDAC 74988
  82. get {
  83. //Bid.Trace("<comm.DataAdapter.get_AcceptChangesDuringUpdate|API> %d#\n", ObjectID);
  84. return _acceptChangesDuringUpdate;
  85. }
  86. set {
  87. _acceptChangesDuringUpdate = value;
  88. //Bid.Trace("<comm.DataAdapter.set_AcceptChangesDuringUpdate|API> %d#, %d\n", ObjectID, value);
  89. }
  90. }
  91. [
  92. DefaultValue(false),
  93. ResCategoryAttribute(Res.DataCategory_Update),
  94. ResDescriptionAttribute(Res.DataAdapter_ContinueUpdateOnError),
  95. ]
  96. public bool ContinueUpdateOnError { // V1.0.3300, MDAC 66900
  97. get {
  98. //Bid.Trace("<comm.DataAdapter.get_ContinueUpdateOnError|API> %d#\n", ObjectID);
  99. return _continueUpdateOnError;
  100. }
  101. set {
  102. _continueUpdateOnError = value;
  103. //Bid.Trace("<comm.DataAdapter.set_ContinueUpdateOnError|API> %d#, %d\n", ObjectID, value);
  104. }
  105. }
  106. [
  107. RefreshProperties(RefreshProperties.All),
  108. ResCategoryAttribute(Res.DataCategory_Fill),
  109. ResDescriptionAttribute(Res.DataAdapter_FillLoadOption),
  110. ]
  111. public LoadOption FillLoadOption { // V1.2.3300
  112. get {
  113. //Bid.Trace("<comm.DataAdapter.get_FillLoadOption|API> %d#\n", ObjectID);
  114. LoadOption fillLoadOption = _fillLoadOption;
  115. return ((0 != fillLoadOption) ? _fillLoadOption : LoadOption.OverwriteChanges);
  116. }
  117. set {
  118. switch(value) {
  119. case 0: // to allow simple resetting
  120. case LoadOption.OverwriteChanges:
  121. case LoadOption.PreserveChanges:
  122. case LoadOption.Upsert:
  123. _fillLoadOption = value;
  124. //Bid.Trace("<comm.DataAdapter.set_FillLoadOption|API> %d#, %d{ds.LoadOption}\n", ObjectID, (int)value);
  125. break;
  126. default:
  127. throw ADP.InvalidLoadOption(value);
  128. }
  129. }
  130. }
  131. [
  132. EditorBrowsableAttribute(EditorBrowsableState.Never)
  133. ]
  134. public void ResetFillLoadOption() {
  135. _fillLoadOption = 0;
  136. }
  137. [
  138. EditorBrowsableAttribute(EditorBrowsableState.Never)
  139. ]
  140. virtual public bool ShouldSerializeFillLoadOption() {
  141. return (0 != _fillLoadOption);
  142. }
  143. [
  144. DefaultValue(System.Data.MissingMappingAction.Passthrough),
  145. ResCategoryAttribute(Res.DataCategory_Mapping),
  146. ResDescriptionAttribute(Res.DataAdapter_MissingMappingAction),
  147. ]
  148. public MissingMappingAction MissingMappingAction { // V1.0.3300
  149. get {
  150. //Bid.Trace("<comm.DataAdapter.get_MissingMappingAction|API> %d#\n", ObjectID);
  151. return _missingMappingAction;
  152. }
  153. set {
  154. switch(value) { // @perfnote: Enum.IsDefined
  155. case MissingMappingAction.Passthrough:
  156. case MissingMappingAction.Ignore:
  157. case MissingMappingAction.Error:
  158. _missingMappingAction = value;
  159. //Bid.Trace("<comm.DataAdapter.set_MissingMappingAction|API> %d#, %d{ds.MissingMappingAction}\n", ObjectID, (int)value);
  160. break;
  161. default:
  162. throw ADP.InvalidMissingMappingAction(value);
  163. }
  164. }
  165. }
  166. [
  167. DefaultValue(Data.MissingSchemaAction.Add),
  168. ResCategoryAttribute(Res.DataCategory_Mapping),
  169. ResDescriptionAttribute(Res.DataAdapter_MissingSchemaAction),
  170. ]
  171. public MissingSchemaAction MissingSchemaAction { // V1.0.3300
  172. get {
  173. //Bid.Trace("<comm.DataAdapter.get_MissingSchemaAction|API> %d#\n", ObjectID);
  174. return _missingSchemaAction;
  175. }
  176. set {
  177. switch(value) { // @perfnote: Enum.IsDefined
  178. case MissingSchemaAction.Add:
  179. case MissingSchemaAction.Ignore:
  180. case MissingSchemaAction.Error:
  181. case MissingSchemaAction.AddWithKey:
  182. _missingSchemaAction = value;
  183. //Bid.Trace("<comm.DataAdapter.set_MissingSchemaAction|API> %d#, %d{MissingSchemaAction}\n", ObjectID, (int)value);
  184. break;
  185. default:
  186. throw ADP.InvalidMissingSchemaAction(value);
  187. }
  188. }
  189. }
  190. internal int ObjectID {
  191. get {
  192. return _objectID;
  193. }
  194. }
  195. [
  196. DefaultValue(false),
  197. ResCategoryAttribute(Res.DataCategory_Fill),
  198. ResDescriptionAttribute(Res.DataAdapter_ReturnProviderSpecificTypes),
  199. ]
  200. virtual public bool ReturnProviderSpecificTypes {
  201. get {
  202. //Bid.Trace("<comm.DataAdapter.get_ReturnProviderSpecificTypes|API> %d#\n", ObjectID);
  203. return _returnProviderSpecificTypes;
  204. }
  205. set {
  206. _returnProviderSpecificTypes = value;
  207. //Bid.Trace("<comm.DataAdapter.set_ReturnProviderSpecificTypes|API> %d#, %d\n", ObjectID, (int)value);
  208. }
  209. }
  210. [
  211. DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
  212. ResCategoryAttribute(Res.DataCategory_Mapping),
  213. ResDescriptionAttribute(Res.DataAdapter_TableMappings),
  214. ]
  215. public DataTableMappingCollection TableMappings { // V1.0.3300
  216. get {
  217. //Bid.Trace("<comm.DataAdapter.get_TableMappings|API> %d#\n", ObjectID);
  218. DataTableMappingCollection mappings = _tableMappings;
  219. if (null == mappings) {
  220. mappings = CreateTableMappings();
  221. if (null == mappings) {
  222. mappings = new DataTableMappingCollection();
  223. }
  224. _tableMappings = mappings;
  225. }
  226. return mappings; // constructed by base class
  227. }
  228. }
  229. ITableMappingCollection IDataAdapter.TableMappings { // V1.0.3300
  230. get {
  231. return TableMappings;
  232. }
  233. }
  234. virtual protected bool ShouldSerializeTableMappings() { // V1.0.3300, MDAC 65548
  235. return true; /*HasTableMappings();*/ // VS7 300569
  236. }
  237. protected bool HasTableMappings() { // V1.2.3300
  238. return ((null != _tableMappings) && (0 < TableMappings.Count));
  239. }
  240. [
  241. ResCategoryAttribute(Res.DataCategory_Fill),
  242. ResDescriptionAttribute(Res.DataAdapter_FillError),
  243. ]
  244. public event FillErrorEventHandler FillError { // V1.2.3300, DbDataADapter V1.0.3300
  245. add {
  246. _hasFillErrorHandler = true;
  247. Events.AddHandler(EventFillError, value);
  248. }
  249. remove {
  250. Events.RemoveHandler(EventFillError, value);
  251. }
  252. }
  253. [ Obsolete("CloneInternals() has been deprecated. Use the DataAdapter(DataAdapter from) constructor. http://go.microsoft.com/fwlink/?linkid=14202") ] // V1.1.3300, MDAC 81448
  254. [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")] // MDAC 82936
  255. virtual protected DataAdapter CloneInternals() { // V1.0.3300
  256. DataAdapter clone = (DataAdapter)Activator.CreateInstance(GetType(), System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Instance, null, null, CultureInfo.InvariantCulture, null);
  257. clone.CloneFrom(this);
  258. return clone;
  259. }
  260. private void CloneFrom(DataAdapter from) {
  261. _acceptChangesDuringUpdate = from._acceptChangesDuringUpdate;
  262. _acceptChangesDuringUpdateAfterInsert = from._acceptChangesDuringUpdateAfterInsert;
  263. _continueUpdateOnError = from._continueUpdateOnError;
  264. _returnProviderSpecificTypes = from._returnProviderSpecificTypes; // WebData 101795
  265. _acceptChangesDuringFill = from._acceptChangesDuringFill;
  266. _fillLoadOption = from._fillLoadOption;
  267. _missingMappingAction = from._missingMappingAction;
  268. _missingSchemaAction = from._missingSchemaAction;
  269. if ((null != from._tableMappings) && (0 < from.TableMappings.Count)) {
  270. DataTableMappingCollection parameters = this.TableMappings;
  271. foreach(object parameter in from.TableMappings) {
  272. parameters.Add((parameter is ICloneable) ? ((ICloneable)parameter).Clone() : parameter);
  273. }
  274. }
  275. }
  276. virtual protected DataTableMappingCollection CreateTableMappings() { // V1.0.3300
  277. Bid.Trace("<comm.DataAdapter.CreateTableMappings|API> %d#\n", ObjectID);
  278. return new DataTableMappingCollection();
  279. }
  280. override protected void Dispose(bool disposing) { // V1.0.3300, MDAC 65459
  281. if (disposing) { // release mananged objects
  282. _tableMappings = null;
  283. }
  284. // release unmanaged objects
  285. base.Dispose(disposing); // notify base classes
  286. }
  287. virtual public DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType) { // V1.0.3300
  288. throw ADP.NotSupported();
  289. }
  290. virtual protected DataTable[] FillSchema(DataSet dataSet, SchemaType schemaType, string srcTable, IDataReader dataReader) { // V1.2.3300
  291. IntPtr hscp;
  292. Bid.ScopeEnter(out hscp, "<comm.DataAdapter.FillSchema|API> %d#, dataSet, schemaType=%d{ds.SchemaType}, srcTable, dataReader\n", ObjectID, (int)schemaType);
  293. try {
  294. if (null == dataSet) {
  295. throw ADP.ArgumentNull("dataSet");
  296. }
  297. if ((SchemaType.Source != schemaType) && (SchemaType.Mapped != schemaType)) {
  298. throw ADP.InvalidSchemaType(schemaType);
  299. }
  300. if (ADP.IsEmpty(srcTable)) {
  301. throw ADP.FillSchemaRequiresSourceTableName("srcTable");
  302. }
  303. if ((null == dataReader) || dataReader.IsClosed) {
  304. throw ADP.FillRequires("dataReader");
  305. }
  306. // user must Close/Dispose of the dataReader
  307. object value = FillSchemaFromReader(dataSet, null, schemaType, srcTable, dataReader);
  308. return (DataTable[]) value;
  309. }
  310. finally {
  311. Bid.ScopeLeave(ref hscp);
  312. }
  313. }
  314. virtual protected DataTable FillSchema(DataTable dataTable, SchemaType schemaType, IDataReader dataReader) { // V1.2.3300
  315. IntPtr hscp;
  316. Bid.ScopeEnter(out hscp, "<comm.DataAdapter.FillSchema|API> %d#, dataTable, schemaType, dataReader\n", ObjectID);
  317. try {
  318. if (null == dataTable) {
  319. throw ADP.ArgumentNull("dataTable");
  320. }
  321. if ((SchemaType.Source != schemaType) && (SchemaType.Mapped != schemaType)) {
  322. throw ADP.InvalidSchemaType(schemaType);
  323. }
  324. if ((null == dataReader) || dataReader.IsClosed) {
  325. throw ADP.FillRequires("dataReader");
  326. }
  327. // user must Close/Dispose of the dataReader
  328. // user will have to call NextResult to access remaining results
  329. object value = FillSchemaFromReader(null, dataTable, schemaType, null, dataReader);
  330. return (DataTable) value;
  331. }
  332. finally {
  333. Bid.ScopeLeave(ref hscp);
  334. }
  335. }
  336. internal object FillSchemaFromReader(DataSet dataset, DataTable datatable, SchemaType schemaType, string srcTable, IDataReader dataReader) {
  337. DataTable[] dataTables = null;
  338. int schemaCount = 0;
  339. do {
  340. DataReaderContainer readerHandler = DataReaderContainer.Create(dataReader, ReturnProviderSpecificTypes);
  341. AssertReaderHandleFieldCount(readerHandler);
  342. if (0 >= readerHandler.FieldCount) {
  343. continue;
  344. }
  345. string tmp = null;
  346. if (null != dataset) {
  347. tmp = DataAdapter.GetSourceTableName(srcTable, schemaCount);
  348. schemaCount++; // don't increment if no SchemaTable ( a non-row returning result )
  349. }
  350. SchemaMapping mapping = new SchemaMapping(this, dataset, datatable, readerHandler, true, schemaType, tmp, false, null, null);
  351. if (null != datatable) {
  352. // do not read remaining results in single DataTable case
  353. return mapping.DataTable;
  354. }
  355. else if (null != mapping.DataTable) {
  356. if (null == dataTables) {
  357. dataTables = new DataTable[1] { mapping.DataTable };
  358. }
  359. else {
  360. dataTables = DataAdapter.AddDataTableToArray(dataTables, mapping.DataTable);
  361. }
  362. }
  363. } while (dataReader.NextResult()); // FillSchema does not capture errors for FillError event
  364. object value = dataTables;
  365. if ((null == value) && (null == datatable)) { // WebData 101757
  366. value = new DataTable[0];
  367. }
  368. return value; // null if datatable had no results
  369. }
  370. virtual public int Fill(DataSet dataSet) { // V1.0.3300
  371. throw ADP.NotSupported();
  372. }
  373. virtual protected int Fill(DataSet dataSet, string srcTable, IDataReader dataReader, int startRecord, int maxRecords) { // V1.2.3300, DbDataAdapter V1.0.3300
  374. IntPtr hscp;
  375. Bid.ScopeEnter(out hscp, "<comm.DataAdapter.Fill|API> %d#, dataSet, srcTable, dataReader, startRecord, maxRecords\n", ObjectID);
  376. try {
  377. if (null == dataSet) {
  378. throw ADP.FillRequires("dataSet");
  379. }
  380. if (ADP.IsEmpty(srcTable)) {
  381. throw ADP.FillRequiresSourceTableName("srcTable");
  382. }
  383. if (null == dataReader) {
  384. throw ADP.FillRequires("dataReader");
  385. }
  386. if (startRecord < 0) {
  387. throw ADP.InvalidStartRecord("startRecord", startRecord);
  388. }
  389. if (maxRecords < 0) {
  390. throw ADP.InvalidMaxRecords("maxRecords", maxRecords);
  391. }
  392. if (dataReader.IsClosed) {
  393. return 0;
  394. }
  395. // user must Close/Dispose of the dataReader
  396. DataReaderContainer readerHandler = DataReaderContainer.Create(dataReader, ReturnProviderSpecificTypes);
  397. return FillFromReader(dataSet, null, srcTable, readerHandler, startRecord, maxRecords, null, null);
  398. }
  399. finally {
  400. Bid.ScopeLeave(ref hscp);
  401. }
  402. }
  403. virtual protected int Fill(DataTable dataTable, IDataReader dataReader) { // V1.2.3300, DbDataADapter V1.0.3300
  404. DataTable[] dataTables = new DataTable[] { dataTable };
  405. return Fill(dataTables, dataReader, 0, 0);
  406. }
  407. virtual protected int Fill(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords) { // V1.2.3300
  408. IntPtr hscp;
  409. Bid.ScopeEnter(out hscp, "<comm.DataAdapter.Fill|API> %d#, dataTables[], dataReader, startRecord, maxRecords\n", ObjectID);
  410. try {
  411. ADP.CheckArgumentLength(dataTables, "tables");
  412. if ((null == dataTables) || (0 == dataTables.Length) || (null == dataTables[0])) {
  413. throw ADP.FillRequires("dataTable");
  414. }
  415. if (null == dataReader) {
  416. throw ADP.FillRequires("dataReader");
  417. }
  418. if ((1 < dataTables.Length) && ((0 != startRecord) || (0 != maxRecords))) {
  419. throw ADP.NotSupported(); // FillChildren is not supported with FillPage
  420. }
  421. int result = 0;
  422. bool enforceContraints = false;
  423. DataSet commonDataSet = dataTables[0].DataSet;
  424. try {
  425. if (null != commonDataSet) {
  426. enforceContraints = commonDataSet.EnforceConstraints;
  427. commonDataSet.EnforceConstraints = false;
  428. }
  429. for(int i = 0; i < dataTables.Length; ++i) {
  430. Debug.Assert(null != dataTables[i], "null DataTable Fill");
  431. if (dataReader.IsClosed) {
  432. #if DEBUG
  433. Debug.Assert(!_debugHookNonEmptySelectCommand, "Debug hook asserts data reader should be open");
  434. #endif
  435. break;
  436. }
  437. DataReaderContainer readerHandler = DataReaderContainer.Create(dataReader, ReturnProviderSpecificTypes);
  438. AssertReaderHandleFieldCount(readerHandler);
  439. if (readerHandler.FieldCount <= 0) {
  440. if (i == 0)
  441. {
  442. bool lastFillNextResult;
  443. do {
  444. lastFillNextResult = FillNextResult(readerHandler);
  445. }
  446. while (lastFillNextResult && readerHandler.FieldCount <= 0);
  447. if (!lastFillNextResult) {
  448. break;
  449. }
  450. }
  451. else {
  452. continue;
  453. }
  454. }
  455. if ((0 < i) && !FillNextResult(readerHandler)) {
  456. break;
  457. }
  458. // user must Close/Dispose of the dataReader
  459. // user will have to call NextResult to access remaining results
  460. int count = FillFromReader(null, dataTables[i], null, readerHandler, startRecord, maxRecords, null, null);
  461. if (0 == i) {
  462. result = count;
  463. }
  464. }
  465. }
  466. catch(ConstraintException) {
  467. enforceContraints = false;
  468. throw;
  469. }
  470. finally {
  471. if (enforceContraints) {
  472. commonDataSet.EnforceConstraints = true;
  473. }
  474. }
  475. return result;
  476. }
  477. finally {
  478. Bid.ScopeLeave(ref hscp);
  479. }
  480. }
  481. internal int FillFromReader(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int startRecord, int maxRecords, DataColumn parentChapterColumn, object parentChapterValue) {
  482. int rowsAddedToDataSet = 0;
  483. int schemaCount = 0;
  484. do {
  485. AssertReaderHandleFieldCount(dataReader);
  486. if (0 >= dataReader.FieldCount) {
  487. continue; // loop to next result
  488. }
  489. SchemaMapping mapping = FillMapping(dataset, datatable, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue);
  490. schemaCount++; // don't increment if no SchemaTable ( a non-row returning result )
  491. AssertSchemaMapping(mapping);
  492. if (null == mapping) {
  493. continue; // loop to next result
  494. }
  495. if (null == mapping.DataValues) {
  496. continue; // loop to next result
  497. }
  498. if (null == mapping.DataTable) {
  499. continue; // loop to next result
  500. }
  501. mapping.DataTable.BeginLoadData();
  502. try {
  503. // startRecord and maxRecords only apply to the first resultset
  504. if ((1 == schemaCount) && ((0 < startRecord) || (0 < maxRecords))) {
  505. rowsAddedToDataSet = FillLoadDataRowChunk(mapping, startRecord, maxRecords);
  506. }
  507. else {
  508. int count = FillLoadDataRow(mapping);
  509. if (1 == schemaCount) { // MDAC 71347
  510. // only return LoadDataRow count for first resultset
  511. // not secondary or chaptered results
  512. rowsAddedToDataSet = count;
  513. }
  514. }
  515. }
  516. finally {
  517. mapping.DataTable.EndLoadData();
  518. }
  519. if (null != datatable) {
  520. break; // do not read remaining results in single DataTable case
  521. }
  522. } while (FillNextResult(dataReader));
  523. return rowsAddedToDataSet;
  524. }
  525. private int FillLoadDataRowChunk(SchemaMapping mapping, int startRecord, int maxRecords) {
  526. DataReaderContainer dataReader = mapping.DataReader;
  527. while (0 < startRecord) {
  528. if (!dataReader.Read()) {
  529. // there are no more rows on first resultset
  530. return 0;
  531. }
  532. --startRecord;
  533. }
  534. int rowsAddedToDataSet = 0;
  535. if (0 < maxRecords) {
  536. while ((rowsAddedToDataSet < maxRecords) && dataReader.Read()) {
  537. if (_hasFillErrorHandler) {
  538. try {
  539. mapping.LoadDataRowWithClear();
  540. rowsAddedToDataSet++;
  541. }
  542. catch(Exception e) {
  543. //
  544. if (!ADP.IsCatchableExceptionType(e)) {
  545. throw;
  546. }
  547. ADP.TraceExceptionForCapture(e);
  548. OnFillErrorHandler(e, mapping.DataTable, mapping.DataValues);
  549. }
  550. }
  551. else {
  552. mapping.LoadDataRow();
  553. rowsAddedToDataSet++;
  554. }
  555. }
  556. // skip remaining rows of the first resultset
  557. }
  558. else {
  559. rowsAddedToDataSet = FillLoadDataRow(mapping);
  560. }
  561. return rowsAddedToDataSet;
  562. }
  563. private int FillLoadDataRow(SchemaMapping mapping) {
  564. int rowsAddedToDataSet = 0;
  565. DataReaderContainer dataReader = mapping.DataReader;
  566. if (_hasFillErrorHandler) {
  567. while (dataReader.Read()) { // read remaining rows of first and subsequent resultsets
  568. try {
  569. // only try-catch if a FillErrorEventHandler is registered so that
  570. // in the default case we get the full callstack from users
  571. mapping.LoadDataRowWithClear();
  572. rowsAddedToDataSet++;
  573. }
  574. catch(Exception e) {
  575. //
  576. if (!ADP.IsCatchableExceptionType(e)) {
  577. throw;
  578. }
  579. ADP.TraceExceptionForCapture(e);
  580. OnFillErrorHandler(e, mapping.DataTable, mapping.DataValues);
  581. }
  582. }
  583. }
  584. else {
  585. while (dataReader.Read()) { // read remaining rows of first and subsequent resultset
  586. mapping.LoadDataRow();
  587. rowsAddedToDataSet++;
  588. }
  589. }
  590. return rowsAddedToDataSet;
  591. }
  592. private SchemaMapping FillMappingInternal(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue) {
  593. bool withKeyInfo = (Data.MissingSchemaAction.AddWithKey == MissingSchemaAction);
  594. string tmp = null;
  595. if (null != dataset) {
  596. tmp = DataAdapter.GetSourceTableName(srcTable, schemaCount);
  597. }
  598. return new SchemaMapping(this, dataset, datatable, dataReader, withKeyInfo, SchemaType.Mapped, tmp, true, parentChapterColumn, parentChapterValue);
  599. }
  600. private SchemaMapping FillMapping(DataSet dataset, DataTable datatable, string srcTable, DataReaderContainer dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue) {
  601. SchemaMapping mapping = null;
  602. if (_hasFillErrorHandler) {
  603. try {
  604. // only try-catch if a FillErrorEventHandler is registered so that
  605. // in the default case we get the full callstack from users
  606. mapping = FillMappingInternal(dataset, datatable, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue);
  607. }
  608. catch(Exception e) {
  609. //
  610. if (!ADP.IsCatchableExceptionType(e)) {
  611. throw;
  612. }
  613. ADP.TraceExceptionForCapture(e);
  614. OnFillErrorHandler(e, null, null);
  615. }
  616. }
  617. else {
  618. mapping = FillMappingInternal(dataset, datatable, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue);
  619. }
  620. return mapping;
  621. }
  622. private bool FillNextResult(DataReaderContainer dataReader) {
  623. bool result = true;
  624. if (_hasFillErrorHandler) {
  625. try {
  626. // only try-catch if a FillErrorEventHandler is registered so that
  627. // in the default case we get the full callstack from users
  628. result = dataReader.NextResult();
  629. }
  630. catch(Exception e) {
  631. //
  632. if (!ADP.IsCatchableExceptionType(e)) {
  633. throw;
  634. }
  635. ADP.TraceExceptionForCapture(e);
  636. OnFillErrorHandler(e, null, null);
  637. }
  638. }
  639. else {
  640. result = dataReader.NextResult();
  641. }
  642. return result;
  643. }
  644. [ EditorBrowsableAttribute(EditorBrowsableState.Advanced) ] // MDAC 69508
  645. virtual public IDataParameter[] GetFillParameters() { // V1.0.3300
  646. return new IDataParameter[0];
  647. }
  648. internal DataTableMapping GetTableMappingBySchemaAction(string sourceTableName, string dataSetTableName, MissingMappingAction mappingAction) {
  649. return DataTableMappingCollection.GetTableMappingBySchemaAction(_tableMappings, sourceTableName, dataSetTableName, mappingAction);
  650. }
  651. internal int IndexOfDataSetTable(string dataSetTable) {
  652. if (null != _tableMappings) {
  653. return TableMappings.IndexOfDataSetTable(dataSetTable);
  654. }
  655. return -1;
  656. }
  657. virtual protected void OnFillError(FillErrorEventArgs value) { // V1.2.3300, DbDataAdapter V1.0.3300
  658. FillErrorEventHandler handler = (FillErrorEventHandler) Events[EventFillError];
  659. if (null != handler) {
  660. handler(this, value);
  661. }
  662. }
  663. private void OnFillErrorHandler(Exception e, DataTable dataTable, object[] dataValues) {
  664. FillErrorEventArgs fillErrorEvent = new FillErrorEventArgs(dataTable, dataValues);
  665. fillErrorEvent.Errors = e;
  666. OnFillError(fillErrorEvent);
  667. if (!fillErrorEvent.Continue) {
  668. if (null != fillErrorEvent.Errors) {
  669. throw fillErrorEvent.Errors;
  670. }
  671. throw e;
  672. }
  673. }
  674. virtual public int Update(DataSet dataSet) { // V1.0.3300
  675. throw ADP.NotSupported();
  676. }
  677. // used by FillSchema which returns an array of datatables added to the dataset
  678. static private DataTable[] AddDataTableToArray(DataTable[] tables, DataTable newTable) {
  679. for (int i = 0; i < tables.Length; ++i) { // search for duplicates
  680. if (tables[i] == newTable) {
  681. return tables; // duplicate found
  682. }
  683. }
  684. DataTable[] newTables = new DataTable[tables.Length+1]; // add unique data table
  685. for (int i = 0; i < tables.Length; ++i) {
  686. newTables[i] = tables[i];
  687. }
  688. newTables[tables.Length] = newTable;
  689. return newTables;
  690. }
  691. // dynamically generate source table names
  692. static private string GetSourceTableName(string srcTable, int index) {
  693. //if ((null != srcTable) && (0 <= index) && (index < srcTable.Length)) {
  694. if (0 == index) {
  695. return srcTable; //[index];
  696. }
  697. return srcTable + index.ToString(System.Globalization.CultureInfo.InvariantCulture);
  698. }
  699. }
  700. internal sealed class LoadAdapter : DataAdapter {
  701. internal LoadAdapter() {
  702. }
  703. internal int FillFromReader(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords) {
  704. return Fill(dataTables, dataReader, startRecord, maxRecords);
  705. }
  706. }
  707. }