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;
38 #if NET_2_0 && !TARGET_JVM
39 using System.Transactions;
42 namespace System.Data.Odbc
44 [DefaultEvent ("InfoMessage")]
46 public sealed class OdbcConnection : DbConnection, ICloneable
48 public sealed class OdbcConnection : Component, ICloneable, IDbConnection
53 string connectionString;
54 int connectionTimeout;
55 internal OdbcTransaction transaction;
56 IntPtr henv=IntPtr.Zero, hdbc=IntPtr.Zero;
57 bool disposed = false;
63 public OdbcConnection () : this (String.Empty)
67 public OdbcConnection (string connectionString)
69 Init (connectionString);
72 private void Init (string connectionString)
74 connectionTimeout = 15;
75 ConnectionString = connectionString;
78 #endregion // Constructors
87 [OdbcCategoryAttribute ("DataCategory_Data")]
89 [OdbcDescriptionAttribute ("Information used to connect to a Data Source")]
90 [RefreshPropertiesAttribute (RefreshProperties.All)]
91 [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
92 [RecommendedAsConfigurableAttribute (true)]
97 string ConnectionString {
99 return connectionString;
102 connectionString = value;
106 [OdbcDescriptionAttribute ("Current connection timeout value, not settable in the ConnectionString")]
109 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
115 int ConnectionTimeout {
117 return connectionTimeout;
121 throw new ArgumentException("Timout should not be less than zero.");
123 connectionTimeout = value;
127 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
128 [OdbcDescriptionAttribute ("Current data source Catlog value, 'Database=X' in the ConnectionString")]
135 return GetInfo (OdbcInfo.DatabaseName);
139 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
140 [OdbcDescriptionAttribute ("The ConnectionState indicating whether the connection is open or closed")]
141 [BrowsableAttribute (false)]
146 ConnectionState State
149 if (hdbc!=IntPtr.Zero) {
150 return ConnectionState.Open;
153 return ConnectionState.Closed;
157 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
158 [OdbcDescriptionAttribute ("Current data source, 'Server=X' in the ConnectionString")]
168 return GetInfo (OdbcInfo.DataSourceName);
175 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
176 [OdbcDescriptionAttribute ("Current ODBC Driver")]
177 public string Driver {
179 return GetInfo (OdbcInfo.DriverName);
183 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
184 [OdbcDescriptionAttribute ("Version of the product accessed by the ODBC Driver")]
185 [BrowsableAttribute (false)]
190 string ServerVersion {
192 return GetInfo (OdbcInfo.DbmsVersion);
197 #endregion // Properties
205 OdbcTransaction BeginTransaction ()
207 return BeginTransaction(IsolationLevel.Unspecified);
211 IDbTransaction IDbConnection.BeginTransaction ()
213 return (IDbTransaction) BeginTransaction();
217 protected override DbTransaction BeginDbTransaction (IsolationLevel level)
219 return BeginTransaction (level);
227 OdbcTransaction BeginTransaction (IsolationLevel level)
229 if (transaction==null)
231 transaction=new OdbcTransaction(this,level);
235 throw new InvalidOperationException();
239 IDbTransaction IDbConnection.BeginTransaction (IsolationLevel level)
241 return (IDbTransaction) BeginTransaction(level);
251 OdbcReturn ret = OdbcReturn.Error;
252 if (State == ConnectionState.Open) {
254 ret = libodbc.SQLDisconnect (hdbc);
255 if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo)) {
256 throw new OdbcException (new OdbcError ("SQLDisconnect", OdbcHandleType.Dbc, hdbc));
263 RaiseStateChange (ConnectionState.Open, ConnectionState.Closed);
271 OdbcCommand CreateCommand ()
273 return new OdbcCommand ("", this, transaction);
280 void ChangeDatabase(string Database)
282 IntPtr ptr = IntPtr.Zero;
283 OdbcReturn ret = OdbcReturn.Error;
286 ptr = Marshal.StringToHGlobalAnsi (Database);
287 ret = libodbc.SQLSetConnectAttr (hdbc, OdbcConnectionAttribute.CurrentCatalog, ptr, Database.Length);
289 if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
290 throw new OdbcException (new OdbcError ("SQLSetConnectAttr", OdbcHandleType.Dbc, hdbc));
292 if (ptr != IntPtr.Zero)
293 Marshal.FreeCoTaskMem (ptr);
297 protected override void Dispose (bool disposing)
299 if (!this.disposed) {
302 // release the native unmananged resources
304 this.disposed = true;
308 // call Dispose on the base class
309 base.Dispose(disposing);
315 object ICloneable.Clone ()
317 throw new NotImplementedException();
321 IDbCommand IDbConnection.CreateCommand ()
323 return (IDbCommand) CreateCommand ();
328 protected override DbCommand CreateDbCommand ()
330 return CreateCommand ();
340 if (State == ConnectionState.Open)
341 throw new InvalidOperationException ();
343 OdbcReturn ret = OdbcReturn.Error;
344 OdbcException e = null;
347 // allocate Environment handle
348 ret = libodbc.SQLAllocHandle (OdbcHandleType.Env, IntPtr.Zero, ref henv);
349 if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo)) {
350 e = new OdbcException (new OdbcError ("SQLAllocHandle"));
355 ret = libodbc.SQLSetEnvAttr (henv, OdbcEnv.OdbcVersion, (IntPtr) libodbc.SQL_OV_ODBC3 , 0);
356 if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
357 throw new OdbcException (new OdbcError ("SQLSetEnvAttr", OdbcHandleType.Env, henv));
359 // allocate connection handle
360 ret = libodbc.SQLAllocHandle (OdbcHandleType.Dbc, henv, ref hdbc);
361 if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
362 throw new OdbcException (new OdbcError ("SQLAllocHandle", OdbcHandleType.Env, henv));
365 if (ConnectionString.ToLower ().IndexOf ("dsn=") >= 0)
367 string _uid = "", _pwd = "", _dsn = "";
368 string [] items = ConnectionString.Split (new char[1]{';'});
369 foreach (string item in items)
371 string [] parts = item.Split (new char[1] {'='});
372 switch (parts [0].Trim ().ToLower ())
375 _dsn = parts [1].Trim ();
378 _uid = parts [1].Trim ();
381 _pwd = parts [1].Trim ();
385 ret = libodbc.SQLConnect(hdbc, _dsn, -3, _uid, -3, _pwd, -3);
386 if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
387 throw new OdbcException (new OdbcError ("SQLConnect", OdbcHandleType.Dbc, hdbc));
391 // DSN-less Connection
392 string OutConnectionString = new String (' ',1024);
394 ret = libodbc.SQLDriverConnect (hdbc, IntPtr.Zero, ConnectionString, -3,
395 OutConnectionString, (short) OutConnectionString.Length, ref OutLen, 0);
396 if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
397 throw new OdbcException (new OdbcError ("SQLDriverConnect", OdbcHandleType.Dbc, hdbc));
400 RaiseStateChange (ConnectionState.Closed, ConnectionState.Open);
401 } catch (Exception) {
402 // free handles if any.
410 public static void ReleaseObjectPool ()
412 throw new NotImplementedException ();
415 private void FreeHandles ()
417 OdbcReturn ret = OdbcReturn.Error;
418 if (hdbc != IntPtr.Zero) {
419 ret = libodbc.SQLFreeHandle ((ushort) OdbcHandleType.Dbc, hdbc);
420 if ( (ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
421 throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Dbc, hdbc));
425 if (henv != IntPtr.Zero) {
426 ret = libodbc.SQLFreeHandle ((ushort) OdbcHandleType.Env, henv);
427 if ( (ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
428 throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Env, henv));
434 public new DataTable GetSchema ()
436 if (State == ConnectionState.Open)
437 throw new InvalidOperationException ();
438 return MetaDataCollections.Instance;
441 public new DataTable GetSchema (string collectionName)
443 if (State == ConnectionState.Open)
444 throw new InvalidOperationException ();
445 return GetSchema (collectionName, null);
449 public override void EnlistTransaction (Transaction transaction)
451 throw new NotImplementedException ();
456 public void EnlistDistributedTransaction ( ITransaction transaction)
458 throw new NotImplementedException ();
461 internal string GetInfo (OdbcInfo info)
463 if (State == ConnectionState.Closed)
464 throw new InvalidOperationException ("The connection is closed.");
466 OdbcReturn ret = OdbcReturn.Error;
467 short max_length = 256;
468 byte [] buffer = new byte [max_length];
469 short actualLength = 0;
471 ret = libodbc.SQLGetInfo (hdbc, info, buffer, max_length, ref actualLength);
472 if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
473 throw new OdbcException (new OdbcError ("SQLGetInfo",
477 return System.Text.Encoding.Default.GetString (buffer);
480 private void RaiseStateChange (ConnectionState from, ConnectionState to)
483 if (StateChange != null)
484 StateChange (this, new StateChangeEventArgs (from, to));
486 base.OnStateChange (new StateChangeEventArgs (from, to));
490 private OdbcInfoMessageEventArgs CreateOdbcInfoMessageEvent (OdbcErrorCollection errors)
492 return new OdbcInfoMessageEventArgs (errors);
495 private void OnOdbcInfoMessage (OdbcInfoMessageEventArgs e) {
496 if (null != InfoMessage) {
497 InfoMessage (this, e);
503 #region Events and Delegates
506 [OdbcDescription ("DbConnection_StateChange")]
507 [OdbcCategory ("DataCategory_StateChange")]
508 public event StateChangeEventHandler StateChange;
511 [OdbcDescription ("DbConnection_InfoMessage")]
512 [OdbcCategory ("DataCategory_InfoMessage")]
513 public event OdbcInfoMessageEventHandler InfoMessage;
515 private void MessageHandler (OdbcException e)
517 OnOdbcInfoMessage (CreateOdbcInfoMessageEvent (e.Errors));