2 // System.Data.OleDb.OleDbDataReader
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Tim Coleman (tim@timcoleman.com)
8 // Copyright (C) Rodrigo Moya, 2002
9 // Copyright (C) Tim Coleman, 2002
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.ComponentModel;
34 using System.Data.Common;
35 using System.Runtime.InteropServices;
37 namespace System.Data.OleDb
39 public sealed class OleDbDataReader : DbDataReader, IDisposable
43 private OleDbCommand command;
45 private ArrayList gdaResults;
46 private int currentResult;
47 private int currentRow;
48 private bool disposed;
54 internal OleDbDataReader (OleDbCommand command, ArrayList results)
56 this.command = command;
61 gdaResults = new ArrayList ();
74 return 0; // no nested selects supported
82 if (currentResult < 0 || currentResult >= gdaResults.Count)
85 return libgda.gda_data_model_get_n_columns (
86 (IntPtr) gdaResults[currentResult]);
100 object this[string name] {
104 if (currentResult == -1)
105 throw new InvalidOperationException ();
107 pos = libgda.gda_data_model_get_column_position (
108 (IntPtr) gdaResults[currentResult],
111 throw new IndexOutOfRangeException ();
119 object this[int index] {
121 return (object) GetValue (index);
127 int RecordsAffected {
131 if (currentResult < 0 || currentResult >= gdaResults.Count)
134 total_rows = libgda.gda_data_model_get_n_rows (
135 (IntPtr) gdaResults[currentResult]);
136 if (total_rows > 0) {
137 if (FieldCount > 0) {
138 // It's a SELECT statement
143 return FieldCount > 0 ? -1 : total_rows;
152 throw new NotImplementedException ();
157 public override int VisibleFieldCount {
159 throw new NotImplementedException ();
171 for (int i = 0; i < gdaResults.Count; i++) {
172 IntPtr obj = (IntPtr) gdaResults[i];
173 libgda.FreeObject (obj);
186 bool GetBoolean (int ordinal)
190 if (currentResult == -1)
191 throw new InvalidCastException ();
193 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
194 ordinal, currentRow);
195 if (value == IntPtr.Zero)
196 throw new InvalidCastException ();
198 if (libgda.gda_value_get_type (value) != GdaValueType.Boolean)
199 throw new InvalidCastException ();
200 return libgda.gda_value_get_boolean (value);
205 byte GetByte (int ordinal)
209 if (currentResult == -1)
210 throw new InvalidCastException ();
212 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
213 ordinal, currentRow);
214 if (value == IntPtr.Zero)
215 throw new InvalidCastException ();
217 if (libgda.gda_value_get_type (value) != GdaValueType.Tinyint)
218 throw new InvalidCastException ();
219 return libgda.gda_value_get_tinyint (value);
225 long GetBytes (int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length)
227 throw new NotImplementedException ();
230 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
233 char GetChar (int ordinal)
237 if (currentResult == -1)
238 throw new InvalidCastException ();
240 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
241 ordinal, currentRow);
242 if (value == IntPtr.Zero)
243 throw new InvalidCastException ();
245 if (libgda.gda_value_get_type (value) != GdaValueType.Tinyint)
246 throw new InvalidCastException ();
247 return (char) libgda.gda_value_get_tinyint (value);
253 long GetChars (int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length)
255 throw new NotImplementedException ();
259 [EditorBrowsable (EditorBrowsableState.Advanced)]
260 public new OleDbDataReader GetData (int ordinal)
262 throw new NotImplementedException ();
265 protected override DbDataReader GetDbDataReader (int ordinal)
267 return this.GetData (ordinal);
272 string GetDataTypeName (int index)
277 if (currentResult == -1)
281 attrs = libgda.gda_data_model_describe_column ((IntPtr) gdaResults[currentResult],
283 if (attrs == IntPtr.Zero)
286 type = libgda.gda_field_attributes_get_gdatype (attrs);
287 libgda.gda_field_attributes_free (attrs);
289 return libgda.gda_type_to_string (type);
294 DateTime GetDateTime (int ordinal)
298 if (currentResult == -1)
299 throw new InvalidCastException ();
301 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
302 ordinal, currentRow);
303 if (value == IntPtr.Zero)
304 throw new InvalidCastException ();
306 if (libgda.gda_value_get_type (value) == GdaValueType.Date) {
309 gdt = (GdaDate) Marshal.PtrToStructure (libgda.gda_value_get_date (value),
311 return new DateTime ((int) gdt.year, (int) gdt.month, (int) gdt.day);
312 } else if (libgda.gda_value_get_type (value) == GdaValueType.Time) {
315 gdt = (GdaTime) Marshal.PtrToStructure (libgda.gda_value_get_time (value),
317 return new DateTime (0, 0, 0, (int) gdt.hour, (int) gdt.minute, (int) gdt.second, 0);
318 } else if (libgda.gda_value_get_type (value) == GdaValueType.Timestamp) {
321 gdt = (GdaTimestamp) Marshal.PtrToStructure (libgda.gda_value_get_timestamp (value),
322 typeof (GdaTimestamp));
324 return new DateTime ((int) gdt.year, (int) gdt.month, (int) gdt.day,
325 (int) gdt.hour, (int) gdt.minute, (int) gdt.second,
329 throw new InvalidCastException ();
335 decimal GetDecimal (int ordinal)
337 throw new NotImplementedException ();
342 double GetDouble (int ordinal)
346 if (currentResult == -1)
347 throw new InvalidCastException ();
349 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
350 ordinal, currentRow);
351 if (value == IntPtr.Zero)
352 throw new InvalidCastException ();
354 if (libgda.gda_value_get_type (value) != GdaValueType.Double)
355 throw new InvalidCastException ();
356 return libgda.gda_value_get_double (value);
361 Type GetFieldType (int index)
366 if (currentResult == -1)
367 throw new IndexOutOfRangeException ();
369 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
371 if (value == IntPtr.Zero)
372 throw new IndexOutOfRangeException ();
374 type = libgda.gda_value_get_type (value);
376 case GdaValueType.Bigint : return typeof (long);
377 case GdaValueType.Boolean : return typeof (bool);
378 case GdaValueType.Date : return typeof (DateTime);
379 case GdaValueType.Double : return typeof (double);
380 case GdaValueType.Integer : return typeof (int);
381 case GdaValueType.Single : return typeof (float);
382 case GdaValueType.Smallint : return typeof (byte);
383 case GdaValueType.String : return typeof (string);
384 case GdaValueType.Time : return typeof (DateTime);
385 case GdaValueType.Timestamp : return typeof (DateTime);
386 case GdaValueType.Tinyint : return typeof (byte);
389 return typeof(string); // default
394 float GetFloat (int ordinal)
398 if (currentResult == -1)
399 throw new InvalidCastException ();
401 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
402 ordinal, currentRow);
403 if (value == IntPtr.Zero)
404 throw new InvalidCastException ();
406 if (libgda.gda_value_get_type (value) != GdaValueType.Single)
407 throw new InvalidCastException ();
408 return libgda.gda_value_get_single (value);
414 Guid GetGuid (int ordinal)
416 throw new NotImplementedException ();
421 short GetInt16 (int ordinal)
425 if (currentResult == -1)
426 throw new InvalidCastException ();
428 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
429 ordinal, currentRow);
430 if (value == IntPtr.Zero)
431 throw new InvalidCastException ();
433 if (libgda.gda_value_get_type (value) != GdaValueType.Smallint)
434 throw new InvalidCastException ();
435 return (short) libgda.gda_value_get_smallint (value);
440 int GetInt32 (int ordinal)
444 if (currentResult == -1)
445 throw new InvalidCastException ();
447 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
448 ordinal, currentRow);
449 if (value == IntPtr.Zero)
450 throw new InvalidCastException ();
452 if (libgda.gda_value_get_type (value) != GdaValueType.Integer)
453 throw new InvalidCastException ();
454 return libgda.gda_value_get_integer (value);
459 long GetInt64 (int ordinal)
463 if (currentResult == -1)
464 throw new InvalidCastException ();
466 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
467 ordinal, currentRow);
468 if (value == IntPtr.Zero)
469 throw new InvalidCastException ();
471 if (libgda.gda_value_get_type (value) != GdaValueType.Bigint)
472 throw new InvalidCastException ();
473 return libgda.gda_value_get_bigint (value);
478 string GetName (int index)
480 if (currentResult == -1)
483 return libgda.gda_data_model_get_column_title (
484 (IntPtr) gdaResults[currentResult], index);
489 int GetOrdinal (string name)
491 if (currentResult == -1)
492 throw new IndexOutOfRangeException ();
494 for (int i = 0; i < FieldCount; i++) {
495 if (GetName (i) == name)
499 throw new IndexOutOfRangeException ();
504 DataTable GetSchemaTable ()
506 DataTable dataTableSchema = null;
507 // Only Results from SQL SELECT Queries
508 // get a DataTable for schema of the result
509 // otherwise, DataTable is null reference
510 if(this.FieldCount > 0) {
513 GdaValueType gdaType;
516 if (currentResult == -1) {
517 // FIXME: throw an exception?
518 #if DEBUG_OleDbDataReader
519 Console.WriteLine("Error: current result -1");
524 dataTableSchema = new DataTable ();
526 dataTableSchema.Columns.Add ("ColumnName", typeof (string));
527 dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
528 dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
529 dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
530 dataTableSchema.Columns.Add ("NumericScale", typeof (int));
531 dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
532 dataTableSchema.Columns.Add ("IsKey", typeof (bool));
533 DataColumn dc = dataTableSchema.Columns["IsKey"];
534 dc.AllowDBNull = true; // IsKey can have a DBNull
535 dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
536 dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
537 dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
538 dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
539 dataTableSchema.Columns.Add ("DataType", typeof(Type));
540 dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
541 dataTableSchema.Columns.Add ("ProviderType", typeof (int));
542 dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
543 dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
544 dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
545 dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
546 dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
547 dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
548 dataTableSchema.Columns.Add ("IsLong", typeof (bool));
549 dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
553 for (int i = 0; i < this.FieldCount; i += 1 ) {
555 schemaRow = dataTableSchema.NewRow ();
557 attrs = libgda.gda_data_model_describe_column ((IntPtr) gdaResults[currentResult],
559 if (attrs == IntPtr.Zero){
560 // FIXME: throw exception
561 #if DEBUG_OleDbDataReader
562 Console.WriteLine("Error: attrs null");
567 gdaType = libgda.gda_field_attributes_get_gdatype (attrs);
568 columnSize = libgda.gda_field_attributes_get_defined_size (attrs);
569 libgda.gda_field_attributes_free (attrs);
571 schemaRow["ColumnName"] = this.GetName(i);
572 schemaRow["ColumnOrdinal"] = i + 1;
574 schemaRow["ColumnSize"] = (int) columnSize;
575 schemaRow["NumericPrecision"] = 0;
576 schemaRow["NumericScale"] = 0;
577 // TODO: need to get KeyInfo
578 //if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
579 // bool IsUnique, IsKey;
580 // GetKeyInfo(field[i].Name, out IsUnique, out IsKey);
583 schemaRow["IsUnique"] = false;
584 schemaRow["IsKey"] = DBNull.Value;
586 schemaRow["BaseCatalogName"] = "";
588 schemaRow["BaseColumnName"] = this.GetName(i);
589 schemaRow["BaseSchemaName"] = "";
590 schemaRow["BaseTableName"] = "";
592 schemaRow["DataType"] = this.GetFieldType(i);
594 schemaRow["AllowDBNull"] = false;
596 schemaRow["ProviderType"] = (int) gdaType;
597 schemaRow["IsAliased"] = false;
598 schemaRow["IsExpression"] = false;
599 schemaRow["IsIdentity"] = false;
600 schemaRow["IsAutoIncrement"] = false;
601 schemaRow["IsRowVersion"] = false;
602 schemaRow["IsHidden"] = false;
603 schemaRow["IsLong"] = false;
604 schemaRow["IsReadOnly"] = false;
606 schemaRow.AcceptChanges();
608 dataTableSchema.Rows.Add (schemaRow);
611 #if DEBUG_OleDbDataReader
612 Console.WriteLine("********** DEBUG Table Schema BEGIN ************");
613 foreach (DataRow myRow in dataTableSchema.Rows) {
614 foreach (DataColumn myCol in dataTableSchema.Columns)
615 Console.WriteLine(myCol.ColumnName + " = " + myRow[myCol]);
618 Console.WriteLine("********** DEBUG Table Schema END ************");
619 #endif // DEBUG_OleDbDataReader
623 return dataTableSchema;
628 string GetString (int ordinal)
632 if (currentResult == -1)
633 throw new InvalidCastException ();
635 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
636 ordinal, currentRow);
637 if (value == IntPtr.Zero)
638 throw new InvalidCastException ();
640 if (libgda.gda_value_get_type (value) != GdaValueType.String)
641 throw new InvalidCastException ();
642 return libgda.gda_value_get_string (value);
646 public TimeSpan GetTimeSpan (int ordinal)
648 throw new NotImplementedException ();
653 object GetValue (int ordinal)
658 if (currentResult == -1)
659 throw new IndexOutOfRangeException ();
661 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
662 ordinal, currentRow);
663 if (value == IntPtr.Zero)
664 throw new IndexOutOfRangeException ();
666 type = libgda.gda_value_get_type (value);
668 case GdaValueType.Bigint : return GetInt64 (ordinal);
669 case GdaValueType.Boolean : return GetBoolean (ordinal);
670 case GdaValueType.Date : return GetDateTime (ordinal);
671 case GdaValueType.Double : return GetDouble (ordinal);
672 case GdaValueType.Integer : return GetInt32 (ordinal);
673 case GdaValueType.Single : return GetFloat (ordinal);
674 case GdaValueType.Smallint : return GetByte (ordinal);
675 case GdaValueType.String : return GetString (ordinal);
676 case GdaValueType.Time : return GetDateTime (ordinal);
677 case GdaValueType.Timestamp : return GetDateTime (ordinal);
678 case GdaValueType.Tinyint : return GetByte (ordinal);
681 return (object) libgda.gda_value_stringify (value);
687 int GetValues (object[] values)
689 throw new NotImplementedException ();
693 public override IEnumerator GetEnumerator()
695 return new DbEnumerator(this);
700 bool IsDBNull (int ordinal)
704 if (currentResult == -1)
705 throw new IndexOutOfRangeException ();
707 value = libgda.gda_data_model_get_value_at ((IntPtr) gdaResults[currentResult],
708 ordinal, currentRow);
709 if (value == IntPtr.Zero)
710 throw new IndexOutOfRangeException ();
712 return libgda.gda_value_is_null (value);
719 int i = currentResult + 1;
720 if (i >= 0 && i < gdaResults.Count) {
732 if (currentResult < 0 || currentResult >= gdaResults.Count)
736 if (currentRow < libgda.gda_data_model_get_n_rows ((IntPtr) gdaResults[currentResult]))
746 private new void Dispose (bool disposing)
748 if (!this.disposed) {
750 // release any managed resources
752 GC.SuppressFinalize (this);
754 // release any unmanaged resources
755 if (gdaResults != null) {
764 this.disposed = true;
768 void IDisposable.Dispose() {
772 #endregion // Destructors