4 // Part of the Mono class libraries at
5 // mcs/class/System.Data.OracleClient/System.Data.OracleClient
7 // Assembly: System.Data.OracleClient.dll
8 // Namespace: System.Data.OracleClient
11 // Daniel Morgan <danielmorgan@verizon.net>
12 // Tim Coleman <tim@timcoleman.com>
13 // Hubert FONGARNAND <informatique.internet@fiducial.fr>
15 // Copyright (C) Daniel Morgan, 2002, 2005
16 // Copyright (C) Tim Coleman, 2003
17 // Copyright (C) Hubert FONGARNAND, 2005
19 // Original source code for setting ConnectionString
20 // by Tim Coleman <tim@timcoleman.com>
22 // Copyright (C) Tim Coleman, 2002
24 // Licensed under the MIT/X11 License.
28 using System.Collections;
29 using System.Collections.Specialized;
30 using System.ComponentModel;
32 using System.Data.OracleClient.Oci;
33 using System.Drawing.Design;
34 using System.EnterpriseServices;
37 namespace System.Data.OracleClient
39 internal struct OracleConnectionInfo
41 internal string Username;
42 internal string Password;
43 internal string Database;
44 internal string ConnectionString;
47 [DefaultEvent ("InfoMessage")]
48 public sealed class OracleConnection : Component, ICloneable, IDbConnection
53 ConnectionState state;
54 OracleConnectionInfo conInfo;
55 OracleTransaction transaction = null;
56 string connectionString = "";
57 OracleDataReader dataReader = null;
59 static OracleConnectionPoolManager pools = new OracleConnectionPoolManager ();
60 OracleConnectionPool pool;
62 int maxPoolSize = 100;
68 public OracleConnection ()
70 state = ConnectionState.Closed;
73 public OracleConnection (string connectionString)
76 SetConnectionString (connectionString);
79 #endregion // Constructors
83 int IDbConnection.ConnectionTimeout {
88 string IDbConnection.Database {
90 get { return String.Empty; }
93 internal OracleDataReader DataReader {
94 get { return dataReader; }
95 set { dataReader = value; }
98 internal OciEnvironmentHandle Environment {
99 get { return oci.Environment; }
102 internal OciErrorHandle ErrorHandle {
103 get { return oci.ErrorHandle; }
106 internal OciServiceHandle ServiceContext {
107 get { return oci.ServiceContext; }
110 internal OciSessionHandle Session {
111 get { return oci.SessionHandle; }
115 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
116 public string DataSource {
118 return conInfo.Database;
123 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
124 public ConnectionState State {
125 get { return state; }
129 [RecommendedAsConfigurable (true)]
130 [RefreshProperties (RefreshProperties.All)]
131 [Editor ("Microsoft.VSDesigner.Data.Oracle.Design.OracleConnectionStringEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
132 public string ConnectionString {
133 get { return connectionString; }
134 set { SetConnectionString (value); }
139 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
140 public string ServerVersion {
142 if (this.State != ConnectionState.Open)
143 throw new System.InvalidOperationException ("Invalid operation. The connection is closed.");
144 return GetOracleVersion ();
148 internal string GetOracleVersion ()
150 byte[] buffer = new Byte[256];
151 uint bufflen = (uint) buffer.Length;
153 IntPtr sh = oci.ServiceContext;
154 IntPtr eh = oci.ErrorHandle;
156 OciCalls.OCIServerVersion (sh, eh, ref buffer, bufflen, OciHandleType.Service);
158 // Get length of returned string
160 IntPtr env = oci.Environment;
161 OciCalls.OCICharSetToUnicode (env, null, buffer, out rsize);
164 StringBuilder ret = new StringBuilder(rsize);
165 OciCalls.OCICharSetToUnicode (env, ret, buffer, out rsize);
167 return ret.ToString ();
170 internal OciGlue Oci {
174 internal OracleTransaction Transaction {
175 get { return transaction; }
176 set { transaction = value; }
179 #endregion // Properties
183 public OracleTransaction BeginTransaction ()
185 return BeginTransaction (IsolationLevel.ReadCommitted);
188 public OracleTransaction BeginTransaction (IsolationLevel il)
190 if (state == ConnectionState.Closed)
191 throw new InvalidOperationException ("The connection is not open.");
192 if (transaction != null)
193 throw new InvalidOperationException ("OracleConnection does not support parallel transactions.");
195 OciTransactionHandle transactionHandle = oci.CreateTransaction ();
196 if (transactionHandle == null)
197 throw new Exception("Error: Unable to start transaction");
199 transactionHandle.Begin ();
200 transaction = new OracleTransaction (this, il, transactionHandle);
207 void IDbConnection.ChangeDatabase (string databaseName)
209 throw new NotImplementedException ();
212 public OracleCommand CreateCommand ()
214 OracleCommand command = new OracleCommand ();
215 command.Connection = this;
220 object ICloneable.Clone ()
222 OracleConnection con = new OracleConnection ();
223 con.ConnectionString = this.ConnectionString;
224 if (this.State == ConnectionState.Open)
226 // TODO: what other properties need to be cloned?
230 IDbTransaction IDbConnection.BeginTransaction ()
232 return BeginTransaction ();
235 IDbTransaction IDbConnection.BeginTransaction (IsolationLevel iso)
237 return BeginTransaction (iso);
240 IDbCommand IDbConnection.CreateCommand ()
242 return CreateCommand ();
245 void IDisposable.Dispose ()
248 GC.SuppressFinalize (this);
252 protected override void Dispose (bool disposing)
254 base.Dispose (disposing);
258 public void EnlistDistributedTransaction (ITransaction distributedTransaction)
260 throw new NotImplementedException ();
263 // Get NLS_DATE_FORMAT string from Oracle server
264 internal string GetSessionDateFormat ()
266 // 23 is 22 plus 1 for NUL terminated character
267 // a DATE format has a max size of 22
268 return GetNlsInfo (Session, 23, OciNlsServiceType.DATEFORMAT);
273 // handle = OciEnvironmentHandle or OciSessionHandle
274 // bufflen = Length of byte buffer to allocate to retrieve the NLS info
275 // item = OciNlsServiceType enum value
277 // if unsure how much you need, use OciNlsServiceType.MAXBUFSZ
278 internal string GetNlsInfo (OciHandle handle, uint bufflen, OciNlsServiceType item)
280 byte[] buffer = new Byte[bufflen];
282 OciCalls.OCINlsGetInfo (handle, ErrorHandle,
283 ref buffer, bufflen, (ushort) item);
285 // Get length of returned string
287 OciCalls.OCICharSetToUnicode (Environment, null, buffer, out rsize);
290 StringBuilder ret = new StringBuilder (rsize);
291 OciCalls.OCICharSetToUnicode (Environment, ret, buffer, out rsize);
293 return ret.ToString ();
299 oci = new OciGlue ();
300 oci.CreateConnection (conInfo);
303 pool = pools.GetConnectionPool (conInfo, minPoolSize, maxPoolSize);
304 oci = pool.GetConnection ();
306 state = ConnectionState.Open;
307 CreateStateChange (ConnectionState.Closed, ConnectionState.Open);
310 internal void CreateInfoMessage (OciErrorInfo info)
312 OracleInfoMessageEventArgs a = new OracleInfoMessageEventArgs (info);
316 private void OnInfoMessage (OracleInfoMessageEventArgs e)
318 if (InfoMessage != null)
319 InfoMessage (this, e);
322 internal void CreateStateChange (ConnectionState original, ConnectionState current)
324 StateChangeEventArgs a = new StateChangeEventArgs (original, current);
328 private void OnStateChange (StateChangeEventArgs e)
330 if (StateChange != null)
331 StateChange (this, e);
336 if (transaction != null)
337 transaction.Rollback ();
341 else if (pool != null)
342 pool.ReleaseConnection (oci);
344 state = ConnectionState.Closed;
345 CreateStateChange (ConnectionState.Open, ConnectionState.Closed);
348 void SetConnectionString (string connectionString)
350 this.connectionString = connectionString;
351 conInfo.Username = "";
352 conInfo.Database = "";
353 conInfo.Password = "";
355 if (connectionString == String.Empty)
358 connectionString += ";";
359 NameValueCollection parameters = new NameValueCollection ();
361 bool inQuote = false;
362 bool inDQuote = false;
364 string name = String.Empty;
365 string value = String.Empty;
366 StringBuilder sb = new StringBuilder ();
368 foreach (char c in connectionString) {
374 inDQuote = !inDQuote;
377 if (!inDQuote && !inQuote) {
378 if (name != String.Empty && name != null) {
379 value = sb.ToString ();
380 parameters [name.ToUpper ().Trim ()] = value.Trim ();
383 value = String.Empty;
384 sb = new StringBuilder ();
390 if (!inDQuote && !inQuote) {
391 name = sb.ToString ();
392 sb = new StringBuilder ();
403 SetProperties (parameters);
405 conInfo.ConnectionString = connectionString;
408 private void SetProperties (NameValueCollection parameters)
411 foreach (string name in parameters) {
412 value = parameters[name];
419 case "CONNECTION LIFETIME":
422 case "INTEGRATED SECURITY":
423 throw new NotImplementedException ();
424 case "PERSIST SECURITY INFO":
427 case "MIN POOL SIZE":
428 minPoolSize = int.Parse (value);
430 case "MAX POOL SIZE":
431 maxPoolSize = int.Parse (value);
435 conInfo.Database = value;
439 conInfo.Password = value;
443 conInfo.Username = value;
446 switch (value.ToUpper ()) {
456 throw new ArgumentException("Connection parameter not supported: '" + name + "'");
460 throw new ArgumentException("Connection parameter not supported: '" + name + "'");
470 #endregion // Methods
472 public event OracleInfoMessageEventHandler InfoMessage;
473 public event StateChangeEventHandler StateChange;