2 // System.Data.Common.AbstractDBConnection
\r
5 // Boris Kirzner (borisk@mainsoft.com)
\r
9 using System.Data.ProviderBase;
\r
10 using System.Data.Configuration;
\r
11 using System.Configuration;
\r
12 using System.Collections;
\r
13 using System.Collections.Specialized;
\r
15 using System.Text.RegularExpressions;
\r
20 // can not use java.util here - it manes ArrayList an ambiguous reference
\r
22 namespace System.Data.Common
\r
24 public abstract class AbstractDBConnection : DbConnection
\r
26 #region ObjectNamesHelper
\r
28 private sealed class ObjectNamesHelper
\r
30 //static readonly Regex NameOrder = new Regex(@"^\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
31 static readonly Regex NameOrder = new Regex(@"^((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
33 //static readonly Regex SchemaNameOrder = new Regex(@"^\s*((\[(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
34 static readonly Regex SchemaNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
35 //static readonly Regex CatalogSchemaNameOrder = new Regex(@"^\s*((\[\s*(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
36 //static readonly Regex CatalogSchemaNameOrder = new Regex(@"^\s*((\[\s*(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<SCHEMA>(\s*[^\]\s])+)\s*\])|(?<SCHEMA>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
37 static readonly Regex CatalogSchemaNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
39 //static readonly Regex CatalogNameOrder = new Regex(@"^\s*((\[(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
40 //static readonly Regex CatalogNameOrder = new Regex(@"^\s*((\[(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
41 static readonly Regex CatalogNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
42 //static readonly Regex SchemaCatalogNameOrder = new Regex(@"^\s*((\[\s*(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
43 //static readonly Regex SchemaCatalogNameOrder = new Regex(@"^\s*((\[\s*(?<SCHEMA>(\s*[^\]\s])+)\s*\])|(?<SCHEMA>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
44 static readonly Regex SchemaCatalogNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
46 internal static ObjectNameResolver[] GetSyntaxPatterns(AbstractDBConnection connection)
\r
48 ArrayList collection = new ArrayList();
\r
49 collection.Add(new ObjectNameResolver(NameOrder));
\r
51 ObjectNameResolversCollection basic = (ObjectNameResolversCollection)ConfigurationSettings.GetConfig("system.data/objectnameresolution");
\r
53 DatabaseMetaData metaData = connection.JdbcConnection.getMetaData();
\r
54 string productName = metaData.getDatabaseProductName();
\r
56 foreach(ObjectNameResolver nameResolver in basic) {
\r
57 if (productName.IndexOf(nameResolver.DbName) != -1) {
\r
58 collection.Add(nameResolver);
\r
63 if (metaData.isCatalogAtStart()) {
\r
64 collection.Add(new ObjectNameResolver(SchemaNameOrder));
\r
65 collection.Add(new ObjectNameResolver(CatalogNameOrder));
\r
66 collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
\r
67 collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
\r
70 collection.Add(new ObjectNameResolver(CatalogNameOrder));
\r
71 collection.Add(new ObjectNameResolver(SchemaNameOrder));
\r
72 collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
\r
73 collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
\r
76 return (ObjectNameResolver[])collection.ToArray(typeof(ObjectNameResolver));
\r
80 #endregion // ObjectNamesHelper
\r
82 #region ConnectionStringHelper
\r
84 internal sealed class ConnectionStringHelper
\r
86 internal static string FindValue(NameValueCollection collection, string[] keys)
\r
88 if (collection == null || keys == null || keys.Length == 0) {
\r
89 return String.Empty;
\r
92 for(int i=0; i < keys.Length; i++) {
\r
93 string value = FindValue(collection,keys[i]);
\r
94 if (!String.Empty.Equals(value)) {
\r
98 return String.Empty;
\r
101 internal static string FindValue(NameValueCollection collection, string key)
\r
103 if (collection == null) {
\r
104 return String.Empty;
\r
107 string value = collection[key];
\r
108 return (value != null) ? value : String.Empty;
\r
111 internal static void UpdateValue(NameValueCollection collection,string[] keys,string value)
\r
113 for(int i=0; i < keys.Length; i++) {
\r
114 if (collection[keys[i]] != null) {
\r
115 collection[keys[i]] = value;
\r
120 internal static void AddValue(NameValueCollection collection,string[] keys,string value)
\r
122 for(int i=0; i < keys.Length; i++) {
\r
123 collection[keys[i]] = value;
\r
128 * Parses connection string and builds NameValueCollection
\r
131 internal static NameValueCollection BuildUserParameters (string connectionString)
\r
133 NameValueCollection userParameters = new NameValueCollection();
\r
135 if (connectionString == null || connectionString.Length == 0) {
\r
136 return userParameters;
\r
138 connectionString += ";";
\r
140 bool inQuote = false;
\r
141 bool inDQuote = false;
\r
142 bool inName = true;
\r
144 string name = String.Empty;
\r
145 string value = String.Empty;
\r
146 StringBuilder sb = new StringBuilder ();
\r
148 for (int i = 0; i < connectionString.Length; i += 1) {
\r
149 char c = connectionString [i];
\r
151 if (i == connectionString.Length - 1)
\r
154 peek = connectionString [i + 1];
\r
160 else if (peek.Equals(c)) {
\r
165 inQuote = !inQuote;
\r
170 else if (peek.Equals(c)) {
\r
175 inDQuote = !inDQuote;
\r
178 if (inDQuote || inQuote)
\r
181 if (name != String.Empty && name != null) {
\r
182 value = sb.ToString();
\r
183 userParameters [name.Trim()] = value.Trim();
\r
186 name = String.Empty;
\r
187 value = String.Empty;
\r
188 sb = new StringBuilder();
\r
192 if (inDQuote || inQuote || !inName)
\r
194 else if (peek.Equals(c)) {
\r
199 name = sb.ToString();
\r
200 sb = new StringBuilder();
\r
205 if (inQuote || inDQuote)
\r
207 else if (sb.Length > 0 && !peek.Equals(';'))
\r
215 return userParameters;
\r
219 #endregion // ConnectionStringHelper
\r
221 #region DataSourceCache
\r
223 private sealed class DataSourceCache : AbstractDbMetaDataCache
\r
225 internal DataSource GetDataSource(string dataSourceName,string namingProviderUrl,string namingFactoryInitial)
\r
227 Hashtable cache = Cache;
\r
229 DataSource ds = cache[dataSourceName] as DataSource;
\r
235 Context ctx = null;
\r
237 java.util.Properties properties = new java.util.Properties();
\r
239 if ((namingProviderUrl != null) && (namingProviderUrl.Length > 0)) {
\r
240 properties.put("java.naming.provider.url",namingProviderUrl);
\r
243 if ((namingFactoryInitial != null) && (namingFactoryInitial.Length > 0)) {
\r
244 properties.put("java.naming.factory.initial",namingFactoryInitial);
\r
247 ctx = new InitialContext(properties);
\r
250 ds = (DataSource)ctx.lookup(dataSourceName);
\r
252 catch(javax.naming.NameNotFoundException e) {
\r
253 // possible that is a Tomcat bug,
\r
254 // so try to lookup for jndi datasource with "java:comp/env/" appended
\r
255 ds = (DataSource)ctx.lookup("java:comp/env/" + dataSourceName);
\r
258 cache[dataSourceName] = ds;
\r
263 #endregion // DatasourceCache
\r
265 #region Declarations
\r
267 protected internal enum JDBC_MODE { NONE, DATA_SOURCE_MODE, JDBC_DRIVER_MODE, PROVIDER_MODE }
\r
268 protected internal enum PROVIDER_TYPE { NONE, SQLOLEDB, MSDAORA, IBMDADB2 }
\r
270 #endregion // Declarations
\r
274 private static DataSourceCache _dataSourceCache = new DataSourceCache();
\r
275 private const int DEFAULT_TIMEOUT = 15;
\r
277 private Connection _jdbcConnnection;
\r
278 private ConnectionState _internalState;
\r
279 private object _internalStateSync = new object();
\r
281 private NameValueCollection _userParameters;
\r
283 protected string _connectionString = String.Empty;
\r
284 protected string _jdbcUrl;
\r
286 private ArrayList _referencedObjects = new ArrayList();
\r
287 private ObjectNameResolver[] _syntaxPatterns;
\r
289 #endregion // Fields
\r
291 #region Constructors
\r
293 public AbstractDBConnection(string connectionString)
\r
295 _connectionString = connectionString;
\r
296 InitializeSkippedUserParameters();
\r
299 #endregion // Constructors
\r
303 public override String ConnectionString
\r
305 get { return _connectionString; }
\r
308 throw ExceptionHelper.NotAllowedWhileConnectionOpen("ConnectionString",_internalState);
\r
310 _connectionString = value;
\r
311 _userParameters = null;
\r
316 public override int ConnectionTimeout
\r
319 string timeoutStr = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_TIMEOUT"));
\r
320 if (!String.Empty.Equals(timeoutStr)) {
\r
322 return Convert.ToInt32(timeoutStr);
\r
324 catch(FormatException e) {
\r
325 throw ExceptionHelper.InvalidValueForKey("connect timeout");
\r
327 catch (OverflowException e) {
\r
328 throw ExceptionHelper.InvalidValueForKey("connect timeout");
\r
331 return DEFAULT_TIMEOUT;
\r
335 public override String Database
\r
337 get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATABASE")); }
\r
340 public override ConnectionState State
\r
344 if ((JdbcConnection == null) || JdbcConnection.isClosed()) {
\r
345 // jdbc connection not initialized or closed
\r
346 if (_internalState == ConnectionState.Closed ) {
\r
347 return ConnectionState.Closed;
\r
351 // jdbc connection is opened
\r
352 if ((_internalState & ConnectionState.Open) != 0) {
\r
353 return ConnectionState.Open;
\r
356 return ConnectionState.Broken;
\r
358 catch (SQLException) {
\r
359 return ConnectionState.Broken;
\r
364 internal bool IsExecuting
\r
367 return ((_internalState & ConnectionState.Executing) != 0);
\r
371 lock(_internalStateSync) {
\r
372 // to switch to executing, the connection must be in opened
\r
374 if (_internalState != ConnectionState.Open) {
\r
376 throw ExceptionHelper.OpenedReaderExists();
\r
378 throw ExceptionHelper.OpenConnectionRequired("",_internalState);
\r
380 _internalState |= ConnectionState.Executing;
\r
383 if (!IsExecuting) {
\r
384 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Executing.ToString() + " while in state " + _internalState.ToString());
\r
386 _internalState &= ~ConnectionState.Executing;
\r
392 internal bool IsFetching
\r
395 return ((_internalState & ConnectionState.Fetching) != 0);
\r
399 lock(_internalStateSync) {
\r
401 // to switch to fetching connection must be in opened, executing
\r
402 if (((_internalState & ConnectionState.Open) == 0) || ((_internalState & ConnectionState.Executing) == 0)) {
\r
403 throw ExceptionHelper.OpenConnectionRequired("",_internalState);
\r
405 _internalState |= ConnectionState.Fetching;
\r
409 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Fetching.ToString() + " while in state " + _internalState.ToString());
\r
411 _internalState &= ~ConnectionState.Fetching;
\r
417 internal bool IsOpened
\r
420 return ((_internalState & ConnectionState.Open) != 0);
\r
424 lock(_internalStateSync) {
\r
426 // only connecting connection can be opened
\r
427 if ((_internalState != ConnectionState.Connecting)) {
\r
428 throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
\r
430 _internalState |= ConnectionState.Open;
\r
434 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Open.ToString() + " while in state " + _internalState.ToString());
\r
436 _internalState &= ~ConnectionState.Open;
\r
442 internal bool IsConnecting
\r
445 return ((_internalState & ConnectionState.Connecting) != 0);
\r
449 lock(_internalStateSync) {
\r
451 // to switch to connecting conection must be in closed or in opened
\r
452 if ((_internalState != ConnectionState.Closed) && (_internalState != ConnectionState.Open)) {
\r
453 throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
\r
455 _internalState |= ConnectionState.Connecting;
\r
458 if (!IsConnecting) {
\r
459 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Connecting.ToString() + " while in state " + _internalState.ToString());
\r
461 _internalState &= ~ConnectionState.Connecting;
\r
467 protected virtual PROVIDER_TYPE ProviderType
\r
470 if (JdbcMode != JDBC_MODE.PROVIDER_MODE) {
\r
471 return PROVIDER_TYPE.NONE;
\r
474 string providerStr = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_PROVIDER"));
\r
475 if (providerStr.StartsWith("SQLOLEDB")) {
\r
476 return PROVIDER_TYPE.SQLOLEDB;
\r
478 else if (providerStr.StartsWith("MSDAORA")) {
\r
479 return PROVIDER_TYPE.MSDAORA;
\r
481 else if (providerStr.StartsWith("IBMDADB2")) {
\r
482 return PROVIDER_TYPE.IBMDADB2;
\r
484 return PROVIDER_TYPE.NONE;
\r
488 protected internal virtual JDBC_MODE JdbcMode
\r
491 string[] conJndiNameStr = StringManager.GetStringArray("CON_JNDI_NAME");
\r
492 if ( !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,conJndiNameStr))) {
\r
493 return JDBC_MODE.DATA_SOURCE_MODE;
\r
496 string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
\r
497 string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
\r
498 bool jdbcDriverSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr));
\r
499 bool jdbcUrlSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr));
\r
501 if (jdbcDriverSpecified && jdbcUrlSpecified) {
\r
502 return JDBC_MODE.JDBC_DRIVER_MODE;
\r
505 string[] providerStr = StringManager.GetStringArray("CON_PROVIDER");
\r
506 if (!String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,providerStr))) {
\r
507 return JDBC_MODE.PROVIDER_MODE;
\r
510 return JDBC_MODE.NONE;
\r
514 protected virtual string JdbcDriverName
\r
516 get { return String.Empty; }
\r
519 protected abstract DbStringManager StringManager
\r
524 protected virtual string ServerName
\r
526 get { return DataSource; }
\r
529 protected virtual string CatalogName
\r
531 get { return Database; }
\r
534 protected virtual string Port
\r
537 string port = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_PORT"));
\r
538 switch (ProviderType) {
\r
539 case PROVIDER_TYPE.SQLOLEDB :
\r
540 if (String.Empty.Equals(port)) {
\r
541 // if needed - resolve MSSQL port
\r
542 // FIXME : decide about behaviour in the case all the timeout spent on port resolution
\r
543 //long start = DateTime.Now.Ticks;
\r
544 port = DbPortResolver.getMSSqlPort(DataSource,InstanceName,ConnectionTimeout).ToString();
\r
545 //long end = DateTime.Now.Ticks;
\r
546 //if( (end - start) < ConnectionTimeout*1000000) {
\r
547 //timeout -= (int)(end - start)/1000000;
\r
550 // todo : what should we do if all the timeout spent on port resolution ?
\r
551 if ("-1".Equals(port)) {
\r
552 port = StringManager.GetString("SQL_CON_PORT", "1433"); //default port of MSSql Server 3167.
\r
554 ConnectionStringHelper.AddValue(UserParameters,StringManager.GetStringArray("CON_PORT"),port);
\r
561 public override string DataSource
\r
564 string dataSource = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATA_SOURCE"));
\r
566 if (ProviderType == PROVIDER_TYPE.SQLOLEDB) {
\r
568 if ((instanceIdx = dataSource.IndexOf("\\")) != -1) {
\r
569 // throw out named instance name
\r
570 dataSource = dataSource.Substring(0,instanceIdx);
\r
573 if (dataSource != null && dataSource.StartsWith("(") && dataSource.EndsWith(")")) {
\r
574 dataSource = dataSource.Substring(1,dataSource.Length - 2);
\r
577 if(String.Empty.Equals(dataSource) || (String.Compare("local",dataSource,true) == 0)) {
\r
578 dataSource = "localhost";
\r
585 protected virtual string InstanceName
\r
588 string dataSource = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATA_SOURCE"));
\r
589 string instanceName = String.Empty;
\r
590 if (ProviderType == PROVIDER_TYPE.SQLOLEDB) {
\r
592 if ((instanceIdx = dataSource.IndexOf("\\")) == -1) {
\r
593 // no named instance specified - use a default name
\r
594 instanceName = StringManager.GetString("SQL_DEFAULT_INSTANCE_NAME");
\r
597 // get named instance name
\r
598 instanceName = dataSource.Substring(instanceIdx + 1);
\r
601 return instanceName;
\r
605 protected virtual string User
\r
607 get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_USER_ID")); }
\r
610 protected virtual string Password
\r
612 get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_PASSWORD")); }
\r
615 protected NameValueCollection UserParameters
\r
618 if (_userParameters == null) {
\r
619 _userParameters = ConnectionStringHelper.BuildUserParameters(ConnectionString);
\r
621 return _userParameters;
\r
625 internal String JdbcUrl
\r
628 if ( UserParameters == null) {
\r
629 return String.Empty;
\r
632 if (_jdbcUrl == null) {
\r
633 _jdbcUrl = BuildJdbcUrl();
\r
639 internal ConnectionState InternalState
\r
641 get { return _internalState; }
\r
645 protected internal Connection JdbcConnection
\r
647 get { return _jdbcConnnection; }
\r
648 set { _jdbcConnnection = value; }
\r
651 protected virtual string[] ResourceIgnoredKeys
\r
653 get { return new string[0]; }
\r
656 protected virtual Hashtable SkippedUserParameters
\r
658 get { return new Hashtable(new CaseInsensitiveHashCodeProvider(),new CaseInsensitiveComparer()); }
\r
661 internal ObjectNameResolver[] SyntaxPatterns
\r
664 if (_syntaxPatterns == null) {
\r
665 _syntaxPatterns = ObjectNamesHelper.GetSyntaxPatterns(this);
\r
667 return _syntaxPatterns;
\r
671 #endregion // Properties
\r
674 // since WS also does not permits dynamically change of login timeout and tomcat does no implements - do not do it at all
\r
675 //ds.setLoginTimeout(ConnectionTimeout);
\r
677 internal abstract void OnSqlWarning(SQLWarning warning);
\r
679 internal abstract void OnStateChanged(ConnectionState orig, ConnectionState current);
\r
681 protected abstract SystemException CreateException(SQLException e);
\r
683 public override void Close()
\r
687 if (JdbcConnection != null && !JdbcConnection.isClosed()) {
\r
688 JdbcConnection.close();
\r
691 catch (SQLException e) {
\r
692 // suppress exception
\r
693 JdbcConnection = null;
\r
695 Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
\r
698 catch (Exception e) {
\r
699 // suppress exception
\r
700 JdbcConnection = null;
\r
702 Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
\r
706 lock(_internalStateSync) {
\r
707 _internalState = ConnectionState.Closed;
\r
712 protected internal virtual void CopyTo(AbstractDBConnection target)
\r
714 target._connectionString = _connectionString;
\r
717 internal protected virtual void OnSqlException(SQLException exp)
\r
719 throw CreateException(exp);
\r
722 internal void AddReference(object referencedObject)
\r
723 { lock(_referencedObjects.SyncRoot) {
\r
724 _referencedObjects.Add(new WeakReference(referencedObject));
\r
728 internal void RemoveReference(object referencedObject)
\r
730 lock(_referencedObjects.SyncRoot) {
\r
731 for(int i = 0; i < _referencedObjects.Count; i++) {
\r
732 WeakReference wr = (WeakReference) _referencedObjects[i];
\r
733 if (wr.IsAlive && (wr.Target == referencedObject)) {
\r
734 _referencedObjects.RemoveAt(i);
\r
740 private void ClearReferences()
\r
742 ArrayList oldList = _referencedObjects;
\r
743 _referencedObjects = new ArrayList();
\r
745 for(int i = 0; i < oldList.Count; i++) {
\r
746 WeakReference wr = (WeakReference) oldList[i];
\r
748 ClearReference(wr.Target);
\r
753 private void ClearReference(object referencedObject)
\r
756 if (referencedObject is AbstractDbCommand) {
\r
757 ((AbstractDbCommand)referencedObject).CloseInternal();
\r
759 else if (referencedObject is AbstractDataReader) {
\r
760 ((AbstractDataReader)referencedObject).CloseInternal();
\r
763 catch (SQLException) {
\r
764 // suppress exception since it's possible that command or reader are in inconsistent state
\r
768 public override void Open()
\r
770 if (_connectionString == null || _connectionString.Length == 0) {
\r
771 throw ExceptionHelper.ConnectionStringNotInitialized();
\r
774 IsConnecting = true;
\r
776 if (JdbcConnection != null && !JdbcConnection.isClosed()) {
\r
777 throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
\r
781 case JDBC_MODE.DATA_SOURCE_MODE :
\r
782 JdbcConnection = GetConnectionFromDataSource();
\r
785 case JDBC_MODE.JDBC_DRIVER_MODE:
\r
786 JdbcConnection = GetConnectionFromJdbcDriver();
\r
789 case JDBC_MODE.PROVIDER_MODE :
\r
790 JdbcConnection = GetConnectionFromProvider();
\r
795 OnStateChanged(ConnectionState.Closed, ConnectionState.Open);
\r
797 catch (SQLWarning warning) {
\r
798 OnSqlWarning(warning);
\r
800 catch (SQLException exp) {
\r
801 OnSqlException(exp);
\r
804 IsConnecting = false;
\r
808 public override void ChangeDatabase(String database)
\r
810 IsConnecting = true;
\r
813 Connection con = JdbcConnection;
\r
814 con.setCatalog(database);
\r
815 ConnectionStringHelper.UpdateValue(UserParameters,StringManager.GetStringArray("CON_DATABASE"),database);
\r
817 catch (SQLWarning warning) {
\r
818 OnSqlWarning(warning);
\r
820 catch (SQLException exp) {
\r
821 throw CreateException(exp);
\r
824 IsConnecting = false;
\r
828 public override string ServerVersion {
\r
830 // only if the driver support this methods
\r
832 if (JdbcConnection == null)
\r
833 return String.Empty;
\r
835 DatabaseMetaData metaData = JdbcConnection.getMetaData();
\r
836 return metaData.getDatabaseProductVersion();
\r
838 catch (SQLException exp) {
\r
839 throw CreateException(exp);
\r
844 internal string JdbcProvider {
\r
846 // only if the driver support this methods
\r
848 if (JdbcConnection == null)
\r
849 return String.Empty;
\r
851 DatabaseMetaData metaData = JdbcConnection.getMetaData();
\r
852 return metaData.getDriverName() + " " + metaData.getDriverVersion();
\r
854 catch (SQLException exp) {
\r
855 return String.Empty; //suppress
\r
860 protected override void Dispose(bool disposing)
\r
864 if (JdbcConnection != null && !JdbcConnection.isClosed()) {
\r
865 JdbcConnection.close();
\r
867 JdbcConnection = null;
\r
869 catch (java.sql.SQLException exp) {
\r
870 throw CreateException(exp);
\r
873 base.Dispose(disposing);
\r
876 protected internal virtual void ValidateConnectionString(string connectionString)
\r
878 JDBC_MODE currentJdbcMode = JdbcMode;
\r
880 if (currentJdbcMode == JDBC_MODE.NONE) {
\r
881 string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
\r
882 string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
\r
883 bool jdbcDriverSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr));
\r
884 bool jdbcUrlSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr));
\r
886 if (jdbcDriverSpecified ^ jdbcUrlSpecified) {
\r
887 throw new ArgumentException("Invalid format of connection string. If you want to use third-party JDBC driver, the format is: \"JdbcDriverClassName=<jdbc driver class name>;JdbcURL=<jdbc url>\"");
\r
892 protected virtual string BuildJdbcUrl()
\r
894 switch (JdbcMode) {
\r
895 case JDBC_MODE.JDBC_DRIVER_MODE :
\r
896 return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("JDBC_URL"));
\r
898 return String.Empty;
\r
902 protected java.util.Properties BuildProperties()
\r
904 java.util.Properties properties = new java.util.Properties();
\r
906 string user = User;
\r
907 if (user != null && user.Length > 0)
\r
908 properties.put("user", user);
\r
909 string password = Password;
\r
910 if (user != null && user.Length > 0)
\r
911 properties.put("password", password);
\r
913 string[] userKeys = UserParameters.AllKeys;
\r
915 for(int i=0; i < userKeys.Length; i++) {
\r
916 string userKey = userKeys[i];
\r
917 string userParameter = UserParameters[userKey];
\r
918 if (!SkipUserParameter(userKey)) {
\r
919 properties.put(userKey,userParameter);
\r
925 protected virtual bool SkipUserParameter(string parameterName)
\r
927 if (SkippedUserParameters.Count == 0) {
\r
928 // skipped parameters not initialized - skip all
\r
932 return SkippedUserParameters.Contains(parameterName);
\r
935 protected virtual void InitializeSkippedUserParameters()
\r
937 if (SkippedUserParameters.Count > 0) {
\r
941 for(int i=0; i < ResourceIgnoredKeys.Length; i++) {
\r
942 string[] userKeys = StringManager.GetStringArray(ResourceIgnoredKeys[i]);
\r
943 for(int j=0; j < userKeys.Length; j++) {
\r
944 SkippedUserParameters.Add(userKeys[j],userKeys[j]);
\r
949 internal void ValidateBeginTransaction()
\r
951 if (State != ConnectionState.Open) {
\r
952 throw new InvalidOperationException(Res.GetString("ADP_OpenConnectionRequired_BeginTransaction", new object[] {"BeginTransaction", State}));
\r
955 if (!JdbcConnection.getAutoCommit()) {
\r
956 throw new System.InvalidOperationException("Parallel transactions are not supported.");
\r
960 internal virtual Connection GetConnectionFromProvider()
\r
962 ActivateJdbcDriver(JdbcDriverName);
\r
963 DriverManager.setLoginTimeout(ConnectionTimeout);
\r
964 java.util.Properties properties = BuildProperties();
\r
965 return DriverManager.getConnection (JdbcUrl, properties);
\r
968 internal Connection GetConnectionFromDataSource()
\r
970 string dataSourceJndi = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_NAME"));
\r
971 string namingProviderUrl = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_PROVIDER"));
\r
972 string namingFactoryInitial = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_FACTORY"));
\r
973 DataSource ds = _dataSourceCache.GetDataSource(dataSourceJndi,namingProviderUrl,namingFactoryInitial);
\r
975 ds.setLoginTimeout(ConnectionTimeout);
\r
977 catch (java.lang.Exception) {
\r
978 // WebSphere does not allows dynamicall change of login timeout
\r
979 // setLoginTimeout is not supported yet
\r
980 // in Tomcat data source.
\r
981 // In this case we work wthout timeout.
\r
983 return ds.getConnection();
\r
986 internal virtual Connection GetConnectionFromJdbcDriver()
\r
988 string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
\r
989 string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
\r
991 string jdbcDriverName = ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr);
\r
992 string jdbcUrl = ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr);
\r
994 ActivateJdbcDriver(jdbcDriverName);
\r
995 DriverManager.setLoginTimeout(ConnectionTimeout);
\r
997 java.util.Properties properties = BuildProperties();
\r
999 return DriverManager.getConnection(jdbcUrl,properties);
\r
1002 internal ArrayList GetProcedureColumns(String procedureString, AbstractDbCommand command)
\r
1004 ArrayList col = new ArrayList();
\r
1006 ObjectNameResolver[] nameResolvers = SyntaxPatterns;
\r
1007 ResultSet res = null;
\r
1008 string catalog = null;
\r
1009 string schema = null;
\r
1010 string spname = null;
\r
1012 DatabaseMetaData metadata = JdbcConnection.getMetaData();
\r
1013 bool storesUpperCaseIdentifiers = false;
\r
1014 bool storesLowerCaseIdentifiers = false;
\r
1016 storesUpperCaseIdentifiers = metadata.storesUpperCaseIdentifiers();
\r
1017 storesLowerCaseIdentifiers = metadata.storesLowerCaseIdentifiers();
\r
1019 catch (SQLException e) {
\r
1023 for(int i=0; i < nameResolvers.Length; i++) {
\r
1024 ObjectNameResolver nameResolver = nameResolvers[i];
\r
1025 Match match = nameResolver.Match(procedureString);
\r
1027 if (match.Success) {
\r
1028 spname = ObjectNameResolver.GetName(match);
\r
1029 schema = ObjectNameResolver.GetSchema(match);
\r
1030 catalog = ObjectNameResolver.GetCatalog(match);
\r
1032 // make all identifiers uppercase or lowercase according to database metadata
\r
1033 if (storesUpperCaseIdentifiers) {
\r
1034 spname = (spname.Length > 0) ? spname.ToUpper() : null;
\r
1035 schema = (schema.Length > 0) ? schema.ToUpper() : null;
\r
1036 catalog = (catalog.Length > 0) ? catalog.ToUpper() : null;
\r
1038 else if (storesLowerCaseIdentifiers) {
\r
1039 spname = (spname.Length > 0) ? spname.ToLower() : null;
\r
1040 schema = (schema.Length > 0) ? schema.ToLower() : null;
\r
1041 catalog = (catalog.Length > 0) ? catalog.ToLower() : null;
\r
1044 spname = (spname.Length > 0) ? spname : null;
\r
1045 schema = (schema.Length > 0) ? schema : null;
\r
1046 catalog = (catalog.Length > 0) ? catalog : null;
\r
1049 // catalog from db is always in correct caps
\r
1050 if (catalog == null) {
\r
1051 catalog = JdbcConnection.getCatalog();
\r
1055 // always get the first procedure that db returns
\r
1056 res = metadata.getProcedures(catalog, schema, spname);
\r
1058 catalog = res.getString(1);
\r
1059 schema = res.getString(2);
\r
1060 spname = res.getString(3);
\r
1066 catch { // suppress exception
\r
1070 if (res != null) {
\r
1077 if (spname == null || spname.Length == 0) {
\r
1082 // get procedure columns based o procedure metadata
\r
1083 res = metadata.getProcedureColumns(catalog, schema, spname, null);
\r
1084 while (res.next()) {
\r
1085 // since there is still a possibility that some of the parameters to getProcedureColumn were nulls,
\r
1086 // we need to filter the results with strict matching
\r
1087 if ((res.getString(1) != catalog ) || (res.getString(2) != schema) || (res.getString(3) != spname)) {
\r
1091 AbstractDbParameter parameter = (AbstractDbParameter)command.CreateParameter();
\r
1093 parameter.SetParameterName(res);
\r
1094 parameter.SetParameterDbType(res);
\r
1095 parameter.SetSpecialFeatures(res);
\r
1097 //get parameter direction
\r
1098 short direction = res.getShort("COLUMN_TYPE");
\r
1099 if(direction == 1) //DatabaseMetaData.procedureColumnIn
\r
1100 parameter.Direction = ParameterDirection.Input;
\r
1101 else if(direction == 2) //DatabaseMetaData.procedureColumnInOut
\r
1102 parameter.Direction = ParameterDirection.InputOutput;
\r
1103 else if(direction == 4) //DatabaseMetaData.procedureColumnOut
\r
1104 parameter.Direction = ParameterDirection.Output;
\r
1105 else if(direction == 5) //DatabaseMetaData.procedureColumnReturn
\r
1106 parameter.Direction = ParameterDirection.ReturnValue;
\r
1108 //get parameter precision and scale
\r
1109 parameter.SetParameterPrecisionAndScale(res);
\r
1111 parameter.SetParameterSize(res);
\r
1112 parameter.SetParameterIsNullable(res);
\r
1114 col.Add(parameter);
\r
1118 if (res != null) {
\r
1123 catch(Exception e) {
\r
1126 Console.WriteLine("Exception catched at AbstractDBConnection.GetProcedureColumns() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
\r
1132 protected static void ActivateJdbcDriver(string driver)
\r
1134 if(driver != null) {
\r
1136 java.lang.Class.forName(driver).newInstance();
\r
1138 catch (java.lang.ClassNotFoundException e) {
\r
1139 throw new TypeLoadException(e.Message);
\r
1141 catch (java.lang.InstantiationException e) {
\r
1142 throw new MemberAccessException(e.Message);
\r
1144 catch (java.lang.IllegalAccessException e) {
\r
1145 throw new MissingMethodException(e.Message);
\r
1150 protected String BuildMsSqlUrl()
\r
1152 return StringManager.GetString("SQL_JDBC_URL") //"jdbc:microsoft:sqlserver://"
\r
1153 + ServerName + ":" + Port + ";DatabaseName=" + CatalogName;
\r
1156 #endregion // Methods
\r