[runtime] Overwrite stacktrace for exception on re-throw. Fixes #1856.
[mono.git] / mcs / class / System.Data / System.Data.Common / RecordCache.cs
1 //
2 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 using System;
24 using System.Collections;
25
26 namespace System.Data.Common
27 {
28         internal class RecordCache {
29                 #region Fields
30
31                 const int MIN_CACHE_SIZE = 128;
32
33                 Stack _records = new Stack (16);
34                 int _nextFreeIndex = 0;
35                 int _currentCapacity = 0;
36                 DataTable _table;
37                 DataRow [] _rowsToRecords;
38
39                 #endregion // Fields
40
41                 #region Constructors
42
43                 internal RecordCache (DataTable table)
44                 {
45                         _table = table;
46                         _rowsToRecords = table.NewRowArray (16);
47                 }
48
49                 #endregion //Constructors
50
51                 #region Properties
52
53                 internal int CurrentCapacity {
54                         get { return _currentCapacity; }
55                 }
56
57                 internal DataRow this [int index] {
58                         get { return _rowsToRecords [index]; }
59                         set {
60                                 if (index >= 0)
61                                         _rowsToRecords [index] = value;
62                         }
63                 }
64
65                 #endregion // Properties
66
67                 #region Methods
68
69                 internal int NewRecord ()
70                 {
71                         if (_records.Count > 0)
72                                 return (int) _records.Pop ();
73
74                         DataColumnCollection cols = _table.Columns;
75                         if (_nextFreeIndex >= _currentCapacity) {
76                                 _currentCapacity *= 2;
77                                 if (_currentCapacity < MIN_CACHE_SIZE)
78                                         _currentCapacity = MIN_CACHE_SIZE;
79
80                                 for (int i = 0; i < cols.Count; ++i)
81                                         cols [i].DataContainer.Capacity = _currentCapacity;
82
83                                 DataRow [] old = _rowsToRecords;
84                                 _rowsToRecords = _table.NewRowArray (_currentCapacity);
85                                 Array.Copy (old, 0, _rowsToRecords, 0, old.Length);
86                         }
87                         return _nextFreeIndex++;
88                 }
89
90                 internal void DisposeRecord (int index)
91                 {
92                         if (index < 0)
93                                 throw new ArgumentException ();
94
95                         if (!_records.Contains (index))
96                                 _records.Push (index);
97
98                         this [index] = null;
99                 }
100
101                 // FIXME: This doesn't seem to be the right class to have this method
102                 internal int CopyRecord (DataTable fromTable, int fromRecordIndex, int toRecordIndex)
103                 {
104                         int recordIndex = toRecordIndex;
105                         if (toRecordIndex == -1)
106                                 recordIndex = NewRecord ();
107
108                         try {
109                                 foreach (DataColumn toColumn in _table.Columns) {
110                                         DataColumn fromColumn = fromTable.Columns [toColumn.ColumnName];
111                                         if (fromColumn != null)
112                                                 toColumn.DataContainer.CopyValue (fromColumn.DataContainer, fromRecordIndex, recordIndex);
113                                         else
114                                                 toColumn.DataContainer.CopyValue (_table.DefaultValuesRowIndex, recordIndex);                                   
115                                 }
116                                 return recordIndex;
117                         } catch {
118                                 if (toRecordIndex == -1)
119                                         DisposeRecord (recordIndex);
120
121                                 throw;
122                         }
123                 }
124
125                 // FIXME: This doesn't seem to be the right class to have this method
126                 internal void ReadIDataRecord (int recordIndex, IDataRecord record, int [] mapping, int length)
127                 {
128                         if (mapping.Length > _table.Columns.Count)
129                                 throw new ArgumentException ();
130
131                         int i = 0;
132                         for(; i < length; i++) {
133                                 DataColumn column = _table.Columns [mapping [i]];
134                                 column.DataContainer.SetItemFromDataRecord (recordIndex, record, i);
135                         }
136
137                         for (; i < mapping.Length; i++) {
138                                 DataColumn column = _table.Columns [mapping [i]];
139                                 if (column.AutoIncrement)
140                                         column.DataContainer [recordIndex] = column.AutoIncrementValue ();
141                                 else
142                                         column.DataContainer [recordIndex] = column.DefaultValue;
143                         }
144                 }
145
146                 #endregion // Methods
147         }
148 }