[Mono-list] ODBC.NET Data Provider

Brian Ritchie brianlritchie@hotmail.com
Wed, 09 Oct 2002 09:48:29 -0400


This is a multi-part message in MIME format.

------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; format=flowed

Ok...I've attached the ODBC.NET files.  Could someone put them in CVS for 
me?  Thanks :)

Just a couple of notes:
- The code is still in the works...but I've performed selects and inserts 
with it (including parameterized queries).
- Requires unixODBC to be installed and configured
- I've tested it on Debian with DB2

Known Issues:
- Only works with DSN connections (no DSN-less yet)
- It has transaction support, but not through the Transaction object
- Parameters only support integer types
- DBNull is not handled correctly
- Currently most errors are printed to the console instead of throwing 
exceptions...this wil change as I tighten things up.

Any feedback is appreciated...
Brian

>From: "Daniel Morgan" <danmorg@sc.rr.com>
>To: "Brian Ritchie" <brianlritchie@hotmail.com>, <mono-list@ximian.com>
>Subject: RE: [Mono-list] ODBC.NET Data Provider
>Date: Wed, 9 Oct 2002 01:40:07 -0400
>
>Hey Brian,
>
>Once you contribute something, you can get a cvs account.  You can attach
>your patch or files in an email to this list.  Someone like Rodrigo, me, or
>someone else would be happy to commit it for you.  Rodrigo is real good at
>this because he does a code review and let's you know what improvements can
>be done to it.
>
>Once something of yours has been contributed, you need to go
>to http://www.go-mono.com/ccvs.html
>and follow those directions on getting your own cvs account.
>
>Happy hacking,
>Daniel
>
>-----Original Message-----
>From: mono-list-admin@ximian.com [mailto:mono-list-admin@ximian.com]On
>Behalf Of Brian Ritchie
>Sent: Wednesday, October 09, 2002 12:34 AM
>To: danmorg@sc.rr.com; mono-list@ximian.com
>Subject: RE: [Mono-list] ODBC.NET Data Provider
>
>
>Daniel,
>
>Do I need to get setup with CVS access first?
>
>Brian
>
>
> >From: "Daniel Morgan" <danmorg@sc.rr.com>
> >To: "Brian Ritchie" <brianlritchie@hotmail.com>, <mono-list@ximian.com>
> >Subject: RE: [Mono-list] ODBC.NET Data Provider
> >Date: Tue, 8 Oct 2002 23:11:06 -0400
> >
> >Brian,
> >
> >Being able to connet to a database and do queries is a milestone in 
>itself.
> >It wouldn't hurt to go ahead and check it into cvs.  Besides, I feel 
>safer
> >anything I have worked on has been put into cvs because I know Ximian 
>guys
> >keep things backed up unlike my computer. :-)
> >
> >I don't know what the namespace or assembly for the ODBC provider in .NET
> >1.1, but the MSDN download of the ODBC provider for .NET 1.0 uses
> >Microsoft.Data.Odbc as the namespace and Microsoft.Data.Odbc.dll as the
> >assembly name.
> >
> >We have SQL# which is a command-line SQL query tool written in C# that 
>can
> >connect to various databases using the various ADO.NET providers.  It can
> >be
> >found
> >at mcs/class/System.Data/Test/SqlSharpCli.cs   However, don't be to
> >disappointed in the tool, it was mainly meant for testing Mono's
> >System.Data.
> >
> >What would be nice is to have a MS SQL Server 2000 Enterprise Manager,
> >Query
> >Analyzer, or TOAD like tool for Mono System.Data written in C# and using
> >GTK#.
> >
> >Daniel
> >
> >-----Original Message-----
> >From: mono-list-admin@ximian.com [mailto:mono-list-admin@ximian.com]On
> >Behalf Of Brian Ritchie
> >Sent: Tuesday, October 08, 2002 9:39 PM
> >To: danmorg@sc.rr.com; mono-list@ximian.com
> >Subject: RE: [Mono-list] ODBC.NET Data Provider
> >
> >
> >Sounds good, I've got a little more work before I send in the patch.  I
> >don't want to send in anything that is too raw :)
> >
> >Has anyone looked at .NET 1.1 yet?  I'm assuming they are moving the Odbc
> >stuff under the System.Data namespace...so that is how my stuff is setup.
> >(System.Data.Odbc)
> >
> >Have you guys talked about providing any basic db tools with the mono
> >framework?  Like a isql-style command line tool?  This might be a good 
>way
> >for people to test their database connections, etc.
> >
> >Keep up the good work guys...the framework is looking good.
> >
> >Brian
> >
> >
> > >From: "Daniel Morgan" <danmorg@sc.rr.com>
> > >To: "Brian Ritchie" <brianlritchie@hotmail.com>, <mono-list@ximian.com>
> > >Subject: RE: [Mono-list] ODBC.NET Data Provider
> > >Date: Mon, 7 Oct 2002 01:08:32 -0400
> > >
> > >Brian,
> > >
> > >This is good news.
> > >
> > >Can provide us with a patch please in an email to the
> >mono-list@ximian.com?
> > >If you don't know how to make a patch, you can look here on how:
> > >http://www.go-mono.com/ccvs.html
> > >
> > >This way people can get a preview of your work and be able to help
> > >contribute too.  Since unixODBC supports so many databases, it will
> > >definitely be appreciated.
> > >
> > >Do you know if unixODBC works on Windows?
> > >
> > >Thanks,
> > >Daniel
> > >
> > >-----Original Message-----
> > >From: mono-list-admin@ximian.com [mailto:mono-list-admin@ximian.com]On
> > >Behalf Of Brian Ritchie
> > >Sent: Monday, October 07, 2002 12:02 AM
> > >To: danmorg@sc.rr.com; mono-list@ximian.com
> > >Subject: RE: [Mono-list] ODBC.NET Data Provider
> > >
> > >
> > >Daniel,
> > >
> > >Thanks for the quick response.  I have basic implementations of
> > >OdbcConnection, OdbcCommand, OdbcDataReader, OdbcParameter, and
> > >OdbcParameterCollection.  It can execute queries and display result 
>sets
> > >(and ExecuteNonQuery too).  I'm currently working on the Parameter &
> > >Transaction support.  I've been doing my development on Debian against 
>a
> > >DB2
> > >7.2 UDB.
> > >
> > >Brian
> > >
> > >
> > > >From: "Daniel Morgan" <danmorg@sc.rr.com>
> > > >To: "Brian Ritchie" <brianlritchie@hotmail.com>, 
><mono-list@ximian.com>
> > > >Subject: RE: [Mono-list] ODBC.NET Data Provider
> > > >Date: Sun, 6 Oct 2002 22:51:07 -0400
> > > >
> > > >Brian
> > > >
> > > >No one is working on the ODBC.NET Data Provider as far as i know.  
>Just
> > > >attach your diff in an email, and someone, such as (passing the buck 
>-
> > > >hehehe) Rodrigo Moya can do that for you. Rodrigo is the coordinator
> >for
> > > >the
> > > >ADO.NET technology in Mono.
> > > >
> > > >What can you do witht he provider so far?  Can you connect to a
> >database
> > > >yet?  How about run any queries?  Or is it just C# bindings to the
> > >unixODBC
> > > >library(ies) right now?
> > > >
> > > >Daniel
> > > >
> > > >-----Original Message-----
> > > >From: mono-list-admin@ximian.com 
>[mailto:mono-list-admin@ximian.com]On
> > > >Behalf Of Brian Ritchie
> > > >Sent: Sunday, October 06, 2002 10:03 PM
> > > >To: mono-list@ximian.com
> > > >Subject: [Mono-list] ODBC.NET Data Provider
> > > >
> > > >
> > > >Is anyone working on a ODBC data provider?  I've started one using
> > >unixodbc
> > > >and I'd like to contribute it to the project.
> > > >
> > > >Brian
>
>
>
>
>_________________________________________________________________
>Send and receive Hotmail on your mobile device: http://mobile.msn.com
>
>
>_______________________________________________
>Mono-list maillist  -  Mono-list@ximian.com
>http://lists.ximian.com/mailman/listinfo/mono-list
>
>
>_______________________________________________
>Mono-list maillist  -  Mono-list@ximian.com
>http://lists.ximian.com/mailman/listinfo/mono-list




_________________________________________________________________
Send and receive Hotmail on your mobile device: http://mobile.msn.com

------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; name="libodbc.cs"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="libodbc.cs"

//
// System.Data.Odbc.libodbc
//
// Authors:
//   Brian Ritchie (brianlritchie@hotmail.com)
//
//
// Copyright (C) Brian Ritchie, 2002
//
//

using System.Data;
using System.Data.Common;
using System.Runtime.InteropServices;

namespace System.Data.Odbc
{
	internal enum OdbcHandleType {
		Env = 1,
		Dbc = 2,
		Stmt = 3,
		Desc = 4
	};

	internal enum OdbcReturn {
		Error = -1,
		InvalidHandle = -2,
		StillExecuting = 2,
		NeedData = 99,
		Success = 0,
		SuccessWithInfo = 1
	}

	internal enum OdbcEnv {
		OdbcVersion = 200,
		ConnectionPooling = 201,
		CPMatch = 202
	}

	[StructLayout(LayoutKind.Sequential)]
	public struct OdbcTimestamp
	{
		public short year;
		public ushort month;
		public ushort day;
		public ushort hour;
		public ushort minute;
		public ushort second;
		public ulong fraction;
	}

	sealed internal class libodbc
	{
		public static void DisplayError(string Msg, OdbcReturn Ret)
		{
			if ((Ret!=OdbcReturn.Success) && (Ret!=OdbcReturn.SuccessWithInfo)) {
				Console.WriteLine("ERROR: {0}: <{1}>",Msg,Ret);

			}
		}



		[DllImport("libodbc")]
		public static extern OdbcReturn SQLAllocHandle (ushort HandleType, int 
InputHandle, ref int OutputHandlePtr);


		[DllImport("libodbc")]
		public static extern OdbcReturn SQLSetEnvAttr (int EnvHandle, ushort 
Attribute, IntPtr Value, int StringLength);


		[DllImport("libodbc")]
		public static extern OdbcReturn SQLConnect (int ConnectionHandle, string 
ServerName, short NameLength1, string UserName, short NameLength2, string 
Authentication, short NameLength3);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLExecDirect (int StatementHandle, string 
StatementText, int TextLength);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLRowCount (int StatementHandle, ref int 
RowCount);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLNumResultCols (int StatementHandle, ref 
short ColumnCount);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLFetch (int StatementHandle);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLGetData (int StatementHandle, ushort 
ColumnNumber, short TargetType, ref int TargetPtr, int BufferLen, ref int 
Len);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLGetData (int StatementHandle, ushort 
ColumnNumber, short TargetType, byte[] TargetPtr, int BufferLen, ref int 
Len);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLGetData (int StatementHandle, ushort 
ColumnNumber, short TargetType, ref float TargetPtr, int BufferLen, ref int 
Len);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLGetData (int StatementHandle, ushort 
ColumnNumber, short TargetType, ref OdbcTimestamp TargetPtr, int BufferLen, 
ref int Len);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLDescribeCol(int StatmentHandle, ushort 
ColumnNumber, byte[] ColumnName, short BufferLength, ref short NameLength, 
ref short DataType, ref short ColumnSize, ref short DecimalDigits, ref short 
Nullable);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLFreeHandle(ushort HandleType, int 
SqlHandle);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLDisconnect(int ConnectionHandle);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLPrepare(int StatementHandle, string 
Statement, int TextLength);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLExecute(int StatementHandle);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLSetConnectAttr(int ConnectionHandle, 
int Attribute, uint Value, int Length);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLEndTran(int HandleType, int Handle, 
short CompletionType);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLBindParam(int StatementHandle, short 
ParamNum, short ValueType,
				short ParamType, int LenPrecision, short ParamScale, ref int ParamValue, 
int StrLen);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLBindParam(int StatementHandle, short 
ParamNum, short ValueType,
				short ParamType, int LenPrecision, short ParamScale, byte[] ParamValue, 
int StrLen);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLCancel(int StatementHandle);

		[DllImport("libodbc")]
		public static extern OdbcReturn SQLCloseCursor(int StatementHandle);
	}
}


------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; name="OdbcCommand.cs"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="OdbcCommand.cs"

//
// System.Data.Odbc.OdbcCommand
//
// Authors:
//   Brian Ritchie (brianlritchie@hotmail.com)
//
// Copyright (C) Brian Ritchie, 2002
//

using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Collections;
using System.Runtime.InteropServices;

namespace System.Data.Odbc
{
	/// <summary>
	/// Represents an SQL statement or stored procedure to execute against a 
data source.
	/// </summary>
	public sealed class OdbcCommand : Component, ICloneable, IDbCommand
	{
		#region Fields

		string commandText;
		int timeout;
		CommandType commandType;
		OdbcConnection connection;
		OdbcParameterCollection parameters;
		//OdbcTransaction transaction;
		bool designTimeVisible;
		bool prepared=false;
		OdbcDataReader dataReader;
		CommandBehavior behavior;
		public int hstmt;

		#endregion // Fields

		#region Constructors

		public OdbcCommand ()
	        {
			commandText = String.Empty;
			timeout = 30; // default timeout
			commandType = CommandType.Text;
			connection = null;
			parameters = new OdbcParameterCollection ();
			//transaction = null;
			designTimeVisible = false;
			dataReader = null;
			behavior = CommandBehavior.Default;
		}

		public OdbcCommand (string cmdText) : this ()
		{
			CommandText = cmdText;
		}

		public OdbcCommand (string cmdText, OdbcConnection connection)
			: this (cmdText)
		{
			Connection = connection;
		}

//		public OdbcCommand (string cmdText,
//				     OdbcConnection connection,
//				     OdbcTransaction transaction) : this (cmdText, connection)
//		{
//			this.transaction = transaction;
//		}

		#endregion // Constructors

		#region Properties

		public int hStmt
		{
			get { return hstmt; }
		}

		public string CommandText
		{
			get {
				return commandText;
			}
			set {
				prepared=false;
				commandText = value;
			}
		}

		public int CommandTimeout {
			get {
				return timeout;
			}
			set {
				timeout = value;
			}
		}

		public CommandType CommandType {
			get {
				return commandType;
			}
			set {
				commandType = value;
			}
		}

		public OdbcConnection Connection {
			get {
				return connection;
			}
			set {
				connection = value;
			}
		}

		public bool DesignTimeVisible {
			get {
				return designTimeVisible;
			}
			set {
				designTimeVisible = value;
			}
		}

		public OdbcParameterCollection Parameters {
			get {
				return parameters;
			}
			set {
				parameters = value;
			}
		}

//		public OdbcTransaction Transaction {
//			get {
//				return transaction;
//			}
//			set {
//				transaction = value;
//			}
//		}

		public UpdateRowSource UpdatedRowSource {
			[MonoTODO]
			get {
				throw new NotImplementedException ();
			}
			[MonoTODO]
			set {
				throw new NotImplementedException ();
			}
		}

		IDbConnection IDbCommand.Connection {
			get {
				return Connection;
			}
			set {
				Connection = (OdbcConnection) value;
			}
		}

		IDataParameterCollection IDbCommand.Parameters  {
			get {
				throw new NotImplementedException ();
				//return Parameters;
			}
		}

		IDbTransaction IDbCommand.Transaction  {
			get {
				throw new NotImplementedException ();
				//return Transaction;
			}
			set {
				throw new NotImplementedException ();
			}
		}

		#endregion // Properties

		#region Methods

		[MonoTODO]
		public void Cancel ()
		{
			throw new NotImplementedException ();
		}

		public OdbcParameter CreateParameter ()
		{
			return new OdbcParameter ();
		}

		IDbDataParameter IDbCommand.CreateParameter ()
		{
			return CreateParameter ();
		}

		[MonoTODO]
		protected override void Dispose (bool disposing)
		{
			throw new NotImplementedException ();
		}

		protected void ExecSQL(string sql)
		{
			OdbcReturn ret;

			if (!prepared)
			{
				Prepare();
				if (Parameters.Count>0)
					Parameters.Bind(hstmt);
			}

			if (prepared)
			{
				ret=libodbc.SQLExecute(hstmt);
				libodbc.DisplayError("SQLExecute",ret);
			}
			else
			{
				ret=libodbc.SQLAllocHandle((ushort) OdbcHandleType.Stmt, 
Connection.hDbc, ref hstmt);
				libodbc.DisplayError("SQLAllocHandle(hstmt)",ret);
				ret=libodbc.SQLExecDirect(hstmt, sql, sql.Length);
				libodbc.DisplayError("SQLExecDirect",ret);
			}
		}

		public int ExecuteNonQuery ()
		{
			if (connection == null)
				throw new InvalidOperationException ();
			if (connection.State == ConnectionState.Closed)
				throw new InvalidOperationException ();
			// FIXME: a third check is mentioned in .NET docs
			if (connection.DataReader != null)
				throw new InvalidOperationException ();

			ExecSQL(CommandText);

			if (!prepared)
				libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, hstmt);
			return 0;
		}

		public void Prepare()
		{
			OdbcReturn ret;
			ret=libodbc.SQLAllocHandle((ushort) OdbcHandleType.Stmt, Connection.hDbc, 
ref hstmt);
			libodbc.DisplayError("SQLAlloc(Prepare)",ret);
			ret=libodbc.SQLPrepare(hstmt, CommandText, CommandText.Length);
			libodbc.DisplayError("SQLPrepare",ret);
			prepared=true;
		}

		public OdbcDataReader ExecuteReader ()
		{
			return ExecuteReader (CommandBehavior.Default);
		}

		IDataReader IDbCommand.ExecuteReader ()
		{
			return ExecuteReader ();
		}

		public OdbcDataReader ExecuteReader (CommandBehavior behavior)
		{
			ExecuteNonQuery();
			dataReader=new OdbcDataReader(this);
			return dataReader;
		}

		IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
		{
			return ExecuteReader (behavior);
		}

		public object ExecuteScalar ()
		{
					throw new NotImplementedException ();
//			if (connection.DataReader != null)
//				throw new InvalidOperationException ();
//
		}

		[MonoTODO]
		object ICloneable.Clone ()
		{
			throw new NotImplementedException ();
		}

		public void ResetCommandTimeout ()
		{
			timeout = 30;
		}

		#endregion
	}
}


------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; name="OdbcConnection.cs"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="OdbcConnection.cs"


//
// System.Data.Odbc.OdbcConnection
//
// Authors:
//  Brian Ritchie (brianlritchie@hotmail.com)
//
// Copyright (C) Brian Ritchie, 2002
//

using System.ComponentModel;
using System.Data;
using System.Data.Common;

namespace System.Data.Odbc
{
	public sealed class OdbcConnection : Component, ICloneable, IDbConnection
	{
		#region Fields

		string connectionString;
		int connectionTimeout;
		OdbcDataReader dataReader;
		int henv=0, hdbc=0;
		private string _uid, _pwd, _dsn;

		#endregion

		#region Constructors

		public OdbcConnection ()
		{
			OdbcReturn ret;

			// allocate Environment handle
			ret=libodbc.SQLAllocHandle((ushort) OdbcHandleType.Env, 0, ref henv);
			libodbc.DisplayError("SQLAllocHandle", ret);

			ret=libodbc.SQLSetEnvAttr(henv, (ushort) OdbcEnv.OdbcVersion, (IntPtr) 3 
, 0);
			libodbc.DisplayError("SQLSetEnvAttr", ret);

			Console.WriteLine("ODBCInit Complete.");
			connectionTimeout = 15;
			connectionString = null;
			dataReader = null;
		}

		public OdbcConnection (string connectionString) : this ()
		{
			ConnectionString = connectionString;
		}

		#endregion // Constructors

		#region Properties

		public int hDbc
		{
			get { return hdbc; }
		}

		public string ConnectionString {
			get {
				return connectionString;
			}
			set {
				connectionString = value;

				string[] items=connectionString.Split(new char[1]{';'});
				foreach (string item in items)
				{
					string[] parts=item.Split(new char[1] {'='});
					switch (parts[0].Trim().ToLower())
					{
						case "dsn":
							_dsn=parts[1].Trim();
							break;
						case "uid":
							_uid=parts[1].Trim();
							break;
						case "pwd":
							_pwd=parts[1].Trim();
							break;
					}
				}
			}
		}

		public int ConnectionTimeout {
			get {
				return connectionTimeout;
			}
		}

		public string DataSource {
			get {
				if (State==ConnectionState.Open)
					return _dsn;
				else
					return null;
			}
		}

		public string Database {
			get {
				return "";
			}
		}

		public ConnectionState State
		{
			get {
				if (hdbc!=0) {
					return ConnectionState.Open;
				}
				else
					return ConnectionState.Closed;
			}
		}

		internal OdbcDataReader DataReader
	        {
			get {
				return dataReader;
			}
			set {
				dataReader = value;
			}
		}

		#endregion // Properties

		#region Methods

		public void BeginTransaction()
		{
			OdbcReturn ret;
			// Set Auto-commit to false
			ret=libodbc.SQLSetConnectAttr(hdbc, 102, 0, 0);
			libodbc.DisplayError("SQLSetConnectAttr(NoAutoCommit)", ret);
		}

		public void CommitTransaction()
		{
			OdbcReturn ret;
			ret=libodbc.SQLEndTran((short) OdbcHandleType.Dbc, hdbc, 0);
			libodbc.DisplayError("SQLEndTran(commit)", ret);
		}

		public void RollbackTransaction()
		{
			OdbcReturn ret;
			ret=libodbc.SQLEndTran((short) OdbcHandleType.Dbc, hdbc, 1);
			libodbc.DisplayError("SQLEndTran(rollback)", ret);
		}

//		public OdbcTransaction BeginTransaction ()
//		{
//              }

		IDbTransaction IDbConnection.BeginTransaction ()
		{
			throw new NotImplementedException ();
	//		return BeginTransaction ();
		}

//		public OdbcTransaction BeginTransaction (IsolationLevel level)
//		{
//
//		}

		IDbTransaction IDbConnection.BeginTransaction (IsolationLevel level)
		{
			throw new NotImplementedException ();
		//	return BeginTransaction (level);
		}

		public void Close ()
		{
			if (State == ConnectionState.Open) {
				hdbc = 0;
			}

			dataReader = null;
		}

		public OdbcCommand CreateCommand ()
		{
			throw new NotImplementedException ();
		}

		[MonoTODO]
		public void ChangeDatabase(string Database)
		{
			throw new NotImplementedException ();
		}


		[MonoTODO]
		protected override void Dispose (bool disposing)
		{
			throw new NotImplementedException ();
		}

		[MonoTODO]
		object ICloneable.Clone ()
		{
			throw new NotImplementedException();
		}

		IDbCommand IDbConnection.CreateCommand ()
		{
			throw new NotImplementedException();
	//		return CreateCommand ();
		}

		public void Open ()
		{
			if (State == ConnectionState.Open)
				throw new InvalidOperationException ();

			OdbcReturn ret;

			// allocate connection handle
			ret=libodbc.SQLAllocHandle((ushort) OdbcHandleType.Dbc, henv, ref hdbc);
			libodbc.DisplayError("SQLAllocHandle(hdbc)", ret);

			// Connect to data source
			ret=libodbc.SQLConnect(hdbc, _dsn, -3, _uid, -3, _pwd, -3);
			libodbc.DisplayError("SQLConnect",ret);

		}

		[MonoTODO]
		public static void ReleaseObjectPool ()
		{
			throw new NotImplementedException ();
		}

		#endregion

		#region Events and Delegates

		public event StateChangeEventHandler StateChange;

		#endregion
	}
}


------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; name="OdbcDataReader.cs"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="OdbcDataReader.cs"

//
// 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
	}
}


------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; name="OdbcParameter.cs"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="OdbcParameter.cs"

//
// System.Data.Odbc.OdbcParameter
//
// Authors:
//   Brian Ritchie (brianlritchie@hotmail.com)
//
// Copyright (C) Brian Ritchie, 2002
//

using System;
using System.Data;
using System.Data.Common;

namespace System.Data.Odbc
{
	public sealed class OdbcParameter : MarshalByRefObject, IDbDataParameter, 
IDataParameter, ICloneable
	{
		#region Fields

		string name;
		object value;
		int size;
		bool isNullable;
		byte precision;
		byte scale;
		DataRowVersion sourceVersion;
		string sourceColumn;
		ParameterDirection direction;
		OdbcType odbcType;
		DbType dbType;

		int IntValue;

		#endregion

		#region Constructors

		public OdbcParameter ()
		{
			name = String.Empty;
			value = null;
			size = 0;
			isNullable = true;
			precision = 0;
			scale = 0;
			sourceColumn = String.Empty;
		}

		public OdbcParameter (string name, object value)
			: this ()
		{
			this.name = name;
			this.value = value;
		}

		public OdbcParameter (string name, OdbcType dataType)
			: this ()
		{
			this.name = name;
			OdbcType = dataType;
		}

		public OdbcParameter (string name, OdbcType dataType, int size)
			: this (name, dataType)
		{
			this.size = size;
		}

		public OdbcParameter (string name, OdbcType dataType, int size, string 
srcColumn)
			: this (name, dataType, size)
		{
			this.sourceColumn = srcColumn;
		}

		public OdbcParameter(string name, OdbcType dataType, int size, 
ParameterDirection direction, bool isNullable, byte precision, byte scale, 
string srcColumn, DataRowVersion srcVersion, object value)
			: this (name, dataType, size, srcColumn)
		{
			this.direction = direction;
			this.isNullable = isNullable;
			this.precision = precision;
			this.scale = scale;
			this.sourceVersion = srcVersion;
			this.value = value;
		}

		#endregion

		#region Properties

		public DbType DbType {
			get { return dbType; }
			set {
				dbType = value;
			}
		}

		public ParameterDirection Direction {
			get { return direction; }
			set { direction = value; }
		}

		public bool IsNullable {
			get { return isNullable; }
		}

		public OdbcType OdbcType {
			get { return odbcType; }
			set {
				odbcType = value;
			}
		}

		public string ParameterName {
			get { return name; }
			set { name = value; }
		}

		public byte Precision {
			get { return precision; }
			set { precision = value; }
		}

		public byte Scale {
			get { return scale; }
			set { scale = value; }
		}

		public int Size {
			get { return size; }
			set { size = value; }
		}

		public string SourceColumn {
			get { return sourceColumn; }
			set { sourceColumn = value; }
		}

		public DataRowVersion SourceVersion {
			get { return sourceVersion; }
			set { sourceVersion = value; }
		}

		public object Value {
			get {
				return IntValue;
			}
			set { this.IntValue =(int) value; }
		}

		#endregion // Properties

		#region Internal Properties

		internal void Bind(int hstmt,int ParamNum)
		{
			if (OdbcType==OdbcType.Integer)
			{
				OdbcReturn ret=libodbc.SQLBindParam(hstmt, Convert.ToInt16(ParamNum), 4, 
4, 0,0,ref IntValue, 0);
				libodbc.DisplayError("SQLBindParam",ret);

			}
			else Console.WriteLine("Unknown Paramter Type");

		}

		#endregion // Internal Properties

		#region Methods

		[MonoTODO]
		object ICloneable.Clone ()
		{
			throw new NotImplementedException ();
		}

		public override string ToString ()
		{
			return ParameterName;
		}
		#endregion
	}
}


------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; name="OdbcParameterCollection.cs"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="OdbcParameterCollection.cs"


//
// System.Data.Odbc.OdbcParameterCollection
//
// Author:
//   Brian Ritchie (brianlritchie@hotmail.com)
//
// Copyright (C) Brian Ritchie, 2002
//

using System.Collections;
using System.Data;
using System.Data.Common;

namespace System.Data.Odbc
{
	public sealed class OdbcParameterCollection : MarshalByRefObject,
		IDataParameterCollection, IList, ICollection, IEnumerable
	{
		#region Fields

		ArrayList list = new ArrayList ();

		#endregion // Fields

		#region Properties

		public int Count {
			get { return list.Count; }
		}

		public OdbcParameter this[int index] {
			get { return (OdbcParameter) list[index]; }
			set { list[index] = value; }
		}

		public OdbcParameter this[string parameterName] {
			[MonoTODO]
			get { throw new NotImplementedException (); }
			[MonoTODO]
			set { throw new NotImplementedException (); }
		}

		int ICollection.Count {
			get { return list.Count; }
		}

		bool IList.IsFixedSize {
			get { return false; }
		}

		bool IList.IsReadOnly {
			get { return false; }
		}

		bool ICollection.IsSynchronized {
			get { return list.IsSynchronized; }
		}

		object ICollection.SyncRoot {
			get { return list.SyncRoot; }
		}

		object IList.this[int index] {
			get { return list[index]; }
			set { list[index] = value; }
		}

		object IDataParameterCollection.this[string name]
		{
			[MonoTODO]
			get {
				throw new NotImplementedException ();
			}
			[MonoTODO]
			set {
				throw new NotImplementedException ();
			}
		}

		#endregion // Properties

		#region Methods


		public OdbcParameter Add (OdbcParameter parameter)
		{
			list.Add (parameter);
			return parameter;
		}

		public OdbcParameter Add (string name, object value)
		{
			OdbcParameter parameter = new OdbcParameter (name, value);
			list.Add (parameter);
			return parameter;
		}

		public OdbcParameter Add (string name, OdbcType type)
	        {
			OdbcParameter parameter = new OdbcParameter (name, type);
			list.Add (parameter);
			return parameter;
		}

		public OdbcParameter Add (string name, OdbcType type, int width)
		{
			OdbcParameter parameter = new OdbcParameter (name, type, width);
			list.Add (parameter);
			return parameter;
		}

		public OdbcParameter Add (string name, OdbcType type,
					   int width, string src_col)
		{
			OdbcParameter parameter = new OdbcParameter (name, type, width, src_col);
			list.Add (parameter);
			return parameter;
		}


		internal void Bind(int hstmt)
		{
			for (int i=0;i<Count;i++)
			{
				this[i].Bind(hstmt,i+1);

			}
		}

		int IList.Add (object value)
		{
			if (!(value is IDataParameter))
				throw new InvalidCastException ();


			list.Add (value);
			return list.IndexOf (value);
		}

		void IList.Clear ()
		{
			list.Clear ();
		}

		bool IList.Contains (object value)
		{
			return list.Contains (value);
		}

		bool IDataParameterCollection.Contains (string value)
		{
			for (int i = 0; i < list.Count; i++) {
				IDataParameter parameter;

				parameter = (IDataParameter) list[i];
				if (parameter.ParameterName == value)
					return true;
			}

			return false;
		}

		void ICollection.CopyTo (Array array, int index)
		{
			((OdbcParameter[])(list.ToArray ())).CopyTo (array, index);
		}

		IEnumerator IEnumerable.GetEnumerator ()
		{
			return list.GetEnumerator ();
		}

		int IList.IndexOf (object value)
		{
			return list.IndexOf (value);
		}

		int IDataParameterCollection.IndexOf (string name)
		{
			return list.IndexOf (((IDataParameterCollection) this)[name]);
		}

		void IList.Insert (int index, object value)
	        {
			list.Insert (index, value);
		}

		void IList.Remove (object value)
		{
			list.Remove (value);
		}

		void IList.RemoveAt (int index)
		{
			list.Remove ((object) list[index]);
		}

		void IDataParameterCollection.RemoveAt (string name)
		{
			list.Remove (((IDataParameterCollection) this)[name]);
		}

		#endregion // Methods
	}
}


------=_NextPart_000_1137_7ffa_3c09
Content-Type: text/plain; name="OdbcType.cs"; format=flowed
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="OdbcType.cs"

//
// System.Data.Odbc.OdbcType
//
// Author:
//   Brian Ritchie
//
// Copyright (C) Brian Ritchie, 2002
//

using System.Data;
using System.Data.Common;

namespace System.Data.Odbc
{
	public enum OdbcType {
		BigInt,
		Binary,
		Boolean,
		BSTR,
		Char,
		Currency,
		Date,
		DBDate,
		DBTime,
		DBTimeStamp,
		Decimal,
		Double,
		Empty,
		Error,
		Filetime,
		Guid,
		IDispatch,
		Integer,
		IUnknown,
		LongVarBinary,
		LongVarChar,
		LongVarWChar,
		Numeric,
		PropVariant,
		Single,
		SmallInt,
		TinyInt,
		UnsignedBigInt,
		UnsignedInt,
		UnsignedSmallInt,
		UnsignedTinyInt,
		VarBinary,
		VarChar,
		Variant,
		VarNumeric,
		VarWChar,
		WChar
	}
}


------=_NextPart_000_1137_7ffa_3c09--