2
0

OdbcConnection.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. //
  2. // System.Data.Odbc.OdbcConnection
  3. //
  4. // Authors:
  5. // Brian Ritchie ([email protected])
  6. //
  7. // Copyright (C) Brian Ritchie, 2002
  8. //
  9. //
  10. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System.ComponentModel;
  32. using System.Data;
  33. using System.Data.Common;
  34. #if NET_2_0
  35. using System.Data.ProviderBase;
  36. #endif // NET_2_0
  37. using System.EnterpriseServices;
  38. namespace System.Data.Odbc
  39. {
  40. [DefaultEvent("InfoMessage")]
  41. #if NET_2_0
  42. public sealed class OdbcConnection : DbConnectionBase, ICloneable
  43. #else
  44. public sealed class OdbcConnection : Component, ICloneable, IDbConnection
  45. #endif //NET_2_0
  46. {
  47. #region Fields
  48. #if ONLY_1_1
  49. string connectionString;
  50. #endif //ONLY_1_1
  51. int connectionTimeout;
  52. internal OdbcTransaction transaction;
  53. IntPtr henv=IntPtr.Zero, hdbc=IntPtr.Zero;
  54. bool disposed = false;
  55. #endregion
  56. #region Constructors
  57. public OdbcConnection () : this (String.Empty)
  58. {
  59. }
  60. public OdbcConnection (string connectionString)
  61. {
  62. Init (connectionString);
  63. }
  64. private void Init (string connectionString)
  65. {
  66. connectionTimeout = 15;
  67. ConnectionString = connectionString;
  68. }
  69. #if NET_2_0
  70. internal OdbcConnection (OdbcConnectionFactory factory)
  71. : base ( (DbConnectionFactory) factory)
  72. {
  73. Init (String.Empty);
  74. }
  75. #endif //NET_2_0
  76. #endregion // Constructors
  77. #region Properties
  78. internal IntPtr hDbc
  79. {
  80. get { return hdbc; }
  81. }
  82. #if ONLY_1_1
  83. [OdbcCategoryAttribute ("DataCategory_Data")]
  84. [DefaultValue ("")]
  85. [OdbcDescriptionAttribute ("Information used to connect to a Data Source")]
  86. [RefreshPropertiesAttribute (RefreshProperties.All)]
  87. [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
  88. [RecommendedAsConfigurableAttribute (true)]
  89. public string ConnectionString {
  90. get {
  91. return connectionString;
  92. }
  93. set {
  94. connectionString = value;
  95. }
  96. }
  97. #endif // ONLY_1_1
  98. [OdbcDescriptionAttribute ("Current connection timeout value, not settable in the ConnectionString")]
  99. [DefaultValue (15)]
  100. public
  101. #if NET_2_0
  102. new
  103. #endif // NET_2_0
  104. int ConnectionTimeout {
  105. get {
  106. return connectionTimeout;
  107. }
  108. set {
  109. if (value < 0) {
  110. throw new ArgumentException("Timout should not be less than zero.");
  111. }
  112. connectionTimeout = value;
  113. }
  114. }
  115. [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
  116. [OdbcDescriptionAttribute ("Current data source Catlog value, 'Database=X' in the ConnectionString")]
  117. public
  118. #if NET_2_0
  119. override
  120. #endif // NET_2_0
  121. string Database {
  122. get {
  123. return GetInfo (OdbcInfo.DatabaseName);
  124. }
  125. }
  126. [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
  127. [OdbcDescriptionAttribute ("The ConnectionState indicating whether the connection is open or closed")]
  128. [BrowsableAttribute (false)]
  129. public
  130. #if NET_2_0
  131. override
  132. #endif // NET_2_0
  133. ConnectionState State
  134. {
  135. get {
  136. if (hdbc!=IntPtr.Zero) {
  137. return ConnectionState.Open;
  138. }
  139. else
  140. return ConnectionState.Closed;
  141. }
  142. }
  143. [MonoTODO]
  144. [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
  145. [OdbcDescriptionAttribute ("Current data source, 'Server=X' in the ConnectionString")]
  146. public
  147. #if NET_2_0
  148. override
  149. #endif // NET_2_0
  150. string DataSource {
  151. get {
  152. return GetInfo (OdbcInfo.DataSourceName);
  153. }
  154. }
  155. [MonoTODO]
  156. [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
  157. [OdbcDescriptionAttribute ("Current ODBC Driver")]
  158. public string Driver {
  159. get {
  160. return GetInfo (OdbcInfo.DriverName);
  161. }
  162. }
  163. [MonoTODO]
  164. [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
  165. [OdbcDescriptionAttribute ("Version of the product accessed by the ODBC Driver")]
  166. [BrowsableAttribute (false)]
  167. public
  168. #if NET_2_0
  169. override
  170. #endif // NET_2_0
  171. string ServerVersion {
  172. get {
  173. return GetInfo (OdbcInfo.DbmsVersion);
  174. }
  175. }
  176. #endregion // Properties
  177. #region Methods
  178. public
  179. #if NET_2_0
  180. new
  181. #endif // NET_2_0
  182. OdbcTransaction BeginTransaction ()
  183. {
  184. return BeginTransaction(IsolationLevel.Unspecified);
  185. }
  186. #if ONLY_1_1
  187. IDbTransaction IDbConnection.BeginTransaction ()
  188. {
  189. return (IDbTransaction) BeginTransaction();
  190. }
  191. #endif // ONLY_1_1
  192. public
  193. #if NET_2_0
  194. new
  195. #endif // NET_2_0
  196. OdbcTransaction BeginTransaction (IsolationLevel level)
  197. {
  198. if (transaction==null)
  199. {
  200. transaction=new OdbcTransaction(this,level);
  201. return transaction;
  202. }
  203. else
  204. throw new InvalidOperationException();
  205. }
  206. #if ONLY_1_1
  207. IDbTransaction IDbConnection.BeginTransaction (IsolationLevel level)
  208. {
  209. return (IDbTransaction) BeginTransaction(level);
  210. }
  211. #endif // ONLY_1_1
  212. public
  213. #if NET_2_0
  214. override
  215. #endif // NET_2_0
  216. void Close ()
  217. {
  218. OdbcReturn ret = OdbcReturn.Error;
  219. if (State == ConnectionState.Open) {
  220. // disconnect
  221. ret = libodbc.SQLDisconnect (hdbc);
  222. if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  223. throw new OdbcException (new OdbcError ("SQLDisconnect", OdbcHandleType.Dbc,hdbc));
  224. FreeHandles ();
  225. transaction = null;
  226. OnStateChange (ConnectionState.Open, ConnectionState.Closed);
  227. }
  228. }
  229. public
  230. #if NET_2_0
  231. new
  232. #endif // NET_2_0
  233. OdbcCommand CreateCommand ()
  234. {
  235. return new OdbcCommand("", this, transaction);
  236. }
  237. [MonoTODO]
  238. public
  239. #if NET_2_0
  240. override
  241. #endif // NET_2_0
  242. void ChangeDatabase(string Database)
  243. {
  244. throw new NotImplementedException ();
  245. }
  246. protected override void Dispose (bool disposing)
  247. {
  248. if (!this.disposed) {
  249. try
  250. {
  251. // release the native unmananged resources
  252. this.Close();
  253. this.disposed = true;
  254. }
  255. finally
  256. {
  257. // call Dispose on the base class
  258. base.Dispose(disposing);
  259. }
  260. }
  261. }
  262. [MonoTODO]
  263. object ICloneable.Clone ()
  264. {
  265. throw new NotImplementedException();
  266. }
  267. #if ONLY_1_1
  268. IDbCommand IDbConnection.CreateCommand ()
  269. {
  270. return (IDbCommand) CreateCommand ();
  271. }
  272. #endif //ONLY_1_1
  273. public
  274. #if NET_2_0
  275. override
  276. #endif // NET_2_0
  277. void Open ()
  278. {
  279. if (State == ConnectionState.Open)
  280. throw new InvalidOperationException ();
  281. OdbcReturn ret = OdbcReturn.Error;
  282. try {
  283. // allocate Environment handle
  284. ret = libodbc.SQLAllocHandle (OdbcHandleType.Env, IntPtr.Zero, ref henv);
  285. if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  286. throw new OdbcException (new OdbcError ("SQLAllocHandle"));
  287. ret=libodbc.SQLSetEnvAttr (henv, OdbcEnv.OdbcVersion, (IntPtr) libodbc.SQL_OV_ODBC3 , 0);
  288. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  289. throw new OdbcException (new OdbcError ("SQLSetEnvAttr", OdbcHandleType.Env,henv));
  290. // allocate connection handle
  291. ret=libodbc.SQLAllocHandle (OdbcHandleType.Dbc, henv, ref hdbc);
  292. if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  293. throw new OdbcException (new OdbcError ("SQLAllocHandle",OdbcHandleType.Env,henv));
  294. // DSN connection
  295. if (ConnectionString.ToLower().IndexOf("dsn=")>=0)
  296. {
  297. string _uid="", _pwd="", _dsn="";
  298. string[] items=ConnectionString.Split(new char[1]{';'});
  299. foreach (string item in items)
  300. {
  301. string[] parts=item.Split(new char[1] {'='});
  302. switch (parts[0].Trim().ToLower())
  303. {
  304. case "dsn":
  305. _dsn=parts[1].Trim();
  306. break;
  307. case "uid":
  308. _uid=parts[1].Trim();
  309. break;
  310. case "pwd":
  311. _pwd=parts[1].Trim();
  312. break;
  313. }
  314. }
  315. ret=libodbc.SQLConnect(hdbc, _dsn, -3, _uid, -3, _pwd, -3);
  316. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  317. throw new OdbcException(new OdbcError("SQLConnect",OdbcHandleType.Dbc,hdbc));
  318. }
  319. else
  320. {
  321. // DSN-less Connection
  322. string OutConnectionString=new String(' ',1024);
  323. short OutLen=0;
  324. ret=libodbc.SQLDriverConnect(hdbc, IntPtr.Zero, ConnectionString, -3,
  325. OutConnectionString, (short) OutConnectionString.Length, ref OutLen, 0);
  326. if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  327. throw new OdbcException(new OdbcError("SQLDriverConnect",OdbcHandleType.Dbc,hdbc));
  328. }
  329. OnStateChange (ConnectionState.Closed, ConnectionState.Open);
  330. } catch (Exception) {
  331. // free handles if any.
  332. FreeHandles ();
  333. throw;
  334. }
  335. disposed = false;
  336. }
  337. [MonoTODO]
  338. public static void ReleaseObjectPool ()
  339. {
  340. throw new NotImplementedException ();
  341. }
  342. private void FreeHandles ()
  343. {
  344. OdbcReturn ret = OdbcReturn.Error;
  345. if (hdbc != IntPtr.Zero) {
  346. ret = libodbc.SQLFreeHandle ( (ushort) OdbcHandleType.Dbc, hdbc);
  347. if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  348. throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Dbc,hdbc));
  349. }
  350. hdbc = IntPtr.Zero;
  351. if (henv != IntPtr.Zero) {
  352. ret = libodbc.SQLFreeHandle ( (ushort) OdbcHandleType.Env, henv);
  353. if ( (ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
  354. throw new OdbcException (new OdbcError ("SQLFreeHandle", OdbcHandleType.Env,henv));
  355. }
  356. henv = IntPtr.Zero;
  357. }
  358. [MonoTODO]
  359. public
  360. #if NET_2_0
  361. override
  362. #endif // NET_2_0
  363. void EnlistDistributedTransaction ( ITransaction transaction) {
  364. throw new NotImplementedException ();
  365. }
  366. internal string GetInfo (OdbcInfo info)
  367. {
  368. if (State == ConnectionState.Closed)
  369. throw new InvalidOperationException ("The connection is closed.");
  370. OdbcReturn ret = OdbcReturn.Error;
  371. short max_length = 256;
  372. byte [] buffer = new byte [max_length];
  373. short actualLength = 0;
  374. ret = libodbc.SQLGetInfo (hdbc, info, buffer, max_length, ref actualLength);
  375. if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
  376. throw new OdbcException (new OdbcError ("SQLGetInfo",
  377. OdbcHandleType.Dbc,
  378. hdbc));
  379. return System.Text.Encoding.Default.GetString (buffer);
  380. }
  381. #if ONLY_1_1
  382. private void OnStateChange (ConnectionState from, ConnectionState to)
  383. {
  384. if (StateChange != null)
  385. StateChange (this, new StateChangeEventArgs (from, to));
  386. }
  387. #endif // ONLY_1_1
  388. #endregion
  389. #region Events and Delegates
  390. #if ONLY_1_1
  391. [OdbcDescription ("DbConnection_StateChange")]
  392. [OdbcCategory ("DataCategory_StateChange")]
  393. public event StateChangeEventHandler StateChange;
  394. #endif // ONLY_1_1
  395. [OdbcDescription ("DbConnection_InfoMessage")]
  396. [OdbcCategory ("DataCategory_InfoMessage")]
  397. public event OdbcInfoMessageEventHandler InfoMessage;
  398. #endregion
  399. }
  400. }