Applied patch from: David Pickens <dsp@rci.rutgers.edu>
[mono.git] / mcs / class / System.Data.OracleClient / System.Data.OracleClient / OracleDataReader.cs
1 //
2 // OracleDataReader.cs 
3 //
4 // Part of the Mono class libraries at
5 // mcs/class/System.Data.OracleClient/System.Data.OracleClient
6 //
7 // Assembly: System.Data.OracleClient.dll
8 // Namespace: System.Data.OracleClient
9 //
10 // Authors: Tim Coleman <tim@timcoleman.com>
11 //          Daniel Morgan <danmorg@sc.rr.com>
12 //
13 // Copyright (C) Tim Coleman, 2003
14 // Copyright (C) Daniel Morgan, 2003
15 //
16 // Licensed under the MIT/X11 License.
17 //
18
19 using System;
20 using System.Collections;
21 using System.ComponentModel;
22 using System.Data;
23 using System.Data.Common;
24 using System.Data.OracleClient.Oci;
25 using System.Runtime.InteropServices;
26
27 namespace System.Data.OracleClient {
28         public sealed class OracleDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
29         {
30                 #region Fields
31
32                 OracleCommand command;
33                 ArrayList dataTypeNames;
34                 bool disposed = false;
35                 bool isClosed;
36                 bool hasRows;
37                 bool moreResults;
38                 DataTable schemaTable;
39
40                 int recordsAffected = -1;
41                 OciStatementType statementType;
42                 OciStatementHandle statement;
43
44                 #endregion // Fields
45
46                 #region Constructors
47
48                 internal OracleDataReader (OracleCommand command, OciStatementHandle statement)
49                 {
50                         this.command = command;
51                         this.hasRows = false;
52                         this.isClosed = false;
53                         this.schemaTable = ConstructSchemaTable ();
54                         this.statement = statement;
55                         this.statementType = statement.GetStatementType ();
56                 }
57
58                 ~OracleDataReader ()
59                 {
60                         Dispose ();
61                 }
62
63                 #endregion // Constructors
64
65                 #region Properties
66
67                 public int Depth {
68                         get { return 0; }
69                 }
70
71                 public int FieldCount {
72                         get { return statement.ColumnCount; }
73                 }
74
75                 public bool HasRows {
76                         get { return hasRows; }
77                 }
78
79                 public bool IsClosed {
80                         get { return isClosed; }
81                 }
82
83                 public object this [string name] {
84                         get { return GetValue (GetOrdinal (name)); }
85                 }
86
87                 public object this [int i] {
88                         get { return GetValue (i); }
89                 }
90
91                 public int RecordsAffected {
92                         get { 
93                                 if (statementType == OciStatementType.Select)
94                                         return -1;
95                                 else
96                                         return GetRecordsAffected ();
97                         }
98                 }
99
100                 #endregion // Properties
101
102                 #region Methods
103
104                 public void Close ()
105                 {
106                         if (!isClosed) 
107                                 command.CloseDataReader ();
108                         isClosed = true;
109                 }
110
111                 private static DataTable ConstructSchemaTable ()
112                 {
113                         Type booleanType = Type.GetType ("System.Boolean");
114                         Type stringType = Type.GetType ("System.String");
115                         Type intType = Type.GetType ("System.Int32");
116                         Type typeType = Type.GetType ("System.Type");
117                         Type shortType = Type.GetType ("System.Int16");
118
119                         DataTable schemaTable = new DataTable ("SchemaTable");
120                         schemaTable.Columns.Add ("ColumnName", stringType);
121                         schemaTable.Columns.Add ("ColumnOrdinal", intType);
122                         schemaTable.Columns.Add ("ColumnSize", intType);
123                         schemaTable.Columns.Add ("NumericPrecision", shortType);
124                         schemaTable.Columns.Add ("NumericScale", shortType);
125                         schemaTable.Columns.Add ("DataType", typeType);
126                         schemaTable.Columns.Add ("IsLong", booleanType);
127                         schemaTable.Columns.Add ("AllowDBNull", booleanType);
128                         schemaTable.Columns.Add ("IsUnique", booleanType);
129                         schemaTable.Columns.Add ("IsKey", booleanType);
130                         schemaTable.Columns.Add ("IsReadOnly", booleanType);
131                         schemaTable.Columns.Add ("BaseSchemaTable", stringType);
132                         schemaTable.Columns.Add ("BaseCatalogName", stringType);
133                         schemaTable.Columns.Add ("BaseTableName", stringType);
134                         schemaTable.Columns.Add ("BaseColumnName", stringType);
135                         schemaTable.Columns.Add ("BaseSchemaName", stringType);
136
137                         return schemaTable;
138                 }
139
140                 private void Dispose (bool disposing)
141                 {
142                         if (!disposed) {
143                                 if (disposing) {
144                                         schemaTable.Dispose ();
145                                         Close ();
146                                 }
147                                 disposed = true;
148                         }
149                 }
150
151                 public void Dispose ()
152                 {
153                         Dispose (true);
154                         GC.SuppressFinalize (this);
155                 }
156
157                 public bool GetBoolean (int i)
158                 {
159                         throw new NotSupportedException ();
160                 }
161
162                 public byte GetByte (int i)
163                 {
164                         throw new NotSupportedException ();
165                 }
166
167                 public long GetBytes (int i, long fieldOffset, byte[] buffer2, int bufferoffset, int length)
168                 {
169                         object value = GetValue (i);
170                         if (!(value is byte[]))
171                                 throw new InvalidCastException ();
172                         Array.Copy ((byte[]) value, (int) fieldOffset, buffer2, bufferoffset, length);
173                         return ((byte[]) value).Length - fieldOffset;
174                 }
175
176                 public char GetChar (int i)
177                 {
178                         throw new NotSupportedException ();
179                 }
180
181                 public long GetChars (int i, long fieldOffset, char[] buffer2, int bufferoffset, int length)
182                 {
183                         object value = GetValue (i);
184                         if (!(value is char[]))
185                                 throw new InvalidCastException ();
186                         Array.Copy ((char[]) value, (int) fieldOffset, buffer2, bufferoffset, length);
187                         return ((char[]) value).Length - fieldOffset;
188                 }
189
190                 [MonoTODO]
191                 public IDataReader GetData (int i)
192                 {
193                         throw new NotImplementedException ();
194                 }
195
196                 public string GetDataTypeName (int i)
197                 {
198                         return (string) dataTypeNames [i];
199                 }
200
201                 public DateTime GetDateTime (int i)
202                 {
203                         object value = GetValue (i);
204                         if (!(value is DateTime))
205                                 throw new InvalidCastException ();
206                         return (DateTime) value;
207                 }
208
209                 public decimal GetDecimal (int i)
210                 {
211                         object value = GetValue (i);
212                         if (!(value is decimal))
213                                 throw new InvalidCastException ();
214                         return (decimal) value;
215                 }
216
217                 public double GetDouble (int i)
218                 {
219                         object value = GetValue (i);
220                         if (!(value is double))
221                                 throw new InvalidCastException ();
222                         return (double) value;
223                 }
224
225                 public Type GetFieldType (int i)
226                 {
227                         // FIXME: "DataType" need to implement
228                         //OciColumnInfo columnInfo = command.StatementHandle.DescribeColumn (i);
229                         //Type fieldType = OciGlue.OciDataTypeToDbType (columnInfo.DataType);
230                         //return fieldType;
231                         return typeof(string);
232                 }
233
234                 public float GetFloat (int i)
235                 {
236                         object value = GetValue (i);
237                         if (!(value is float))
238                                 throw new InvalidCastException ();
239                         return (float) value;
240                 }
241
242                 public Guid GetGuid (int i)
243                 {
244                         throw new NotSupportedException ();
245                 }
246
247                 public short GetInt16 (int i)
248                 {
249                         throw new NotSupportedException ();
250                 }
251
252                 public int GetInt32 (int i)
253                 {
254                         object value = GetValue (i);
255                         if (!(value is int))
256                                 throw new InvalidCastException ();
257                         return (int) value;
258                 }
259
260                 public long GetInt64 (int i)
261                 {
262                         object value = GetValue (i);
263                         if (!(value is long))
264                                 throw new InvalidCastException ();
265                         return (long) value;
266                 }
267
268                 public string GetName (int i)
269                 {
270                         return statement.GetParameter (i).GetName ();
271                 }
272
273                 [MonoTODO]
274                 public OracleBFile GetOracleBFile (int i)
275                 {
276                         throw new NotImplementedException ();
277                 }
278
279                 [MonoTODO]
280                 public OracleBinary GetOracleBinary (int i)
281                 {
282                         throw new NotImplementedException ();
283                 }
284
285                 public OracleLob GetOracleLob (int i)
286                 {
287                         OracleLob output = ((OciDefineHandle) statement.Values [i]).GetOracleLob ();
288                         output.connection = command.Connection;
289                         return output;
290                 }
291
292                 public OracleNumber GetOracleNumber (int i)
293                 {
294                         return new OracleNumber ((decimal) GetValue (i));
295                 }
296
297                 public int GetOrdinal (string name)
298                 {
299                         int i;
300                         
301                         for (i = 0; i < statement.ColumnCount; i += 1) {
302                                 if (String.Compare (statement.GetParameter(i).GetName(), name, false) == 0)
303                                         return i;
304                         }
305
306                         for (i = 0; i < statement.ColumnCount; i += 1) {
307                                 if (String.Compare (statement.GetParameter(i).GetName(), name, true) == 0)
308                                         return i;
309                         }
310
311                         throw new IndexOutOfRangeException ();
312                 }
313
314                 private int GetRecordsAffected ()
315                 {
316                         if (recordsAffected == -1) 
317                                 recordsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, command.ErrorHandle);
318                         return recordsAffected;
319                 }
320
321                 public DataTable GetSchemaTable ()
322                 {
323                         if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
324                                 return schemaTable;
325
326                         dataTypeNames = new ArrayList ();
327
328                         for (int i = 0; i < statement.ColumnCount; i += 1) {
329                                 DataRow row = schemaTable.NewRow ();
330
331                                 OciParameterDescriptor parameter = statement.GetParameter (i);
332
333                                 dataTypeNames.Add(parameter.GetDataTypeName());
334
335                                 row ["ColumnName"]              = parameter.GetName ();
336                                 row ["ColumnOrdinal"]           = i + 1;
337                                 row ["ColumnSize"]              = parameter.GetDataSize ();
338                                 row ["NumericPrecision"]        = parameter.GetPrecision ();
339                                 row ["NumericScale"]            = parameter.GetScale ();
340                                 // FIXME: "DataType" need to implement
341                                 //row ["DataType"] = OciGlue.OciDataTypeToDbType (columnInfo.DataType);
342                                 row ["DataType"]                = typeof(string);
343                                 row ["AllowDBNull"]             = parameter.GetIsNull ();
344                                 row ["BaseColumnName"]          = parameter.GetName ();
345                                 row ["IsReadOnly"]              = true;
346
347                                 schemaTable.Rows.Add (row);
348                         }
349
350                         return schemaTable;
351                 }
352
353                 public string GetString (int i)
354                 {
355                         object value = GetValue (i);
356                         if (!(value is string))
357                                 throw new InvalidCastException ();
358                         return (string) value;
359                 }
360
361                 public TimeSpan GetTimeSpan (int i)
362                 {
363                         object value = GetValue (i);
364                         if (!(value is TimeSpan))
365                                 throw new InvalidCastException ();
366                         return (TimeSpan) value;
367                 }
368
369                 public object GetValue (int i)
370                 {
371                         OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [i];
372
373                         if (IsDBNull (i))
374                                 return DBNull.Value;
375
376                         return defineHandle.GetValue ();
377                 }
378
379                 public int GetValues (object[] values)
380                 {
381                         int len = values.Length;
382                         int count = statement.ColumnCount;
383                         int retval = 0;
384
385                         if (len > count)
386                                 retval = count;
387                         else
388                                 retval = len;
389
390                         for (int i = 0; i < retval; i += 1) 
391                                 values [i] = GetValue (i);
392
393                         return retval;
394                 }
395
396                 IEnumerator IEnumerable.GetEnumerator ()
397                 {
398                         return new DbEnumerator (this);
399                 }
400
401                 public bool IsDBNull (int i)
402                 {
403                         return ((OciDefineHandle) statement.Values [i]).IsNull;
404                 }
405
406                 [MonoTODO]
407                 public bool NextResult ()
408                 {
409                         // FIXME: get next result
410                         //throw new NotImplementedException ();
411                         return false; 
412                 }
413
414                 public bool Read ()
415                 {
416                         bool retval = statement.Fetch ();
417                         return retval;
418                         //return command.StatementHandle.Fetch ();
419                 }
420
421                 #endregion // Methods
422         }
423 }