2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Data / Mainsoft.Data.Jdbc.Providers.jvm / OleDbSqlServerProvider.cs
blob6995c54c4a580a56f9137baf2a2c2179688f1975
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 //
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.
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;
39 using java.net;
40 using System.Globalization;
42 namespace Mainsoft.Data.Jdbc.Providers
44 #region OleDbSqlServerProvider2000
46 public class OleDbSqlServerProvider2000 : GenericProvider
48 #region Consts
50 private const string Port = "Port";
51 private const string DefaultInstanceName = "MSSQLSERVER";
52 private const int DefaultTimeout = 15;
54 #endregion //Consts
56 #region Fields
58 #endregion // Fields
60 #region Constructors
62 public OleDbSqlServerProvider2000 (IDictionary providerInfo) : base (providerInfo)
66 #endregion // Constructors
68 #region Properties
70 #endregion // Properties
72 #region Methods
74 public override IConnectionStringDictionary GetConnectionStringBuilder (string connectionString)
76 //TBD: should wrap the IConnectionStringDictionary
77 IConnectionStringDictionary conectionStringBuilder = base.GetConnectionStringBuilder (connectionString);
78 OleDbSqlHelper.InitConnectionStringBuilder (conectionStringBuilder);
80 string port = (string) conectionStringBuilder [Port];
81 if (port == null || port.Length == 0) {
82 port = GetMSSqlPort (OleDbSqlHelper.GetInstanceName (conectionStringBuilder, DefaultInstanceName), OleDbSqlHelper.GetDataSource (conectionStringBuilder), OleDbSqlHelper.GetTimeout (conectionStringBuilder, DefaultTimeout));
83 conectionStringBuilder.Add (Port, port);
86 return conectionStringBuilder;
89 static string GetMSSqlPort(string instanceName, string dataSource, int timeout) {
90 string port = String.Empty;
91 try {
92 DatagramSocket socket = new DatagramSocket();
94 // send request
95 sbyte[] buf = new sbyte[] {2};
96 InetAddress address = InetAddress.getByName(dataSource);
97 DatagramPacket packet = new DatagramPacket(buf, buf.Length, address, 1434);
98 socket.send(packet);
99 sbyte[] recbuf = new sbyte[1024];
100 packet = new DatagramPacket(recbuf, recbuf.Length, packet.getAddress(), packet.getPort());
102 // try to receive from socket while increasing timeouts in geometric progression
103 int iterationTimeout = 1;
104 int totalTimeout = 0;
105 for(;;) {
106 socket.setSoTimeout(iterationTimeout);
107 try {
108 socket.receive(packet);
109 break;
111 catch (SocketTimeoutException e) {
112 totalTimeout += iterationTimeout;
113 iterationTimeout *= 2;
114 if (totalTimeout >= timeout*1000) {
115 throw new java.sql.SQLException(
116 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)
121 sbyte[] rcvdSbytes = packet.getData();
122 char[] rcvdChars = new char[rcvdSbytes.Length];
123 for(int i=0; i < rcvdSbytes.Length; i++) {
124 rcvdChars[i] = (char)rcvdSbytes[i];
126 String received = new String(rcvdChars);
128 java.util.StringTokenizer st = new java.util.StringTokenizer(received, ";");
129 String prev = "";
130 bool instanceReached = instanceName == null || instanceName.Length == 0;
131 while (st.hasMoreTokens()) {
132 if (!instanceReached) {
133 if (prev.Trim().Equals("InstanceName")) {
134 if (String.Compare(instanceName,st.nextToken().Trim(),true, CultureInfo.InvariantCulture) == 0) {
135 instanceReached = true;
139 else {
140 if (prev.Trim().Equals("tcp")) {
141 port = st.nextToken().Trim();
142 //ensure we got a valid int
143 java.lang.Integer.parseInt(port);
144 break;
147 prev = st.nextToken();
149 socket.close();
151 if (!instanceReached)
152 throw new java.sql.SQLException(
153 String.Format ("Specified SQL Server '{0}\\{1}' not found.", dataSource, instanceName)
155 return port;
158 catch (java.sql.SQLException) {
159 throw;
161 catch (Exception e) {
162 throw new java.sql.SQLException(e.Message);
166 #endregion // Methods
169 #endregion // OleDbSqlServerProvider2000
171 #region OleDbSqlServerProvider2005
173 public class OleDbSqlServerProvider2005 : GenericProvider
175 #region Consts
177 #endregion //Consts
179 #region Fields
181 #endregion // Fields
183 #region Constructors
185 public OleDbSqlServerProvider2005 (IDictionary providerInfo) : base (providerInfo)
189 #endregion // Constructors
191 #region Properties
193 #endregion // Properties
195 #region Methods
197 public override IConnectionStringDictionary GetConnectionStringBuilder (string connectionString)
199 //TBD: should wrap the IConnectionStringDictionary
200 IConnectionStringDictionary conectionStringBuilder = base.GetConnectionStringBuilder (connectionString);
201 OleDbSqlHelper.InitConnectionStringBuilder (conectionStringBuilder);
202 return conectionStringBuilder;
205 public override java.sql.Connection GetConnection(IConnectionStringDictionary conectionStringBuilder)
207 return new SqlServer2005Connection (base.GetConnection (conectionStringBuilder));
210 #endregion // Methods
212 #region SqlServer2005Connection
214 sealed class SqlServer2005Connection : Connection
216 #region Constructors
218 public SqlServer2005Connection(java.sql.Connection connection) : base (connection)
222 #endregion
224 #region Methods
226 public override java.sql.DatabaseMetaData getMetaData()
228 return new SqlServer2005DatabaseMetaData (base.getMetaData ());
231 #endregion
234 #endregion
236 #region SqlServer2005DatabaseMetaData
238 sealed class SqlServer2005DatabaseMetaData : DatabaseMetaData
240 #region Fields
242 #endregion // Fields
244 #region Constructors
246 public SqlServer2005DatabaseMetaData (java.sql.DatabaseMetaData databaseMetaData) : base (databaseMetaData)
250 #endregion // Constructors
252 #region Properties
254 #endregion // Properties
256 #region Methods
258 public override java.sql.ResultSet getProcedureColumns(string arg_0, string arg_1, string arg_2, string arg_3)
260 return new SqlServer2005DatbaseMetaDataResultSet (Wrapped.getProcedureColumns (arg_0, arg_1, arg_2, arg_3));
263 #endregion // Methods
266 #endregion
268 #region SqlServer2005DatbaseMetaDataResultSet
270 sealed class SqlServer2005DatbaseMetaDataResultSet : ResultSet
272 #region Consts
274 private const string DataType = "DATA_TYPE";
276 #endregion
278 #region Fields
280 #endregion // Fields
282 #region Constructors
284 public SqlServer2005DatbaseMetaDataResultSet (java.sql.ResultSet resultSet) : base (resultSet)
288 #endregion // Constructors
290 #region Properties
292 #endregion // Properties
294 #region Methods
296 public override int getInt(int arg_0)
298 int res = base.getInt (arg_0);
299 if (res == -9) // sql server 2005 jdbc driver value for NVARCHAR
300 if (String.CompareOrdinal (getMetaData ().getColumnName (arg_0), DataType) == 0)
301 return java.sql.Types.VARCHAR;
302 if (res == -8) // sql server 2005 jdbc driver value for NVARCHAR
303 if (String.CompareOrdinal (getMetaData ().getColumnName (arg_0), DataType) == 0)
304 return java.sql.Types.CHAR;
305 return res;
308 public override int getInt(string arg_0)
310 int res = base.getInt (arg_0);
312 if (res == -9) // sql server 2005 jdbc driver value for NVARCHAR
313 if (String.CompareOrdinal (arg_0, DataType) == 0)
314 return java.sql.Types.VARCHAR;
316 if (res == -8) // sql server 2005 jdbc driver value for NVARCHAR
317 if (String.CompareOrdinal (arg_0, DataType) == 0)
318 return java.sql.Types.CHAR;
319 return res;
322 #endregion // Methods
325 #endregion
328 #endregion // OleDbSqlServerProvider2005
330 #region OleDbSqlHelper
332 class OleDbSqlHelper
334 private const string Database = "Database";
335 private const string ServerName = "ServerName";
336 private const string Timeout = "Timeout";
338 internal static void InitConnectionStringBuilder (IConnectionStringDictionary conectionStringBuilder)
340 if (!conectionStringBuilder.Contains("jndi-datasource-name")) {
342 string database = (string) conectionStringBuilder [Database];
343 if (database == null)
344 conectionStringBuilder.Add (Database, String.Empty);
346 string dataSource = GetDataSource (conectionStringBuilder);
347 string instanceName = GetInstanceName (conectionStringBuilder, null);
349 if (instanceName != null)
350 conectionStringBuilder [ServerName] = dataSource + "\\" + instanceName;
351 else
352 conectionStringBuilder [ServerName] = dataSource;
356 // TBD : refactor GetInstanceName and GetDataSource to single method
357 internal static string GetInstanceName (IDictionary keyMapper, string defaultInstanceName)
359 string dataSource = (string) keyMapper [ServerName];
360 string instanceName = String.Empty;
361 int instanceIdx;
362 if (dataSource == null || (instanceIdx = dataSource.IndexOf ("\\")) == -1)
363 // no named instance specified - use a default name
364 return defaultInstanceName;
365 else
366 // get named instance name
367 return dataSource.Substring (instanceIdx + 1);
370 internal static string GetDataSource (IDictionary keyMapper)
372 string dataSource = (string) keyMapper [ServerName];
373 int instanceIdx;
374 if (dataSource != null && (instanceIdx = dataSource.IndexOf ("\\")) != -1)
375 // throw out named instance name
376 dataSource = dataSource.Substring (0,instanceIdx);
378 if (dataSource != null && dataSource.StartsWith ("(") && dataSource.EndsWith (")"))
379 dataSource = dataSource.Substring (1,dataSource.Length - 2);
381 if (String.Empty.Equals (dataSource) || (String.Compare ("local", dataSource, true, CultureInfo.InvariantCulture) == 0) || (String.CompareOrdinal (".", dataSource) == 0))
382 dataSource = "localhost";
384 return dataSource;
387 internal static int GetTimeout (IDictionary keyMapper, int defaultTimeout)
389 string timeoutStr = (string) keyMapper [Timeout];
390 if ((timeoutStr != null) && (timeoutStr.Length != 0)) {
391 try {
392 return Convert.ToInt32(timeoutStr);
394 catch(FormatException e) {
395 throw ExceptionHelper.InvalidValueForKey("connect timeout");
397 catch (OverflowException e) {
398 throw ExceptionHelper.InvalidValueForKey("connect timeout");
401 return defaultTimeout;
405 #endregion // OleDbSqlHelper