**** Merged from MCS ****
[mono-project.git] / mcs / class / System.Data / System.Data.OleDb / OleDbDataReader.cs
blobcc19391d813b6f20a5f8abca21b21f21009216d1
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
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
36 using System.ComponentModel;
37 using System.Data;
38 using System.Data.Common;
39 using System.Runtime.InteropServices;
41 namespace System.Data.OleDb
43 public sealed class OleDbDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
45 #region Fields
47 private OleDbCommand command;
48 private bool open;
49 private ArrayList gdaResults;
50 private int currentResult;
51 private int currentRow;
52 private bool disposed = false;
54 #endregion
56 #region Constructors
58 internal OleDbDataReader (OleDbCommand command, ArrayList results)
60 this.command = command;
61 open = true;
62 if (results != null)
63 gdaResults = results;
64 else
65 gdaResults = new ArrayList ();
66 currentResult = -1;
67 currentRow = -1;
70 #endregion
72 #region Properties
74 public int Depth {
75 get {
76 return 0; // no nested selects supported
80 public int FieldCount {
81 get {
82 if (currentResult < 0 ||
83 currentResult >= gdaResults.Count)
84 return 0;
86 return libgda.gda_data_model_get_n_columns (
87 (IntPtr) gdaResults[currentResult]);
91 public bool IsClosed {
92 get {
93 return !open;
97 public object this[string name] {
98 get {
99 int pos;
101 if (currentResult == -1)
102 throw new InvalidOperationException ();
104 pos = libgda.gda_data_model_get_column_position (
105 (IntPtr) gdaResults[currentResult],
106 name);
107 if (pos == -1)
108 throw new IndexOutOfRangeException ();
110 return this[pos];
114 public object this[int index] {
115 get {
116 return (object) GetValue (index);
120 public int RecordsAffected {
121 get {
122 int total_rows;
124 if (currentResult < 0 ||
125 currentResult >= gdaResults.Count)
126 return 0;
128 total_rows = libgda.gda_data_model_get_n_rows (
129 (IntPtr) gdaResults[currentResult]);
130 if (total_rows > 0) {
131 if (FieldCount > 0) {
132 // It's a SELECT statement
133 return -1;
137 return FieldCount > 0 ? -1 : total_rows;
141 [MonoTODO]
142 public bool HasRows {
143 get {
144 throw new NotImplementedException ();
148 #endregion
150 #region Methods
152 public void Close ()
154 for (int i = 0; i < gdaResults.Count; i++) {
155 IntPtr obj = (IntPtr) gdaResults[i];
156 libgda.FreeObject (obj);
159 gdaResults.Clear ();
160 gdaResults = null;
162 open = false;
163 currentResult = -1;
164 currentRow = -1;
167 public bool GetBoolean (int ordinal)
169 IntPtr value;
171 if (currentResult == -1)
172 throw new InvalidCastException ();
174 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
175 ordinal, currentRow);
176 if (value == IntPtr.Zero)
177 throw new InvalidCastException ();
179 if (libgda.gda_value_get_type (value) != GdaValueType.Boolean)
180 throw new InvalidCastException ();
181 return libgda.gda_value_get_boolean (value);
184 public byte GetByte (int ordinal)
186 IntPtr value;
188 if (currentResult == -1)
189 throw new InvalidCastException ();
191 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
192 ordinal, currentRow);
193 if (value == IntPtr.Zero)
194 throw new InvalidCastException ();
196 if (libgda.gda_value_get_type (value) != GdaValueType.Tinyint)
197 throw new InvalidCastException ();
198 return libgda.gda_value_get_tinyint (value);
201 [MonoTODO]
202 public long GetBytes (int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length)
204 throw new NotImplementedException ();
207 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
208 public char GetChar (int ordinal)
210 IntPtr value;
212 if (currentResult == -1)
213 throw new InvalidCastException ();
215 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
216 ordinal, currentRow);
217 if (value == IntPtr.Zero)
218 throw new InvalidCastException ();
220 if (libgda.gda_value_get_type (value) != GdaValueType.Tinyint)
221 throw new InvalidCastException ();
222 return (char) libgda.gda_value_get_tinyint (value);
225 [MonoTODO]
226 public long GetChars (int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length)
228 throw new NotImplementedException ();
231 [MonoTODO]
232 public OleDbDataReader GetData (int ordinal)
234 throw new NotImplementedException ();
237 public string GetDataTypeName (int index)
239 IntPtr attrs;
240 GdaValueType type;
242 if (currentResult == -1)
243 return "unknown";
246 attrs = libgda.gda_data_model_describe_column ((IntPtr) gdaResults[currentResult],
247 index);
248 if (attrs == IntPtr.Zero)
249 return "unknown";
251 type = libgda.gda_field_attributes_get_gdatype (attrs);
252 libgda.gda_field_attributes_free (attrs);
254 return libgda.gda_type_to_string (type);
257 public DateTime GetDateTime (int ordinal)
259 IntPtr value;
260 DateTime dt;
262 if (currentResult == -1)
263 throw new InvalidCastException ();
265 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
266 ordinal, currentRow);
267 if (value == IntPtr.Zero)
268 throw new InvalidCastException ();
270 if (libgda.gda_value_get_type (value) == GdaValueType.Date) {
271 GdaDate gdt;
273 gdt = (GdaDate) Marshal.PtrToStructure (libgda.gda_value_get_date (value),
274 typeof (GdaDate));
275 return new DateTime ((int) gdt.year, (int) gdt.month, (int) gdt.day);
276 } else if (libgda.gda_value_get_type (value) == GdaValueType.Time) {
277 GdaTime gdt;
279 gdt = (GdaTime) Marshal.PtrToStructure (libgda.gda_value_get_time (value),
280 typeof (GdaTime));
281 return new DateTime (0, 0, 0, (int) gdt.hour, (int) gdt.minute, (int) gdt.second, 0);
282 } else if (libgda.gda_value_get_type (value) == GdaValueType.Timestamp) {
283 GdaTimestamp gdt;
285 gdt = (GdaTimestamp) Marshal.PtrToStructure (libgda.gda_value_get_timestamp (value),
286 typeof (GdaTimestamp));
288 return new DateTime ((int) gdt.year, (int) gdt.month, (int) gdt.day,
289 (int) gdt.hour, (int) gdt.minute, (int) gdt.second,
290 (int) gdt.fraction);
293 throw new InvalidCastException ();
296 [MonoTODO]
297 public decimal GetDecimal (int ordinal)
299 throw new NotImplementedException ();
302 public double GetDouble (int ordinal)
304 IntPtr value;
306 if (currentResult == -1)
307 throw new InvalidCastException ();
309 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
310 ordinal, currentRow);
311 if (value == IntPtr.Zero)
312 throw new InvalidCastException ();
314 if (libgda.gda_value_get_type (value) != GdaValueType.Double)
315 throw new InvalidCastException ();
316 return libgda.gda_value_get_double (value);
319 [MonoTODO]
320 public Type GetFieldType (int index)
322 IntPtr value;
323 GdaValueType type;
325 if (currentResult == -1)
326 throw new IndexOutOfRangeException ();
328 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
329 index, currentRow);
330 if (value == IntPtr.Zero)
331 throw new IndexOutOfRangeException ();
333 type = libgda.gda_value_get_type (value);
334 switch (type) {
335 case GdaValueType.Bigint : return typeof (long);
336 case GdaValueType.Boolean : return typeof (bool);
337 case GdaValueType.Date : return typeof (DateTime);
338 case GdaValueType.Double : return typeof (double);
339 case GdaValueType.Integer : return typeof (int);
340 case GdaValueType.Single : return typeof (float);
341 case GdaValueType.Smallint : return typeof (byte);
342 case GdaValueType.String : return typeof (string);
343 case GdaValueType.Time : return typeof (DateTime);
344 case GdaValueType.Timestamp : return typeof (DateTime);
345 case GdaValueType.Tinyint : return typeof (byte);
348 return typeof(string); // default
351 public float GetFloat (int ordinal)
353 IntPtr value;
355 if (currentResult == -1)
356 throw new InvalidCastException ();
358 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
359 ordinal, currentRow);
360 if (value == IntPtr.Zero)
361 throw new InvalidCastException ();
363 if (libgda.gda_value_get_type (value) != GdaValueType.Single)
364 throw new InvalidCastException ();
365 return libgda.gda_value_get_single (value);
368 [MonoTODO]
369 public Guid GetGuid (int ordinal)
371 throw new NotImplementedException ();
374 public short GetInt16 (int ordinal)
376 IntPtr value;
378 if (currentResult == -1)
379 throw new InvalidCastException ();
381 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
382 ordinal, currentRow);
383 if (value == IntPtr.Zero)
384 throw new InvalidCastException ();
386 if (libgda.gda_value_get_type (value) != GdaValueType.Smallint)
387 throw new InvalidCastException ();
388 return (short) libgda.gda_value_get_smallint (value);
391 public int GetInt32 (int ordinal)
393 IntPtr value;
395 if (currentResult == -1)
396 throw new InvalidCastException ();
398 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
399 ordinal, currentRow);
400 if (value == IntPtr.Zero)
401 throw new InvalidCastException ();
403 if (libgda.gda_value_get_type (value) != GdaValueType.Integer)
404 throw new InvalidCastException ();
405 return libgda.gda_value_get_integer (value);
408 public long GetInt64 (int ordinal)
410 IntPtr value;
412 if (currentResult == -1)
413 throw new InvalidCastException ();
415 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
416 ordinal, currentRow);
417 if (value == IntPtr.Zero)
418 throw new InvalidCastException ();
420 if (libgda.gda_value_get_type (value) != GdaValueType.Bigint)
421 throw new InvalidCastException ();
422 return libgda.gda_value_get_bigint (value);
425 public string GetName (int index)
427 if (currentResult == -1)
428 return null;
430 return libgda.gda_data_model_get_column_title (
431 (IntPtr) gdaResults[currentResult], index);
434 public int GetOrdinal (string name)
436 if (currentResult == -1)
437 throw new IndexOutOfRangeException ();
439 for (int i = 0; i < FieldCount; i++) {
440 if (GetName (i) == name)
441 return i;
444 throw new IndexOutOfRangeException ();
447 public DataTable GetSchemaTable ()
449 DataTable dataTableSchema = null;
450 // Only Results from SQL SELECT Queries
451 // get a DataTable for schema of the result
452 // otherwise, DataTable is null reference
453 if(this.FieldCount > 0) {
455 IntPtr attrs;
456 GdaValueType gdaType;
457 long columnSize = 0;
459 if (currentResult == -1) {
460 // FIXME: throw an exception?
461 #if DEBUG_OleDbDataReader
462 Console.WriteLine("Error: current result -1");
463 #endif
464 return null;
467 dataTableSchema = new DataTable ();
469 dataTableSchema.Columns.Add ("ColumnName", typeof (string));
470 dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
471 dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
472 dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
473 dataTableSchema.Columns.Add ("NumericScale", typeof (int));
474 dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
475 dataTableSchema.Columns.Add ("IsKey", typeof (bool));
476 DataColumn dc = dataTableSchema.Columns["IsKey"];
477 dc.AllowDBNull = true; // IsKey can have a DBNull
478 dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
479 dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
480 dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
481 dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
482 dataTableSchema.Columns.Add ("DataType", typeof(Type));
483 dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
484 dataTableSchema.Columns.Add ("ProviderType", typeof (int));
485 dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
486 dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
487 dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
488 dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
489 dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
490 dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
491 dataTableSchema.Columns.Add ("IsLong", typeof (bool));
492 dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
494 DataRow schemaRow;
495 DbType dbType;
496 Type typ;
498 for (int i = 0; i < this.FieldCount; i += 1 ) {
500 schemaRow = dataTableSchema.NewRow ();
502 attrs = libgda.gda_data_model_describe_column ((IntPtr) gdaResults[currentResult],
504 if (attrs == IntPtr.Zero){
505 // FIXME: throw exception
506 #if DEBUG_OleDbDataReader
507 Console.WriteLine("Error: attrs null");
508 #endif
509 return null;
512 gdaType = libgda.gda_field_attributes_get_gdatype (attrs);
513 columnSize = libgda.gda_field_attributes_get_defined_size (attrs);
514 libgda.gda_field_attributes_free (attrs);
516 schemaRow["ColumnName"] = this.GetName(i);
517 schemaRow["ColumnOrdinal"] = i + 1;
519 schemaRow["ColumnSize"] = (int) columnSize;
520 schemaRow["NumericPrecision"] = 0;
521 schemaRow["NumericScale"] = 0;
522 // TODO: need to get KeyInfo
523 //if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
524 // bool IsUnique, IsKey;
525 // GetKeyInfo(field[i].Name, out IsUnique, out IsKey);
527 //else {
528 schemaRow["IsUnique"] = false;
529 schemaRow["IsKey"] = DBNull.Value;
531 schemaRow["BaseCatalogName"] = "";
533 schemaRow["BaseColumnName"] = this.GetName(i);
534 schemaRow["BaseSchemaName"] = "";
535 schemaRow["BaseTableName"] = "";
537 schemaRow["DataType"] = this.GetFieldType(i);
539 schemaRow["AllowDBNull"] = false;
541 schemaRow["ProviderType"] = (int) gdaType;
542 schemaRow["IsAliased"] = false;
543 schemaRow["IsExpression"] = false;
544 schemaRow["IsIdentity"] = false;
545 schemaRow["IsAutoIncrement"] = false;
546 schemaRow["IsRowVersion"] = false;
547 schemaRow["IsHidden"] = false;
548 schemaRow["IsLong"] = false;
549 schemaRow["IsReadOnly"] = false;
551 schemaRow.AcceptChanges();
553 dataTableSchema.Rows.Add (schemaRow);
556 #if DEBUG_OleDbDataReader
557 Console.WriteLine("********** DEBUG Table Schema BEGIN ************");
558 foreach (DataRow myRow in dataTableSchema.Rows) {
559 foreach (DataColumn myCol in dataTableSchema.Columns)
560 Console.WriteLine(myCol.ColumnName + " = " + myRow[myCol]);
561 Console.WriteLine();
563 Console.WriteLine("********** DEBUG Table Schema END ************");
564 #endif // DEBUG_OleDbDataReader
568 return dataTableSchema;
571 public string GetString (int ordinal)
573 IntPtr value;
575 if (currentResult == -1)
576 throw new InvalidCastException ();
578 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
579 ordinal, currentRow);
580 if (value == IntPtr.Zero)
581 throw new InvalidCastException ();
583 if (libgda.gda_value_get_type (value) != GdaValueType.String)
584 throw new InvalidCastException ();
585 return libgda.gda_value_get_string (value);
588 [MonoTODO]
589 public TimeSpan GetTimeSpan (int ordinal)
591 throw new NotImplementedException ();
594 public object GetValue (int ordinal)
596 IntPtr value;
597 GdaValueType type;
599 if (currentResult == -1)
600 throw new IndexOutOfRangeException ();
602 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
603 ordinal, currentRow);
604 if (value == IntPtr.Zero)
605 throw new IndexOutOfRangeException ();
607 type = libgda.gda_value_get_type (value);
608 switch (type) {
609 case GdaValueType.Bigint : return GetInt64 (ordinal);
610 case GdaValueType.Boolean : return GetBoolean (ordinal);
611 case GdaValueType.Date : return GetDateTime (ordinal);
612 case GdaValueType.Double : return GetDouble (ordinal);
613 case GdaValueType.Integer : return GetInt32 (ordinal);
614 case GdaValueType.Single : return GetFloat (ordinal);
615 case GdaValueType.Smallint : return GetByte (ordinal);
616 case GdaValueType.String : return GetString (ordinal);
617 case GdaValueType.Time : return GetDateTime (ordinal);
618 case GdaValueType.Timestamp : return GetDateTime (ordinal);
619 case GdaValueType.Tinyint : return GetByte (ordinal);
622 return (object) libgda.gda_value_stringify (value);
625 [MonoTODO]
626 public int GetValues (object[] values)
628 throw new NotImplementedException ();
631 [MonoTODO]
632 IDataReader IDataRecord.GetData (int ordinal)
634 throw new NotImplementedException ();
637 IEnumerator IEnumerable.GetEnumerator ()
639 return new DbEnumerator (this);
642 public bool IsDBNull (int ordinal)
644 IntPtr value;
646 if (currentResult == -1)
647 throw new IndexOutOfRangeException ();
649 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
650 ordinal, currentRow);
651 if (value == IntPtr.Zero)
652 throw new IndexOutOfRangeException ();
654 return libgda.gda_value_is_null (value);
657 public bool NextResult ()
659 int i = currentResult + 1;
660 if (i >= 0 && i < gdaResults.Count) {
661 currentResult++;
662 return true;
665 return false;
668 public bool Read ()
670 if (currentResult < 0 ||
671 currentResult >= gdaResults.Count)
672 return false;
674 currentRow++;
675 if (currentRow <
676 libgda.gda_data_model_get_n_rows ((IntPtr) gdaResults[currentResult]))
677 return true;
679 return false;
682 #endregion
684 #region Destructors
686 private void Dispose (bool disposing) {
687 if (!this.disposed) {
688 if (disposing) {
689 // release any managed resources
690 command = null;
692 // release any unmanaged resources
693 if (gdaResults != null) {
694 gdaResults.Clear ();
695 gdaResults = null;
698 // close any handles
699 if (open)
700 Close ();
702 this.disposed = true;
706 void IDisposable.Dispose() {
707 Dispose (true);
710 ~OleDbDataReader() {
711 Dispose (false);
714 #endregion // Destructors