2005-03-06 Daniel Morgan <danielmorgan@verizon.net>
[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, 2005
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.Globalization;
26 using System.Runtime.InteropServices;
27 using System.Text;
28
29 namespace System.Data.OracleClient {
30         public sealed class OracleDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
31         {
32                 #region Fields
33
34                 OracleCommand command;
35                 ArrayList dataTypeNames;
36                 bool disposed = false;
37                 bool isClosed;
38                 bool hasRows;
39                 DataTable schemaTable;
40
41                 int recordsAffected = -1;
42                 OciStatementType statementType;
43                 OciStatementHandle statement;
44
45                 #endregion // Fields
46
47                 #region Constructors
48
49                 internal OracleDataReader (OracleCommand command, OciStatementHandle statement)
50                 {
51                         this.command = command;
52                         this.hasRows = false;
53                         this.isClosed = false;
54                         this.schemaTable = ConstructSchemaTable ();
55                         this.statement = statement;
56                         this.statementType = statement.GetStatementType ();
57                 }
58
59                 internal OracleDataReader (OracleCommand command, OciStatementHandle statement, bool extHasRows ) 
60                 {
61                         this.command = command;
62                         this.hasRows = extHasRows;
63                         this.isClosed = false;
64                         this.schemaTable = ConstructSchemaTable ();
65                         this.statement = statement;
66                         this.statementType = statement.GetStatementType ();
67                 }
68
69
70                 ~OracleDataReader ()
71                 {
72                         Dispose (false);
73                 }
74
75                 #endregion // Constructors
76
77                 #region Properties
78
79                 public int Depth {
80                         get { return 0; }
81                 }
82
83                 public int FieldCount {
84                         get { return statement.ColumnCount; }
85                 }
86
87                 public bool HasRows {
88                         get { return hasRows; }
89                 }
90
91                 public bool IsClosed {
92                         get { return isClosed; }
93                 }
94
95                 public object this [string name] {
96                         get { return GetValue (GetOrdinal (name)); }
97                 }
98
99                 public object this [int i] {
100                         get { return GetValue (i); }
101                 }
102
103                 public int RecordsAffected {
104                         get { 
105                                 if (statementType == OciStatementType.Select)
106                                         return -1;
107                                 else
108                                         return GetRecordsAffected ();
109                         }
110                 }
111
112                 #endregion // Properties
113
114                 #region Methods
115
116                 public void Close ()
117                 {
118                         statement.Dispose();
119                         if (!isClosed) 
120                                 command.CloseDataReader ();
121                         isClosed = true;
122                 }
123
124                 private static DataTable ConstructSchemaTable ()
125                 {
126                         Type booleanType = Type.GetType ("System.Boolean");
127                         Type stringType = Type.GetType ("System.String");
128                         Type intType = Type.GetType ("System.Int32");
129                         Type typeType = Type.GetType ("System.Type");
130                         Type shortType = Type.GetType ("System.Int16");
131
132                         DataTable schemaTable = new DataTable ("SchemaTable");
133                         schemaTable.Columns.Add ("ColumnName", stringType);
134                         schemaTable.Columns.Add ("ColumnOrdinal", intType);
135                         schemaTable.Columns.Add ("ColumnSize", intType);
136                         schemaTable.Columns.Add ("NumericPrecision", shortType);
137                         schemaTable.Columns.Add ("NumericScale", shortType);
138                         schemaTable.Columns.Add ("DataType", typeType);
139                         schemaTable.Columns.Add ("IsLong", booleanType);
140                         schemaTable.Columns.Add ("AllowDBNull", booleanType);
141                         schemaTable.Columns.Add ("IsUnique", booleanType);
142                         schemaTable.Columns.Add ("IsKey", booleanType);
143                         schemaTable.Columns.Add ("IsReadOnly", booleanType);
144                         schemaTable.Columns.Add ("BaseSchemaTable", stringType);
145                         schemaTable.Columns.Add ("BaseCatalogName", stringType);
146                         schemaTable.Columns.Add ("BaseTableName", stringType);
147                         schemaTable.Columns.Add ("BaseColumnName", stringType);
148                         schemaTable.Columns.Add ("BaseSchemaName", stringType);
149
150                         return schemaTable;
151                 }
152
153                 private void Dispose (bool disposing)
154                 {
155                         if (!disposed) {
156                                 if (disposing) {
157                                         schemaTable.Dispose ();
158                                         Close ();
159                                 }
160                                 disposed = true;
161                         }
162                 }
163
164                 public void Dispose ()
165                 {
166                         Dispose (true);
167                         GC.SuppressFinalize (this);
168                 }
169
170                 public bool GetBoolean (int i)
171                 {
172                         throw new NotSupportedException ();
173                 }
174
175                 public byte GetByte (int i)
176                 {
177                         throw new NotSupportedException ();
178                 }
179
180                 public long GetBytes (int i, long fieldOffset, byte[] buffer2, int bufferoffset, int length)
181                 {
182                         object value = GetValue (i);
183                         if (!(value is byte[]))
184                                 throw new InvalidCastException ();
185
186                         if ( buffer2 == null )
187                                 return ((byte []) value).Length; // Return length of data
188
189                         // Copy data into buffer
190                         long lobLength = ((byte []) value).Length;
191                         if ( (lobLength - fieldOffset) < length)
192                                 length = (int) (lobLength - fieldOffset);
193                         Array.Copy ( (byte[]) value, (int) fieldOffset, buffer2, bufferoffset, length);
194                         return length; // return actual read count
195                 }
196
197                 public char GetChar (int i)
198                 {
199                         throw new NotSupportedException ();
200                 }
201
202                 public long GetChars (int i, long fieldOffset, char[] buffer2, int bufferoffset, int length)
203                 {
204                         object value = GetValue (i);
205                         if (!(value is char[]))
206                                 throw new InvalidCastException ();
207                         Array.Copy ((char[]) value, (int) fieldOffset, buffer2, bufferoffset, length);
208                         return ((char[]) value).Length - fieldOffset;
209                 }
210
211                 [MonoTODO]
212                 public IDataReader GetData (int i)
213                 {
214                         throw new NotImplementedException ();
215                 }
216
217                 public string GetDataTypeName (int i)
218                 {
219                         return dataTypeNames [i].ToString ().ToUpper ();
220                 }
221
222                 public DateTime GetDateTime (int i)
223                 {
224                         IConvertible c = (IConvertible) GetValue (i);
225                         return c.ToDateTime (CultureInfo.CurrentCulture);
226                 }
227
228                 public decimal GetDecimal (int i)
229                 {
230                         IConvertible c = (IConvertible) GetValue (i);
231                         return c.ToDecimal (CultureInfo.CurrentCulture);
232                 }
233
234                 public double GetDouble (int i)
235                 {
236                         IConvertible c = (IConvertible) GetValue (i);
237                         return c.ToDouble (CultureInfo.CurrentCulture);
238                 }
239
240                 public Type GetFieldType (int i)
241                 {
242                         OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [i];
243                         return defineHandle.FieldType;
244                 }
245
246                 public float GetFloat (int i)
247                 {
248                         IConvertible c = (IConvertible) GetValue (i);
249                         return c.ToSingle (CultureInfo.CurrentCulture);
250                 }
251
252                 public Guid GetGuid (int i)
253                 {
254                         throw new NotSupportedException ();
255                 }
256
257                 public short GetInt16 (int i)
258                 {
259                         throw new NotSupportedException ();
260                 }
261
262                 public int GetInt32 (int i)
263                 {
264                         IConvertible c = (IConvertible) GetValue (i);
265                         return c.ToInt32 (CultureInfo.CurrentCulture);
266                 }
267
268                 public long GetInt64 (int i)
269                 {
270                         IConvertible c = (IConvertible) GetValue (i);
271                         return c.ToInt64 (CultureInfo.CurrentCulture);
272                 }
273
274                 public string GetName (int i)
275                 {
276                         return statement.GetParameter (i).GetName ();
277                 }
278
279                 [MonoTODO]
280                 public OracleBFile GetOracleBFile (int i)
281                 {
282                         throw new NotImplementedException ();
283                 }
284
285                 [MonoTODO]
286                 public OracleBinary GetOracleBinary (int i)
287                 {
288                         if (IsDBNull (i))
289                                 throw new InvalidOperationException("The value is null");
290
291                         return new OracleBinary ((byte[]) GetValue (i));
292                 }
293
294                 public OracleLob GetOracleLob (int i)
295                 {
296                         if (IsDBNull (i))
297                                 throw new InvalidOperationException("The value is null");
298
299                         OracleLob output = (OracleLob) ((OciDefineHandle) statement.Values [i]).GetValue();
300                         output.connection = command.Connection;
301                         return output;
302                 }
303
304                 public OracleNumber GetOracleNumber (int i)
305                 {
306                         if (IsDBNull (i))
307                                 throw new InvalidOperationException("The value is null");
308
309                         return new OracleNumber (GetDecimal (i));
310                 }
311
312                 public OracleDateTime GetOracleDateTime (int i)
313                 {
314                         if (IsDBNull (i))
315                                 throw new InvalidOperationException("The value is null");
316
317                         return new OracleDateTime (GetDateTime (i));
318                 }
319
320                 [MonoTODO]
321                 public OracleMonthSpan GetOracleMonthSpan (int i)
322                 {
323                         throw new NotImplementedException ();
324                 }
325
326                 public OracleString GetOracleString (int i)
327                 {
328                         if (IsDBNull (i))
329                                 throw new InvalidOperationException("The value is null");
330
331                         return new OracleString (GetString (i));
332                 }
333
334                 public object GetOracleValue (int i)
335                 {
336                         OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [i];
337
338                         switch (defineHandle.DataType) {
339                         case OciDataType.Raw:
340                                 return GetOracleBinary (i);
341                         case OciDataType.Date:
342                                 return GetOracleDateTime (i);
343                         case OciDataType.Clob:
344                         case OciDataType.Blob:
345                                 return GetOracleLob (i);
346                         case OciDataType.Integer:
347                         case OciDataType.Number:
348                         case OciDataType.Float:
349                                 return GetOracleNumber (i);
350                         case OciDataType.VarChar2:
351                         case OciDataType.String:
352                         case OciDataType.VarChar:
353                         case OciDataType.Char:
354                         case OciDataType.CharZ:
355                         case OciDataType.OciString:
356                         case OciDataType.LongVarChar:
357                         case OciDataType.Long:
358                         case OciDataType.RowIdDescriptor:
359                                 return GetOracleString (i);
360                         default:
361                                 throw new NotImplementedException ();
362                         }
363                 }
364
365                 public int GetOracleValues (object[] values)
366                 {
367                         int len = values.Length;
368                         int count = statement.ColumnCount;
369                         int retval = 0;
370
371                         if (len > count)
372                                 retval = count;
373                         else
374                                 retval = len;
375
376                         for (int i = 0; i < retval; i += 1) 
377                                 values [i] = GetOracleValue (i);
378
379                         return retval;
380                 }
381
382                 [MonoTODO]
383                 public OracleTimeSpan GetOracleTimeSpan (int i)
384                 {
385                         return new OracleTimeSpan (GetTimeSpan (i));
386                 }
387
388                 public int GetOrdinal (string name)
389                 {
390                         int i;
391                         
392                         for (i = 0; i < statement.ColumnCount; i += 1) {
393                                 if (String.Compare (statement.GetParameter(i).GetName(), name, false) == 0)
394                                         return i;
395                         }
396
397                         for (i = 0; i < statement.ColumnCount; i += 1) {
398                                 if (String.Compare (statement.GetParameter(i).GetName(), name, true) == 0)
399                                         return i;
400                         }
401
402                         throw new IndexOutOfRangeException ();
403                 }
404
405                 private int GetRecordsAffected ()
406                 {
407                         if (recordsAffected == -1) 
408                                 recordsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, command.ErrorHandle);
409                         return recordsAffected;
410                 }
411
412                 public DataTable GetSchemaTable ()
413                 {
414                         if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
415                                 return schemaTable;
416
417                         dataTypeNames = new ArrayList ();
418
419                         for (int i = 0; i < statement.ColumnCount; i += 1) {
420                                 DataRow row = schemaTable.NewRow ();
421
422                                 OciParameterDescriptor parameter = statement.GetParameter (i);
423
424                                 dataTypeNames.Add (parameter.GetDataTypeName ());
425
426                                 row ["ColumnName"]              = parameter.GetName ();
427                                 row ["ColumnOrdinal"]           = i + 1;
428                                 row ["ColumnSize"]              = parameter.GetDataSize ();
429                                 row ["NumericPrecision"]        = parameter.GetPrecision ();
430                                 row ["NumericScale"]            = parameter.GetScale ();
431                                 string sDataTypeName = parameter.GetDataTypeName ();
432                                 row ["DataType"]                = parameter.GetFieldType (sDataTypeName);
433                                 row ["AllowDBNull"]             = parameter.GetIsNull ();
434                                 row ["BaseColumnName"]          = parameter.GetName ();
435                                 row ["IsReadOnly"]              = true;
436
437                                 schemaTable.Rows.Add (row);
438                         }
439
440                         return schemaTable;
441                 }
442
443                 public string GetString (int i)
444                 {
445                         object value = GetValue (i);
446                         if (!(value is string))
447                                 throw new InvalidCastException ();
448                         return (string) value;
449                 }
450
451                 public TimeSpan GetTimeSpan (int i)
452                 {
453                         object value = GetValue (i);
454                         if (!(value is TimeSpan))
455                                 throw new InvalidCastException ();
456                         return (TimeSpan) value;
457                 }
458
459                 public object GetValue (int i)
460                 {
461                         OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [i];
462
463                         if (defineHandle.IsNull)
464                                 return DBNull.Value;
465
466                         switch (defineHandle.DataType) {
467                         case OciDataType.Blob:
468                         case OciDataType.Clob:
469                                 OracleLob lob = GetOracleLob (i);
470                                 object value = lob.Value;
471                                 lob.Close ();
472                                 return value;
473                         default:
474                                 return defineHandle.GetValue ();
475                         }
476                 }
477
478                 public int GetValues (object[] values)
479                 {
480                         int len = values.Length;
481                         int count = statement.ColumnCount;
482                         int retval = 0;
483
484                         if (len > count)
485                                 retval = count;
486                         else
487                                 retval = len;
488
489                         for (int i = 0; i < retval; i += 1) 
490                                 values [i] = GetValue (i);
491
492                         return retval;
493                 }
494
495                 IEnumerator IEnumerable.GetEnumerator ()
496                 {
497                         return new DbEnumerator (this);
498                 }
499
500                 public bool IsDBNull (int i)
501                 {
502                         OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [i];
503                         return defineHandle.IsNull;
504                 }
505
506                 [MonoTODO]
507                 public bool NextResult ()
508                 {
509                         // FIXME: get next result
510                         return false; 
511                 }
512
513                 public bool Read ()
514                 {
515                         bool retval = statement.Fetch ();
516                         hasRows = retval;
517                         return retval;
518                 }
519
520                 #endregion // Methods
521         }
522 }