2 // System.Data.Common.AbstractDBConnection
\r
5 // Konstantin Triger <kostat@mainsoft.com>
6 // Boris Kirzner <borisk@mainsoft.com>
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
34 using System.Data.ProviderBase;
\r
35 using System.Data.Configuration;
\r
36 using System.Configuration;
\r
37 using System.Collections;
\r
38 using System.Collections.Specialized;
\r
40 using System.Text.RegularExpressions;
\r
45 // can not use java.util here - it manes ArrayList an ambiguous reference
\r
47 namespace System.Data.Common
\r
49 public abstract class AbstractDBConnection : DbConnection
\r
51 #region ObjectNamesHelper
\r
53 private sealed class ObjectNamesHelper
\r
55 //static readonly Regex NameOrder = new Regex(@"^\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
56 static readonly Regex NameOrder = new Regex(@"^((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
58 //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
59 static readonly Regex SchemaNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
60 //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
61 //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
62 static readonly Regex CatalogSchemaNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
64 //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
65 //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
66 static readonly Regex CatalogNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
67 //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
68 //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
69 static readonly Regex SchemaCatalogNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
\r
71 internal static ObjectNameResolver[] GetSyntaxPatterns(AbstractDBConnection connection)
\r
73 ArrayList collection = new ArrayList();
\r
74 collection.Add(new ObjectNameResolver(NameOrder));
\r
76 ObjectNameResolversCollection basic = (ObjectNameResolversCollection)ConfigurationSettings.GetConfig("system.data/objectnameresolution");
\r
78 DatabaseMetaData metaData = connection.JdbcConnection.getMetaData();
\r
79 string productName = metaData.getDatabaseProductName();
\r
81 foreach(ObjectNameResolver nameResolver in basic) {
\r
82 if (productName.IndexOf(nameResolver.DbName) != -1) {
\r
83 collection.Add(nameResolver);
\r
88 if (metaData.isCatalogAtStart()) {
\r
89 collection.Add(new ObjectNameResolver(SchemaNameOrder));
\r
90 collection.Add(new ObjectNameResolver(CatalogNameOrder));
\r
91 collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
\r
92 collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
\r
95 collection.Add(new ObjectNameResolver(CatalogNameOrder));
\r
96 collection.Add(new ObjectNameResolver(SchemaNameOrder));
\r
97 collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
\r
98 collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
\r
101 return (ObjectNameResolver[])collection.ToArray(typeof(ObjectNameResolver));
\r
105 #endregion // ObjectNamesHelper
\r
107 #region ConnectionStringHelper
\r
109 internal sealed class ConnectionStringHelper
\r
111 internal static string FindValue(NameValueCollection collection, string[] keys)
\r
113 if (collection == null || keys == null || keys.Length == 0) {
\r
114 return String.Empty;
\r
117 for(int i=0; i < keys.Length; i++) {
\r
118 string value = FindValue(collection,keys[i]);
\r
119 if (!String.Empty.Equals(value)) {
\r
123 return String.Empty;
\r
126 internal static string FindValue(NameValueCollection collection, string key)
\r
128 if (collection == null) {
\r
129 return String.Empty;
\r
132 string value = collection[key];
\r
133 return (value != null) ? value : String.Empty;
\r
136 internal static void UpdateValue(NameValueCollection collection,string[] keys,string value)
\r
138 for(int i=0; i < keys.Length; i++) {
\r
139 if (collection[keys[i]] != null) {
\r
140 collection[keys[i]] = value;
\r
145 internal static void AddValue(NameValueCollection collection,string[] keys,string value)
\r
147 for(int i=0; i < keys.Length; i++) {
\r
148 collection[keys[i]] = value;
\r
153 * Parses connection string and builds NameValueCollection
\r
156 internal static NameValueCollection BuildUserParameters (string connectionString)
\r
158 NameValueCollection userParameters = new NameValueCollection();
\r
160 if (connectionString == null || connectionString.Length == 0) {
\r
161 return userParameters;
\r
163 connectionString += ";";
\r
165 bool inQuote = false;
\r
166 bool inDQuote = false;
\r
167 bool inName = true;
\r
169 string name = String.Empty;
\r
170 string value = String.Empty;
\r
171 StringBuilder sb = new StringBuilder ();
\r
173 for (int i = 0; i < connectionString.Length; i += 1) {
\r
174 char c = connectionString [i];
\r
176 if (i == connectionString.Length - 1)
\r
179 peek = connectionString [i + 1];
\r
185 else if (peek.Equals(c)) {
\r
190 inQuote = !inQuote;
\r
195 else if (peek.Equals(c)) {
\r
200 inDQuote = !inDQuote;
\r
203 if (inDQuote || inQuote)
\r
206 if (name != String.Empty && name != null) {
\r
207 value = sb.ToString();
\r
208 userParameters [name.Trim()] = value.Trim();
\r
211 name = String.Empty;
\r
212 value = String.Empty;
\r
213 sb = new StringBuilder();
\r
217 if (inDQuote || inQuote || !inName)
\r
219 else if (peek.Equals(c)) {
\r
224 name = sb.ToString();
\r
225 sb = new StringBuilder();
\r
230 if (inQuote || inDQuote)
\r
232 else if (sb.Length > 0 && !peek.Equals(';'))
\r
240 return userParameters;
\r
244 #endregion // ConnectionStringHelper
\r
246 #region DataSourceCache
\r
248 private sealed class DataSourceCache : AbstractDbMetaDataCache
\r
250 internal DataSource GetDataSource(string dataSourceName,string namingProviderUrl,string namingFactoryInitial)
\r
252 Hashtable cache = Cache;
\r
254 DataSource ds = cache[dataSourceName] as DataSource;
\r
260 Context ctx = null;
\r
262 java.util.Properties properties = new java.util.Properties();
\r
264 if ((namingProviderUrl != null) && (namingProviderUrl.Length > 0)) {
\r
265 properties.put("java.naming.provider.url",namingProviderUrl);
\r
268 if ((namingFactoryInitial != null) && (namingFactoryInitial.Length > 0)) {
\r
269 properties.put("java.naming.factory.initial",namingFactoryInitial);
\r
272 ctx = new InitialContext(properties);
\r
275 ds = (DataSource)ctx.lookup(dataSourceName);
\r
277 catch(javax.naming.NameNotFoundException e) {
\r
278 // possible that is a Tomcat bug,
\r
279 // so try to lookup for jndi datasource with "java:comp/env/" appended
\r
280 ds = (DataSource)ctx.lookup("java:comp/env/" + dataSourceName);
\r
283 cache[dataSourceName] = ds;
\r
288 #endregion // DatasourceCache
\r
290 #region Declarations
\r
292 protected internal enum JDBC_MODE { NONE, DATA_SOURCE_MODE, JDBC_DRIVER_MODE, PROVIDER_MODE }
\r
293 protected internal enum PROVIDER_TYPE { NONE, SQLOLEDB, MSDAORA, IBMDADB2 }
\r
295 #endregion // Declarations
\r
299 private static DataSourceCache _dataSourceCache = new DataSourceCache();
\r
300 private const int DEFAULT_TIMEOUT = 15;
\r
302 private Connection _jdbcConnnection;
\r
303 private ConnectionState _internalState;
\r
304 private object _internalStateSync = new object();
\r
306 private NameValueCollection _userParameters;
\r
308 protected string _connectionString = String.Empty;
\r
309 protected string _jdbcUrl;
\r
311 private ArrayList _referencedObjects = new ArrayList();
\r
312 private ObjectNameResolver[] _syntaxPatterns;
\r
314 #endregion // Fields
\r
316 #region Constructors
\r
318 public AbstractDBConnection(string connectionString)
\r
320 _connectionString = connectionString;
\r
321 InitializeSkippedUserParameters();
\r
324 #endregion // Constructors
\r
328 public override String ConnectionString
\r
330 get { return _connectionString; }
\r
333 throw ExceptionHelper.NotAllowedWhileConnectionOpen("ConnectionString",_internalState);
\r
335 _connectionString = value;
\r
336 _userParameters = null;
\r
341 public override int ConnectionTimeout
\r
344 string timeoutStr = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_TIMEOUT"));
\r
345 if (!String.Empty.Equals(timeoutStr)) {
\r
347 return Convert.ToInt32(timeoutStr);
\r
349 catch(FormatException e) {
\r
350 throw ExceptionHelper.InvalidValueForKey("connect timeout");
\r
352 catch (OverflowException e) {
\r
353 throw ExceptionHelper.InvalidValueForKey("connect timeout");
\r
356 return DEFAULT_TIMEOUT;
\r
360 public override String Database
\r
362 get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATABASE")); }
\r
365 public override ConnectionState State
\r
369 if ((JdbcConnection == null) || JdbcConnection.isClosed()) {
\r
370 // jdbc connection not initialized or closed
\r
371 if (_internalState == ConnectionState.Closed ) {
\r
372 return ConnectionState.Closed;
\r
376 // jdbc connection is opened
\r
377 if ((_internalState & ConnectionState.Open) != 0) {
\r
378 return ConnectionState.Open;
\r
381 return ConnectionState.Broken;
\r
383 catch (SQLException) {
\r
384 return ConnectionState.Broken;
\r
389 internal bool IsExecuting
\r
392 return ((_internalState & ConnectionState.Executing) != 0);
\r
396 lock(_internalStateSync) {
\r
397 // to switch to executing, the connection must be in opened
\r
399 if (_internalState != ConnectionState.Open) {
\r
401 throw ExceptionHelper.OpenedReaderExists();
\r
403 throw ExceptionHelper.OpenConnectionRequired("",_internalState);
\r
405 _internalState |= ConnectionState.Executing;
\r
408 if (!IsExecuting) {
\r
409 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Executing.ToString() + " while in state " + _internalState.ToString());
\r
411 _internalState &= ~ConnectionState.Executing;
\r
417 internal bool IsFetching
\r
420 return ((_internalState & ConnectionState.Fetching) != 0);
\r
424 lock(_internalStateSync) {
\r
426 // to switch to fetching connection must be in opened, executing
\r
427 if (((_internalState & ConnectionState.Open) == 0) || ((_internalState & ConnectionState.Executing) == 0)) {
\r
428 throw ExceptionHelper.OpenConnectionRequired("",_internalState);
\r
430 _internalState |= ConnectionState.Fetching;
\r
434 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Fetching.ToString() + " while in state " + _internalState.ToString());
\r
436 _internalState &= ~ConnectionState.Fetching;
\r
442 internal bool IsOpened
\r
445 return ((_internalState & ConnectionState.Open) != 0);
\r
449 lock(_internalStateSync) {
\r
451 // only connecting connection can be opened
\r
452 if ((_internalState != ConnectionState.Connecting)) {
\r
453 throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
\r
455 _internalState |= ConnectionState.Open;
\r
459 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Open.ToString() + " while in state " + _internalState.ToString());
\r
461 _internalState &= ~ConnectionState.Open;
\r
467 internal bool IsConnecting
\r
470 return ((_internalState & ConnectionState.Connecting) != 0);
\r
474 lock(_internalStateSync) {
\r
476 // to switch to connecting conection must be in closed or in opened
\r
477 if ((_internalState != ConnectionState.Closed) && (_internalState != ConnectionState.Open)) {
\r
478 throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
\r
480 _internalState |= ConnectionState.Connecting;
\r
483 if (!IsConnecting) {
\r
484 throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Connecting.ToString() + " while in state " + _internalState.ToString());
\r
486 _internalState &= ~ConnectionState.Connecting;
\r
492 protected virtual PROVIDER_TYPE ProviderType
\r
495 if (JdbcMode != JDBC_MODE.PROVIDER_MODE) {
\r
496 return PROVIDER_TYPE.NONE;
\r
499 string providerStr = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_PROVIDER")).ToUpper();
\r
500 if (providerStr.StartsWith("SQLOLEDB")) {
\r
501 return PROVIDER_TYPE.SQLOLEDB;
\r
503 else if (providerStr.StartsWith("MSDAORA")) {
\r
504 return PROVIDER_TYPE.MSDAORA;
\r
506 else if (providerStr.StartsWith("IBMDADB2")) {
\r
507 return PROVIDER_TYPE.IBMDADB2;
\r
509 return PROVIDER_TYPE.NONE;
\r
513 protected internal virtual JDBC_MODE JdbcMode
\r
516 string[] conJndiNameStr = StringManager.GetStringArray("CON_JNDI_NAME");
\r
517 if ( !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,conJndiNameStr))) {
\r
518 return JDBC_MODE.DATA_SOURCE_MODE;
\r
521 string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
\r
522 string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
\r
523 bool jdbcDriverSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr));
\r
524 bool jdbcUrlSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr));
\r
526 if (jdbcDriverSpecified && jdbcUrlSpecified) {
\r
527 return JDBC_MODE.JDBC_DRIVER_MODE;
\r
530 string[] providerStr = StringManager.GetStringArray("CON_PROVIDER");
\r
531 if (!String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,providerStr))) {
\r
532 return JDBC_MODE.PROVIDER_MODE;
\r
535 return JDBC_MODE.NONE;
\r
539 protected virtual string JdbcDriverName
\r
541 get { return String.Empty; }
\r
544 protected abstract DbStringManager StringManager
\r
549 protected virtual string ServerName
\r
551 get { return DataSource; }
\r
554 protected virtual string CatalogName
\r
556 get { return Database; }
\r
559 protected virtual string Port
\r
562 string port = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_PORT"));
\r
563 switch (ProviderType) {
\r
564 case PROVIDER_TYPE.SQLOLEDB :
\r
565 if (String.Empty.Equals(port)) {
\r
566 // if needed - resolve MSSQL port
\r
567 // FIXME : decide about behaviour in the case all the timeout spent on port resolution
\r
568 //long start = DateTime.Now.Ticks;
\r
569 port = DbPortResolver.getMSSqlPort(DataSource,InstanceName,ConnectionTimeout).ToString();
\r
570 //long end = DateTime.Now.Ticks;
\r
571 //if( (end - start) < ConnectionTimeout*1000000) {
\r
572 //timeout -= (int)(end - start)/1000000;
\r
575 // todo : what should we do if all the timeout spent on port resolution ?
\r
576 if ("-1".Equals(port)) {
\r
577 port = StringManager.GetString("SQL_CON_PORT", "1433"); //default port of MSSql Server 3167.
\r
579 ConnectionStringHelper.AddValue(UserParameters,StringManager.GetStringArray("CON_PORT"),port);
\r
586 public override string DataSource
\r
589 string dataSource = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATA_SOURCE"));
\r
591 if (ProviderType == PROVIDER_TYPE.SQLOLEDB) {
\r
593 if ((instanceIdx = dataSource.IndexOf("\\")) != -1) {
\r
594 // throw out named instance name
\r
595 dataSource = dataSource.Substring(0,instanceIdx);
\r
598 if (dataSource != null && dataSource.StartsWith("(") && dataSource.EndsWith(")")) {
\r
599 dataSource = dataSource.Substring(1,dataSource.Length - 2);
\r
602 if(String.Empty.Equals(dataSource) || (String.Compare("local",dataSource,true) == 0)) {
\r
603 dataSource = "localhost";
\r
610 protected virtual string InstanceName
\r
613 string dataSource = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATA_SOURCE"));
\r
614 string instanceName = String.Empty;
\r
615 if (ProviderType == PROVIDER_TYPE.SQLOLEDB) {
\r
617 if ((instanceIdx = dataSource.IndexOf("\\")) == -1) {
\r
618 // no named instance specified - use a default name
\r
619 instanceName = StringManager.GetString("SQL_DEFAULT_INSTANCE_NAME");
\r
622 // get named instance name
\r
623 instanceName = dataSource.Substring(instanceIdx + 1);
\r
626 return instanceName;
\r
630 protected virtual string User
\r
632 get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_USER_ID")); }
\r
635 protected virtual string Password
\r
637 get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_PASSWORD")); }
\r
640 protected NameValueCollection UserParameters
\r
643 if (_userParameters == null) {
\r
644 _userParameters = ConnectionStringHelper.BuildUserParameters(ConnectionString);
\r
646 return _userParameters;
\r
650 internal String JdbcUrl
\r
653 if ( UserParameters == null) {
\r
654 return String.Empty;
\r
657 if (_jdbcUrl == null) {
\r
658 _jdbcUrl = BuildJdbcUrl();
\r
664 internal ConnectionState InternalState
\r
666 get { return _internalState; }
\r
670 protected internal Connection JdbcConnection
\r
672 get { return _jdbcConnnection; }
\r
673 set { _jdbcConnnection = value; }
\r
676 protected virtual string[] ResourceIgnoredKeys
\r
678 get { return new string[0]; }
\r
681 protected virtual Hashtable SkippedUserParameters
\r
683 get { return new Hashtable(new CaseInsensitiveHashCodeProvider(),new CaseInsensitiveComparer()); }
\r
686 internal ObjectNameResolver[] SyntaxPatterns
\r
689 if (_syntaxPatterns == null) {
\r
690 _syntaxPatterns = ObjectNamesHelper.GetSyntaxPatterns(this);
\r
692 return _syntaxPatterns;
\r
696 #endregion // Properties
\r
699 // since WS also does not permits dynamically change of login timeout and tomcat does no implements - do not do it at all
\r
700 //ds.setLoginTimeout(ConnectionTimeout);
\r
702 internal abstract void OnSqlWarning(SQLWarning warning);
\r
704 internal abstract void OnStateChanged(ConnectionState orig, ConnectionState current);
\r
706 protected abstract SystemException CreateException(SQLException e);
\r
708 public override void Close()
\r
712 if (JdbcConnection != null && !JdbcConnection.isClosed()) {
\r
713 JdbcConnection.close();
\r
716 catch (SQLException e) {
\r
717 // suppress exception
\r
718 JdbcConnection = null;
\r
720 Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
\r
723 catch (Exception e) {
\r
724 // suppress exception
\r
725 JdbcConnection = null;
\r
727 Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
\r
731 lock(_internalStateSync) {
\r
732 _internalState = ConnectionState.Closed;
\r
737 protected internal virtual void CopyTo(AbstractDBConnection target)
\r
739 target._connectionString = _connectionString;
\r
742 internal protected virtual void OnSqlException(SQLException exp)
\r
744 throw CreateException(exp);
\r
747 internal void AddReference(object referencedObject)
\r
748 { lock(_referencedObjects.SyncRoot) {
\r
749 _referencedObjects.Add(new WeakReference(referencedObject));
\r
753 internal void RemoveReference(object referencedObject)
\r
755 lock(_referencedObjects.SyncRoot) {
\r
756 for(int i = 0; i < _referencedObjects.Count; i++) {
\r
757 WeakReference wr = (WeakReference) _referencedObjects[i];
\r
758 if (wr.IsAlive && (wr.Target == referencedObject)) {
\r
759 _referencedObjects.RemoveAt(i);
\r
765 private void ClearReferences()
\r
767 ArrayList oldList = _referencedObjects;
\r
768 _referencedObjects = new ArrayList();
\r
770 for(int i = 0; i < oldList.Count; i++) {
\r
771 WeakReference wr = (WeakReference) oldList[i];
\r
773 ClearReference(wr.Target);
\r
778 private void ClearReference(object referencedObject)
\r
781 if (referencedObject is AbstractDbCommand) {
\r
782 ((AbstractDbCommand)referencedObject).CloseInternal();
\r
784 else if (referencedObject is AbstractDataReader) {
\r
785 ((AbstractDataReader)referencedObject).CloseInternal();
\r
788 catch (SQLException) {
\r
789 // suppress exception since it's possible that command or reader are in inconsistent state
\r
793 public override void Open()
\r
795 if (_connectionString == null || _connectionString.Length == 0) {
\r
796 throw ExceptionHelper.ConnectionStringNotInitialized();
\r
799 IsConnecting = true;
\r
801 if (JdbcConnection != null && !JdbcConnection.isClosed()) {
\r
802 throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
\r
806 case JDBC_MODE.DATA_SOURCE_MODE :
\r
807 JdbcConnection = GetConnectionFromDataSource();
\r
810 case JDBC_MODE.JDBC_DRIVER_MODE:
\r
811 JdbcConnection = GetConnectionFromJdbcDriver();
\r
814 case JDBC_MODE.PROVIDER_MODE :
\r
815 JdbcConnection = GetConnectionFromProvider();
\r
820 OnStateChanged(ConnectionState.Closed, ConnectionState.Open);
\r
822 catch (SQLWarning warning) {
\r
823 OnSqlWarning(warning);
\r
825 catch (SQLException exp) {
\r
826 OnSqlException(exp);
\r
829 IsConnecting = false;
\r
833 public override void ChangeDatabase(String database)
\r
835 IsConnecting = true;
\r
838 Connection con = JdbcConnection;
\r
839 con.setCatalog(database);
\r
840 ConnectionStringHelper.UpdateValue(UserParameters,StringManager.GetStringArray("CON_DATABASE"),database);
\r
842 catch (SQLWarning warning) {
\r
843 OnSqlWarning(warning);
\r
845 catch (SQLException exp) {
\r
846 throw CreateException(exp);
\r
849 IsConnecting = false;
\r
853 public override string ServerVersion {
\r
855 // only if the driver support this methods
\r
857 if (JdbcConnection == null)
\r
858 return String.Empty;
\r
860 DatabaseMetaData metaData = JdbcConnection.getMetaData();
\r
861 return metaData.getDatabaseProductVersion();
\r
863 catch (SQLException exp) {
\r
864 throw CreateException(exp);
\r
869 internal string JdbcProvider {
\r
871 // only if the driver support this methods
\r
873 if (JdbcConnection == null)
\r
874 return String.Empty;
\r
876 DatabaseMetaData metaData = JdbcConnection.getMetaData();
\r
877 return metaData.getDriverName() + " " + metaData.getDriverVersion();
\r
879 catch (SQLException exp) {
\r
880 return String.Empty; //suppress
\r
885 protected override void Dispose(bool disposing)
\r
889 if (JdbcConnection != null && !JdbcConnection.isClosed()) {
\r
890 JdbcConnection.close();
\r
892 JdbcConnection = null;
\r
894 catch (java.sql.SQLException exp) {
\r
895 throw CreateException(exp);
\r
898 base.Dispose(disposing);
\r
901 protected internal virtual void ValidateConnectionString(string connectionString)
\r
903 JDBC_MODE currentJdbcMode = JdbcMode;
\r
905 if (currentJdbcMode == JDBC_MODE.NONE) {
\r
906 string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
\r
907 string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
\r
908 bool jdbcDriverSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr));
\r
909 bool jdbcUrlSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr));
\r
911 if (jdbcDriverSpecified ^ jdbcUrlSpecified) {
\r
912 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
917 protected virtual string BuildJdbcUrl()
\r
919 switch (JdbcMode) {
\r
920 case JDBC_MODE.JDBC_DRIVER_MODE :
\r
921 return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("JDBC_URL"));
\r
923 return String.Empty;
\r
927 protected java.util.Properties BuildProperties()
\r
929 java.util.Properties properties = new java.util.Properties();
\r
931 string user = User;
\r
932 if (user != null && user.Length > 0)
\r
933 properties.put("user", user);
\r
934 string password = Password;
\r
935 if (user != null && user.Length > 0)
\r
936 properties.put("password", password);
\r
938 string[] userKeys = UserParameters.AllKeys;
\r
940 for(int i=0; i < userKeys.Length; i++) {
\r
941 string userKey = userKeys[i];
\r
942 string userParameter = UserParameters[userKey];
\r
943 if (!SkipUserParameter(userKey)) {
\r
944 properties.put(userKey,userParameter);
\r
950 protected virtual bool SkipUserParameter(string parameterName)
\r
952 if (SkippedUserParameters.Count == 0) {
\r
953 // skipped parameters not initialized - skip all
\r
957 return SkippedUserParameters.Contains(parameterName);
\r
960 protected virtual void InitializeSkippedUserParameters()
\r
962 if (SkippedUserParameters.Count > 0) {
\r
966 for(int i=0; i < ResourceIgnoredKeys.Length; i++) {
\r
967 string[] userKeys = StringManager.GetStringArray(ResourceIgnoredKeys[i]);
\r
968 for(int j=0; j < userKeys.Length; j++) {
\r
969 SkippedUserParameters.Add(userKeys[j],userKeys[j]);
\r
974 internal void ValidateBeginTransaction()
\r
976 if (State != ConnectionState.Open) {
\r
977 throw new InvalidOperationException(String.Format("{0} requires an open and available Connection. The connection's current state is {1}.", new object[] {"BeginTransaction", State}));
\r
980 if (!JdbcConnection.getAutoCommit()) {
\r
981 throw new System.InvalidOperationException("Parallel transactions are not supported.");
\r
985 internal virtual Connection GetConnectionFromProvider()
\r
987 ActivateJdbcDriver(JdbcDriverName);
\r
988 DriverManager.setLoginTimeout(ConnectionTimeout);
\r
989 java.util.Properties properties = BuildProperties();
\r
990 return DriverManager.getConnection (JdbcUrl, properties);
\r
993 internal Connection GetConnectionFromDataSource()
\r
995 string dataSourceJndi = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_NAME"));
\r
996 string namingProviderUrl = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_PROVIDER"));
\r
997 string namingFactoryInitial = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_FACTORY"));
\r
998 DataSource ds = _dataSourceCache.GetDataSource(dataSourceJndi,namingProviderUrl,namingFactoryInitial);
\r
1000 ds.setLoginTimeout(ConnectionTimeout);
\r
1002 catch (java.lang.Exception) {
\r
1003 // WebSphere does not allows dynamicall change of login timeout
\r
1004 // setLoginTimeout is not supported yet
\r
1005 // in Tomcat data source.
\r
1006 // In this case we work wthout timeout.
\r
1008 return ds.getConnection();
\r
1011 internal virtual Connection GetConnectionFromJdbcDriver()
\r
1013 string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
\r
1014 string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
\r
1016 string jdbcDriverName = ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr);
\r
1017 string jdbcUrl = ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr);
\r
1019 ActivateJdbcDriver(jdbcDriverName);
\r
1020 DriverManager.setLoginTimeout(ConnectionTimeout);
\r
1022 java.util.Properties properties = BuildProperties();
\r
1024 return DriverManager.getConnection(jdbcUrl,properties);
\r
1027 internal ArrayList GetProcedureColumns(String procedureString, AbstractDbCommand command)
\r
1029 ArrayList col = new ArrayList();
\r
1031 ObjectNameResolver[] nameResolvers = SyntaxPatterns;
\r
1032 ResultSet res = null;
\r
1033 string catalog = null;
\r
1034 string schema = null;
\r
1035 string spname = null;
\r
1037 DatabaseMetaData metadata = JdbcConnection.getMetaData();
\r
1038 bool storesUpperCaseIdentifiers = false;
\r
1039 bool storesLowerCaseIdentifiers = false;
\r
1041 storesUpperCaseIdentifiers = metadata.storesUpperCaseIdentifiers();
\r
1042 storesLowerCaseIdentifiers = metadata.storesLowerCaseIdentifiers();
\r
1044 catch (SQLException e) {
\r
1048 for(int i=0; i < nameResolvers.Length; i++) {
\r
1049 ObjectNameResolver nameResolver = nameResolvers[i];
\r
1050 Match match = nameResolver.Match(procedureString);
\r
1052 if (match.Success) {
\r
1053 spname = ObjectNameResolver.GetName(match);
\r
1054 schema = ObjectNameResolver.GetSchema(match);
\r
1055 catalog = ObjectNameResolver.GetCatalog(match);
\r
1057 // make all identifiers uppercase or lowercase according to database metadata
\r
1058 if (storesUpperCaseIdentifiers) {
\r
1059 spname = (spname.Length > 0) ? spname.ToUpper() : null;
\r
1060 schema = (schema.Length > 0) ? schema.ToUpper() : null;
\r
1061 catalog = (catalog.Length > 0) ? catalog.ToUpper() : null;
\r
1063 else if (storesLowerCaseIdentifiers) {
\r
1064 spname = (spname.Length > 0) ? spname.ToLower() : null;
\r
1065 schema = (schema.Length > 0) ? schema.ToLower() : null;
\r
1066 catalog = (catalog.Length > 0) ? catalog.ToLower() : null;
\r
1069 spname = (spname.Length > 0) ? spname : null;
\r
1070 schema = (schema.Length > 0) ? schema : null;
\r
1071 catalog = (catalog.Length > 0) ? catalog : null;
\r
1074 // catalog from db is always in correct caps
\r
1075 if (catalog == null) {
\r
1076 catalog = JdbcConnection.getCatalog();
\r
1080 // always get the first procedure that db returns
\r
1081 res = metadata.getProcedures(catalog, schema, spname);
\r
1083 catalog = res.getString(1);
\r
1084 schema = res.getString(2);
\r
1085 spname = res.getString(3);
\r
1091 catch { // suppress exception
\r
1095 if (res != null) {
\r
1102 if (spname == null || spname.Length == 0) {
\r
1107 // get procedure columns based o procedure metadata
\r
1108 res = metadata.getProcedureColumns(catalog, schema, spname, null);
\r
1109 while (res.next()) {
\r
1110 // since there is still a possibility that some of the parameters to getProcedureColumn were nulls,
\r
1111 // we need to filter the results with strict matching
\r
1112 if ((res.getString(1) != catalog ) || (res.getString(2) != schema) || (res.getString(3) != spname)) {
\r
1116 AbstractDbParameter parameter = (AbstractDbParameter)command.CreateParameter();
\r
1118 parameter.SetParameterName(res);
\r
1119 parameter.SetParameterDbType(res);
\r
1120 parameter.SetSpecialFeatures(res);
\r
1122 //get parameter direction
\r
1123 short direction = res.getShort("COLUMN_TYPE");
\r
1124 if(direction == 1) //DatabaseMetaData.procedureColumnIn
\r
1125 parameter.Direction = ParameterDirection.Input;
\r
1126 else if(direction == 2) //DatabaseMetaData.procedureColumnInOut
\r
1127 parameter.Direction = ParameterDirection.InputOutput;
\r
1128 else if(direction == 4) //DatabaseMetaData.procedureColumnOut
\r
1129 parameter.Direction = ParameterDirection.Output;
\r
1130 else if(direction == 5) //DatabaseMetaData.procedureColumnReturn
\r
1131 parameter.Direction = ParameterDirection.ReturnValue;
\r
1133 //get parameter precision and scale
\r
1134 parameter.SetParameterPrecisionAndScale(res);
\r
1136 parameter.SetParameterSize(res);
\r
1137 parameter.SetParameterIsNullable(res);
\r
1139 col.Add(parameter);
\r
1143 if (res != null) {
\r
1148 catch(Exception e) {
\r
1151 Console.WriteLine("Exception catched at AbstractDBConnection.GetProcedureColumns() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
\r
1157 protected static void ActivateJdbcDriver(string driver)
\r
1159 if(driver != null) {
\r
1161 java.lang.Class.forName(driver).newInstance();
\r
1163 catch (java.lang.ClassNotFoundException e) {
\r
1164 throw new TypeLoadException(e.Message);
\r
1166 catch (java.lang.InstantiationException e) {
\r
1167 throw new MemberAccessException(e.Message);
\r
1169 catch (java.lang.IllegalAccessException e) {
\r
1170 throw new MissingMethodException(e.Message);
\r
1175 protected String BuildMsSqlUrl()
\r
1177 return StringManager.GetString("SQL_JDBC_URL") //"jdbc:microsoft:sqlserver://"
\r
1178 + ServerName + ":" + Port + ";DatabaseName=" + CatalogName;
\r
1181 #endregion // Methods
\r