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
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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
;
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
47 private OleDbCommand command
;
49 private ArrayList gdaResults
;
50 private int currentResult
;
51 private int currentRow
;
52 private bool disposed
= false;
58 internal OleDbDataReader (OleDbCommand command
, ArrayList results
)
60 this.command
= command
;
65 gdaResults
= new ArrayList ();
76 return 0; // no nested selects supported
80 public int FieldCount
{
82 if (currentResult
< 0 ||
83 currentResult
>= gdaResults
.Count
)
86 return libgda
.gda_data_model_get_n_columns (
87 (IntPtr
) gdaResults
[currentResult
]);
91 public bool IsClosed
{
97 public object this[string name
] {
101 if (currentResult
== -1)
102 throw new InvalidOperationException ();
104 pos
= libgda
.gda_data_model_get_column_position (
105 (IntPtr
) gdaResults
[currentResult
],
108 throw new IndexOutOfRangeException ();
114 public object this[int index
] {
116 return (object) GetValue (index
);
120 public int RecordsAffected
{
124 if (currentResult
< 0 ||
125 currentResult
>= gdaResults
.Count
)
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
137 return FieldCount
> 0 ? -1 : total_rows
;
142 public bool HasRows
{
144 throw new NotImplementedException ();
154 for (int i
= 0; i
< gdaResults
.Count
; i
++) {
155 IntPtr obj
= (IntPtr
) gdaResults
[i
];
156 libgda
.FreeObject (obj
);
167 public bool GetBoolean (int ordinal
)
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
)
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);
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
)
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);
226 public long GetChars (int ordinal
, long dataIndex
, char[] buffer
, int bufferIndex
, int length
)
228 throw new NotImplementedException ();
232 public OleDbDataReader
GetData (int ordinal
)
234 throw new NotImplementedException ();
237 public string GetDataTypeName (int index
)
242 if (currentResult
== -1)
246 attrs
= libgda
.gda_data_model_describe_column ((IntPtr
) gdaResults
[currentResult
],
248 if (attrs
== IntPtr
.Zero
)
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
)
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
) {
273 gdt
= (GdaDate
) Marshal
.PtrToStructure (libgda
.gda_value_get_date (value),
275 return new DateTime ((int) gdt
.year
, (int) gdt
.month
, (int) gdt
.day
);
276 } else if (libgda
.gda_value_get_type (value) == GdaValueType
.Time
) {
279 gdt
= (GdaTime
) Marshal
.PtrToStructure (libgda
.gda_value_get_time (value),
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
) {
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
,
293 throw new InvalidCastException ();
297 public decimal GetDecimal (int ordinal
)
299 throw new NotImplementedException ();
302 public double GetDouble (int ordinal
)
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);
320 public Type
GetFieldType (int index
)
325 if (currentResult
== -1)
326 throw new IndexOutOfRangeException ();
328 value = libgda
.gda_data_model_get_value_at ((IntPtr
) gdaResults
[currentResult
],
330 if (value == IntPtr
.Zero
)
331 throw new IndexOutOfRangeException ();
333 type
= libgda
.gda_value_get_type (value);
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
)
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);
369 public Guid
GetGuid (int ordinal
)
371 throw new NotImplementedException ();
374 public short GetInt16 (int ordinal
)
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
)
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
)
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)
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
)
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) {
456 GdaValueType gdaType
;
459 if (currentResult
== -1) {
460 // FIXME: throw an exception?
461 #if DEBUG_OleDbDataReader
462 Console
.WriteLine("Error: current result -1");
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));
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");
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);
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
]);
563 Console
.WriteLine("********** DEBUG Table Schema END ************");
564 #endif // DEBUG_OleDbDataReader
568 return dataTableSchema
;
571 public string GetString (int ordinal
)
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);
589 public TimeSpan
GetTimeSpan (int ordinal
)
591 throw new NotImplementedException ();
594 public object GetValue (int ordinal
)
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);
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);
626 public int GetValues (object[] values
)
628 throw new NotImplementedException ();
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
)
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
) {
670 if (currentResult
< 0 ||
671 currentResult
>= gdaResults
.Count
)
676 libgda
.gda_data_model_get_n_rows ((IntPtr
) gdaResults
[currentResult
]))
686 private void Dispose (bool disposing
) {
687 if (!this.disposed
) {
689 // release any managed resources
692 // release any unmanaged resources
693 if (gdaResults
!= null) {
702 this.disposed
= true;
706 void IDisposable
.Dispose() {
714 #endregion // Destructors