Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data / System / Data / DataTableReader.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DataTableReader.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 // <owner current="false" primary="false">Microsoft</owner>
8 //------------------------------------------------------------------------------
9
10 namespace System.Data {
11     using System;
12     using System.Data.Common;
13     using System.Data.SqlTypes;
14     using System.Collections;
15     using System.ComponentModel;
16
17     public sealed class DataTableReader : DbDataReader  {
18
19         private readonly DataTable[] tables = null;
20         private bool isOpen = true;
21         private DataTable schemaTable = null;
22
23         private int tableCounter = -1;
24         private int rowCounter = -1;
25         private DataTable currentDataTable = null;
26         private DataRow currentDataRow = null;
27
28         private bool hasRows= true;
29         private bool reachEORows = false;
30         private bool currentRowRemoved = false;
31         private bool schemaIsChanged = false;
32         private bool started = false;
33         private bool readerIsInvalid = false;
34         private DataTableReaderListener listener = null;
35         private bool tableCleared = false;
36
37        public  DataTableReader(DataTable dataTable) {
38             if (dataTable == null)
39                 throw ExceptionBuilder.ArgumentNull("DataTable");
40             tables = new DataTable[1] {dataTable};
41
42             init();
43 //            schemaTable = GetSchemaTableFromDataTable(currentDataTable);
44         }
45
46         public  DataTableReader(DataTable [] dataTables) {
47            if (dataTables == null)
48                 throw ExceptionBuilder.ArgumentNull("DataTable");
49
50            if (dataTables.Length == 0)
51                throw ExceptionBuilder.DataTableReaderArgumentIsEmpty();
52
53
54            tables = new DataTable[dataTables.Length];
55            for (int i = 0; i < dataTables.Length ; i++) {
56                if (dataTables[i] == null)
57                    throw ExceptionBuilder.ArgumentNull("DataTable");
58                tables[i] = dataTables[i];
59            }
60
61            init();
62 //           schemaTable = GetSchemaTableFromDataTable(currentDataTable);
63         }
64
65         private bool ReaderIsInvalid {
66             get {
67                 return readerIsInvalid;
68             }
69             set {
70                 if (readerIsInvalid == value)
71                     return;
72                 readerIsInvalid = value;
73                 if (readerIsInvalid && listener != null) {
74                     listener.CleanUp();
75                 }
76             }
77         }
78
79         private bool IsSchemaChanged {
80             get {
81                 return schemaIsChanged;
82             }
83             set {
84                 if (!value || schemaIsChanged == value) //once it is set to false; should not change unless in init() or NextResult()
85                     return;
86                 schemaIsChanged  = value;
87                 if (listener != null) {
88                     listener.CleanUp();
89                 }
90             }
91         }
92
93         internal DataTable CurrentDataTable {
94             get {
95                 return currentDataTable;
96             }
97         }
98
99         private void init() {
100             tableCounter = 0;
101             reachEORows = false;
102             schemaIsChanged = false;
103             currentDataTable = tables[tableCounter];
104             hasRows = (currentDataTable.Rows.Count > 0);
105             ReaderIsInvalid = false;
106  
107 // we need to listen to current tables event so create a listener, it will listen to events and call us back.
108             listener = new DataTableReaderListener(this);
109         }
110
111
112         override public void Close() {
113             if (!isOpen)
114                 return;
115 // no need to listen to events after close
116             if (listener != null)
117                 listener.CleanUp();
118
119             listener = null;
120             schemaTable = null;
121
122             isOpen = false;
123         }
124
125         override public DataTable GetSchemaTable(){
126             ValidateOpen("GetSchemaTable");
127             ValidateReader();
128
129 // each time, we just get schema table of current table for once, no need to recreate each time, if schema is changed, reader is already
130 // is invalid
131             if (schemaTable == null)
132                 schemaTable = GetSchemaTableFromDataTable(currentDataTable);
133
134             return schemaTable;
135         }
136
137         override public bool  NextResult() {
138 // next result set; reset everything
139             ValidateOpen("NextResult");
140
141             if ((tableCounter ==  tables.Length -1))
142                 return false;
143
144            currentDataTable = tables[++tableCounter];
145
146            if (listener != null)
147                 listener.UpdataTable(currentDataTable); // it will unsubscribe from preveous tables events and subscribe to new table's events
148
149            schemaTable = null;
150            rowCounter = -1;
151            currentRowRemoved = false;
152            reachEORows = false;
153            schemaIsChanged = false;
154            started = false;
155            ReaderIsInvalid = false;
156            tableCleared = false;
157
158             hasRows = (currentDataTable.Rows.Count > 0);
159
160            return true;
161         }
162
163         override public bool Read() {
164
165 /*            else if (tableCleared) {
166                 return false;
167                 throw  ExceptionBuilder.EmptyDataTableReader(currentDataTable.TableName);
168             }
169   */
170             if (!started) {
171                 started = true;
172             }
173             /*else {
174                 ValidateRow(rowCounter);
175             }*/
176
177             ValidateOpen("Read");
178
179             ValidateReader();
180
181
182             if(reachEORows) {
183                 return false;
184             }
185
186             if (rowCounter >=  currentDataTable.Rows.Count  -1 ) {
187                 reachEORows = true;
188                 if (listener != null)
189                     listener.CleanUp();
190                return false;
191             }
192
193             rowCounter ++;
194             ValidateRow(rowCounter);
195             currentDataRow = currentDataTable.Rows[rowCounter];
196
197             while (currentDataRow.RowState == DataRowState.Deleted) {
198                 rowCounter++;
199                 if (rowCounter ==  currentDataTable.Rows.Count) {
200                     reachEORows = true;
201                     if (listener != null)
202                         listener.CleanUp();
203                     return false;
204                 }
205                 ValidateRow(rowCounter);
206                 currentDataRow = currentDataTable.Rows[rowCounter];
207             }
208             if (currentRowRemoved)
209                 currentRowRemoved = false;
210
211             return true;
212         }
213
214         override public int Depth {
215            get {
216                ValidateOpen("Depth");
217                ValidateReader();
218                return 0;
219            }
220         }
221
222         override public bool IsClosed {
223             get {
224                 return (!isOpen);
225             }
226         }
227
228         override public int RecordsAffected {
229             get {
230                 ValidateReader();
231                 return 0;
232             }
233         }
234
235         override public bool HasRows {
236             get {
237                 ValidateOpen("HasRows");
238                 ValidateReader();
239                 return hasRows;
240             }
241         }
242
243         override public object this[int ordinal] {
244             get {
245                 ValidateOpen("Item");
246                 ValidateReader();
247                 if ((currentDataRow == null) || (currentDataRow.RowState == DataRowState.Deleted)) {
248                     ReaderIsInvalid = true;
249                     throw  ExceptionBuilder.InvalidDataTableReader(currentDataTable.TableName);
250                 }
251                 try {
252                     return currentDataRow[ordinal];
253                 }
254                 catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
255                     ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
256                     throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
257                 }
258             }
259         }
260
261         override public object this[string name] {
262             get {
263                 ValidateOpen("Item");
264                 ValidateReader();
265                 if ((currentDataRow == null) || (currentDataRow.RowState == DataRowState.Deleted)) {
266                     ReaderIsInvalid = true;
267                     throw  ExceptionBuilder.InvalidDataTableReader(currentDataTable.TableName);
268                 }
269                 return currentDataRow[name];
270             }
271         }
272
273         override public Int32 FieldCount {
274             get {
275                 ValidateOpen("FieldCount");
276                 ValidateReader();
277                 return currentDataTable.Columns.Count;
278             }
279         }
280
281         override public Type GetProviderSpecificFieldType(int ordinal) {
282             ValidateOpen("GetProviderSpecificFieldType");
283             ValidateReader();
284             return GetFieldType(ordinal);
285         }
286
287         override public Object GetProviderSpecificValue(int ordinal) {
288             ValidateOpen("GetProviderSpecificValue");
289             ValidateReader();
290             return GetValue(ordinal);
291         }
292
293         override  public int GetProviderSpecificValues(object[] values) {
294             ValidateOpen("GetProviderSpecificValues");
295             ValidateReader();
296             return GetValues(values);
297         }
298
299         override public  bool GetBoolean (int ordinal) {
300             ValidateState("GetBoolean");
301             ValidateReader();
302             try {
303                 return (bool) currentDataRow[ordinal];
304             }
305             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
306                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
307                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
308             }
309         }
310
311         override public  byte GetByte (int ordinal) {
312             ValidateState("GetByte");
313             ValidateReader();
314             try {
315                 return (byte) currentDataRow[ordinal];
316             }
317             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
318                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
319                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
320             }
321         }
322
323        override public long GetBytes(int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length) {
324             ValidateState("GetBytes");
325             ValidateReader();
326             byte[] tempBuffer;
327             try {
328                 tempBuffer = (byte[]) currentDataRow[ordinal];
329             }
330             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
331                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
332                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
333             }
334             if (buffer == null) {
335                 return tempBuffer.Length;
336             }
337             int srcIndex = (int) dataIndex;
338             int byteCount = Math.Min(tempBuffer.Length - srcIndex, length);
339             if (srcIndex < 0) {
340                 throw ADP.InvalidSourceBufferIndex(tempBuffer.Length, srcIndex, "dataIndex");
341             }
342             else if ((bufferIndex < 0) || (bufferIndex > 0 && bufferIndex >= buffer.Length)) {
343                 throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
344             }
345
346             if (0 < byteCount) {
347                 Array.Copy(tempBuffer, dataIndex, buffer, bufferIndex, byteCount);
348             }
349             else if (length < 0) {
350                 throw ADP.InvalidDataLength(length);
351             }
352             else {
353                 byteCount = 0;
354             }
355             return byteCount;
356
357         }
358
359         override public  char GetChar (int ordinal) {
360             ValidateState("GetChar");
361             ValidateReader();
362             try {
363                 return (char) currentDataRow[ordinal];
364             }
365             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
366                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
367                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
368             }
369         }
370
371        override public long GetChars(int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length) {
372             ValidateState("GetChars");
373             ValidateReader();
374             char[] tempBuffer;
375             try {
376                 tempBuffer = (char[]) currentDataRow[ordinal];
377             }
378             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
379                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
380                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
381             }
382
383             if (buffer == null) {
384                 return tempBuffer.Length;
385             }
386
387             int srcIndex = (int) dataIndex;
388             int charCount = Math.Min(tempBuffer.Length - srcIndex, length);
389             if (srcIndex < 0) {
390                 throw ADP.InvalidSourceBufferIndex(tempBuffer.Length, srcIndex, "dataIndex");
391             }
392             else if ((bufferIndex < 0) || (bufferIndex > 0 && bufferIndex >= buffer.Length)) {
393                 throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, "bufferIndex");
394             }
395
396             if (0 < charCount) {
397                 Array.Copy(tempBuffer, dataIndex, buffer, bufferIndex, charCount);
398             }
399             else if (length < 0) {
400                 throw ADP.InvalidDataLength(length);
401             }
402             else {
403                 charCount = 0;
404             }
405             return charCount;
406         }
407
408         override public  String GetDataTypeName (int ordinal) {
409             ValidateOpen("GetDataTypeName");
410             ValidateReader();
411             return ((Type)GetFieldType(ordinal)).Name;
412         }
413
414         override public  DateTime GetDateTime (int ordinal) {
415             ValidateState("GetDateTime");
416             ValidateReader();
417             try {
418                 return (DateTime) currentDataRow[ordinal];
419             }
420             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
421                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
422                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
423             }
424         }
425
426         override public  Decimal GetDecimal (int ordinal) {
427             ValidateState("GetDecimal");
428             ValidateReader();
429             try {
430                 return (Decimal) currentDataRow[ordinal];
431             }
432             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
433                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
434                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
435             }
436         }
437
438         override public  Double GetDouble (int ordinal) {
439             ValidateState("GetDouble");
440             ValidateReader();
441             try {
442                 return (double) currentDataRow[ordinal];
443             }
444             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
445                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
446                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
447             }
448         }
449
450         override public  Type GetFieldType (int ordinal) {
451             ValidateOpen("GetFieldType");
452             ValidateReader();
453             try {
454                 return (currentDataTable.Columns[ordinal].DataType);
455             }
456             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
457                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
458                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
459             }
460         }
461
462         override public  Single GetFloat (int ordinal) {
463             ValidateState("GetFloat");
464             ValidateReader();
465             try {
466                 return (Single) currentDataRow[ordinal];
467             }
468             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
469                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
470                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
471             }
472         }
473
474         override public  Guid GetGuid (int ordinal) {
475             ValidateState("GetGuid");
476             ValidateReader();
477             try {
478                 return (Guid) currentDataRow[ordinal];
479             }
480             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
481                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
482                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
483             }
484         }
485
486         override public  Int16 GetInt16 (int ordinal) {
487             ValidateState("GetInt16");
488             ValidateReader();
489             try {
490                 return (Int16) currentDataRow[ordinal];
491             }
492             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
493                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
494                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
495             }
496         }
497
498         override public Int32 GetInt32 (int ordinal) {
499             ValidateState("GetInt32");
500             ValidateReader();
501             try {
502                 return (Int32) currentDataRow[ordinal];
503             }
504             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
505                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
506                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
507             }
508         }
509
510         override public  Int64 GetInt64 (int ordinal) {
511             ValidateState("GetInt64");
512             ValidateReader();
513             try {
514                 return (Int64) currentDataRow[ordinal];
515             }
516             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
517                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
518                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
519             }
520         }
521
522         override public  String GetName (int ordinal) {
523             ValidateOpen("GetName");
524             ValidateReader();
525             try {
526                 return (currentDataTable.Columns[ordinal].ColumnName);
527             }
528             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
529                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
530                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
531             }
532         }
533
534         override public  Int32 GetOrdinal (string name) {
535             ValidateOpen("GetOrdinal");
536             ValidateReader();
537             DataColumn dc = currentDataTable.Columns[name];
538
539             if (dc != null) {
540                 return dc.Ordinal;// WebData 113248
541             }
542             else{
543                 throw ExceptionBuilder.ColumnNotInTheTable(name, currentDataTable.TableName);
544             }
545         }
546
547         override public  string GetString (int ordinal) {
548             ValidateState("GetString");
549             ValidateReader();
550             try {
551                 return (string) currentDataRow[ordinal];
552             }
553             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
554                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
555                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
556             }
557         }
558
559
560         override public  object GetValue (int ordinal) {
561             ValidateState("GetValue");
562             ValidateReader();
563             try {
564                 return currentDataRow[ordinal];
565             }
566             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
567                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
568                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
569             }
570         }
571
572         override public  Int32 GetValues (object[] values) {
573             ValidateState("GetValues");
574             ValidateReader();
575
576             if (values ==null)
577                 throw ExceptionBuilder.ArgumentNull("values");
578
579             Array.Copy(currentDataRow.ItemArray, values,  currentDataRow.ItemArray.Length > values.Length ? values.Length : currentDataRow.ItemArray.Length);
580             return (currentDataRow.ItemArray.Length > values.Length ? values.Length : currentDataRow.ItemArray.Length);
581         }
582         override public bool IsDBNull (int ordinal) {
583             ValidateState("IsDBNull");
584             ValidateReader();
585             try {
586                 return (currentDataRow.IsNull(ordinal));
587             }
588             catch(IndexOutOfRangeException e) { // thrown by DataColumnCollection
589                 ExceptionBuilder.TraceExceptionWithoutRethrow(e);                
590                 throw ExceptionBuilder.ArgumentOutOfRange("ordinal");
591             }
592         }
593
594 // IEnumerable
595         override public IEnumerator GetEnumerator() {
596             ValidateOpen("GetEnumerator");
597             return new DbEnumerator((IDataReader)this);
598         }
599
600         static internal DataTable GetSchemaTableFromDataTable(DataTable table) {
601             if (table == null) {
602                 throw ExceptionBuilder.ArgumentNull("DataTable");
603             }
604
605             DataTable tempSchemaTable = new DataTable("SchemaTable");
606             tempSchemaTable.Locale = System.Globalization.CultureInfo.InvariantCulture;
607
608             DataColumn ColumnName          = new DataColumn(SchemaTableColumn.ColumnName,          typeof(System.String));
609             DataColumn ColumnOrdinal       = new DataColumn(SchemaTableColumn.ColumnOrdinal,       typeof(System.Int32));
610             DataColumn ColumnSize          = new DataColumn(SchemaTableColumn.ColumnSize,          typeof(System.Int32));
611             DataColumn NumericPrecision    = new DataColumn(SchemaTableColumn.NumericPrecision,    typeof(System.Int16));
612             DataColumn NumericScale        = new DataColumn(SchemaTableColumn.NumericScale,        typeof(System.Int16));
613             DataColumn DataType            = new DataColumn(SchemaTableColumn.DataType,            typeof(System.Type));
614             DataColumn ProviderType        = new DataColumn(SchemaTableColumn.ProviderType,        typeof(System.Int32));
615             DataColumn IsLong              = new DataColumn(SchemaTableColumn.IsLong,              typeof(System.Boolean));
616             DataColumn AllowDBNull         = new DataColumn(SchemaTableColumn.AllowDBNull,         typeof(System.Boolean));
617             DataColumn IsReadOnly          = new DataColumn(SchemaTableOptionalColumn.IsReadOnly,   typeof(System.Boolean));
618             DataColumn IsRowVersion        = new DataColumn(SchemaTableOptionalColumn.IsRowVersion, typeof(System.Boolean));
619             DataColumn IsUnique            = new DataColumn(SchemaTableColumn.IsUnique,            typeof(System.Boolean));
620             DataColumn IsKeyColumn         = new DataColumn(SchemaTableColumn.IsKey,               typeof(System.Boolean));
621             DataColumn IsAutoIncrement     = new DataColumn(SchemaTableOptionalColumn.IsAutoIncrement,     typeof(System.Boolean));
622             DataColumn BaseSchemaName      = new DataColumn(SchemaTableColumn.BaseSchemaName,      typeof(System.String));
623             DataColumn BaseCatalogName     = new DataColumn(SchemaTableOptionalColumn.BaseCatalogName,     typeof(System.String));
624             DataColumn BaseTableName       = new DataColumn(SchemaTableColumn.BaseTableName,       typeof(System.String));
625             DataColumn BaseColumnName      = new DataColumn(SchemaTableColumn.BaseColumnName,      typeof(System.String));
626             DataColumn AutoIncrementSeed   = new DataColumn(SchemaTableOptionalColumn.AutoIncrementSeed,   typeof(System.Int64));
627             DataColumn AutoIncrementStep   = new DataColumn(SchemaTableOptionalColumn.AutoIncrementStep,   typeof(System.Int64));
628             DataColumn DefaultValue        = new DataColumn(SchemaTableOptionalColumn.DefaultValue,        typeof(System.Object));
629             DataColumn Expression          = new DataColumn(SchemaTableOptionalColumn.Expression,          typeof(System.String));
630             DataColumn ColumnMapping       = new DataColumn(SchemaTableOptionalColumn.ColumnMapping,       typeof(System.Data.MappingType));
631             DataColumn BaseTableNamespace  = new DataColumn(SchemaTableOptionalColumn.BaseTableNamespace,  typeof(System.String));
632             DataColumn BaseColumnNamespace = new DataColumn(SchemaTableOptionalColumn.BaseColumnNamespace, typeof(System.String));
633
634            ColumnSize.DefaultValue = -1;
635
636            if (table.DataSet != null)
637                BaseCatalogName.DefaultValue =  table.DataSet.DataSetName;
638
639            BaseTableName.DefaultValue = table.TableName;
640            BaseTableNamespace.DefaultValue = table.Namespace;
641            IsRowVersion.DefaultValue = false;
642            IsLong.DefaultValue = false;
643            IsReadOnly.DefaultValue = false;
644            IsKeyColumn.DefaultValue = false;
645            IsAutoIncrement.DefaultValue = false;
646            AutoIncrementSeed.DefaultValue = 0;
647            AutoIncrementStep.DefaultValue = 1;
648
649
650            tempSchemaTable.Columns.Add(ColumnName);
651            tempSchemaTable.Columns.Add(ColumnOrdinal);
652            tempSchemaTable.Columns.Add(ColumnSize);
653            tempSchemaTable.Columns.Add(NumericPrecision);
654            tempSchemaTable.Columns.Add(NumericScale);
655            tempSchemaTable.Columns.Add(DataType);
656            tempSchemaTable.Columns.Add(ProviderType);
657            tempSchemaTable.Columns.Add(IsLong);
658            tempSchemaTable.Columns.Add(AllowDBNull);
659            tempSchemaTable.Columns.Add(IsReadOnly);
660            tempSchemaTable.Columns.Add(IsRowVersion);
661            tempSchemaTable.Columns.Add(IsUnique);
662            tempSchemaTable.Columns.Add(IsKeyColumn);
663            tempSchemaTable.Columns.Add(IsAutoIncrement);
664            tempSchemaTable.Columns.Add(BaseCatalogName);
665            tempSchemaTable.Columns.Add(BaseSchemaName);
666            // specific to datatablereader
667            tempSchemaTable.Columns.Add(BaseTableName);
668            tempSchemaTable.Columns.Add(BaseColumnName);
669            tempSchemaTable.Columns.Add(AutoIncrementSeed);
670            tempSchemaTable.Columns.Add(AutoIncrementStep);
671            tempSchemaTable.Columns.Add(DefaultValue);
672            tempSchemaTable.Columns.Add(Expression);
673            tempSchemaTable.Columns.Add(ColumnMapping);
674            tempSchemaTable.Columns.Add(BaseTableNamespace);
675            tempSchemaTable.Columns.Add(BaseColumnNamespace);
676
677            foreach (DataColumn dc in table.Columns) {
678                DataRow dr = tempSchemaTable.NewRow();
679
680                dr[ColumnName] = dc.ColumnName;
681                dr[ColumnOrdinal] = dc.Ordinal;
682                dr[DataType] = dc.DataType;
683
684                if (dc.DataType == typeof(string)) {
685                    dr[ColumnSize] = dc.MaxLength;
686                }
687
688                dr[AllowDBNull] = dc.AllowDBNull;
689                dr[IsReadOnly] = dc.ReadOnly;
690                dr[IsUnique] = dc.Unique;
691
692                if (dc.AutoIncrement) {
693                    dr[IsAutoIncrement] = true;
694                    dr[AutoIncrementSeed] = dc.AutoIncrementSeed;
695                    dr[AutoIncrementStep] = dc.AutoIncrementStep;
696                }
697
698                if (dc.DefaultValue != DBNull.Value)
699                    dr[DefaultValue] =  dc.DefaultValue;
700
701                if (dc.Expression.Length  != 0)  {
702                    bool hasExternalDependency = false;
703                    DataColumn[] dependency = dc.DataExpression.GetDependency();
704                    for (int j = 0; j < dependency.Length; j++) {
705                        if (dependency[j].Table != table) {
706                            hasExternalDependency = true;
707                            break;
708                        }
709                    }
710                    if (!hasExternalDependency)
711                        dr[Expression] =  dc.Expression;
712                }
713
714                dr[ColumnMapping] =  dc.ColumnMapping;
715                dr[BaseColumnName] = dc.ColumnName;
716                dr[BaseColumnNamespace] = dc.Namespace;
717
718                tempSchemaTable.Rows.Add(dr);
719            }
720
721            foreach(DataColumn key in table.PrimaryKey) {
722                tempSchemaTable.Rows[key.Ordinal][IsKeyColumn] = true;
723            }
724
725
726                tempSchemaTable.AcceptChanges();
727
728            return tempSchemaTable;
729         }
730
731         private void ValidateOpen(string caller) {
732            if (!isOpen)
733                throw ADP.DataReaderClosed(caller);
734        }
735
736        private void ValidateReader() {
737            if (ReaderIsInvalid)
738                throw  ExceptionBuilder.InvalidDataTableReader(currentDataTable.TableName);
739
740            if (IsSchemaChanged) {
741                throw  ExceptionBuilder.DataTableReaderSchemaIsInvalid(currentDataTable.TableName); // may be we can use better error message!
742            }
743
744        }
745
746        private void ValidateState(string caller) {
747            ValidateOpen(caller);
748            if (tableCleared) {
749                throw  ExceptionBuilder.EmptyDataTableReader(currentDataTable.TableName);
750            }
751            // see if without any event raising, if our curent row has some changes!if so reader is invalid.
752            if ((currentDataRow == null) || (currentDataTable == null) ) {//|| (currentDataRow != currentDataTable.Rows[rowCounter])) do we need thios check!
753                ReaderIsInvalid = true;
754                throw  ExceptionBuilder.InvalidDataTableReader(currentDataTable.TableName);
755            }
756            //See if without any event raing, if our rows are deleted, or removed! Reader is not invalid, user should be able to read and reach goo row WebData98325
757            if ((currentDataRow.RowState == DataRowState.Deleted) || (currentDataRow.RowState == DataRowState.Detached) ||currentRowRemoved)
758                 throw  ExceptionBuilder.InvalidCurrentRowInDataTableReader();
759            // user may have called clear (which removes the rows without raing event) or deleted part of rows without raising event!if so reader is invalid.
760            if (0 > rowCounter ||currentDataTable.Rows.Count <= rowCounter) {
761                 ReaderIsInvalid = true;
762                throw  ExceptionBuilder.InvalidDataTableReader(currentDataTable.TableName);
763            }
764            else {
765
766            }
767        }
768
769        private void ValidateRow(Int32 rowPosition) {
770            if (ReaderIsInvalid)
771                throw  ExceptionBuilder.InvalidDataTableReader(currentDataTable.TableName);
772
773            if (0 > rowPosition ||currentDataTable.Rows.Count <= rowPosition) {
774                ReaderIsInvalid = true;
775                throw  ExceptionBuilder.InvalidDataTableReader(currentDataTable.TableName);
776            }
777        }
778  
779 // Event Call backs from DataTableReaderListener,  will invoke these methods
780        internal void SchemaChanged() {
781            IsSchemaChanged = true;
782        }
783        internal void DataTableCleared() {
784            if (!started)
785                return;
786
787             rowCounter = -1;
788             if (!reachEORows)
789                 currentRowRemoved = true;
790        }
791
792        internal void DataChanged(DataRowChangeEventArgs args ) {
793            if ((!started) ||(rowCounter == -1 && !tableCleared))
794                return;
795 /*           if (rowCounter == -1 && tableCleared && args.Action == DataRowAction.Add) {
796                tableCleared = false;
797                return;
798            }
799 */
800            switch (args.Action) {
801                case DataRowAction.Add:
802                    ValidateRow(rowCounter + 1);
803 /*                   if (tableCleared) {
804                        tableCleared = false;
805                        rowCounter++;
806                        currentDataRow = currentDataTable.Rows[rowCounter];
807                        currentRowRemoved = false;
808                    }
809                    else 
810 */
811                     if (currentDataRow == currentDataTable.Rows[rowCounter + 1]) { // check if we moved one position up
812                        rowCounter++;  // if so, refresh the datarow and fix the counter
813                    }
814                    break;
815                case DataRowAction.Delete: // delete
816                case DataRowAction.Rollback:// rejectchanges
817                case DataRowAction.Commit: // acceptchanges
818                    if ( args.Row.RowState == DataRowState.Detached ) {
819                        if (args.Row != currentDataRow) {
820                            if (rowCounter == 0) // if I am at first row and no previous row exist,NOOP
821                                break;
822                            ValidateRow(rowCounter -1);
823                            if (currentDataRow == currentDataTable.Rows[rowCounter - 1]) { // one of previous rows is detached, collection size is changed!
824                                rowCounter--;
825                            }
826                        }
827                        else { // we are proccessing current datarow
828                            currentRowRemoved = true;
829                            if (rowCounter > 0) {  // go back one row, no matter what the state is
830                                rowCounter--;
831                                currentDataRow = currentDataTable.Rows[rowCounter];
832                            }
833                            else {  // we are on 0th row, so reset data to initial state!
834                                rowCounter = -1;
835                                currentDataRow = null;
836                            }
837                        }
838                    }
839                    break;
840                default:
841                    break;
842            }
843        }
844
845     }
846 }