2 // System.Data.Odbc.OdbcConnection
5 // Brian Ritchie (brianlritchie@hotmail.com)
7 // Copyright (C) Brian Ritchie, 2002
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.ComponentModel;
35 using System.Data.Common;
36 using System.Runtime.InteropServices;
38 using System.Data.ProviderBase;
40 using System.EnterpriseServices;
42 namespace System.Data.Odbc
44 [DefaultEvent("InfoMessage")]
46 public sealed class OdbcConnection : DbConnectionBase, ICloneable
48 public sealed class OdbcConnection : Component, ICloneable, IDbConnection
54 string connectionString;
57 int connectionTimeout;
58 internal OdbcTransaction transaction;
59 IntPtr henv=IntPtr.Zero, hdbc=IntPtr.Zero;
60 bool disposed = false;
66 public OdbcConnection () : this (String.Empty)
70 public OdbcConnection (string connectionString)
72 Init (connectionString);
75 private void Init (string connectionString)
77 connectionTimeout = 15;
78 ConnectionString = connectionString;
82 internal OdbcConnection (OdbcConnectionFactory factory)
83 : base ( (DbConnectionFactory) factory)
91 #endregion // Constructors
101 [OdbcCategoryAttribute ("DataCategory_Data")]
103 [OdbcDescriptionAttribute ("Information used to connect to a Data Source")]
104 [RefreshPropertiesAttribute (RefreshProperties.All)]
105 [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
106 [RecommendedAsConfigurableAttribute (true)]
107 public string ConnectionString {
109 return connectionString;
112 connectionString = value;
117 [OdbcDescriptionAttribute ("Current connection timeout value, not settable in the ConnectionString")]
123 int ConnectionTimeout {
125 return connectionTimeout;
129 throw new ArgumentException("Timout should not be less than zero.");
131 connectionTimeout = value;
135 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
136 [OdbcDescriptionAttribute ("Current data source Catlog value, 'Database=X' in the ConnectionString")]
143 return GetInfo (OdbcInfo.DatabaseName);
147 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
148 [OdbcDescriptionAttribute ("The ConnectionState indicating whether the connection is open or closed")]
149 [BrowsableAttribute (false)]
154 ConnectionState State
157 if (hdbc!=IntPtr.Zero) {
158 return ConnectionState.Open;
161 return ConnectionState.Closed;
166 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
167 [OdbcDescriptionAttribute ("Current data source, 'Server=X' in the ConnectionString")]
174 return GetInfo (OdbcInfo.DataSourceName);
179 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
180 [OdbcDescriptionAttribute ("Current ODBC Driver")]
181 public string Driver {
183 return GetInfo (OdbcInfo.DriverName);
188 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
189 [OdbcDescriptionAttribute ("Version of the product accessed by the ODBC Driver")]
190 [BrowsableAttribute (false)]
195 string ServerVersion {
197 return GetInfo (OdbcInfo.DbmsVersion);
202 #endregion // Properties
210 OdbcTransaction BeginTransaction ()
212 return BeginTransaction(IsolationLevel.Unspecified);
216 IDbTransaction IDbConnection.BeginTransaction ()
218 return (IDbTransaction) BeginTransaction();
226 OdbcTransaction BeginTransaction (IsolationLevel level)
228 if (transaction==null)
230 transaction=new OdbcTransaction(this,level);
234 throw new InvalidOperationException();
238 IDbTransaction IDbConnection.BeginTransaction (IsolationLevel level)
240 return (IDbTransaction) BeginTransaction(level);
250 OdbcReturn ret = OdbcReturn.Error;
251 if (State == ConnectionState.Open) {
253 ret = libodbc.SQLDisconnect (hdbc);
254 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
255 throw new OdbcException (new OdbcError ("SQLDisconnect", OdbcHandleType.Dbc,hdbc));
261 OnStateChange (ConnectionState.Open, ConnectionState.Closed);
269 OdbcCommand CreateCommand ()
271 return new OdbcCommand("", this, transaction);
279 void ChangeDatabase(string Database)
281 IntPtr ptr = IntPtr.Zero;
282 OdbcReturn ret = OdbcReturn.Error;
285 ptr = Marshal.StringToHGlobalAnsi (Database);
286 ret = libodbc.SQLSetConnectAttr (hdbc, OdbcConnectionAttribute.CurrentCatalog, ptr, Database.Length);
288 if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
289 throw new OdbcException (new OdbcError ("SQLSetConnectAttr", OdbcHandleType.Dbc, hdbc));
291 if (ptr != IntPtr.Zero)
292 Marshal.FreeCoTaskMem (ptr);
296 protected override void Dispose (bool disposing)
298 if (!this.disposed) {
301 // release the native unmananged resources
303 this.disposed = true;
307 // call Dispose on the base class
308 base.Dispose(disposing);
314 object ICloneable.Clone ()
316 throw new NotImplementedException();
320 IDbCommand IDbConnection.CreateCommand ()
322 return (IDbCommand) CreateCommand ();
332 if (State == ConnectionState.Open)
333 throw new InvalidOperationException ();
335 OdbcReturn ret = OdbcReturn.Error;
338 // allocate Environment handle
339 ret = libodbc.SQLAllocHandle (OdbcHandleType.Env, IntPtr.Zero, ref henv);
340 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
341 throw new OdbcException (new OdbcError ("SQLAllocHandle"));
343 ret=libodbc.SQLSetEnvAttr (henv, OdbcEnv.OdbcVersion, (IntPtr) libodbc.SQL_OV_ODBC3 , 0);
344 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
345 throw new OdbcException (new OdbcError ("SQLSetEnvAttr", OdbcHandleType.Env,henv));
347 // allocate connection handle
348 ret=libodbc.SQLAllocHandle (OdbcHandleType.Dbc, henv, ref hdbc);
349 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
350 throw new OdbcException (new OdbcError ("SQLAllocHandle",OdbcHandleType.Env,henv));
353 if (ConnectionString.ToLower().IndexOf("dsn=")>=0)
355 string _uid="", _pwd="", _dsn="";
356 string[] items=ConnectionString.Split(new char[1]{';'});
357 foreach (string item in items)
359 string[] parts=item.Split(new char[1] {'='});
360 switch (parts[0].Trim().ToLower())
363 _dsn=parts[1].Trim();
366 _uid=parts[1].Trim();
369 _pwd=parts[1].Trim();
373 ret=libodbc.SQLConnect(hdbc, _dsn, -3, _uid, -3, _pwd, -3);
374 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
375 throw new OdbcException(new OdbcError("SQLConnect",OdbcHandleType.Dbc,hdbc));
379 // DSN-less Connection
380 string OutConnectionString=new String(' ',1024);
382 ret=libodbc.SQLDriverConnect(hdbc, IntPtr.Zero, ConnectionString, -3,
383 OutConnectionString, (short) OutConnectionString.Length, ref OutLen, 0);
384 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
385 throw new OdbcException(new OdbcError("SQLDriverConnect",OdbcHandleType.Dbc,hdbc));
388 OnStateChange (ConnectionState.Closed, ConnectionState.Open);
389 } catch (Exception) {
390 // free handles if any.
398 public static void ReleaseObjectPool ()
400 throw new NotImplementedException ();
403 private void FreeHandles ()
405 OdbcReturn ret = OdbcReturn.Error;
406 if (hdbc != IntPtr.Zero) {
407 ret = libodbc.SQLFreeHandle ( (ushort) OdbcHandleType.Dbc, hdbc);
408 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
409 throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Dbc,hdbc));
413 if (henv != IntPtr.Zero) {
414 ret = libodbc.SQLFreeHandle ( (ushort) OdbcHandleType.Env, henv);
415 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
416 throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Env,henv));
428 void EnlistDistributedTransaction ( ITransaction transaction) {
429 throw new NotImplementedException ();
432 internal string GetInfo (OdbcInfo info)
434 if (State == ConnectionState.Closed)
435 throw new InvalidOperationException ("The connection is closed.");
437 OdbcReturn ret = OdbcReturn.Error;
438 short max_length = 256;
439 byte [] buffer = new byte [max_length];
440 short actualLength = 0;
442 ret = libodbc.SQLGetInfo (hdbc, info, buffer, max_length, ref actualLength);
443 if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
444 throw new OdbcException (new OdbcError ("SQLGetInfo",
448 return System.Text.Encoding.Default.GetString (buffer);
452 private void OnStateChange (ConnectionState from, ConnectionState to)
454 if (StateChange != null)
455 StateChange (this, new StateChangeEventArgs (from, to));
462 #region Events and Delegates
465 [OdbcDescription ("DbConnection_StateChange")]
466 [OdbcCategory ("DataCategory_StateChange")]
467 public event StateChangeEventHandler StateChange;
470 [OdbcDescription ("DbConnection_InfoMessage")]
471 [OdbcCategory ("DataCategory_InfoMessage")]
472 public event OdbcInfoMessageEventHandler InfoMessage;