2 // System.Data.OleDb.OleDbConnection
5 // Konstantin Triger <kostat@mainsoft.com>
6 // Boris Kirzner <borisk@mainsoft.com>
8 // (C) 2006 Mainsoft Corporation (http://www.mainsoft.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Data.Common;
35 using System.Data.Configuration;
36 using System.Data.ProviderBase;
37 using Mainsoft.Data.Configuration;
41 namespace Mainsoft.Data.Jdbc.Providers
43 #region OleDbSqlServerProvider2000
45 public class OleDbSqlServerProvider2000 : GenericProvider
49 private const string Port = "Port";
50 private const string DefaultInstanceName = "MSSQLSERVER";
51 private const int DefaultTimeout = 15;
61 public OleDbSqlServerProvider2000 (IDictionary providerInfo) : base (providerInfo)
65 #endregion // Constructors
69 #endregion // Properties
73 public override IConnectionStringDictionary GetConnectionStringBuilder (string connectionString)
75 //TBD: should wrap the IConnectionStringDictionary
76 IConnectionStringDictionary conectionStringBuilder = base.GetConnectionStringBuilder (connectionString);
77 OleDbSqlHelper.InitConnectionStringBuilder (conectionStringBuilder);
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);
85 return conectionStringBuilder;
88 static string GetMSSqlPort(string instanceName, string dataSource, int timeout) {
89 string port = String.Empty;
91 DatagramSocket socket = new DatagramSocket();
94 sbyte[] buf = new sbyte[] {2};
95 InetAddress address = InetAddress.getByName(dataSource);
96 DatagramPacket packet = new DatagramPacket(buf, buf.Length, address, 1434);
98 sbyte[] recbuf = new sbyte[1024];
99 packet = new DatagramPacket(recbuf, recbuf.Length, packet.getAddress(), packet.getPort());
101 // try to receive from socket while increasing timeouts in geometric progression
102 int iterationTimeout = 1;
103 int totalTimeout = 0;
105 socket.setSoTimeout(iterationTimeout);
107 socket.receive(packet);
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)
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];
125 String received = new String(rcvdChars);
127 java.util.StringTokenizer st = new java.util.StringTokenizer(received, ";");
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;
139 if (prev.Trim().Equals("tcp")) {
140 port = st.nextToken().Trim();
141 //ensure we got a valid int
142 java.lang.Integer.parseInt(port);
146 prev = st.nextToken();
150 if (!instanceReached)
151 throw new java.sql.SQLException(
152 String.Format ("Specified SQL Server '{0}\\{1}' not found.", dataSource, instanceName)
157 catch (java.sql.SQLException) {
160 catch (Exception e) {
161 throw new java.sql.SQLException(e.Message);
165 #endregion // Methods
168 #endregion // OleDbSqlServerProvider2000
170 #region OleDbSqlServerProvider2005
172 public class OleDbSqlServerProvider2005 : GenericProvider
184 public OleDbSqlServerProvider2005 (IDictionary providerInfo) : base (providerInfo)
188 #endregion // Constructors
192 #endregion // Properties
196 public override IConnectionStringDictionary GetConnectionStringBuilder (string connectionString)
198 //TBD: should wrap the IConnectionStringDictionary
199 IConnectionStringDictionary conectionStringBuilder = base.GetConnectionStringBuilder (connectionString);
200 OleDbSqlHelper.InitConnectionStringBuilder (conectionStringBuilder);
201 return conectionStringBuilder;
204 public override java.sql.Connection GetConnection(IConnectionStringDictionary conectionStringBuilder)
206 return new SqlServer2005Connection (base.GetConnection (conectionStringBuilder));
209 #endregion // Methods
211 #region SqlServer2005Connection
213 sealed class SqlServer2005Connection : Connection
217 public SqlServer2005Connection(java.sql.Connection connection) : base (connection)
225 public override java.sql.DatabaseMetaData getMetaData()
227 return new SqlServer2005DatabaseMetaData (base.getMetaData ());
235 #region SqlServer2005DatabaseMetaData
237 sealed class SqlServer2005DatabaseMetaData : DatabaseMetaData
245 public SqlServer2005DatabaseMetaData (java.sql.DatabaseMetaData databaseMetaData) : base (databaseMetaData)
249 #endregion // Constructors
253 #endregion // Properties
257 public override java.sql.ResultSet getProcedureColumns(string arg_0, string arg_1, string arg_2, string arg_3)
259 return new SqlServer2005DatbaseMetaDataResultSet (Wrapped.getProcedureColumns (arg_0, arg_1, arg_2, arg_3));
262 #endregion // Methods
267 #region SqlServer2005DatbaseMetaDataResultSet
269 sealed class SqlServer2005DatbaseMetaDataResultSet : ResultSet
273 private const string DataType = "DATA_TYPE";
283 public SqlServer2005DatbaseMetaDataResultSet (java.sql.ResultSet resultSet) : base (resultSet)
287 #endregion // Constructors
291 #endregion // Properties
295 public override int getInt(int arg_0)
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;
307 public override int getInt(string arg_0)
309 int res = base.getInt (arg_0);
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;
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;
321 #endregion // Methods
327 #endregion // OleDbSqlServerProvider2005
329 #region OleDbSqlHelper
333 private const string Database = "Database";
334 private const string ServerName = "ServerName";
335 private const string Timeout = "Timeout";
337 internal static void InitConnectionStringBuilder (IConnectionStringDictionary conectionStringBuilder)
339 if (!conectionStringBuilder.Contains("jndi-datasource-name")) {
341 string database = (string) conectionStringBuilder [Database];
342 if (database == null)
343 conectionStringBuilder.Add (Database, String.Empty);
345 string dataSource = GetDataSource (conectionStringBuilder);
346 string instanceName = GetInstanceName (conectionStringBuilder, null);
348 if (instanceName != null)
349 conectionStringBuilder [ServerName] = dataSource + "\\" + instanceName;
351 conectionStringBuilder [ServerName] = dataSource;
355 // TBD : refactor GetInstanceName and GetDataSource to single method
356 internal static string GetInstanceName (IDictionary keyMapper, string defaultInstanceName)
358 string dataSource = (string) keyMapper [ServerName];
359 string instanceName = String.Empty;
361 if ((instanceIdx = dataSource.IndexOf ("\\")) == -1)
362 // no named instance specified - use a default name
363 return defaultInstanceName;
365 // get named instance name
366 return dataSource.Substring (instanceIdx + 1);
369 internal static string GetDataSource (IDictionary keyMapper)
371 string dataSource = (string) keyMapper [ServerName];
373 if ((instanceIdx = dataSource.IndexOf ("\\")) != -1)
374 // throw out named instance name
375 dataSource = dataSource.Substring (0,instanceIdx);
377 if (dataSource != null && dataSource.StartsWith ("(") && dataSource.EndsWith (")"))
378 dataSource = dataSource.Substring (1,dataSource.Length - 2);
380 if (String.Empty.Equals (dataSource) || (String.Compare ("local",dataSource,true) == 0))
381 dataSource = "localhost";
386 internal static int GetTimeout (IDictionary keyMapper, int defaultTimeout)
388 string timeoutStr = (string) keyMapper [Timeout];
389 if ((timeoutStr != null) && (timeoutStr.Length != 0)) {
391 return Convert.ToInt32(timeoutStr);
393 catch(FormatException e) {
394 throw ExceptionHelper.InvalidValueForKey("connect timeout");
396 catch (OverflowException e) {
397 throw ExceptionHelper.InvalidValueForKey("connect timeout");
400 return defaultTimeout;
404 #endregion // OleDbSqlHelper