e63dade601d0f35adeac83972dc8bf26a7af6f56
[mono.git] / mcs / class / System.Data / System.Data.ProviderBase.jvm / AbstractDBConnection.cs
1 //\r
2 // System.Data.Common.AbstractDBConnection\r
3 //
4 // Authors:
5 //      Konstantin Triger <kostat@mainsoft.com>
6 //      Boris Kirzner <borisk@mainsoft.com>
7 //      
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //\r
31 \r
32 \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 \r
42 using java.sql;\r
43 using javax.sql;\r
44 using javax.naming;\r
45 // can not use java.util here - it manes ArrayList an ambiguous reference\r
46 \r
47 namespace System.Data.Common\r
48 {\r
49         public abstract class AbstractDBConnection : DbConnection\r
50         {\r
51                 #region ObjectNamesHelper\r
52 \r
53                 private sealed class ObjectNamesHelper\r
54                 {\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
57 \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
63 \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
70 \r
71                         internal static ObjectNameResolver[] GetSyntaxPatterns(AbstractDBConnection connection)\r
72                         {\r
73                                 ArrayList collection = new ArrayList();\r
74                                 collection.Add(new ObjectNameResolver(NameOrder));\r
75 \r
76                                 ObjectNameResolversCollection basic = (ObjectNameResolversCollection)ConfigurationSettings.GetConfig("system.data/objectnameresolution");\r
77                                 \r
78                                 DatabaseMetaData metaData = connection.JdbcConnection.getMetaData();\r
79                                 string productName = metaData.getDatabaseProductName();\r
80 \r
81                                 foreach(ObjectNameResolver nameResolver in basic) {\r
82                                         if (productName.IndexOf(nameResolver.DbName) != -1) {\r
83                                                 collection.Add(nameResolver);\r
84                                         }\r
85                                 }\r
86 \r
87                                 //defaults\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
93                                 }\r
94                                 else {\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
99                                 }\r
100 \r
101                                 return (ObjectNameResolver[])collection.ToArray(typeof(ObjectNameResolver));                            \r
102                         }\r
103                 }\r
104 \r
105                 #endregion // ObjectNamesHelper\r
106 \r
107                 #region ConnectionStringHelper\r
108 \r
109                 internal sealed class ConnectionStringHelper\r
110                 {\r
111                         internal static string FindValue(NameValueCollection collection, string[] keys)\r
112                         {\r
113                                 if (collection == null || keys == null || keys.Length == 0) {\r
114                                         return String.Empty;\r
115                                 }\r
116 \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
120                                                 return value;\r
121                                         }\r
122                                 }\r
123                                 return String.Empty;\r
124                         }\r
125 \r
126                         internal static string FindValue(NameValueCollection collection, string key)\r
127                         {\r
128                                 if (collection == null) {\r
129                                         return String.Empty;\r
130                                 }\r
131 \r
132                                 string value = collection[key];\r
133                                 return (value != null) ? value : String.Empty;\r
134                         }\r
135 \r
136                         internal static void UpdateValue(NameValueCollection collection,string[] keys,string value)\r
137                         {\r
138                                 for(int i=0; i < keys.Length; i++) {\r
139                                         if (collection[keys[i]] != null) {\r
140                                                 collection[keys[i]] = value;\r
141                                         }\r
142                                 }\r
143                         }\r
144 \r
145                         internal static void AddValue(NameValueCollection collection,string[] keys,string value)\r
146                         {\r
147                                 for(int i=0; i < keys.Length; i++) {\r
148                                         collection[keys[i]] = value;\r
149                                 }\r
150                         }\r
151 \r
152                         /**\r
153                         * Parses connection string and builds NameValueCollection \r
154                         * for all keys.\r
155                         */ \r
156                         internal static NameValueCollection BuildUserParameters (string connectionString)\r
157                         {\r
158                                 NameValueCollection userParameters = new NameValueCollection();\r
159 \r
160                                 if (connectionString == null || connectionString.Length == 0) {\r
161                                         return userParameters;\r
162                                 }\r
163                                 connectionString += ";";\r
164 \r
165                                 bool inQuote = false;\r
166                                 bool inDQuote = false;\r
167                                 bool inName = true;\r
168 \r
169                                 string name = String.Empty;\r
170                                 string value = String.Empty;\r
171                                 StringBuilder sb = new StringBuilder ();\r
172 \r
173                                 for (int i = 0; i < connectionString.Length; i += 1) {\r
174                                         char c = connectionString [i];\r
175                                         char peek;\r
176                                         if (i == connectionString.Length - 1)\r
177                                                 peek = '\0';\r
178                                         else\r
179                                                 peek = connectionString [i + 1];\r
180 \r
181                                         switch (c) {\r
182                                                 case '\'':\r
183                                                         if (inDQuote)\r
184                                                                 sb.Append (c);\r
185                                                         else if (peek.Equals(c)) {\r
186                                                                 sb.Append(c);\r
187                                                                 i += 1;\r
188                                                         }\r
189                                                         else\r
190                                                                 inQuote = !inQuote;\r
191                                                         break;\r
192                                                 case '"':\r
193                                                         if (inQuote)\r
194                                                                 sb.Append(c);\r
195                                                         else if (peek.Equals(c)) {\r
196                                                                 sb.Append(c);\r
197                                                                 i += 1;\r
198                                                         }\r
199                                                         else\r
200                                                                 inDQuote = !inDQuote;\r
201                                                         break;\r
202                                                 case ';':\r
203                                                         if (inDQuote || inQuote)\r
204                                                                 sb.Append(c);\r
205                                                         else {\r
206                                                                 if (name != String.Empty && name != null) {\r
207                                                                         value = sb.ToString();\r
208                                                                         userParameters [name.Trim()] = value.Trim();\r
209                                                                 }\r
210                                                                 inName = true;\r
211                                                                 name = String.Empty;\r
212                                                                 value = String.Empty;\r
213                                                                 sb = new StringBuilder();\r
214                                                         }\r
215                                                         break;\r
216                                                 case '=':\r
217                                                         if (inDQuote || inQuote || !inName)\r
218                                                                 sb.Append (c);\r
219                                                         else if (peek.Equals(c)) {\r
220                                                                 sb.Append (c);\r
221                                                                 i += 1;\r
222                                                         }\r
223                                                         else {\r
224                                                                 name = sb.ToString();\r
225                                                                 sb = new StringBuilder();\r
226                                                                 inName = false;\r
227                                                         }\r
228                                                         break;\r
229                                                 case ' ':\r
230                                                         if (inQuote || inDQuote)\r
231                                                                 sb.Append(c);\r
232                                                         else if (sb.Length > 0 && !peek.Equals(';'))\r
233                                                                 sb.Append(c);\r
234                                                         break;\r
235                                                 default:\r
236                                                         sb.Append(c);\r
237                                                         break;\r
238                                         }\r
239                                 }\r
240                                 return userParameters;\r
241                         }\r
242                 }\r
243 \r
244                 #endregion // ConnectionStringHelper\r
245 \r
246                 #region DataSourceCache\r
247 \r
248                 private sealed class DataSourceCache : AbstractDbMetaDataCache\r
249                 {\r
250                         internal DataSource GetDataSource(string dataSourceName,string namingProviderUrl,string namingFactoryInitial)\r
251                         {\r
252                                 Hashtable cache = Cache;\r
253 \r
254                                 DataSource ds = cache[dataSourceName] as DataSource;\r
255 \r
256                                 if (ds != null) {\r
257                                         return ds;\r
258                                 }\r
259 \r
260                                 Context ctx = null;\r
261                                 \r
262                                 java.util.Properties properties = new java.util.Properties();\r
263 \r
264                                 if ((namingProviderUrl != null) && (namingProviderUrl.Length > 0)) {\r
265                                         properties.put("java.naming.provider.url",namingProviderUrl);\r
266                                 }\r
267                                 \r
268                                 if ((namingFactoryInitial != null) && (namingFactoryInitial.Length > 0)) {\r
269                                         properties.put("java.naming.factory.initial",namingFactoryInitial);\r
270                                 }\r
271 \r
272                                 ctx = new InitialContext(properties);\r
273  \r
274                                 try {\r
275                                         ds = (DataSource)ctx.lookup(dataSourceName);\r
276                                 }\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
281                                 }\r
282 \r
283                                 cache[dataSourceName] = ds;\r
284                                 return ds;\r
285                         }\r
286                 }\r
287 \r
288                 #endregion // DatasourceCache\r
289 \r
290                 #region Declarations\r
291 \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
294 \r
295                 #endregion // Declarations\r
296                 \r
297                 #region Fields\r
298 \r
299                 private static DataSourceCache _dataSourceCache = new DataSourceCache();\r
300                 private const int DEFAULT_TIMEOUT = 15;\r
301 \r
302                 private Connection _jdbcConnnection;\r
303                 private ConnectionState _internalState;\r
304                 private object _internalStateSync = new object();\r
305 \r
306                 private NameValueCollection _userParameters;\r
307 \r
308                 protected string _connectionString = String.Empty;\r
309                 protected string _jdbcUrl;              \r
310 \r
311                 private ArrayList _referencedObjects = new ArrayList(); \r
312                 private ObjectNameResolver[] _syntaxPatterns;\r
313 \r
314                 #endregion // Fields\r
315 \r
316                 #region Constructors\r
317 \r
318                 public AbstractDBConnection(string connectionString)\r
319                 {\r
320                         _connectionString = connectionString;\r
321                         InitializeSkippedUserParameters();\r
322                 }\r
323 \r
324                 #endregion // Constructors\r
325 \r
326                 #region Properties\r
327 \r
328                 public override String ConnectionString\r
329                 {\r
330                         get { return _connectionString; }\r
331                         set {\r
332                                 if (IsOpened) {\r
333                                         throw ExceptionHelper.NotAllowedWhileConnectionOpen("ConnectionString",_internalState);\r
334                                 }                                       \r
335                                 _connectionString = value;\r
336                                 _userParameters = null;\r
337                                 _jdbcUrl = null;\r
338                         }\r
339                 }\r
340 \r
341                 public override int ConnectionTimeout\r
342                 {\r
343                         get {\r
344                                 string timeoutStr = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_TIMEOUT"));\r
345                                 if (!String.Empty.Equals(timeoutStr)) {\r
346                                         try {\r
347                                                 return Convert.ToInt32(timeoutStr);\r
348                                         }\r
349                                         catch(FormatException e) {\r
350                                                 throw ExceptionHelper.InvalidValueForKey("connect timeout");\r
351                                         }\r
352                                         catch (OverflowException e) {\r
353                                                 throw ExceptionHelper.InvalidValueForKey("connect timeout");\r
354                                         }\r
355                                 }\r
356                                 return DEFAULT_TIMEOUT;\r
357                         }\r
358                 }\r
359 \r
360                 public override String Database\r
361                 {\r
362                         get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATABASE")); }\r
363                 }\r
364 \r
365                 public override ConnectionState State\r
366                 {\r
367                         get {\r
368                                 try {\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
373                                                 }\r
374                                         }\r
375                                         else {\r
376                                                 // jdbc connection is opened\r
377                                                 if ((_internalState & ConnectionState.Open) != 0) {\r
378                                                         return ConnectionState.Open;\r
379                                                 }\r
380                                         }\r
381                                         return ConnectionState.Broken;                                                                          \r
382                                 }       \r
383                                 catch (SQLException) {\r
384                                         return ConnectionState.Broken;\r
385                                 }                               \r
386                         }\r
387                 }\r
388 \r
389                 internal bool IsExecuting\r
390                 {\r
391                         get { \r
392                                 return ((_internalState & ConnectionState.Executing) != 0);\r
393                         }\r
394 \r
395                         set {\r
396                                 lock(_internalStateSync) {\r
397                                         // to switch to executing, the connection must be in opened\r
398                                         if (value) {\r
399                                                 if (_internalState != ConnectionState.Open) {\r
400                                                         if (IsFetching) {\r
401                                                                 throw ExceptionHelper.OpenedReaderExists();\r
402                                                         }\r
403                                                         throw ExceptionHelper.OpenConnectionRequired("",_internalState);\r
404                                                 }\r
405                                                 _internalState |= ConnectionState.Executing;\r
406                                         }\r
407                                         else { \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
410                                                 }\r
411                                                 _internalState &= ~ConnectionState.Executing;\r
412                                         }\r
413                                 }\r
414                         }\r
415                 }\r
416 \r
417                 internal bool IsFetching\r
418                 {\r
419                         get {\r
420                                 return ((_internalState & ConnectionState.Fetching) != 0);\r
421                         }\r
422 \r
423                         set {\r
424                                 lock(_internalStateSync) {\r
425                                         if (value) {\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
429                                                 }\r
430                                                 _internalState |= ConnectionState.Fetching;\r
431                                         }\r
432                                         else {\r
433                                                 if (!IsFetching) {\r
434                                                         throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Fetching.ToString() + " while in state " + _internalState.ToString());\r
435                                                 }\r
436                                                 _internalState &= ~ConnectionState.Fetching;\r
437                                         }\r
438                                 }\r
439                         }\r
440                 }\r
441 \r
442                 internal bool IsOpened\r
443                 {\r
444                         get {\r
445                                 return ((_internalState & ConnectionState.Open) != 0);\r
446                         }\r
447 \r
448                         set {\r
449                                 lock(_internalStateSync) {                      \r
450                                         if (value) {\r
451                                                 // only connecting connection can be opened\r
452                                                 if ((_internalState != ConnectionState.Connecting)) {\r
453                                                         throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);\r
454                                                 }\r
455                                                 _internalState |= ConnectionState.Open;\r
456                                         }\r
457                                         else {\r
458                                                 if (!IsOpened) {\r
459                                                         throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Open.ToString() + " while in state " + _internalState.ToString());\r
460                                                 }\r
461                                                 _internalState &= ~ConnectionState.Open;\r
462                                         }\r
463                                 }\r
464                         }\r
465                 }\r
466 \r
467                 internal bool IsConnecting\r
468                 {\r
469                         get {\r
470                                 return ((_internalState & ConnectionState.Connecting) != 0);\r
471                         }\r
472 \r
473                         set {\r
474                                 lock(_internalStateSync) {                      \r
475                                         if (value) {\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
479                                                 }\r
480                                                 _internalState |= ConnectionState.Connecting;\r
481                                         }\r
482                                         else {\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
485                                                 }\r
486                                                 _internalState &= ~ConnectionState.Connecting;\r
487                                         }\r
488                                 }\r
489                         }\r
490                 }\r
491 \r
492                 protected virtual PROVIDER_TYPE ProviderType\r
493                 {\r
494                         get {\r
495                                 if (JdbcMode != JDBC_MODE.PROVIDER_MODE) {\r
496                                         return PROVIDER_TYPE.NONE;\r
497                                 }\r
498                                 \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
502                                 }\r
503                                 else if (providerStr.StartsWith("MSDAORA")) {\r
504                                         return PROVIDER_TYPE.MSDAORA;\r
505                                 }\r
506                                 else if (providerStr.StartsWith("IBMDADB2")) {\r
507                                         return PROVIDER_TYPE.IBMDADB2;\r
508                                 }\r
509                                 return PROVIDER_TYPE.NONE;\r
510                         }\r
511                 }\r
512 \r
513                 protected internal virtual JDBC_MODE JdbcMode\r
514                 {\r
515                         get { \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
519                                 }\r
520 \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
525 \r
526                                 if (jdbcDriverSpecified && jdbcUrlSpecified) {\r
527                                         return JDBC_MODE.JDBC_DRIVER_MODE;\r
528                                 }\r
529 \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
533                                 }\r
534                                 \r
535                                 return JDBC_MODE.NONE;\r
536                         }\r
537                 }\r
538 \r
539                 protected virtual string JdbcDriverName\r
540                 {\r
541                         get { return String.Empty; }\r
542                 }\r
543 \r
544                 protected abstract DbStringManager StringManager\r
545                 {\r
546                         get;\r
547                 }\r
548 \r
549                 protected virtual string ServerName\r
550                 {\r
551                         get { return DataSource; }\r
552                 }\r
553 \r
554                 protected virtual string CatalogName\r
555                 {\r
556                         get { return Database; }\r
557                 }\r
558 \r
559                 protected virtual string Port\r
560                 {\r
561                         get {\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
573                                                         //}\r
574                                                 }\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
578                                                 }\r
579                                                 ConnectionStringHelper.AddValue(UserParameters,StringManager.GetStringArray("CON_PORT"),port);\r
580                                                 break;\r
581                                 }\r
582                                 return port;\r
583                         }\r
584                 }\r
585 \r
586                 public override string DataSource\r
587                 {\r
588                         get {\r
589                                 string dataSource = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATA_SOURCE"));\r
590 \r
591                                 if (ProviderType == PROVIDER_TYPE.SQLOLEDB) {\r
592                                         int instanceIdx;\r
593                                         if ((instanceIdx = dataSource.IndexOf("\\")) != -1) {\r
594                                                 // throw out named instance name\r
595                                                 dataSource = dataSource.Substring(0,instanceIdx);\r
596                                         }\r
597 \r
598                                         if (dataSource != null && dataSource.StartsWith("(") && dataSource.EndsWith(")")) {                                             \r
599                                                 dataSource = dataSource.Substring(1,dataSource.Length - 2);\r
600                                         }\r
601 \r
602                                         if(String.Empty.Equals(dataSource) || (String.Compare("local",dataSource,true) == 0)) {\r
603                                                 dataSource = "localhost";\r
604                                         }\r
605                                 }\r
606                                 return dataSource;\r
607                         }\r
608                 }\r
609 \r
610                 protected virtual string InstanceName\r
611                 {\r
612                         get {\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
616                                         int instanceIdx;\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
620                                         }\r
621                                         else {\r
622                                                 // get named instance name\r
623                                                 instanceName = dataSource.Substring(instanceIdx + 1);\r
624                                         }\r
625                                 }\r
626                                 return instanceName;\r
627                         }\r
628                 }\r
629 \r
630                 protected virtual string User\r
631                 {\r
632                         get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_USER_ID")); }\r
633                 }\r
634 \r
635                 protected virtual string Password\r
636                 {\r
637                         get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_PASSWORD")); }\r
638                 }\r
639 \r
640                 protected NameValueCollection UserParameters\r
641                 {\r
642                         get {\r
643                                 if (_userParameters == null) {\r
644                                         _userParameters = ConnectionStringHelper.BuildUserParameters(ConnectionString);\r
645                                 }\r
646                                 return _userParameters;\r
647                         }\r
648                 }\r
649 \r
650                 internal String JdbcUrl \r
651                 {\r
652                         get { \r
653                                 if ( UserParameters == null) {\r
654                                         return String.Empty;\r
655                                 }\r
656 \r
657                                 if (_jdbcUrl == null) {\r
658                                         _jdbcUrl = BuildJdbcUrl();\r
659                                 }\r
660                                 return _jdbcUrl;\r
661                         }\r
662                 }\r
663 \r
664                 internal ConnectionState InternalState\r
665                 {\r
666                         get     { return _internalState; }\r
667                 }\r
668 \r
669 \r
670                 protected internal Connection JdbcConnection\r
671                 {\r
672                         get { return _jdbcConnnection; }\r
673                         set { _jdbcConnnection = value; }\r
674                 }\r
675 \r
676                 protected virtual string[] ResourceIgnoredKeys\r
677                 {\r
678                         get { return new string[0]; }\r
679                 }\r
680 \r
681                 protected virtual Hashtable SkippedUserParameters\r
682                 {\r
683                         get { return new Hashtable(new CaseInsensitiveHashCodeProvider(),new CaseInsensitiveComparer()); }\r
684                 }\r
685 \r
686                 internal ObjectNameResolver[] SyntaxPatterns\r
687                 {\r
688                         get {\r
689                                 if (_syntaxPatterns == null) {\r
690                                         _syntaxPatterns = ObjectNamesHelper.GetSyntaxPatterns(this);\r
691                                 }\r
692                                 return _syntaxPatterns;\r
693                         }\r
694                 }\r
695 \r
696                 #endregion // Properties\r
697 \r
698                 #region Methods\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
701 \r
702                 internal abstract void OnSqlWarning(SQLWarning warning);\r
703 \r
704                 internal abstract void OnStateChanged(ConnectionState orig, ConnectionState current);\r
705 \r
706                 protected abstract SystemException CreateException(SQLException e);\r
707 \r
708                 public override void Close()\r
709                 {\r
710                         try {\r
711                                 ClearReferences();\r
712                                 if (JdbcConnection != null && !JdbcConnection.isClosed()) {\r
713                                         JdbcConnection.close();\r
714                                 }\r
715                         }\r
716                         catch (SQLException e) {\r
717                                 // suppress exception\r
718                                 JdbcConnection = null;\r
719 #if DEBUG\r
720                                 Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);\r
721 #endif\r
722                         }\r
723                         catch (Exception e) {\r
724                                 // suppress exception\r
725                                 JdbcConnection = null;\r
726 #if DEBUG\r
727                                 Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);\r
728 #endif\r
729                         }\r
730                         finally {\r
731                                 lock(_internalStateSync) {\r
732                                         _internalState = ConnectionState.Closed;\r
733                                 }\r
734                         }\r
735                 }\r
736 \r
737                 protected internal virtual void CopyTo(AbstractDBConnection target)\r
738                 {\r
739                         target._connectionString = _connectionString;\r
740                 }\r
741 \r
742                 internal protected virtual void OnSqlException(SQLException exp)\r
743                 {\r
744                         throw CreateException(exp);\r
745                 }\r
746 \r
747                 internal void AddReference(object referencedObject)\r
748                 {       lock(_referencedObjects.SyncRoot) {\r
749                                 _referencedObjects.Add(new WeakReference(referencedObject));\r
750                         }\r
751                 }\r
752 \r
753                 internal void RemoveReference(object referencedObject)\r
754                 {\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
760                                         }\r
761                                 }\r
762                         }\r
763                 }\r
764 \r
765                 private void ClearReferences()\r
766                 {\r
767                         ArrayList oldList = _referencedObjects;\r
768                         _referencedObjects = new ArrayList();\r
769 \r
770                         for(int i = 0; i < oldList.Count; i++) {\r
771                                 WeakReference wr = (WeakReference) oldList[i];\r
772                                 if (wr.IsAlive) {\r
773                                         ClearReference(wr.Target);\r
774                                 }\r
775                         }\r
776                 }\r
777 \r
778                 private void ClearReference(object referencedObject)\r
779                 {\r
780                         try {\r
781                                 if (referencedObject is AbstractDbCommand) {\r
782                                         ((AbstractDbCommand)referencedObject).CloseInternal();\r
783                                 }\r
784                                 else if (referencedObject is AbstractDataReader) {\r
785                                         ((AbstractDataReader)referencedObject).CloseInternal();\r
786                                 }\r
787                         }\r
788                         catch (SQLException) {\r
789                                 // suppress exception since it's possible that command or reader are in inconsistent state\r
790                         }\r
791                 }\r
792 \r
793                 public override void Open()\r
794                 {\r
795                         if (_connectionString == null || _connectionString.Length == 0) {\r
796                                 throw ExceptionHelper.ConnectionStringNotInitialized();\r
797                         }\r
798 \r
799                         IsConnecting = true;\r
800                         try {                   \r
801                                 if (JdbcConnection != null && !JdbcConnection.isClosed()) {\r
802                                         throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);\r
803                                 }\r
804         \r
805                                 switch(JdbcMode) {\r
806                                         case JDBC_MODE.DATA_SOURCE_MODE :\r
807                                                 JdbcConnection = GetConnectionFromDataSource();\r
808                                                 break;\r
809 \r
810                                         case JDBC_MODE.JDBC_DRIVER_MODE:\r
811                                                 JdbcConnection = GetConnectionFromJdbcDriver();\r
812                                                 break;\r
813 \r
814                                         case JDBC_MODE.PROVIDER_MODE :                                  \r
815                                                 JdbcConnection = GetConnectionFromProvider();\r
816                                                 break;\r
817                                 }\r
818                                 IsOpened = true;\r
819 \r
820                                 OnStateChanged(ConnectionState.Closed, ConnectionState.Open);\r
821                         }\r
822                         catch (SQLWarning warning) {\r
823                                 OnSqlWarning(warning);\r
824                         }\r
825                         catch (SQLException exp) {\r
826                                 OnSqlException(exp);\r
827                         }\r
828                         finally {\r
829                                 IsConnecting = false;\r
830                         }\r
831                 }\r
832 \r
833                 public override void ChangeDatabase(String database)\r
834                 {\r
835                         IsConnecting = true;\r
836                         try {\r
837                                 ClearReferences();\r
838                                 Connection con = JdbcConnection;                                \r
839                                 con.setCatalog(database);\r
840                                 ConnectionStringHelper.UpdateValue(UserParameters,StringManager.GetStringArray("CON_DATABASE"),database);\r
841                         }\r
842                         catch (SQLWarning warning) {\r
843                                 OnSqlWarning(warning);\r
844                         }\r
845                         catch (SQLException exp) {\r
846                                 throw CreateException(exp);\r
847                         }\r
848                         finally {\r
849                                 IsConnecting = false;\r
850                         }\r
851                 }\r
852 \r
853                 public override string ServerVersion {\r
854                         get {\r
855                                 // only if the driver support this methods\r
856                                 try {\r
857                                         if (JdbcConnection == null)\r
858                                                 return String.Empty;\r
859 \r
860                                         DatabaseMetaData metaData = JdbcConnection.getMetaData();\r
861                                         return metaData.getDatabaseProductVersion();\r
862                                 }\r
863                                 catch (SQLException exp) {\r
864                                         throw CreateException(exp);\r
865                                 }\r
866                         }\r
867                 }\r
868 \r
869                 internal string JdbcProvider {\r
870                         get {\r
871                                 // only if the driver support this methods\r
872                                 try {\r
873                                         if (JdbcConnection == null)\r
874                                                 return String.Empty;\r
875 \r
876                                         DatabaseMetaData metaData = JdbcConnection.getMetaData();\r
877                                         return metaData.getDriverName() + " " + metaData.getDriverVersion();\r
878                                 }\r
879                                 catch (SQLException exp) {\r
880                                         return String.Empty; //suppress\r
881                                 }\r
882                         }\r
883                 }\r
884 \r
885                 protected override void Dispose(bool disposing)\r
886                 {\r
887                         if (disposing) {\r
888                                 try {\r
889                                         if (JdbcConnection != null && !JdbcConnection.isClosed()) {\r
890                                                 JdbcConnection.close();\r
891                                         }                       \r
892                                         JdbcConnection = null;\r
893                                 }\r
894                                 catch (java.sql.SQLException exp) {\r
895                                         throw CreateException(exp);\r
896                                 }\r
897                         }\r
898                         base.Dispose(disposing);\r
899                 }\r
900 \r
901                 protected internal virtual void ValidateConnectionString(string connectionString)\r
902                 {\r
903                         JDBC_MODE currentJdbcMode = JdbcMode;\r
904                         \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
910 \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
913                                 }                               \r
914                         }\r
915                 }\r
916 \r
917                 protected virtual string BuildJdbcUrl()\r
918                 {\r
919                         switch (JdbcMode) {\r
920                                 case JDBC_MODE.JDBC_DRIVER_MODE :\r
921                                         return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("JDBC_URL"));\r
922                                 default :\r
923                                         return String.Empty;\r
924                         }\r
925                 }\r
926 \r
927                 protected java.util.Properties BuildProperties()\r
928                 {\r
929                         java.util.Properties properties = new java.util.Properties();\r
930 \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
937 \r
938                         string[] userKeys = UserParameters.AllKeys;\r
939 \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
945                                 }\r
946                         }\r
947                         return properties;\r
948                 }\r
949 \r
950                 protected virtual bool SkipUserParameter(string parameterName)\r
951                 {\r
952                         if (SkippedUserParameters.Count == 0) {\r
953                                 // skipped parameters not initialized - skip all\r
954                                 return true;\r
955                         }\r
956 \r
957                         return SkippedUserParameters.Contains(parameterName);\r
958                 }\r
959 \r
960                 protected virtual void InitializeSkippedUserParameters()\r
961                 {\r
962                         if (SkippedUserParameters.Count > 0) {\r
963                                 return;\r
964                         }\r
965 \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
970                                 }\r
971                         }\r
972                 }\r
973  \r
974                 internal void ValidateBeginTransaction()\r
975                 {\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
978                         }\r
979 \r
980                         if (!JdbcConnection.getAutoCommit()) {\r
981                                 throw new System.InvalidOperationException("Parallel transactions are not supported.");\r
982                         }\r
983                 }\r
984 \r
985                 internal virtual Connection GetConnectionFromProvider()\r
986                 {\r
987                         ActivateJdbcDriver(JdbcDriverName);\r
988                         DriverManager.setLoginTimeout(ConnectionTimeout);\r
989                         java.util.Properties properties = BuildProperties();\r
990                         return DriverManager.getConnection (JdbcUrl, properties);\r
991                 }\r
992 \r
993                 internal Connection GetConnectionFromDataSource()\r
994                 {\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
999                         try {\r
1000                                 ds.setLoginTimeout(ConnectionTimeout);\r
1001                         }\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
1007                         }\r
1008                         return ds.getConnection();\r
1009                 }\r
1010 \r
1011                 internal virtual Connection GetConnectionFromJdbcDriver()\r
1012                 {\r
1013                         string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");\r
1014                         string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");\r
1015                 \r
1016                         string jdbcDriverName = ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr);\r
1017                         string jdbcUrl = ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr);\r
1018 \r
1019                         ActivateJdbcDriver(jdbcDriverName);\r
1020                         DriverManager.setLoginTimeout(ConnectionTimeout);\r
1021 \r
1022                         java.util.Properties properties = BuildProperties();\r
1023 \r
1024                         return DriverManager.getConnection(jdbcUrl,properties);\r
1025                 }\r
1026 \r
1027                 internal ArrayList GetProcedureColumns(String procedureString, AbstractDbCommand command)\r
1028                 {\r
1029                         ArrayList col = new ArrayList();\r
1030                         try {\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
1036                                                 \r
1037                                 DatabaseMetaData metadata = JdbcConnection.getMetaData();       \r
1038                                 bool storesUpperCaseIdentifiers = false;\r
1039                                 bool storesLowerCaseIdentifiers = false;\r
1040                                 try {\r
1041                                         storesUpperCaseIdentifiers = metadata.storesUpperCaseIdentifiers();\r
1042                                         storesLowerCaseIdentifiers = metadata.storesLowerCaseIdentifiers();\r
1043                                 }\r
1044                                 catch (SQLException e) {\r
1045                                         // suppress\r
1046                                 }\r
1047 \r
1048                                 for(int i=0; i < nameResolvers.Length; i++) {\r
1049                                         ObjectNameResolver nameResolver = nameResolvers[i];\r
1050                                         Match match = nameResolver.Match(procedureString);\r
1051 \r
1052                                         if (match.Success) {\r
1053                                                 spname = ObjectNameResolver.GetName(match);                             \r
1054                                                 schema = ObjectNameResolver.GetSchema(match);                                           \r
1055                                                 catalog = ObjectNameResolver.GetCatalog(match);                                         \r
1056 \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
1062                                                 }\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
1067                                                 }\r
1068                                                 else {\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
1072                                                 }\r
1073 \r
1074                                                 // catalog from db is always in correct caps\r
1075                                                 if (catalog == null) {\r
1076                                                         catalog = JdbcConnection.getCatalog();\r
1077                                                 }\r
1078 \r
1079                                                 try {\r
1080                                                         // always get the first procedure that db returns\r
1081                                                         res = metadata.getProcedures(catalog, schema, spname);                                                                                          \r
1082                                                         if (res.next()) {\r
1083                                                                 catalog = res.getString(1);\r
1084                                                                 schema = res.getString(2);\r
1085                                                                 spname = res.getString(3);\r
1086                                                                 break;\r
1087                                                         }\r
1088 \r
1089                                                         spname = null;\r
1090                                                 }\r
1091                                                 catch { // suppress exception\r
1092                                                         return null;\r
1093                                                 }\r
1094                                                 finally {\r
1095                                                         if (res != null) {\r
1096                                                                 res.close();\r
1097                                                         }\r
1098                                                 }\r
1099                                         }\r
1100                                 }       \r
1101                 \r
1102                                 if (spname == null || spname.Length == 0) {\r
1103                                         return null;\r
1104                                 }\r
1105                                 \r
1106                                 try {\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
1113                                                         continue;\r
1114                                                 }\r
1115 \r
1116                                                 AbstractDbParameter parameter = (AbstractDbParameter)command.CreateParameter();\r
1117                                                 \r
1118                                                 parameter.SetParameterName(res);\r
1119                                                 parameter.SetParameterDbType(res);\r
1120                                                 parameter.SetSpecialFeatures(res);\r
1121 \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
1132                                         \r
1133                                                 //get parameter precision and scale\r
1134                                                 parameter.SetParameterPrecisionAndScale(res);\r
1135 \r
1136                                                 parameter.SetParameterSize(res);\r
1137                                                 parameter.SetParameterIsNullable(res);\r
1138 \r
1139                                                 col.Add(parameter);\r
1140                                         }\r
1141                                 }\r
1142                                 finally {\r
1143                                         if (res != null) {\r
1144                                                 res.close();\r
1145                                         }\r
1146                                 }                               \r
1147                         }\r
1148                         catch(Exception e) {\r
1149                                 //supress\r
1150 #if DEBUG\r
1151                                 Console.WriteLine("Exception catched at AbstractDBConnection.GetProcedureColumns() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);\r
1152 #endif\r
1153                         }\r
1154                         return col;\r
1155                 }\r
1156 \r
1157                 protected static void ActivateJdbcDriver(string driver)\r
1158                 {\r
1159                         if(driver != null) {\r
1160                                 try {\r
1161                                         java.lang.Class.forName(driver).newInstance();\r
1162                                 }\r
1163                                 catch (java.lang.ClassNotFoundException e) {\r
1164                                         throw new TypeLoadException(e.Message);\r
1165                                 }\r
1166                                 catch (java.lang.InstantiationException e) {\r
1167                                         throw new MemberAccessException(e.Message);\r
1168                                 }\r
1169                 catch (java.lang.IllegalAccessException e) {\r
1170                                         throw new MissingMethodException(e.Message);\r
1171                                 }\r
1172                         }\r
1173                 }\r
1174 \r
1175                 protected String BuildMsSqlUrl()\r
1176                 {\r
1177                         return StringManager.GetString("SQL_JDBC_URL") //"jdbc:microsoft:sqlserver://"\r
1178                                 + ServerName + ":" + Port + ";DatabaseName=" + CatalogName;\r
1179                 }\r
1180 \r
1181                 #endregion // Methods   \r
1182         }\r
1183 }