2002-08-20 Rodrigo Moya <rodrigo@ximian.com>
[mono.git] / mcs / class / System.Data / System.Data.OleDb / OleDbDataReader.cs
1 //
2 // System.Data.OleDb.OleDbDataReader
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Tim Coleman (tim@timcoleman.com)
7 //
8 // Copyright (C) Rodrigo Moya, 2002
9 // Copyright (C) Tim Coleman, 2002
10 //
11
12 using System.Collections;
13 using System.ComponentModel;
14 using System.Data;
15 using System.Data.Common;
16 using System.Runtime.InteropServices;
17
18 namespace System.Data.OleDb
19 {
20         public sealed class OleDbDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
21         {
22                 #region Fields
23                 
24                 private OleDbCommand command;
25                 private bool open;
26                 private ArrayList gdaResults;
27                 private int currentResult;
28                 private int currentRow;
29
30                 #endregion
31
32                 #region Constructors
33
34                 internal OleDbDataReader (OleDbCommand command, ArrayList results) 
35                 {
36                         this.command = command;
37                         this.command.Connection.DataReader = this;
38                         open = true;
39                         if (results != null)
40                                 gdaResults = results;
41                         else
42                                 gdaResults = new ArrayList ();
43                         currentResult = -1;
44                         currentRow = -1;
45                 }
46
47                 #endregion
48
49                 #region Properties
50
51                 public int Depth {
52                         get {
53                                 return 0; // no nested selects supported
54                         }
55                 }
56
57                 public int FieldCount {
58                         get {
59                                 if (currentResult < 0 ||
60                                     currentResult >= gdaResults.Count)
61                                         return 0;
62
63                                 return libgda.gda_data_model_get_n_columns (
64                                         (IntPtr) gdaResults[currentResult]);
65                         }
66                 }
67
68                 public bool IsClosed {
69                         get {
70                                 return !open;
71                         }
72                 }
73
74                 public object this[string name] {
75                         get {
76                                 int pos;
77
78                                 if (currentResult == -1)
79                                         throw new InvalidOperationException ();
80
81                                 pos = libgda.gda_data_model_get_column_position (
82                                         (IntPtr) gdaResults[currentResult],
83                                         name);
84                                 if (pos == -1)
85                                         throw new IndexOutOfRangeException ();
86
87                                 return this[pos];
88                         }
89                 }
90
91                 public object this[int index] {
92                         get {
93                                 return (object) GetValue (index);
94                         }
95                 }
96
97                 public int RecordsAffected {
98                         get {
99                                 int total_rows;
100                                 
101                                 if (currentResult < 0 ||
102                                     currentResult >= gdaResults.Count)
103                                         return 0;
104
105                                 total_rows = libgda.gda_data_model_get_n_rows (
106                                         (IntPtr) gdaResults[currentResult]);
107                                 if (total_rows > 0) {
108                                         if (FieldCount > 0) {
109                                                 // It's a SELECT statement
110                                                 return -1;
111                                         }
112                                 }
113
114                                 return FieldCount > 0 ? -1 : total_rows;
115                         }
116                 }
117
118                 #endregion
119
120                 #region Methods
121
122                 public void Close ()
123                 {
124                         for (int i = 0; i < gdaResults.Count; i++) {
125                                 IntPtr obj = (IntPtr) gdaResults[i];
126                                 libgda.FreeObject (obj);
127                         }
128
129                         gdaResults.Clear ();
130                         gdaResults = null;
131                         
132                         open = false;
133                         currentResult = -1;
134                         currentRow = -1;
135
136                         this.command.Connection.DataReader = null;
137                 }
138
139                 ~OleDbDataReader ()
140                 {
141                         if (open)
142                                 Close ();
143                 }
144
145                 public bool GetBoolean (int ordinal)
146                 {
147                         IntPtr value;
148
149                         if (currentResult == -1)
150                                 throw new InvalidCastException ();
151
152                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
153                                                                     ordinal, currentRow);
154                         if (value == IntPtr.Zero)
155                                 throw new InvalidCastException ();
156                         
157                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Boolean)
158                                 throw new InvalidCastException ();
159                         return libgda.gda_value_get_boolean (value);
160                 }
161
162                 public byte GetByte (int ordinal)
163                 {
164                         IntPtr value;
165
166                         if (currentResult == -1)
167                                 throw new InvalidCastException ();
168
169                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
170                                                                     ordinal, currentRow);
171                         if (value == IntPtr.Zero)
172                                 throw new InvalidCastException ();
173                         
174                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Tinyint)
175                                 throw new InvalidCastException ();
176                         return libgda.gda_value_get_tinyint (value);
177                 }
178
179                 [MonoTODO]
180                 public long GetBytes (int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length)
181                 {
182                         throw new NotImplementedException ();
183                 }
184                 
185                 public char GetChar (int ordinal)
186                 {
187                         IntPtr value;
188
189                         if (currentResult == -1)
190                                 throw new InvalidCastException ();
191
192                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
193                                                                     ordinal, currentRow);
194                         if (value == IntPtr.Zero)
195                                 throw new InvalidCastException ();
196                         
197                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Tinyint)
198                                 throw new InvalidCastException ();
199                         return (char) libgda.gda_value_get_tinyint (value);
200                 }
201
202                 [MonoTODO]
203                 public long GetChars (int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length)
204                 {
205                         throw new NotImplementedException ();
206                 }
207
208                 [MonoTODO]
209                 public OleDbDataReader GetData (int ordinal)
210                 {
211                         throw new NotImplementedException ();
212                 }
213
214                 public string GetDataTypeName (int index)
215                 {
216                         IntPtr attrs;
217                         GdaValueType type;
218
219                         if (currentResult == -1)
220                                 return "unknown";
221
222                         
223                         attrs = libgda.gda_data_model_describe_column ((IntPtr) gdaResults[currentResult],
224                                                                        index);
225                         if (attrs == IntPtr.Zero)
226                                 return "unknown";
227
228                         type = libgda.gda_field_attributes_get_gdatype (attrs);
229                         libgda.gda_field_attributes_free (attrs);
230                         
231                         return libgda.gda_type_to_string (type);
232                 }
233
234                 public DateTime GetDateTime (int ordinal)
235                 {
236                         IntPtr value;
237                         DateTime dt;
238
239                         if (currentResult == -1)
240                                 throw new InvalidCastException ();
241
242                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
243                                                                     ordinal, currentRow);
244                         if (value == IntPtr.Zero)
245                                 throw new InvalidCastException ();
246                         
247                         if (libgda.gda_value_get_vtype (value) == GdaValueType.Date) {
248                                 GdaDate gdt;
249
250                                 gdt = (GdaDate) Marshal.PtrToStructure (libgda.gda_value_get_date (value),
251                                                                         typeof (GdaDate));
252                                 return new DateTime ((int) gdt.year, (int) gdt.month, (int) gdt.day);
253                         } else if (libgda.gda_value_get_vtype (value) == GdaValueType.Time) {
254                                 GdaTime gdt;
255
256                                 gdt = (GdaTime) Marshal.PtrToStructure (libgda.gda_value_get_time (value),
257                                                                         typeof (GdaTime));
258                                 return new DateTime (0, 0, 0, (int) gdt.hour, (int) gdt.minute, (int) gdt.second, 0);
259                         } else if (libgda.gda_value_get_vtype (value) == GdaValueType.Timestamp) {
260                                 GdaTimestamp gdt;
261                                 
262                                 gdt = (GdaTimestamp) Marshal.PtrToStructure (libgda.gda_value_get_timestamp (value),
263                                                                              typeof (GdaTimestamp));
264
265                                 return new DateTime ((int) gdt.year, (int) gdt.month, (int) gdt.day,
266                                                      (int) gdt.hour, (int) gdt.minute, (int) gdt.second,
267                                                      (int) gdt.fraction);
268                         }
269
270                         throw new InvalidCastException ();
271                 }
272
273                 [MonoTODO]
274                 public decimal GetDecimal (int ordinal)
275                 {
276                         throw new NotImplementedException ();
277                 }
278
279                 public double GetDouble (int ordinal)
280                 {
281                         IntPtr value;
282
283                         if (currentResult == -1)
284                                 throw new InvalidCastException ();
285
286                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
287                                                                     ordinal, currentRow);
288                         if (value == IntPtr.Zero)
289                                 throw new InvalidCastException ();
290                         
291                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Double)
292                                 throw new InvalidCastException ();
293                         return libgda.gda_value_get_double (value);
294                 }
295
296                 [MonoTODO]
297                 public Type GetFieldType (int index)
298                 {
299                         throw new NotImplementedException ();
300                 }
301
302                 public float GetFloat (int ordinal)
303                 {
304                         IntPtr value;
305
306                         if (currentResult == -1)
307                                 throw new InvalidCastException ();
308
309                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
310                                                                     ordinal, currentRow);
311                         if (value == IntPtr.Zero)
312                                 throw new InvalidCastException ();
313                         
314                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Single)
315                                 throw new InvalidCastException ();
316                         return libgda.gda_value_get_single (value);
317                 }
318
319                 [MonoTODO]
320                 public Guid GetGuid (int ordinal)
321                 {
322                         throw new NotImplementedException ();
323                 }
324
325                 public short GetInt16 (int ordinal)
326                 {
327                         IntPtr value;
328
329                         if (currentResult == -1)
330                                 throw new InvalidCastException ();
331
332                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
333                                                                     ordinal, currentRow);
334                         if (value == IntPtr.Zero)
335                                 throw new InvalidCastException ();
336                         
337                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Smallint)
338                                 throw new InvalidCastException ();
339                         return (short) libgda.gda_value_get_smallint (value);
340                 }
341
342                 public int GetInt32 (int ordinal)
343                 {
344                         IntPtr value;
345
346                         if (currentResult == -1)
347                                 throw new InvalidCastException ();
348
349                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
350                                                                     ordinal, currentRow);
351                         if (value == IntPtr.Zero)
352                                 throw new InvalidCastException ();
353                         
354                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Integer)
355                                 throw new InvalidCastException ();
356                         return libgda.gda_value_get_integer (value);
357                 }
358
359                 public long GetInt64 (int ordinal)
360                 {
361                         IntPtr value;
362
363                         if (currentResult == -1)
364                                 throw new InvalidCastException ();
365
366                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
367                                                                     ordinal, currentRow);
368                         if (value == IntPtr.Zero)
369                                 throw new InvalidCastException ();
370                         
371                         if (libgda.gda_value_get_vtype (value) != GdaValueType.Bigint)
372                                 throw new InvalidCastException ();
373                         return libgda.gda_value_get_bigint (value);
374                 }
375
376                 public string GetName (int index)
377                 {
378                         if (currentResult == -1)
379                                 return null;
380
381                         return libgda.gda_data_model_get_column_title (
382                                 (IntPtr) gdaResults[currentResult], index);
383                 }
384
385                 public int GetOrdinal (string name)
386                 {
387                         if (currentResult == -1)
388                                 throw new IndexOutOfRangeException ();
389
390                         for (int i = 0; i < FieldCount; i++) {
391                                 if (GetName (i) == name)
392                                         return i;
393                         }
394
395                         throw new IndexOutOfRangeException ();
396                 }
397
398                 public DataTable GetSchemaTable ()
399                 {
400                         DataTable table = new DataTable ();
401
402                         // FIXME: implement
403                         return table;
404                 }
405
406                 public string GetString (int ordinal)
407                 {
408                         IntPtr value;
409
410                         if (currentResult == -1)
411                                 throw new InvalidCastException ();
412
413                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
414                                                                     ordinal, currentRow);
415                         if (value == IntPtr.Zero)
416                                 throw new InvalidCastException ();
417                         
418                         if (libgda.gda_value_get_vtype (value) != GdaValueType.String)
419                                 throw new InvalidCastException ();
420                         return libgda.gda_value_get_string (value);
421                 }
422
423                 [MonoTODO]
424                 public TimeSpan GetTimeSpan (int ordinal)
425                 {
426                         throw new NotImplementedException ();
427                 }
428
429                 public object GetValue (int ordinal)
430                 {
431                         IntPtr value;
432                         GdaValueType type;
433
434                         if (currentResult == -1)
435                                 throw new IndexOutOfRangeException ();
436
437                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
438                                                                     ordinal, currentRow);
439                         if (value == IntPtr.Zero)
440                                 throw new IndexOutOfRangeException ();
441
442                         type = libgda.gda_value_get_vtype (value);
443                         switch (type) {
444                         case GdaValueType.Bigint : return GetInt64 (ordinal);
445                         case GdaValueType.Boolean : return GetBoolean (ordinal);
446                         case GdaValueType.Date : return GetDateTime (ordinal);
447                         case GdaValueType.Double : return GetDouble (ordinal);
448                         case GdaValueType.Integer : return GetInt32 (ordinal);
449                         case GdaValueType.Single : return GetFloat (ordinal);
450                         case GdaValueType.Smallint : return GetByte (ordinal);
451                         case GdaValueType.String : return GetString (ordinal);
452                         case GdaValueType.Time : return GetDateTime (ordinal);
453                         case GdaValueType.Timestamp : return GetDateTime (ordinal);
454                         case GdaValueType.Tinyint : return GetByte (ordinal);
455                         }
456
457                         return (object) libgda.gda_value_stringify (value);
458                 }
459
460                 [MonoTODO]
461                 public int GetValues (object[] values)
462                 {
463                         throw new NotImplementedException ();
464                 }
465
466                 [MonoTODO]
467                 IDataReader IDataRecord.GetData (int ordinal)
468                 {
469                         throw new NotImplementedException ();
470                 }
471
472                 [MonoTODO]
473                 void IDisposable.Dispose ()
474                 {
475                         throw new NotImplementedException ();
476                 }
477
478                 [MonoTODO]
479                 IEnumerator IEnumerable.GetEnumerator ()
480                 {
481                         throw new NotImplementedException ();
482                 }
483
484                 public bool IsDBNull (int ordinal)
485                 {
486                         IntPtr value;
487
488                         if (currentResult == -1)
489                                 throw new IndexOutOfRangeException ();
490
491                         value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
492                                                                     ordinal, currentRow);
493                         if (value == IntPtr.Zero)
494                                 throw new IndexOutOfRangeException ();
495
496                         return libgda.gda_value_is_null (value);
497                 }
498
499                 public bool NextResult ()
500                 {
501                         int i = currentResult + 1;
502                         if (i >= 0 && i < gdaResults.Count) {
503                                 currentResult++;
504                                 return true;
505                         }
506
507                         return false;
508                 }
509
510                 public bool Read ()
511                 {
512                         if (currentResult < 0 ||
513                             currentResult >= gdaResults.Count)
514                                 return false;
515
516                         currentRow++;
517                         if (currentRow <
518                             libgda.gda_data_model_get_n_rows ((IntPtr) gdaResults[currentResult]))
519                                 return true;
520
521                         return false;
522                 }
523
524                 #endregion
525         }
526 }