+//
+// System.Data.Odbc.OdbcDataReader
+//
+// Author:
+// Brian Ritchie (brianlritchie@hotmail.com)
+//
+// Copyright (C) Brian Ritchie, 2002
+//
+
+using System.Collections;
+using System.ComponentModel;
+using System.Data;
+using System.Data.Common;
+using System.Runtime.InteropServices;
+
+namespace System.Data.Odbc
+{
+ public sealed class OdbcDataReader : MarshalByRefObject, IDataReader,
+IDisposable, IDataRecord, IEnumerable
+ {
+ #region Fields
+
+ private OdbcCommand command;
+ private bool open;
+ private int currentRow;
+ private DataColumn[] cols;
+ private int hstmt;
+
+ #endregion
+
+ #region Constructors
+
+ internal OdbcDataReader (OdbcCommand command)
+ {
+ this.command = command;
+ this.command.Connection.DataReader = this;
+ open = true;
+ currentRow = -1;
+ hstmt=command.hStmt;
+ LoadColumns();
+ }
+
+ #endregion
+
+ #region Properties
+
+ public int Depth {
+ get {
+ return 0; // no nested selects supported
+ }
+ }
+
+ public int FieldCount {
+ get {
+
+ return cols.Length;
+ }
+ }
+
+ public bool IsClosed {
+ get {
+ return !open;
+ }
+ }
+
+ public DataColumn[] Columns
+ {
+ get {
+ return cols;
+ }
+ }
+
+ public object this[string name] {
+ get {
+ ushort pos;
+
+ if (currentRow == -1)
+ throw new InvalidOperationException ();
+
+ pos = ColIndex(name);
+
+ if (pos == -1)
+ throw new IndexOutOfRangeException ();
+
+ return this[pos];
+ }
+ }
+
+ public object this[int index] {
+ get {
+ return (object) GetODBCData (index);
+ }
+ }
+
+ public int RecordsAffected {
+ get {
+ return -1;
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ private Type SQLTypeToCILType(short DataType)
+ {
+ switch (DataType)
+ {
+ case 12:
+ case 1:
+ return typeof(string);
+ case 4:
+ return typeof(int);
+ case 5:
+ return typeof(short);
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ case 8:
+ return typeof(float);
+ case 90:
+ case 91:
+ case 92:
+ case 9:
+ return typeof(DateTime);
+ default:
+ Console.WriteLine("WARNING: Unknown type {0}", DataType);
+ return typeof(string);
+ }
+ }
+
+ private short CILTypeToSQLType(Type type)
+ {
+ if (type==typeof(int))
+ return 4;
+ else if (type==typeof(string))
+ return 12;
+ else
+ return 12;
+ }
+
+ private void LoadColumns()
+ {
+ ArrayList colsArray=new ArrayList();
+ short colcount=0;
+ short bufsize=255;
+ byte[] colname_buffer=new byte[bufsize];
+ string colname;
+ short colname_size=0;
+ short DataType=0, ColSize=0, DecDigits=0, Nullable=0;
+
+ libodbc.SQLNumResultCols(hstmt, ref colcount);
+ for (ushort i=1;i<=colcount;i++)
+ {
+ libodbc.SQLDescribeCol(hstmt, i, colname_buffer, bufsize, ref
+colname_size, ref DataType, ref ColSize, ref DecDigits, ref Nullable);
+ colname=System.Text.Encoding.Default.GetString(colname_buffer);
+ DataColumn c=new DataColumn(colname, SQLTypeToCILType(DataType));
+ c.AllowDBNull=(Nullable!=0);
+ if (c.DataType==typeof(string))
+ c.MaxLength=ColSize;
+ colsArray.Add(c);
+ }
+ cols=(DataColumn[]) colsArray.ToArray(typeof(DataColumn));
+ }
+
+ private ushort ColIndex(string colname)
+ {
+ ushort i=0;
+ foreach (DataColumn col in cols)
+ {
+ if (col.ColumnName==colname)
+ return i;
+ i++;
+ }
+ return 0;
+ }
+
+ private object GetODBCData(int colindex)
+ {
+ return GetODBCData(Convert.ToUInt16(colindex));
+ }
+
+ private object GetODBCData(ushort colindex)
+ {
+ OdbcReturn ret;
+ int outsize=0;
+ DataColumn col=cols[colindex];
+ colindex+=1;
+ if (col.DataType==typeof(int))
+ {
+ int data=0;
+ ret=libodbc.SQLGetData(hstmt, colindex, 4, ref data, 0, ref outsize);
+ libodbc.DisplayError("SQLGetData(int)",ret);
+ return data;
+ }
+ else if (col.DataType==typeof(string))
+ {
+ byte[] strbuffer=new byte[255];
+ ret=libodbc.SQLGetData(hstmt, colindex, 1, strbuffer, 255, ref outsize);
+ libodbc.DisplayError("SQLGetData("+col.ColumnName+","+colindex.ToString()+")",ret);
+ return System.Text.Encoding.Default.GetString(strbuffer);
+ }
+ else if (col.DataType==typeof(float))
+ {
+ float data=0;
+ ret=libodbc.SQLGetData(hstmt, colindex, 7, ref data, 0, ref outsize);
+ return data;
+ }
+ else if (col.DataType==typeof(DateTime))
+ {
+ OdbcTimestamp data=new OdbcTimestamp();
+ ret=libodbc.SQLGetData(hstmt, colindex, 91, ref data, 0, ref outsize);
+ return new
+DateTime(data.year,data.month,data.day,data.hour,data.minute,data.second,Convert.ToInt32(data.fraction));
+ }
+ else return "";
+ }
+
+
+ public void Close ()
+ {
+ // libodbc.SQLFreeHandle((ushort) OdbcHandleType.Stmt, hstmt);
+
+ OdbcReturn ret=libodbc.SQLCloseCursor(hstmt);
+ libodbc.DisplayError("SQLCancel",ret);
+
+ open = false;
+ currentRow = -1;
+
+ this.command.Connection.DataReader = null;
+ }
+
+ ~OdbcDataReader ()
+ {
+ if (open)
+ Close ();
+ }
+
+ public bool GetBoolean (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public byte GetByte (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public long GetBytes (int ordinal, long dataIndex, byte[] buffer, int
+bufferIndex, int length)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public char GetChar (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public long GetChars (int ordinal, long dataIndex, char[] buffer, int
+bufferIndex, int length)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public OdbcDataReader GetData (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public string GetDataTypeName (int index)
+ {
+ return "";
+ }
+
+ public DateTime GetDateTime (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public decimal GetDecimal (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public double GetDouble (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public Type GetFieldType (int index)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public float GetFloat (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public Guid GetGuid (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public short GetInt16 (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public int GetInt32 (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public long GetInt64 (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public string GetName (int index)
+ {
+ if (currentRow == -1)
+ return null;
+ return cols[index].ColumnName;
+ }
+
+ public int GetOrdinal (string name)
+ {
+ if (currentRow == -1)
+ throw new IndexOutOfRangeException ();
+
+ int i=ColIndex(name);
+
+ if (i==-1)
+ throw new IndexOutOfRangeException ();
+ else
+ return i;
+ }
+
+ public DataTable GetSchemaTable ()
+ {
+ DataTable table = new DataTable ();
+
+ // FIXME: implement
+ return table;
+ }
+
+ public string GetString (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public TimeSpan GetTimeSpan (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public object GetValue (int ordinal)
+ {
+ if (currentRow == -1)
+ throw new IndexOutOfRangeException ();
+
+ if (ordinal>cols.Length-1 || ordinal<0)
+ throw new IndexOutOfRangeException ();
+
+ return (object) GetODBCData(ordinal);
+ }
+
+ [MonoTODO]
+ public int GetValues (object[] values)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ IDataReader IDataRecord.GetData (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ void IDisposable.Dispose ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool IsDBNull (int ordinal)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public bool NextResult ()
+ {
+ OdbcReturn ret=libodbc.SQLFetch(hstmt);
+ return (ret==OdbcReturn.Success);
+ }
+
+ public bool Read ()
+ {
+ return NextResult();
+ }
+
+ #endregion
+ }
+}
+