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