2010-07-25 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / System.Data / System.Data.ProviderBase.jvm / AbstractDBConnection.cs
1 //\r
2 // System.Data.Common.AbstractDBConnection\r
3 //\r
4 // Authors:\r
5 //      Konstantin Triger <kostat@mainsoft.com>\r
6 //      Boris Kirzner <borisk@mainsoft.com>\r
7 //      \r
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)\r
9 //\r
10 \r
11 //\r
12 // Permission is hereby granted, free of charge, to any person obtaining\r
13 // a copy of this software and associated documentation files (the\r
14 // "Software"), to deal in the Software without restriction, including\r
15 // without limitation the rights to use, copy, modify, merge, publish,\r
16 // distribute, sublicense, and/or sell copies of the Software, and to\r
17 // permit persons to whom the Software is furnished to do so, subject to\r
18 // the following conditions:\r
19 // \r
20 // The above copyright notice and this permission notice shall be\r
21 // included in all copies or substantial portions of the Software.\r
22 // \r
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
30 //\r
31 \r
32 using System.Globalization;\r
33 using System.Data;\r
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
39 using System.Text;\r
40 using System.Text.RegularExpressions;\r
41 using Mainsoft.Data.Jdbc.Providers;\r
42 using System.Data.Common;\r
43 \r
44 using java.sql;\r
45 using javax.sql;\r
46 using javax.naming;\r
47 \r
48 using Mainsoft.Data.Configuration;\r
49 \r
50 namespace System.Data.ProviderBase\r
51 {\r
52         public abstract class AbstractDBConnection : DbConnection, ICloneable\r
53         {\r
54                 #region ObjectNamesHelper\r
55 \r
56                 private sealed class ObjectNamesHelper\r
57                 {\r
58                         //static readonly Regex NameOrder = new Regex(@"^\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
59                         static readonly Regex NameOrder = new Regex(@"^((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
60 \r
61                         //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
62                         static readonly Regex SchemaNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
63                         //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
64                         //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
65                         static readonly Regex CatalogSchemaNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
66 \r
67                         //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
68                         //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
69                         static readonly Regex CatalogNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
70                         //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
71                         //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
72                         static readonly Regex SchemaCatalogNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);\r
73 \r
74                         internal static ObjectNameResolver[] GetSyntaxPatterns(AbstractDBConnection connection)\r
75                         {\r
76                                 ArrayList collection = new ArrayList();\r
77                                 collection.Add(new ObjectNameResolver(NameOrder));\r
78 \r
79                                 ObjectNameResolversCollection basic = (ObjectNameResolversCollection) ConfigurationSettings.GetConfig ("Mainsoft.Data.Configuration/objectnameresolution");\r
80                                 \r
81                                 java.sql.DatabaseMetaData metaData = connection.JdbcConnection.getMetaData();\r
82                                 string productName = metaData.getDatabaseProductName();\r
83 \r
84                                 foreach(ObjectNameResolver nameResolver in basic) {\r
85                                         if (productName.IndexOf(nameResolver.DbName) != -1) {\r
86                                                 collection.Add(nameResolver);\r
87                                         }\r
88                                 }\r
89 \r
90                                 //defaults\r
91                                 if (metaData.isCatalogAtStart()) {\r
92                                         collection.Add(new ObjectNameResolver(SchemaNameOrder));\r
93                                         collection.Add(new ObjectNameResolver(CatalogNameOrder));\r
94                                         collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));\r
95                                         collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));\r
96                                 }\r
97                                 else {\r
98                                         collection.Add(new ObjectNameResolver(CatalogNameOrder));\r
99                                         collection.Add(new ObjectNameResolver(SchemaNameOrder));\r
100                                         collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));\r
101                                         collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));\r
102                                 }\r
103 \r
104                                 return (ObjectNameResolver[])collection.ToArray(typeof(ObjectNameResolver));                            \r
105                         }\r
106                 }\r
107 \r
108                 #endregion // ObjectNamesHelper\r
109                 \r
110                 #region Fields\r
111 \r
112                 private const int DEFAULT_TIMEOUT = 15;\r
113 \r
114                 private java.sql.Connection _jdbcConnnection;\r
115                 private ConnectionState _internalState;\r
116                 private object _internalStateSync = new object();\r
117 \r
118                 private string _connectionString = String.Empty;\r
119                 IConnectionStringDictionary _connectionStringBuilder;\r
120                 IConnectionProvider                     _connectionProvider;\r
121 \r
122                 private ArrayList _referencedObjects = new ArrayList(); \r
123                 private ObjectNameResolver[] _syntaxPatterns;\r
124 \r
125                 #endregion // Fields\r
126 \r
127                 #region Constructors\r
128 \r
129                 public AbstractDBConnection(string connectionString)\r
130                 {\r
131                         _connectionString = connectionString;\r
132                 }\r
133 \r
134                 #endregion // Constructors\r
135 \r
136                 #region Properties\r
137 \r
138                 public override String ConnectionString\r
139                 {\r
140                         get { return _connectionString; }\r
141                         set {\r
142                                 if (IsOpened) {\r
143                                         throw ExceptionHelper.NotAllowedWhileConnectionOpen("ConnectionString",_internalState);\r
144                                 }                                       \r
145                                 _connectionString = value;\r
146                                 _connectionProvider = null;\r
147                                 _connectionStringBuilder = null;\r
148                         }\r
149                 }\r
150 \r
151                 public override int ConnectionTimeout\r
152                 {\r
153                         get {\r
154                                 string timeoutStr = (string)ConnectionStringBuilder["loginTimeout"];\r
155                                 if (timeoutStr != null && timeoutStr.Length > 0) {\r
156                                         try {\r
157                                                 return Convert.ToInt32(timeoutStr);\r
158                                         }\r
159                                         catch(FormatException) {\r
160                                                 throw ExceptionHelper.InvalidValueForKey("connect timeout");\r
161                                         }\r
162                                         catch (OverflowException) {\r
163                                                 throw ExceptionHelper.InvalidValueForKey("connect timeout");\r
164                                         }\r
165                                 }\r
166                                 return DEFAULT_TIMEOUT;\r
167                         }\r
168                 }\r
169 \r
170                 public override String Database\r
171                 {\r
172                         get { \r
173                                 if ((State & ConnectionState.Open) != 0)\r
174                                         return JdbcConnection.getCatalog();\r
175 \r
176                                 return (string)ConnectionStringBuilder["DATABASE"];\r
177                         }\r
178                 }\r
179 \r
180                 public override ConnectionState State\r
181                 {\r
182                         get {\r
183                                 try {\r
184                                         if ((JdbcConnection == null) || JdbcConnection.isClosed()) {\r
185                                                 // jdbc connection not initialized or closed\r
186                                                 if (_internalState == ConnectionState.Closed ) {\r
187                                                         return ConnectionState.Closed;\r
188                                                 }\r
189                                         }\r
190                                         else {\r
191                                                 // jdbc connection is opened\r
192                                                 if ((_internalState & ConnectionState.Open) != 0) {\r
193                                                         return ConnectionState.Open;\r
194                                                 }\r
195                                         }\r
196                                         return ConnectionState.Broken;                                                                          \r
197                                 }       \r
198                                 catch (SQLException) {\r
199                                         return ConnectionState.Broken;\r
200                                 }                               \r
201                         }\r
202                 }\r
203 \r
204                 internal bool IsExecuting\r
205                 {\r
206                         get { \r
207                                 return ((_internalState & ConnectionState.Executing) != 0);\r
208                         }\r
209 \r
210                         set {\r
211                                 lock(_internalStateSync) {\r
212                                         // to switch to executing, the connection must be in opened\r
213                                         if (value) {\r
214                                                 if (_internalState != ConnectionState.Open) {\r
215                                                         if (IsFetching) {\r
216                                                                 throw ExceptionHelper.OpenedReaderExists();\r
217                                                         }\r
218                                                         throw ExceptionHelper.OpenConnectionRequired("",_internalState);\r
219                                                 }\r
220                                                 _internalState |= ConnectionState.Executing;\r
221                                         }\r
222                                         else { \r
223                                                 if (!IsExecuting) {\r
224                                                         throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Executing.ToString() + " while in state " + _internalState.ToString());\r
225                                                 }\r
226                                                 _internalState &= ~ConnectionState.Executing;\r
227                                         }\r
228                                 }\r
229                         }\r
230                 }\r
231 \r
232                 internal bool IsFetching\r
233                 {\r
234                         get {\r
235                                 return ((_internalState & ConnectionState.Fetching) != 0);\r
236                         }\r
237 \r
238                         set {\r
239                                 lock(_internalStateSync) {\r
240                                         if (value) {\r
241                                                 // to switch to fetching connection must be in opened, executing\r
242                                                 if (((_internalState & ConnectionState.Open) == 0) || ((_internalState & ConnectionState.Executing) == 0)) {\r
243                                                         throw ExceptionHelper.OpenConnectionRequired("",_internalState);\r
244                                                 }\r
245                                                 _internalState |= ConnectionState.Fetching;\r
246                                         }\r
247                                         else {\r
248                                                 if (!IsFetching) {\r
249                                                         throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Fetching.ToString() + " while in state " + _internalState.ToString());\r
250                                                 }\r
251                                                 _internalState &= ~ConnectionState.Fetching;\r
252                                         }\r
253                                 }\r
254                         }\r
255                 }\r
256 \r
257                 internal bool IsOpened\r
258                 {\r
259                         get {\r
260                                 return ((_internalState & ConnectionState.Open) != 0);\r
261                         }\r
262 \r
263                         set {\r
264                                 lock(_internalStateSync) {                      \r
265                                         if (value) {\r
266                                                 // only connecting connection can be opened\r
267                                                 if ((_internalState != ConnectionState.Connecting)) {\r
268                                                         throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);\r
269                                                 }\r
270                                                 _internalState |= ConnectionState.Open;\r
271                                         }\r
272                                         else {\r
273                                                 if (!IsOpened) {\r
274                                                         throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Open.ToString() + " while in state " + _internalState.ToString());\r
275                                                 }\r
276                                                 _internalState &= ~ConnectionState.Open;\r
277                                         }\r
278                                 }\r
279                         }\r
280                 }\r
281 \r
282                 internal bool IsConnecting\r
283                 {\r
284                         get {\r
285                                 return ((_internalState & ConnectionState.Connecting) != 0);\r
286                         }\r
287 \r
288                         set {\r
289                                 lock(_internalStateSync) {                      \r
290                                         if (value) {\r
291                                                 // to switch to connecting conection must be in closed or in opened\r
292                                                 if ((_internalState != ConnectionState.Closed) && (_internalState != ConnectionState.Open)) {\r
293                                                         throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);\r
294                                                 }\r
295                                                 _internalState |= ConnectionState.Connecting;\r
296                                         }\r
297                                         else {\r
298                                                 if (!IsConnecting) {\r
299                                                         throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Connecting.ToString() + " while in state " + _internalState.ToString());\r
300                                                 }\r
301                                                 _internalState &= ~ConnectionState.Connecting;\r
302                                         }\r
303                                 }\r
304                         }\r
305                 }\r
306 \r
307                 public override string DataSource\r
308                 {\r
309                         get {\r
310                                 return (string)ConnectionStringBuilder["SERVERNAME"];\r
311                         }\r
312                 }\r
313 \r
314                 internal ConnectionState InternalState\r
315                 {\r
316                         get     { return _internalState; }\r
317                 }\r
318 \r
319 \r
320                 protected internal java.sql.Connection JdbcConnection\r
321                 {\r
322                         get { return _jdbcConnnection; }\r
323                         set { _jdbcConnnection = value; }\r
324                 }\r
325 \r
326                 internal ObjectNameResolver[] SyntaxPatterns\r
327                 {\r
328                         get {\r
329                                 if (_syntaxPatterns == null) {\r
330                                         _syntaxPatterns = ObjectNamesHelper.GetSyntaxPatterns(this);\r
331                                 }\r
332                                 return _syntaxPatterns;\r
333                         }\r
334                 }\r
335 \r
336                 protected internal IConnectionProvider ConnectionProvider { \r
337                         get {\r
338                                 try {\r
339                                         if (_connectionProvider == null)\r
340                                                 _connectionProvider = GetConnectionProvider();\r
341 \r
342                                         return _connectionProvider;\r
343                                 }\r
344                                 catch(SQLException exp) {\r
345                                         throw CreateException(exp);\r
346                                 }\r
347                         }\r
348                 }\r
349                 protected internal IConnectionStringDictionary ConnectionStringBuilder {\r
350                         get {\r
351                                 try {\r
352                                         if (_connectionStringBuilder == null)\r
353                                                 _connectionStringBuilder = ConnectionProvider.GetConnectionStringBuilder(ConnectionString);\r
354 \r
355                                         return _connectionStringBuilder;\r
356                                 }\r
357                                 catch(SQLException exp) {\r
358                                         throw CreateException(exp);\r
359                                 }\r
360                         }\r
361                 }\r
362                 protected abstract IConnectionProvider GetConnectionProvider();\r
363 \r
364                 static protected IConnectionProvider GetConnectionProvider(string sectionMame, string provider) {\r
365                         if (provider == null)\r
366                                 throw new ArgumentNullException("provider");\r
367 \r
368                         IList providers = (IList) ConfigurationSettings.GetConfig(sectionMame);\r
369                         if (providers.Count == 0)\r
370                                 throw new ArgumentException("Configuration section is empty.", "sectionName");\r
371 \r
372                         for (int i = 0; i < providers.Count; i++) {\r
373                                 IDictionary providerInfo = (IDictionary) providers[i];\r
374                                         \r
375                                 string curProvider = (string)providerInfo[ConfigurationConsts.Name];\r
376                                 if (String.Compare(provider, 0, curProvider, 0, provider.Length, StringComparison.OrdinalIgnoreCase) == 0) {\r
377                                         string providerType = (string) providerInfo [ConfigurationConsts.ProviderType];\r
378                                         if (providerType == null || providerType.Length == 0)\r
379                                                 return new GenericProvider (providerInfo); \r
380                                         else {\r
381                                                 Type t = Type.GetType (providerType);\r
382                                                 return (IConnectionProvider) Activator.CreateInstance (t , new object[] {providerInfo});\r
383                                         }\r
384                                 }\r
385                         }\r
386 \r
387                         throw new ArgumentException(
388                                 String.Format("Unknown provider name '{0}'", provider), "ConnectionString");\r
389                 }\r
390 \r
391                 #endregion // Properties\r
392 \r
393                 #region Methods\r
394                         // since WS also does not permits dynamically change of login timeout and tomcat does no implements - do not do it at all\r
395                         //ds.setLoginTimeout(ConnectionTimeout);\r
396 \r
397                 protected internal abstract void OnSqlWarning(SQLWarning warning);\r
398 \r
399                 protected abstract SystemException CreateException(SQLException e);\r
400 \r
401                 protected abstract SystemException CreateException(string message);\r
402 \r
403                 public override void Close()\r
404                 {\r
405                         ConnectionState orig = State;\r
406                         try {\r
407                                 ClearReferences();\r
408                                 if (JdbcConnection != null && !JdbcConnection.isClosed()) {\r
409                                         if (!JdbcConnection.getAutoCommit())\r
410                                                 JdbcConnection.rollback();\r
411                                         JdbcConnection.close();\r
412                                 }\r
413                         }\r
414                         catch (Exception e) {\r
415                                 // suppress exception\r
416 #if DEBUG\r
417                                 Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);\r
418 #endif\r
419                         }\r
420                         finally {\r
421                                 JdbcConnection = null;\r
422                                 lock(_internalStateSync) {\r
423                                         _internalState = ConnectionState.Closed;\r
424                                 }\r
425                         }\r
426 \r
427                         ConnectionState current = State;\r
428                         if (current != orig)\r
429                                 OnStateChange (new StateChangeEventArgs (orig, current));\r
430                 }\r
431 \r
432                 internal protected virtual void OnSqlException(SQLException exp)\r
433                 {\r
434                         throw CreateException(exp);\r
435                 }\r
436 \r
437                 internal void AddReference(object referencedObject)\r
438                 {       lock(_referencedObjects.SyncRoot) {\r
439                                 _referencedObjects.Add(new WeakReference(referencedObject));\r
440                         }\r
441                 }\r
442 \r
443                 internal void RemoveReference(object referencedObject)\r
444                 {\r
445                         lock(_referencedObjects.SyncRoot) {\r
446                                 for(int i = 0; i < _referencedObjects.Count; i++) {\r
447                                         WeakReference wr = (WeakReference) _referencedObjects[i];\r
448                                         if (wr.IsAlive && (wr.Target == referencedObject)) {\r
449                                                 _referencedObjects.RemoveAt(i);\r
450                                         }\r
451                                 }\r
452                         }\r
453                 }\r
454 \r
455                 private void ClearReferences()\r
456                 {\r
457                         ArrayList oldList = _referencedObjects;\r
458                         _referencedObjects = new ArrayList();\r
459 \r
460                         for(int i = 0; i < oldList.Count; i++) {\r
461                                 WeakReference wr = (WeakReference) oldList[i];\r
462                                 if (wr.IsAlive) {\r
463                                         ClearReference(wr.Target);\r
464                                 }\r
465                         }\r
466                 }\r
467 \r
468                 private void ClearReference(object referencedObject)\r
469                 {\r
470                         try {\r
471                                 if (referencedObject is AbstractDbCommand) {\r
472                                         ((AbstractDbCommand)referencedObject).CloseInternal();\r
473                                 }\r
474                                 else if (referencedObject is AbstractDataReader) {\r
475                                         ((AbstractDataReader)referencedObject).CloseInternal();\r
476                                 }\r
477                         }\r
478                         catch (SQLException) {\r
479                                 // suppress exception since it's possible that command or reader are in inconsistent state\r
480                         }\r
481                 }\r
482 \r
483                 public override void Open()\r
484                 {\r
485                         if (_connectionString == null || _connectionString.Length == 0) {\r
486                                 throw ExceptionHelper.ConnectionStringNotInitialized();\r
487                         }\r
488 \r
489                         IsConnecting = true;\r
490                         try {                   \r
491                                 if (JdbcConnection != null && !JdbcConnection.isClosed()) {\r
492                                         throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);\r
493                                 }\r
494 \r
495                                 JdbcConnection = ConnectionProvider.GetConnection (ConnectionStringBuilder);\r
496 \r
497                                 IsOpened = true;\r
498 \r
499                                 OnStateChange (new StateChangeEventArgs (ConnectionState.Closed, ConnectionState.Open));\r
500                         }\r
501                         catch (SQLWarning warning) {\r
502                                 OnSqlWarning(warning);\r
503                         }\r
504                         catch (SQLException exp) {\r
505                                 OnSqlException(exp);\r
506                         }\r
507                         finally {\r
508                                 IsConnecting = false;\r
509                         }\r
510                 }\r
511 \r
512                 public override void ChangeDatabase(String database)\r
513                 {\r
514                         IsConnecting = true;\r
515                         try {\r
516                                 ClearReferences();\r
517                                 java.sql.Connection con = JdbcConnection;                               \r
518                                 con.setCatalog(database);\r
519 //                              ConnectionStringHelper.UpdateValue(UserParameters,StringManager.GetStringArray("CON_DATABASE"),database);\r
520                         }\r
521                         catch (SQLWarning warning) {\r
522                                 OnSqlWarning(warning);\r
523                         }\r
524                         catch (SQLException exp) {\r
525                                 throw CreateException(exp);\r
526                         }\r
527                         finally {\r
528                                 IsConnecting = false;\r
529                         }\r
530                 }\r
531 \r
532                 public override string ServerVersion {\r
533                         get {\r
534                                 // only if the driver support this methods\r
535                                 try {\r
536                                         if (JdbcConnection == null)\r
537                                                 return String.Empty;\r
538 \r
539                                         java.sql.DatabaseMetaData metaData = JdbcConnection.getMetaData();\r
540                                         return metaData.getDatabaseProductVersion();\r
541                                 }\r
542                                 catch (SQLException exp) {\r
543                                         throw CreateException(exp);\r
544                                 }\r
545                         }\r
546                 }\r
547 \r
548                 internal string JdbcProvider {\r
549                         get {\r
550                                 // only if the driver support this methods\r
551                                 try {\r
552                                         if (JdbcConnection == null)\r
553                                                 return String.Empty;\r
554 \r
555                                         java.sql.DatabaseMetaData metaData = JdbcConnection.getMetaData();\r
556                                         return metaData.getDriverName() + " " + metaData.getDriverVersion();\r
557                                 }\r
558                                 catch (SQLException exp) {\r
559                                         return String.Empty; //suppress\r
560                                 }\r
561                         }\r
562                 }\r
563 \r
564                 protected override void Dispose(bool disposing)\r
565                 {\r
566                         if (disposing) {\r
567                                 try {\r
568                                         if (JdbcConnection != null && !JdbcConnection.isClosed()) {\r
569                                                 JdbcConnection.close();\r
570                                         }                       \r
571                                         JdbcConnection = null;\r
572                                 }\r
573                                 catch (java.sql.SQLException exp) {\r
574                                         throw CreateException(exp);\r
575                                 }\r
576                         }\r
577                         base.Dispose(disposing);\r
578                 }\r
579 \r
580                 internal void ValidateBeginTransaction()\r
581                 {\r
582                         if (State != ConnectionState.Open) {\r
583                                 throw new InvalidOperationException(String.Format("{0} requires an open and available Connection. The connection's current state is {1}.", new object[] {"BeginTransaction", State}));\r
584                         }\r
585 \r
586                         if (!JdbcConnection.getAutoCommit()) {\r
587                                 throw new System.InvalidOperationException("Parallel transactions are not supported.");\r
588                         }\r
589                 }\r
590 \r
591                 internal ArrayList GetProcedureColumns(String procedureString, AbstractDbCommand command)\r
592                 {\r
593                         ArrayList col = new ArrayList();\r
594                         try {\r
595                                 ObjectNameResolver[] nameResolvers = SyntaxPatterns;\r
596                                 java.sql.ResultSet res = null;\r
597                                 string catalog = null;\r
598                                 string schema = null;\r
599                                 string spname = null;\r
600                                                 \r
601                                 java.sql.DatabaseMetaData metadata = JdbcConnection.getMetaData();      \r
602                                 bool storesUpperCaseIdentifiers = false;\r
603                                 bool storesLowerCaseIdentifiers = false;\r
604                                 try {\r
605                                         storesUpperCaseIdentifiers = metadata.storesUpperCaseIdentifiers();\r
606                                         storesLowerCaseIdentifiers = metadata.storesLowerCaseIdentifiers();\r
607                                 }\r
608                                 catch (SQLException e) {\r
609                                         // suppress\r
610                                 }\r
611 \r
612                                 for(int i=0; i < nameResolvers.Length; i++) {\r
613                                         ObjectNameResolver nameResolver = nameResolvers[i];\r
614                                         Match match = nameResolver.Match(procedureString);\r
615 \r
616                                         if (match.Success) {\r
617                                                 spname = ObjectNameResolver.GetName(match);                             \r
618                                                 schema = ObjectNameResolver.GetSchema(match);                                           \r
619                                                 catalog = ObjectNameResolver.GetCatalog(match);                                         \r
620 \r
621                                                 // make all identifiers uppercase or lowercase according to database metadata\r
622                                                 if (storesUpperCaseIdentifiers) {\r
623                                                         spname = (spname.Length > 0) ? spname.ToUpper() : null;\r
624                                                         schema = (schema.Length > 0) ? schema.ToUpper() : null;\r
625                                                         catalog = (catalog.Length > 0) ? catalog.ToUpper() : null;\r
626                                                 }\r
627                                                 else if (storesLowerCaseIdentifiers) {\r
628                                                         spname = (spname.Length > 0) ? spname.ToLower() : null;\r
629                                                         schema = (schema.Length > 0) ? schema.ToLower() : null;\r
630                                                         catalog = (catalog.Length > 0) ? catalog.ToLower() : null;\r
631                                                 }\r
632                                                 else {\r
633                                                         spname = (spname.Length > 0) ? spname : null;\r
634                                                         schema = (schema.Length > 0) ? schema : null;\r
635                                                         catalog = (catalog.Length > 0) ? catalog : null;\r
636                                                 }\r
637 \r
638                                                 // catalog from db is always in correct caps\r
639                                                 if (catalog == null) {\r
640                                                         catalog = JdbcConnection.getCatalog();\r
641                                                 }\r
642 \r
643                                                 try {\r
644                                                         // always get the first procedure that db returns\r
645                                                         res = metadata.getProcedures(catalog, schema, spname);                                                                                          \r
646                                                         if (res.next()) {\r
647                                                                 catalog = res.getString(1);\r
648                                                                 schema = res.getString(2);\r
649                                                                 spname = res.getString(3);\r
650                                                                 break;\r
651                                                         }\r
652 \r
653                                                         spname = null;\r
654                                                 }\r
655                                                 catch { // suppress exception\r
656                                                         return null;\r
657                                                 }\r
658                                                 finally {\r
659                                                         if (res != null) {\r
660                                                                 res.close();\r
661                                                         }\r
662                                                 }\r
663                                         }\r
664                                 }       \r
665                 \r
666                                 if (spname == null || spname.Length == 0) {\r
667                                         return null;\r
668                                 }\r
669                                 \r
670                                 try {\r
671                                         // get procedure columns based o  procedure metadata\r
672                                         res = metadata.getProcedureColumns(catalog, schema, spname, null);                              \r
673                                         while (res.next()) {\r
674                                                 // since there is still a possibility that some of the parameters to getProcedureColumn were nulls, \r
675                                                 // we need to filter the results with strict matching\r
676                                                 if ((res.getString(1) != catalog ) || (res.getString(2) != schema) || (res.getString(3) != spname)) {\r
677                                                         continue;\r
678                                                 }\r
679 \r
680                                                 AbstractDbParameter parameter = (AbstractDbParameter)command.CreateParameter();\r
681                                                 \r
682                                                 parameter.SetParameterName(res);\r
683                                                 parameter.SetParameterDbType(res);\r
684                                                 parameter.SetSpecialFeatures(res);\r
685 \r
686                                                 //get parameter direction\r
687                                                 short direction = res.getShort("COLUMN_TYPE");\r
688                                                 if(direction == 1) //DatabaseMetaData.procedureColumnIn\r
689                                                         parameter.Direction = ParameterDirection.Input;\r
690                                                 else if(direction == 2) //DatabaseMetaData.procedureColumnInOut\r
691                                                         parameter.Direction = ParameterDirection.InputOutput;\r
692                                                 else if(direction == 4) //DatabaseMetaData.procedureColumnOut\r
693                                                         parameter.Direction = ParameterDirection.Output;\r
694                                                 else if(direction == 5) //DatabaseMetaData.procedureColumnReturn\r
695                                                         parameter.Direction = ParameterDirection.ReturnValue;\r
696                                         \r
697                                                 //get parameter precision and scale\r
698                                                 parameter.SetParameterPrecisionAndScale(res);\r
699 \r
700                                                 parameter.SetParameterSize(res);\r
701                                                 parameter.SetParameterIsNullable(res);\r
702 \r
703                                                 col.Add(parameter);\r
704                                         }\r
705                                 }\r
706                                 finally {\r
707                                         if (res != null) {\r
708                                                 res.close();\r
709                                         }\r
710                                 }                               \r
711                         }\r
712                         catch(Exception e) {\r
713                                 //supress\r
714 #if DEBUG\r
715                                 Console.WriteLine("Exception catched at AbstractDBConnection.GetProcedureColumns() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);\r
716 #endif\r
717                         }\r
718                         return col;\r
719                 }\r
720 \r
721                 #endregion // Methods   \r
722 \r
723                 #region ICloneable Members\r
724 \r
725                 public virtual object Clone() {\r
726                         AbstractDBConnection con  = (AbstractDBConnection)MemberwiseClone();\r
727                         con._internalState = ConnectionState.Closed;\r
728                         con._internalStateSync = new object();\r
729                         con._jdbcConnnection = null;\r
730                         con._referencedObjects = new ArrayList();\r
731                         con._syntaxPatterns = null;\r
732                         return con;\r
733                 }\r
734 \r
735                 #endregion\r
736         }\r
737 }\r