Kill all executable flags on *.cs and ChangeLog files.
[mono.git] / mcs / class / System.Data / Mainsoft.Data.Jdbc.Providers.jvm / OleDbSqlServerProvider.cs
1 //
2 // System.Data.OleDb.OleDbConnection
3 //
4 // Authors:
5 //      Konstantin Triger <kostat@mainsoft.com>
6 //      Boris Kirzner <borisk@mainsoft.com>
7 //      
8 // (C) 2006 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 //
31
32 using System;
33 using System.Collections;
34 using System.Data.Common;
35 using System.Data.Configuration;
36 using System.Data.ProviderBase;
37 using Mainsoft.Data.Configuration;
38
39 using java.net;
40
41 namespace Mainsoft.Data.Jdbc.Providers
42 {
43         #region OleDbSqlServerProvider2000
44
45         public class OleDbSqlServerProvider2000 : GenericProvider
46         {
47                 #region Consts
48
49                 private const string Port = "Port";
50                 private const string DefaultInstanceName = "MSSQLSERVER";
51                 private const int DefaultTimeout = 15;
52
53                 #endregion //Consts
54
55                 #region Fields
56
57                 #endregion // Fields
58
59                 #region Constructors
60
61                 public OleDbSqlServerProvider2000 (IDictionary providerInfo) : base (providerInfo)
62                 {
63                 }
64
65                 #endregion // Constructors
66
67                 #region Properties
68
69                 #endregion // Properties
70
71                 #region Methods
72
73                 public override IConnectionStringDictionary GetConnectionStringBuilder (string connectionString)
74                 {
75                         //TBD: should wrap the IConnectionStringDictionary
76                         IConnectionStringDictionary conectionStringBuilder = base.GetConnectionStringBuilder (connectionString);
77                         OleDbSqlHelper.InitConnectionStringBuilder (conectionStringBuilder);
78                         
79                         string port = (string) conectionStringBuilder [Port];
80                         if (port == null || port.Length == 0) {
81                                 port = GetMSSqlPort (OleDbSqlHelper.GetInstanceName (conectionStringBuilder, DefaultInstanceName), OleDbSqlHelper.GetDataSource (conectionStringBuilder), OleDbSqlHelper.GetTimeout (conectionStringBuilder, DefaultTimeout));
82                                 conectionStringBuilder.Add (Port, port);
83                         }
84
85                         return conectionStringBuilder;
86                 }
87
88                 static string GetMSSqlPort(string instanceName, string dataSource, int timeout) {
89                         string port = String.Empty;
90                         try {
91                                 DatagramSocket socket = new DatagramSocket();
92
93                                 // send request
94                                 sbyte[] buf = new sbyte[] {2};
95                                 InetAddress address = InetAddress.getByName(dataSource);
96                                 DatagramPacket packet = new DatagramPacket(buf, buf.Length, address, 1434);
97                                 socket.send(packet);
98                                 sbyte[] recbuf = new sbyte[1024];
99                                 packet = new DatagramPacket(recbuf, recbuf.Length, packet.getAddress(), packet.getPort());
100
101                                 // try to receive from socket while increasing timeouts in geometric progression
102                                 int iterationTimeout = 1;
103                                 int totalTimeout = 0;
104                                 for(;;) {
105                                         socket.setSoTimeout(iterationTimeout);
106                                         try {
107                                                 socket.receive(packet);
108                                                 break;
109                                         }
110                                         catch (SocketTimeoutException e) {
111                                                 totalTimeout += iterationTimeout;
112                                                 iterationTimeout *= 2;
113                                                 if (totalTimeout >= timeout*1000) {
114                                                         throw new java.sql.SQLException(
115                                                                 String.Format ("Unable to retrieve the port number for {0} using UDP on port 1434. Please see your network administrator to solve this problem or add the port number of your SQL server instance to your connection string (i.e. port=1433).", dataSource)
116                                                                 );
117                                                 }
118                                         }
119                                 }
120                                 sbyte[] rcvdSbytes = packet.getData();
121                                 char[] rcvdChars = new char[rcvdSbytes.Length];
122                                 for(int i=0; i < rcvdSbytes.Length; i++) {
123                                         rcvdChars[i] = (char)rcvdSbytes[i];
124                                 }
125                                 String received = new String(rcvdChars);
126
127                                 java.util.StringTokenizer st = new java.util.StringTokenizer(received, ";");
128                                 String prev = "";
129                                 bool instanceReached = instanceName == null || instanceName.Length == 0;
130                                 while (st.hasMoreTokens()) {
131                                         if (!instanceReached) {
132                                                 if (prev.Trim().Equals("InstanceName")) {
133                                                         if (String.Compare(instanceName,st.nextToken().Trim(),true) == 0) {
134                                                                 instanceReached = true;
135                                                         }
136                                                 }
137                                         }
138                                         else {
139                                                 if (prev.Trim().Equals("tcp")) {
140                                                         port = st.nextToken().Trim();
141                                                         //ensure we got a valid int
142                                                         java.lang.Integer.parseInt(port);
143                                                         break;
144                                                 }
145                                         }
146                                         prev = st.nextToken();
147                                 }
148                                 socket.close();
149
150                                 if (!instanceReached)
151                                         throw new java.sql.SQLException(
152                                                 String.Format ("Specified SQL Server '{0}\\{1}' not found.", dataSource, instanceName)
153                                                 );
154                                 return port;
155
156                         }
157                         catch (java.sql.SQLException) {
158                                 throw;
159                         }
160                         catch (Exception e) {
161                                 throw new java.sql.SQLException(e.Message);
162                         }
163                 }
164
165                 #endregion // Methods
166         }
167
168         #endregion // OleDbSqlServerProvider2000
169
170         #region OleDbSqlServerProvider2005
171
172         public class OleDbSqlServerProvider2005 : GenericProvider
173         {
174                 #region Consts
175
176                 #endregion //Consts
177
178                 #region Fields
179
180                 #endregion // Fields
181
182                 #region Constructors
183
184                 public OleDbSqlServerProvider2005 (IDictionary providerInfo) : base (providerInfo)
185                 {
186                 }
187
188                 #endregion // Constructors
189
190                 #region Properties
191
192                 #endregion // Properties
193
194                 #region Methods
195
196                 public override IConnectionStringDictionary GetConnectionStringBuilder (string connectionString)
197                 {
198                         //TBD: should wrap the IConnectionStringDictionary
199                         IConnectionStringDictionary conectionStringBuilder = base.GetConnectionStringBuilder (connectionString);
200                         OleDbSqlHelper.InitConnectionStringBuilder (conectionStringBuilder);
201                         return conectionStringBuilder;
202                 }               
203                 
204                 public override java.sql.Connection GetConnection(IConnectionStringDictionary conectionStringBuilder)
205                 {
206                         return new SqlServer2005Connection (base.GetConnection (conectionStringBuilder));
207                 }
208
209                 #endregion // Methods
210
211                 #region SqlServer2005Connection
212
213                 sealed class SqlServer2005Connection : Connection
214                 {
215                         #region Constructors
216
217                         public SqlServer2005Connection(java.sql.Connection connection) : base (connection)
218                         {
219                         }
220
221                         #endregion
222
223                         #region Methods
224
225                         public override java.sql.DatabaseMetaData getMetaData()
226                         {
227                                 return new SqlServer2005DatabaseMetaData (base.getMetaData ());
228                         }
229
230                         #endregion
231                 }
232
233                 #endregion
234
235                 #region SqlServer2005DatabaseMetaData
236
237                 sealed class SqlServer2005DatabaseMetaData : DatabaseMetaData
238                 {
239                         #region Fields
240
241                         #endregion // Fields
242
243                         #region Constructors
244
245                         public SqlServer2005DatabaseMetaData (java.sql.DatabaseMetaData databaseMetaData) : base (databaseMetaData)
246                         {
247                         }
248
249                         #endregion // Constructors
250
251                         #region Properties
252
253                         #endregion // Properties
254
255                         #region Methods
256
257                         public override java.sql.ResultSet getProcedureColumns(string arg_0, string arg_1, string arg_2, string arg_3)
258                         {
259                                 return new SqlServer2005DatbaseMetaDataResultSet (Wrapped.getProcedureColumns (arg_0, arg_1, arg_2, arg_3));
260                         }
261
262                         #endregion // Methods                                           
263                 }
264
265                 #endregion
266
267                 #region SqlServer2005DatbaseMetaDataResultSet
268
269                 sealed class SqlServer2005DatbaseMetaDataResultSet : ResultSet
270                 {
271                         #region Consts
272
273                         private const string DataType = "DATA_TYPE";
274
275                         #endregion
276
277                         #region Fields
278
279                         #endregion // Fields
280
281                         #region Constructors
282
283                         public SqlServer2005DatbaseMetaDataResultSet (java.sql.ResultSet resultSet) : base (resultSet)
284                         {
285                         }
286
287                         #endregion // Constructors
288
289                         #region Properties
290
291                         #endregion // Properties
292
293                         #region Methods
294
295                         public override int getInt(int arg_0)
296                         {
297                                 int res = base.getInt (arg_0);
298                                 if (res == -9) // sql server 2005 jdbc driver value for NVARCHAR
299                                         if (String.CompareOrdinal (getMetaData ().getColumnName (arg_0), DataType) == 0)
300                                                 return java.sql.Types.VARCHAR;
301                                 if (res == -8) // sql server 2005 jdbc driver value for NVARCHAR
302                                         if (String.CompareOrdinal (getMetaData ().getColumnName (arg_0), DataType) == 0)
303                                                 return java.sql.Types.CHAR;
304                                 return res;
305                         }
306
307                         public override int getInt(string arg_0)
308                         {
309                                 int res = base.getInt (arg_0);
310
311                                 if (res == -9) // sql server 2005 jdbc driver value for NVARCHAR
312                                         if (String.CompareOrdinal (arg_0, DataType) == 0)
313                                                 return java.sql.Types.VARCHAR;
314
315                                 if (res == -8) // sql server 2005 jdbc driver value for NVARCHAR
316                                         if (String.CompareOrdinal (arg_0, DataType) == 0)
317                                                 return java.sql.Types.CHAR;
318                                 return res;
319                         }
320
321                         #endregion // Methods   
322                 }
323
324                 #endregion
325         }
326
327         #endregion // OleDbSqlServerProvider2005
328
329         #region OleDbSqlHelper
330
331         class OleDbSqlHelper
332         {
333                 private const string Database = "Database";
334                 private const string ServerName = "ServerName";
335                 private const string Timeout = "Timeout";
336
337                 internal static void InitConnectionStringBuilder (IConnectionStringDictionary conectionStringBuilder)
338                 {
339                         if (!conectionStringBuilder.Contains("jndi-datasource-name")) {
340
341                                 string database = (string) conectionStringBuilder [Database];
342                                 if (database == null)
343                                         conectionStringBuilder.Add (Database, String.Empty);
344
345                                 string dataSource = GetDataSource (conectionStringBuilder);
346                                 string instanceName = GetInstanceName (conectionStringBuilder, null);
347
348                                 if (instanceName != null)
349                                         conectionStringBuilder [ServerName] = dataSource + "\\" + instanceName;
350                                 else
351                                         conectionStringBuilder [ServerName] = dataSource;                                               
352                         }
353                 }               
354
355                 // TBD : refactor GetInstanceName and GetDataSource to single method
356                 internal static string GetInstanceName (IDictionary keyMapper, string defaultInstanceName)
357                 {
358                         string dataSource = (string) keyMapper [ServerName];
359                         string instanceName = String.Empty;
360                         int instanceIdx;
361                         if ((instanceIdx = dataSource.IndexOf ("\\")) == -1) 
362                                 // no named instance specified - use a default name
363                                 return defaultInstanceName;
364                         else 
365                                 // get named instance name
366                                 return dataSource.Substring (instanceIdx + 1);
367                 }
368
369                 internal static string GetDataSource (IDictionary keyMapper)
370                 {
371                         string dataSource = (string) keyMapper [ServerName];
372                         int instanceIdx;
373                         if ((instanceIdx = dataSource.IndexOf ("\\")) != -1)
374                                 // throw out named instance name
375                                 dataSource = dataSource.Substring (0,instanceIdx);
376
377                         if (dataSource != null && dataSource.StartsWith ("(") && dataSource.EndsWith (")"))                                     
378                                 dataSource = dataSource.Substring (1,dataSource.Length - 2);
379
380                         if (String.Empty.Equals (dataSource) || (String.Compare ("local",dataSource,true) == 0)) 
381                                 dataSource = "localhost";
382
383                         return dataSource;
384                 }
385
386                 internal static int GetTimeout (IDictionary keyMapper, int defaultTimeout)
387                 {
388                         string timeoutStr = (string) keyMapper [Timeout];
389                         if ((timeoutStr != null) && (timeoutStr.Length != 0)) {
390                                 try {
391                                         return Convert.ToInt32(timeoutStr);
392                                 }
393                                 catch(FormatException e) {
394                                         throw ExceptionHelper.InvalidValueForKey("connect timeout");
395                                 }
396                                 catch (OverflowException e) {
397                                         throw ExceptionHelper.InvalidValueForKey("connect timeout");
398                                 }
399                         }
400                         return defaultTimeout;
401                 }
402         }
403
404         #endregion // OleDbSqlHelper
405
406 }