2 // System.Data.Odbc.OdbcDataReader
5 // Brian Ritchie (brianlritchie@hotmail.com)
7 // Copyright (C) Brian Ritchie, 2002
10 using System.Collections;
11 using System.ComponentModel;
13 using System.Data.Common;
14 using System.Runtime.InteropServices;
16 namespace System.Data.Odbc
18 public sealed class OdbcDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
22 private OdbcCommand command;
24 private int currentRow;
25 private OdbcColumn[] cols;
32 internal OdbcDataReader (OdbcCommand command)
34 this.command = command;
35 this.command.Connection.DataReader = this;
39 // Init columns array;
41 libodbc.SQLNumResultCols(hstmt, ref colcount);
42 cols=new OdbcColumn[colcount];
51 return 0; // no nested selects supported
55 public int FieldCount {
62 public bool IsClosed {
68 public object this[string name] {
73 throw new InvalidOperationException ();
78 throw new IndexOutOfRangeException ();
84 public object this[int index] {
86 return (object) GetValue (index);
90 public int RecordsAffected {
100 private int ColIndex(string colname)
103 foreach (OdbcColumn col in cols)
105 if (col.ColumnName==colname)
112 // Dynamically load column descriptions as needed.
113 private OdbcColumn GetColumn(int ordinal)
115 if (cols[ordinal]==null)
118 byte[] colname_buffer=new byte[bufsize];
120 short colname_size=0;
121 OdbcType DataType=OdbcType.Int;
122 short ColSize=0, DecDigits=0, Nullable=0, dt=0;
123 OdbcReturn ret=libodbc.SQLDescribeCol(hstmt, Convert.ToUInt16(ordinal+1),
124 colname_buffer, bufsize, ref colname_size, ref dt, ref ColSize,
125 ref DecDigits, ref Nullable);
126 libodbchelper.DisplayError("SQLDescribeCol",ret);
127 colname=System.Text.Encoding.Default.GetString(colname_buffer);
128 colname=colname.Replace((char) 0,' ').Trim();
\r
129 OdbcColumn c=new OdbcColumn(colname, (OdbcType) dt);
130 c.AllowDBNull=(Nullable!=0);
136 return cols[ordinal];
141 // libodbc.SQLFreeHandle((ushort) OdbcHandleType.Stmt, hstmt);
143 OdbcReturn ret=libodbc.SQLCloseCursor(hstmt);
144 libodbchelper.DisplayError("SQLCancel",ret);
149 this.command.Connection.DataReader = null;
158 public bool GetBoolean (int ordinal)
160 return (bool) GetValue(ordinal);
164 public byte GetByte (int ordinal)
166 throw new NotImplementedException ();
170 public long GetBytes (int ordinal, long dataIndex, byte[] buffer, int bufferIndex, int length)
172 throw new NotImplementedException ();
176 public char GetChar (int ordinal)
178 throw new NotImplementedException ();
182 public long GetChars (int ordinal, long dataIndex, char[] buffer, int bufferIndex, int length)
184 throw new NotImplementedException ();
188 public OdbcDataReader GetData (int ordinal)
190 throw new NotImplementedException ();
193 public string GetDataTypeName (int index)
195 return GetColumn(index).OdbcType.ToString();
198 public DateTime GetDateTime (int ordinal)
200 return (DateTime) GetValue(ordinal);
204 public decimal GetDecimal (int ordinal)
206 throw new NotImplementedException ();
209 public double GetDouble (int ordinal)
211 return (double) GetValue(ordinal);
214 public Type GetFieldType (int index)
216 return GetColumn(index).DataType;
219 public float GetFloat (int ordinal)
221 return (float) GetValue(ordinal);
225 public Guid GetGuid (int ordinal)
227 throw new NotImplementedException ();
230 public short GetInt16 (int ordinal)
232 return (short) GetValue(ordinal);
235 public int GetInt32 (int ordinal)
237 return (int) GetValue(ordinal);
240 public long GetInt64 (int ordinal)
242 return (long) GetValue(ordinal);
245 public string GetName (int index)
247 if (currentRow == -1)
249 return GetColumn(index).ColumnName;
252 public int GetOrdinal (string name)
254 if (currentRow == -1)
255 throw new IndexOutOfRangeException ();
257 int i=ColIndex(name);
260 throw new IndexOutOfRangeException ();
266 public DataTable GetSchemaTable()
\r
269 DataTable dataTableSchema = null;
270 // Only Results from SQL SELECT Queries
271 // get a DataTable for schema of the result
272 // otherwise, DataTable is null reference
273 if(cols.Length > 0)
\r
276 dataTableSchema = new DataTable ();
278 dataTableSchema.Columns.Add ("ColumnName", typeof (string));
279 dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
280 dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
281 dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
282 dataTableSchema.Columns.Add ("NumericScale", typeof (int));
283 dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
284 dataTableSchema.Columns.Add ("IsKey", typeof (bool));
285 DataColumn dc = dataTableSchema.Columns["IsKey"];
286 dc.AllowDBNull = true; // IsKey can have a DBNull
287 dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
288 dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
289 dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
290 dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
291 dataTableSchema.Columns.Add ("DataType", typeof(Type));
292 dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
293 dataTableSchema.Columns.Add ("ProviderType", typeof (int));
294 dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
295 dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
296 dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
297 dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
298 dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
299 dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
300 dataTableSchema.Columns.Add ("IsLong", typeof (bool));
301 dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
305 for (int i = 0; i < cols.Length; i += 1 )
\r
307 OdbcColumn col=GetColumn(i);
308 //Console.WriteLine("{0}:{1}:{2}",col.ColumnName,col.DataType,col.OdbcType);
310 schemaRow = dataTableSchema.NewRow ();
311 dataTableSchema.Rows.Add (schemaRow);
313 schemaRow["ColumnName"] = col.ColumnName;
314 schemaRow["ColumnOrdinal"] = i + 1;
316 schemaRow["ColumnSize"] = col.MaxLength;
317 schemaRow["NumericPrecision"] = 0;
318 schemaRow["NumericScale"] = 0;
319 // TODO: need to get KeyInfo
320 schemaRow["IsUnique"] = false;
321 schemaRow["IsKey"] = DBNull.Value;
\r
323 schemaRow["BaseCatalogName"] = "";
324 schemaRow["BaseColumnName"] = col.ColumnName;
325 schemaRow["BaseSchemaName"] = "";
326 schemaRow["BaseTableName"] = "";
327 schemaRow["DataType"] = col.DataType;
\r
329 schemaRow["AllowDBNull"] = col.AllowDBNull;
331 schemaRow["ProviderType"] = (int) col.OdbcType;
332 // TODO: all of these
333 schemaRow["IsAliased"] = false;
334 schemaRow["IsExpression"] = false;
335 schemaRow["IsIdentity"] = false;
336 schemaRow["IsAutoIncrement"] = false;
337 schemaRow["IsRowVersion"] = false;
338 schemaRow["IsHidden"] = false;
339 schemaRow["IsLong"] = false;
340 schemaRow["IsReadOnly"] = false;
342 schemaRow.AcceptChanges();
348 return dataTableSchema;
351 public string GetString (int ordinal)
353 return (string) GetValue(ordinal);
357 public TimeSpan GetTimeSpan (int ordinal)
359 throw new NotImplementedException ();
362 public object GetValue (int ordinal)
364 if (currentRow == -1)
365 throw new IndexOutOfRangeException ();
367 if (ordinal>cols.Length-1 || ordinal<0)
368 throw new IndexOutOfRangeException ();
371 int outsize=0, bufsize;
373 OdbcColumn col=GetColumn(ordinal);
374 object DataValue=null;
375 ushort ColIndex=Convert.ToUInt16(ordinal+1);
377 // Check cached values
382 // mk:@MSITStore:C:\program%20files\Microsoft%20Data%20Access%20SDK\Docs\odbc.chm::/htm/odbcc_data_types.htm
383 switch (col.OdbcType)
385 case OdbcType.Decimal:
387 buffer=new byte[bufsize]; // According to sqlext.h, use SQL_CHAR for decimal
388 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.Char, buffer, bufsize, ref outsize);
390 DataValue=Decimal.Parse(System.Text.Encoding.Default.GetString(buffer));
392 case OdbcType.TinyInt:
394 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.TinyInt, ref short_data, 0, ref outsize);
395 DataValue=short_data;
399 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.Int, ref int_data, 0, ref outsize);
402 case OdbcType.BigInt:
404 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.BigInt, ref long_data, 0, ref outsize);
407 case OdbcType.NVarChar:
\r
408 bufsize=col.MaxLength*2+1; // Unicode is double byte
\r
409 buffer=new byte[bufsize];
410 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.NVarChar, buffer, bufsize, ref outsize);
412 DataValue=System.Text.Encoding.Unicode.GetString(buffer,0,outsize);
414 case OdbcType.VarChar:
415 bufsize=col.MaxLength+1;
416 buffer=new byte[bufsize]; // According to sqlext.h, use SQL_CHAR for both char and varchar
417 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.Char, buffer, bufsize, ref outsize);
419 DataValue=System.Text.Encoding.Default.GetString(buffer,0,outsize);
423 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.Real, ref float_data, 0, ref outsize);
424 DataValue=float_data;
426 case OdbcType.Timestamp:
427 case OdbcType.DateTime:
428 OdbcTimestamp ts_data=new OdbcTimestamp();
429 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.DateTime, ref ts_data, 0, ref outsize);
430 if (outsize!=-1) // This means SQL_NULL_DATA
431 DataValue=new DateTime(ts_data.year,ts_data.month,ts_data.day,ts_data.hour,
432 ts_data.minute,ts_data.second,Convert.ToInt32(ts_data.fraction));
435 //Console.WriteLine("Fetching unsupported data type as string: "+col.OdbcType.ToString());
437 buffer=new byte[bufsize];
438 ret=libodbc.SQLGetData(hstmt, ColIndex, OdbcType.Char, buffer, bufsize, ref outsize);
439 DataValue=System.Text.Encoding.Default.GetString(buffer);
443 if (outsize==-1) // This means SQL_NULL_DATA
444 col.Value=DBNull.Value;
447 libodbchelper.DisplayError("SQLGetData("+col.OdbcType.ToString()+")",ret);
455 public int GetValues (object[] values)
457 throw new NotImplementedException ();
461 IDataReader IDataRecord.GetData (int ordinal)
463 throw new NotImplementedException ();
467 void IDisposable.Dispose ()
472 IEnumerator IEnumerable.GetEnumerator ()
474 throw new NotImplementedException ();
477 public bool IsDBNull (int ordinal)
479 return (GetValue(ordinal) is DBNull);
482 public bool NextResult ()
484 OdbcReturn ret=libodbc.SQLFetch(hstmt);
485 if (ret!=OdbcReturn.Success)
489 // Clear cached values from last record
490 foreach (OdbcColumn col in cols)
495 return (ret==OdbcReturn.Success);