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;
37 using System.EnterpriseServices;
39 namespace System.Data.Odbc
41 [DefaultEvent("InfoMessage")]
43 public sealed class OdbcConnection : DbConnection, ICloneable
45 public sealed class OdbcConnection : Component, ICloneable, IDbConnection
50 string connectionString;
51 int connectionTimeout;
52 internal OdbcTransaction transaction;
53 IntPtr henv=IntPtr.Zero, hdbc=IntPtr.Zero;
54 bool disposed = false;
60 public OdbcConnection () : this (String.Empty)
64 public OdbcConnection (string connectionString)
66 Init (connectionString);
69 private void Init (string connectionString)
71 connectionTimeout = 15;
72 ConnectionString = connectionString;
75 #endregion // Constructors
84 [OdbcCategoryAttribute ("DataCategory_Data")]
86 [OdbcDescriptionAttribute ("Information used to connect to a Data Source")]
87 [RefreshPropertiesAttribute (RefreshProperties.All)]
88 [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
89 [RecommendedAsConfigurableAttribute (true)]
94 string ConnectionString {
96 return connectionString;
99 connectionString = value;
103 [OdbcDescriptionAttribute ("Current connection timeout value, not settable in the ConnectionString")]
109 int ConnectionTimeout {
111 return connectionTimeout;
115 throw new ArgumentException("Timout should not be less than zero.");
117 connectionTimeout = value;
121 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
122 [OdbcDescriptionAttribute ("Current data source Catlog value, 'Database=X' in the ConnectionString")]
129 return GetInfo (OdbcInfo.DatabaseName);
133 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
134 [OdbcDescriptionAttribute ("The ConnectionState indicating whether the connection is open or closed")]
135 [BrowsableAttribute (false)]
140 ConnectionState State
143 if (hdbc!=IntPtr.Zero) {
144 return ConnectionState.Open;
147 return ConnectionState.Closed;
152 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
153 [OdbcDescriptionAttribute ("Current data source, 'Server=X' in the ConnectionString")]
160 return GetInfo (OdbcInfo.DataSourceName);
165 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
166 [OdbcDescriptionAttribute ("Current ODBC Driver")]
167 public string Driver {
169 return GetInfo (OdbcInfo.DriverName);
174 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
175 [OdbcDescriptionAttribute ("Version of the product accessed by the ODBC Driver")]
176 [BrowsableAttribute (false)]
181 string ServerVersion {
183 return GetInfo (OdbcInfo.DbmsVersion);
188 #endregion // Properties
196 OdbcTransaction BeginTransaction ()
198 return BeginTransaction(IsolationLevel.Unspecified);
202 IDbTransaction IDbConnection.BeginTransaction ()
204 return (IDbTransaction) BeginTransaction();
208 protected override DbTransaction BeginDbTransaction (IsolationLevel level)
210 return BeginTransaction (level);
218 OdbcTransaction BeginTransaction (IsolationLevel level)
220 if (transaction==null)
222 transaction=new OdbcTransaction(this,level);
226 throw new InvalidOperationException();
230 IDbTransaction IDbConnection.BeginTransaction (IsolationLevel level)
232 return (IDbTransaction) BeginTransaction(level);
242 OdbcReturn ret = OdbcReturn.Error;
243 if (State == ConnectionState.Open) {
245 ret = libodbc.SQLDisconnect (hdbc);
246 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
247 throw new OdbcException (new OdbcError ("SQLDisconnect", OdbcHandleType.Dbc,hdbc));
253 RaiseStateChange (ConnectionState.Open, ConnectionState.Closed);
261 OdbcCommand CreateCommand ()
263 return new OdbcCommand("", this, transaction);
271 void ChangeDatabase(string Database)
273 IntPtr ptr = IntPtr.Zero;
274 OdbcReturn ret = OdbcReturn.Error;
277 ptr = Marshal.StringToHGlobalAnsi (Database);
278 ret = libodbc.SQLSetConnectAttr (hdbc, OdbcConnectionAttribute.CurrentCatalog, ptr, Database.Length);
280 if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
281 throw new OdbcException (new OdbcError ("SQLSetConnectAttr", OdbcHandleType.Dbc, hdbc));
283 if (ptr != IntPtr.Zero)
284 Marshal.FreeCoTaskMem (ptr);
288 protected override void Dispose (bool disposing)
290 if (!this.disposed) {
293 // release the native unmananged resources
295 this.disposed = true;
299 // call Dispose on the base class
300 base.Dispose(disposing);
306 object ICloneable.Clone ()
308 throw new NotImplementedException();
312 IDbCommand IDbConnection.CreateCommand ()
314 return (IDbCommand) CreateCommand ();
319 protected override DbCommand CreateDbCommand ()
321 return CreateCommand ();
331 if (State == ConnectionState.Open)
332 throw new InvalidOperationException ();
334 OdbcReturn ret = OdbcReturn.Error;
337 // allocate Environment handle
338 ret = libodbc.SQLAllocHandle (OdbcHandleType.Env, IntPtr.Zero, ref henv);
339 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
340 throw new OdbcException (new OdbcError ("SQLAllocHandle"));
342 ret=libodbc.SQLSetEnvAttr (henv, OdbcEnv.OdbcVersion, (IntPtr) libodbc.SQL_OV_ODBC3 , 0);
343 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
344 throw new OdbcException (new OdbcError ("SQLSetEnvAttr", OdbcHandleType.Env,henv));
346 // allocate connection handle
347 ret=libodbc.SQLAllocHandle (OdbcHandleType.Dbc, henv, ref hdbc);
348 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
349 throw new OdbcException (new OdbcError ("SQLAllocHandle",OdbcHandleType.Env,henv));
352 if (ConnectionString.ToLower().IndexOf("dsn=")>=0)
354 string _uid="", _pwd="", _dsn="";
355 string[] items=ConnectionString.Split(new char[1]{';'});
356 foreach (string item in items)
358 string[] parts=item.Split(new char[1] {'='});
359 switch (parts[0].Trim().ToLower())
362 _dsn=parts[1].Trim();
365 _uid=parts[1].Trim();
368 _pwd=parts[1].Trim();
372 ret=libodbc.SQLConnect(hdbc, _dsn, -3, _uid, -3, _pwd, -3);
373 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
374 throw new OdbcException(new OdbcError("SQLConnect",OdbcHandleType.Dbc,hdbc));
378 // DSN-less Connection
379 string OutConnectionString=new String(' ',1024);
381 ret=libodbc.SQLDriverConnect(hdbc, IntPtr.Zero, ConnectionString, -3,
382 OutConnectionString, (short) OutConnectionString.Length, ref OutLen, 0);
383 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
384 throw new OdbcException(new OdbcError("SQLDriverConnect",OdbcHandleType.Dbc,hdbc));
387 RaiseStateChange (ConnectionState.Closed, ConnectionState.Open);
388 } catch (Exception) {
389 // free handles if any.
397 public static void ReleaseObjectPool ()
399 throw new NotImplementedException ();
402 private void FreeHandles ()
404 OdbcReturn ret = OdbcReturn.Error;
405 if (hdbc != IntPtr.Zero) {
406 ret = libodbc.SQLFreeHandle ( (ushort) OdbcHandleType.Dbc, hdbc);
407 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
408 throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Dbc,hdbc));
412 if (henv != IntPtr.Zero) {
413 ret = libodbc.SQLFreeHandle ( (ushort) OdbcHandleType.Env, henv);
414 if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
415 throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Env,henv));
423 public void EnlistDistributedTransaction ( ITransaction transaction)
426 throw new NotImplementedException ();
429 internal string GetInfo (OdbcInfo info)
431 if (State == ConnectionState.Closed)
432 throw new InvalidOperationException ("The connection is closed.");
434 OdbcReturn ret = OdbcReturn.Error;
435 short max_length = 256;
436 byte [] buffer = new byte [max_length];
437 short actualLength = 0;
439 ret = libodbc.SQLGetInfo (hdbc, info, buffer, max_length, ref actualLength);
440 if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
441 throw new OdbcException (new OdbcError ("SQLGetInfo",
445 return System.Text.Encoding.Default.GetString (buffer);
448 private void RaiseStateChange (ConnectionState from, ConnectionState to)
451 if (StateChange != null)
452 StateChange (this, new StateChangeEventArgs (from, to));
454 base.OnStateChange (new StateChangeEventArgs (from, to));
460 #region Events and Delegates
463 [OdbcDescription ("DbConnection_StateChange")]
464 [OdbcCategory ("DataCategory_StateChange")]
465 public event StateChangeEventHandler StateChange;
468 [OdbcDescription ("DbConnection_InfoMessage")]
469 [OdbcCategory ("DataCategory_InfoMessage")]
470 public event OdbcInfoMessageEventHandler InfoMessage;